deobfuscation of obfuscated software kurucsai istván · final binary morpher is tightly coupled...

Post on 29-May-2020

11 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Deobfuscation of obfuscated software

Kurucsai István

Tartalom

● Bevezetés● Obfuszkáció típusai● Mit és hol?● Deobfuszkáció

– Szintaxis alapú módszerek

– Szemantikus módszerek

● Összefoglalás

Bevezetés

● Anti-reversing: programok visszafejtésének megnehezítése

– Az előadás keretében: natív Windows alkalmazások

● Motivációk:– Illegális szoftvermásolás akadályozása

– Kritikus/értékes algoritmusok védelme

– Kártékony kódok elrejtése

● Csak nehezítés, a visszafejtés időigényét és költségét növelhetjük

– Tökéletes védelem nem megvalósítható

Anti-reversing

● ~ ára– Kódméret növekedése

– Teljesítmény csökkenése

● Kompatibilitási kérdések– SecuROM

● Hatékonyság nehezen mérhető: mennyivel nehezebb visszafejteni a kódot?

– Embernek

– Automatikus eszközöknek

Anti-reversing módszerek

● Szimbólumok/debug információk eltávolítása– Natív alkalmazások esetén szinte mindig

megtörténik

– Bytecode alapú nyelveknél fontos

● Packerek/wrapperek (csomagolás)● Virtualizáció● Anti-debugging/disassembly/VM/dumping

trükkök ● Obfuszkáció● Gyakran együtt jelennek meg

Refused és Stubborn

● Önálló laboratórium keretében készített programok

● Refused: source-to-source transformer– Különböző obfuszkációs módszerek

● Stubborn: Windows PE packer

Kártékony kódok elrejtése (packerek)

Obfuszkáció

● A funkcionalitás megőrzése mellett a kód „összezavarása”, az olvashatóság csökkentése

– Layout obfuscations: szimbólumok és kommentek eltávolítása, formázás megváltoztatása

● Natív bináris készítésekor a fordító elvégzi

– Preventív transzformációk: a deobfuszkálásnál felhasznált eszközök esetleges gyengeségeinek kihasználása

Adat obfuszkáció

● A program által használt adatok struktúrája és a konstansok nagyban segítik a visszafejtést

Adat obfuszkáció

● Számos módszer– Tárolás és kódolás transzformációja

– Tömbök átszervezése (tömbök összevonása és szétválasztása, dimenziók számának növelése/csökkentése, elemek permutációja)

– A hatékonyság és általánosság hiánya illetve költségeik gyakran kérdésessé teszi az alkalmazhatóságukat

Konstansok védelme

● A konstansok védelme azonban egyszerű és hatásos lehet

● Hashelés– Amennyiben a konstanst csak egyenlőség

jellegű vizsgálatoknál használja a program és nincs szükség a konkrét értékére (==, !=, !strcmp, stb...)

– if (a == 24) helyett if (hash(a) == 356725135)

– A megfelelő hash kiválasztása● Ütközésmentesség: a program helyes műküdése● Egyirányúság: visszafejtés nehézsége

Konstansok védelme II

● Ha a konstans eredeti értékére is szükség van– Titkosítás majd futásidőben a használat előtt

ideiglenes dekódolás

– Stringek egyszerű (XOR, SUB) rejtjelezése

– Bonyolultabb algoritmusok, például blokkrejtjelezők alkalmazása nem jelent különösebb nehézséget, mert futásidőben úgyis megjelenik a konstans eredeti értéke és a kulcs is

Adat obfuszkáció

● Összességében– A konstansok védelme alapfunkciónak számít

– Az általánosabb adat obfuszkációs megoldások viszont kevésbé elterjedtek

● Nehéz az általános megvalósítás● Nagy overhead● Gyenge védelem

Control-flow obfuscation

● A program vezérlési struktúrájának összezavarása

● Sokat kutatott terület● A legtöbb obfuszkátor alapja

Opaque predicates (átlátszatlan feltételek)

● Olyan elágazás-feltételek, melyek mindig igazra vagy hamisra értékelődnek ki, de ezt nehéz belátni a visszafejtett programot vizsgálva

– Egyszerű példa: (x + x^2) % 2 == 0

– A hatásosság nagyban függ a predikátumok változatosságától és bonyolultságától

● Ilyen elágazásokat elhelyezve a programban annak vezérlésfolyama bonyolítható

Példa feltételek

Opaque predicates példa I (Refused)

Opaque predicates példa II

Opaque predicates példa III

Opaque predicates

● Platformfüggő feltételek– Kihasználva egyes operációs rendszerek vagy

API-k sajátosságait● Regiszter értéke a program indulásakor vagy

valamelyik API visszatérése után

– Erős feltételek hozhatóak létre

– Kompatibilitás hiánya

● Összességében:– Hatásos és egyszerű

– Jól kombinálható más módszerekkel

CFG flattening(vezérlési gráf kilapítása)

● Célja a vezérlésfolyam elrejtése● Függvény basic blockokra osztása● Eredetileg más mélységben lévő blokkok egy

szintre hozása– switch kifejezésben (kiválasztás)

– A blokkok végén a switch-et vezérlő változó megfelelő beállítása

– A kiválasztás ciklusba ágyazása

CFG flattening példa

CFG flattening példa II

Diablo CFG flattening

Apple FairPlay CFG flattening

Junk code insertion(szemét kód beszúrása)

● Do-nothing vagy do-little● Az ember számára olvashatatlan és

értelmezhetetlen kód automatizált eszközökkel gyakran hatékonyan kezelhető

Junk code példa

További vezérlésfolyam obfuszkációk

● CFG arches meshing● Inlining/outlining● Cloning of functions● Combined functions

Mit és hol?

● A cél a kimeneti bináris obfuszkációja● De az egyes módszerek alkalmazhatóak a

– fordítás különböző lépéseiben (forráskód, köztes reprezentáció, tárgykód)

– kész binárison is

Mit és hol? II

● Célszerű a legmegfelelőbb helyet kiválasztani minden transzformációhoz

– Packelés csak a kész binárison

– CFG kilapítása bármelyik lépésben

– Szemét kód● Ha a forrásba illesztjük, a fordító

kioptimalizálhatja● Ha a kész binárisba, ügyelni kell a

mellékhatásokra (regiszterek, különösen EFLAGS)

Opaque predicates példa I

Refused

● Source-to-source transformation● C/C++ kódok támogatása● Funkciók:

– Opaque predicates

– Szemét kód (félkész)

– CFG flattening (félkész)

Clang/LLVM

● C nehezen parse-olható, a C++ még nehezebben

● Az LLVM frontendjének felhasználása (Clang)– Transzformációk az abstract syntax tree-n

(AST)

Morpher

● „Morpher is a versatile and flexible automatic software transformation toolkit focused on protection of software algorithms. Despite of other software protection solutions on the market which operate only on the final binary Morpher is tightly coupled with the industry-standard C/C++ compiler and thus can exploit much more information about sources to be protected. Note that such information is normally lost during compilation and codegeneration.”

● Functions interleaving and merging;

● Opaque predicates insertion;

● Opaque variables insertion (generic framework used by other transformation passes);

● Automatic constants (e.g. string literals) protection and encryption;

● Code flow graph altering;

● LLVM optimalizációs lépésekként implementált – obfuscating compiler

Deobfuszkáció – szintaktikus vs. szemantikus módszerek

● Szintaxis-alapú: csak az objektumok formátumát figyelembe vevő módszerek

– Gépi kód / assembly utasítások bájtjainak sorozata, esetleges wildcardok

● Szemantikus: az objektumok jelentését is számításba vevő módszerek

– Az utasítások hatásai/mellékhatásai

Szintaxis-alapú módszerek

● Pro– Gyors (gyakorlatilag mintaillesztés)

– Néhány problémára remek megoldást jelentenek

● Con– Sok probléma egyáltalán nem oldható meg így

● Tipikus felhasználás:– Signatures: packer entrypoint, FLIRT, anti-virus

– Egyszerű deobfuszkáció

Szintaxis-alapú deobfuszkáció

● Amennyiben a transzformáció valamilyen felismerhető mintázatot tartalmaz

● Emulált jmp és call: push/ret

Szintaxis-alapú deobfuszkáció II

● A korábbi szemét kód példa:

Korlátok

● Mi történne, ha az előző példa tartalmazna – egy aritmetikai utasítást amire nem készültünk

fel?

– egy feltételes ugrást?

– egy átlátszatlan feltételt?

● A szintaxis-alapú módszerek hatékonyak bizonyos esetekben, de gyorsan korlátokba ütközünk

Szemantikus módszerek

● Az objektumok jelentését is számításba vevő módszerek

● Számos felhasználás a reverse engineering területén

– Automatikus kulcsgenerátor generálás :)

– Automatikus hibafelderítés

– (részben) generikus deobfuszkáció

● A program analízis akadémiai eredményeinek gyakorlatba való átültetése népszerű téma

Egy utasítás szemantikája...

● Az and (x86) utasítás köztes reprezentációja (IR - Intermediate Language translation)

Absztrakt interpretáció

● A program analízis klasszikus technikája● Bonyolult módszer, de alapja egyszerű

– Absztrakt állapot a konkrét helyett

– Absztrakt szemantika a konkrét helyett

● Egyszerű példa: váltózok előjelének meghatározása

– A változók konkrét értéke helyett csak előjelüket tartjuk nyilván

– Ennek megfelelően definiáljuk az egyes műveletek szemantikáját is

Absztrakt interpretáció példa

● Minden más információt figyelmen kívül hagyunk

Absztrakt interpretáció

● Gyakran arra vagyunk kíváncsiak, hogy egy adott pont a programban egy adott változó milyen értékeinél érhető el

● Erre a kérdésre ad választ a szimbolikus végrehajtás,

– Az absztrakt interpretáció speciális esete

Szimbolikus végrehajtás

● Minden elágazás korlátozza az értékkészletet valamilyen módon

SMT (Satisfiability Modulo Theories) solving

● Alapötlet: alakítsuk a kódot logikai formulákká, amelyeken aztán különböző tulajdonságokat bizonyíthatunk be illetve egyszerűsíthetjük

● Felhasználás: input generálás (input crafting)● Milyen értéket kell az eax regiszternek

tartalmaznia kezdetben, hogy a kód lefutása után értéke 0x12345678 legyen?

SMT solving

● A köztes reprezentációból készített SMT formula (Z3)

SMT solving II

● assert(T175d == 0x12345678);

● T175d eax végső értéke

● Sat => a formula kielégíthető

● A kimenet egy model, ami

kielégíti a formulát

● Az utolsó sorban eax értéke

Kryptonite● LLVM IR obfuszkátor

– Az összeadás utasítást lecseréli egy assemblyben megvalósított bitenkénti összeadóra

– Egy összeadásból 2000 sor assembly kód lesz

– Junk code insertion extrém esete

● Deobfuszkáció egy lehetséges megoldása:

– Szimbolikus végrehajtással meghatározzuk, hogy a függvény kimenete hogy függ a bemenetektől (a két összeadandó szám)

– Egy SMT megoldóval megpróbáljuk egyszerűsíteni az előző lépés végén kapott formulát

● Ha minden jól megy megkapjuk, hogy a kimenet minden esetben a két bement összege

Kryptonite I (szimbolikus végrehajtás)

● A szimbolikus végrehajtó motor működése:

– Szimbolikus változók tárolása (gyk. ha inicializálatlan területről találunk olvasást, akkor létrehozunk egy változót). Ezek a változók lesznek a bemenetek.

– Az egyes utasítások emulálása, az állapotok frissítése

– Az obfuszkátor sajátosságai miatt viszonylag egyszerű

Kryptonite II (SMT solving)

● A függvény végén kapott formula még az SMT solverrel való egyszerűsítés után sem túl barátságos

Kryptonite II (SMT solving)

● Miért?– Az SMT solver simplify funkciója többnyire

szintaktikus szabályok alapján dolgozik, túl bonyolult a kifejezés

● Azonban– prove(eax == Sum(sym.sym_variables))

– True

– Azaz: valóban összeadást végez a függvény

– De: ha ezt nem tudtuk volna előre, hogy jöttünk volna rá hogy mit kérdezzünk a solvertől?

– Nyitott kérdés

OptiCode

● Deobfuszkációs megoldás– Opaque predicates

– Junk code

● LLVM köztes reprezentáció● Z3 SMT solver● Részben manuális megoldás

OptiCode (junk code)

● A különböző fordítók optimalizáló és kódgeneráló részei folyamatosan fejlődnek.

● Kiválóan alkalmasak redundáns kódok eltávolítására

● Szintaktikus és szemantikus módszerek● Az obfuszkált kódot a fordító köztes

reprezentációjára konvertálva lefuttathatjuk rajta az optimalizációs lépéseket

● A kimenetet újra lefordítva tisztább kódot kapunk

OptiCode (opaque predicates) ● Dinamikus analízis● Átlátszatlan feltételek kiszűrése● Részben automatizált megoldás

– Az analízist végző plusz információkkal segíti az eszköz működését, illetve ellenőrzi a feltételek kiválasztását

● LLVM IR-ből az egyes feltételek SMT formuláinak meghatározása

● Z3 SMT solverrel a formulák vizsgálata● Amennyiben a feltétel mindig igaz vagy hamis,

csak a megfelelő ág követése

Összefoglalás - deobfuszkáció

● A szemantikus módszerek egyre nagyobb teret nyernek

● Aktív kutatási terület (illetve a kutatási eredmények gyakorlati felhasználása lendületesen halad)

● Tökéletes védelem nem létezik– De reális cél a visszafejtés költségeit jelentősen

növelni

● Kevés a jól használható és ingyenes eszköz● Sok nyitott kérdés

Kérdések?

Köszönöm a figyelmet!

Felhasznált források

http://www.wtbw.co.uk/semantics-based-methods.pdf

● http://doar-e.github.io/blog/2013/09/16/breaking-kryptonites-obfuscation-with-symbolic-execution/

● Binary-Code Obfuscations in Prevalent Packer Tools by KEVIN A. ROUNDY and BARTON P. MILLER

● http://www.inf.u-szeged.hu/~akiss/pub/pdf/laszlo_obfuscating.pdf

● http://blog.sei.cmu.edu/post.cfm/semantic-code-analysis-for-malware-code-deobfuscation

● http://www.data.proidea.org.pl/confidence/11edycja/NGUYEN_Anh_Quynh.pdf

top related