Nebojte se reverzního inženýrství I.

Tento článek by měl být úvodním dílem do problematiky reverzního inženýrství. Seriál by měl být koncipován tak, aby byl i naprostý začátečník schopen po jeho absolvování samostatně aplikovat reverzní inženýrství pro své vlastní potřeby.

Úvod
Reverzní inženýrství je obor, který se zabývá studiem principu fungování sledovaného objektu. Tímto objektem může být nejen software a hardware, ale také předměty běžného užívání (například motor automobilu). Reverzní inženýrství může sloužit k dobrým i ke špatným účelům. Je hojně využíváno při snaze vytvořit ekvivalentní kopii požadovaného předmětu, ale také při analýze škodlivého softwaru. My se dále budeme zabývat pouze reverzním inženýrstvím softwaru. Právní otázkou reverzního inženýrství se zabývat nebudu, protože osobně zastávám názor, že každý člověk by měl být schopný plně pochopit důsledky svého počínání. Já osobně nejsem schopný ovlivnit využití ze strany čtenářů.

Pro doplnění uvedu ještě několik organizačních informací: Reverzní inženýrství se zkráceně označuje jako RE nebo RCE. Já budu používat delší ze zkratek, tedy RCE. Jednotlivé postupy a techniky budou demonstrovány pouze a jen na programech k tomu určených, tak zvaných crackme, keygenme, patchme atd. Každý díl by měl být koncipován tak, že bude obsahovat nezbytnou teorii, která bude následně demonstrována na příkladu.

Prerekvizity
RCE je přesným opakem programování. Cílem je pochopit studovanou binárku na požadované úrovni (v požadovaném rozsahu). Pro tyto účely je nezbytně nutné dokázat číst kód v programovacím jazyce assembler. V některých případech si od assembleru můžeme odpočinout a transformovat kód do podoby jazyka C. Je tedy nezbytné znát minimálně jazyk assembler, v ideálním případě i jazyk C. Protože se soustředíme na platformu Windows, doporučuji si osvojit alespoň základní Windows API funkce, které jsou běžně využívány v programech na této platformě. Do budoucna rovněž doporučuji hlubší studium struktury operačního systému Windows. Ve většině případů se zatím bez znalosti ‚vnitřností‘ Windows obejdeme. Asi nejdůležitějším předpokladem pro RCE je výdrž. Ne vždy se během analýzy daří studovaný program plně pochopit okamžitě. Zvláště v případě, kdy je třeba identifikovat a pojmenovat složité struktury. Ve výsledku se klidně může stát, že podobná struktura zůstane zcela nepochopena, aniž by její neznalost jakkoliv ovlivnila běh/úpravu aplikace. Obecně je vhodné držet se pravidla: I neúspěch je vítězstvím, které tě posune dál.

Programy
RCE využívá celou škálu nejrůznějších druhů programů. Je důležité nepoužívat pouze jeden jediný druh programu z každé skupiny. Hlavním důvodem je fakt, že každý z těchto programů se chová trochu jinak a může tedy více či méně ulehčit práci s testovaným programem. Navíc existují postupy proti konkrétním programům, které znesnadňují nebo zcela znemožňují činnost daného programu.

Hexadecimální editory – Hex editory jsou programy, které umožňují staticky (bez spuštění studovaného programu) upravovat kód studovaného programu. Mezi nejznámější patří WinHex[1], někteří old school reverzeři pak používají dříve velmi populární Hiew[2].

Disassemblery – Jedná se o programy, jejichž cílem je transformovat binární kód do čitelné podoby, tedy do assembleru. Tato analýza probíhá staticky (bez spuštění studovaného programu). Nejznámnějšími zástupci této skupiny jsou IDA Pro[3], OllyDbg[4], Immunity Debugger[5] a W32DASM.

Debuggery – Debuggery můžeme chápat jako vyspělejší disassemblery. Nejenže aplikaci disassemblují. Provedou rovněž její analýzu a následně umožňují zkoumat tok programu krok za krokem. Tato analýza probíhá dynamicky (studovaný program již běží v paměti pod nadvládou debuggeru). Mezi nejznámější zástupce patří IDA Pro[3], WinDBG[6], OllyDbg[4], Immunity Debugger[5] a další.

Dekompilery – Dekompiler můžeme chápat jako pokročilý disassembler, který studovaný kód netransformuje do assembleru, ale pokouší se ho transformovat do vyššího jazyka. V případě strojového kódu většinou C. Protože je tento proces velice složitý a náročný, nemusí se konverze do C vždy povést. V případě jazyků využívajících takzvaný bytekód (například C#) se natransformace zpět do podoby C# povede déměř vždy na 100%. Mezi nejznámější dekompilery patří jednoznačně Hex-Rays Decompiler[7] nebo Boomerang Decompiler Project[8]. Pro jazyk C# se využívá například dotPeek[9] nebo ILSpy[10]. Rovněž existují speciální typy dekompilerů určených pro programy napsané například v programovacím jazyce Delphi. Zde je lídrem dekompiler DeDe[11].

API monitory – API monitory jsou specializované programy určené pro sledování volání konkrétních API funkcí. Reverzer tak může zjistit jaké hodnoty jsou API funkci předávány a jaká je výsledná výstupní hodnota. Tím se studium programu může občas velmi zjednodušit.

Process monitory – Jedná se o podobné programy jako v případě API monitorů s tím rozdílem, že sledují všechny procesy na daném stroji a umožňují jejich spravování. Nejznámější je ProcMon[12].

Registry monitory – Opět se jedná o podobné programy jako v případě API monitorů a Proces monitorů. Registry monitory kontrolují přístup k systémovým registrům a logují operace s nimi. Nejznámějším programem tohoto typu je RegMon[13].

PE editory – PE editory umožňují číst a upravovat tak zvané PE hlavičky (více o PE později). Ty je možné upravovat rovněž v debuggeru, disassembleru nebo hex editoru. Ale PE editor je přímo určen pro snadnou čitelnost a manipulaci s PE a proto se pro tyto účely hodí víc.

Dekompresory/Dekryptory – Jsou aplikace, které umí ‚rozbalit‘ komprimovaný/kryptovaný program. Ve většině případů musí aplikace daný komprimační/kryprovací algoritmus správně detekovat, jinak dekompresi/dekryptování neprovede.

Dumpery – Programy slouží pro dumpování paměti. Tento typ programu je hojně využíván v případě komprimovaných/kryptovaných programů neznámým algoritmem.

Existuje celá řada dalších pomůcek a nástrojů, které může reverzer úspěšně použít. Záleží pouze na vkusu a preferencích jednotlivců. Jako velmi výhodná se rovněž jeví možnost implementace modulů pro některé z nejpoužívanějších programů, čímž je možné efektivně rozšířit schopnosti tohoto programu.

Atomické základy assembleru
Nemá hlubší smysl psát komplexní tutoriál k jazyku assembler. Popíšeme si pouze základní instrukce. Pro hlubší studium doporučuji výbornou knihu Art of Assembly[14], v češtině pak vyšla kniha Mistrovství v jazyce assembler[15]. Ta je však již několik let nedostupná. Občas se však objeví v aukcích nebo antikvariátech. Z webových tutoriálu bych doporučil sérii na tutorialspoint.com[16].

32-bitová architektura Intel má 9 základních/obecných (general) registrů (ve skutečnosti je jich 8 – devátý má speciální význam). Registr EAX, EBX, ECX, EDX, ESI, EDI, ESP, EBP, EIP. Každý z těchto registrů má velikost právě 32 bitů a je dělitelný na menší bloky a to buď 16-bitové nebo 8-bitové. Každý 32-bitový registr má přímo přístupný jeden 16-bitový registr, který je jeho podmnožinou. Máme tedy 16-bitové registry AX, BX, CX, DX, SI, DI, SP, BP. Pokud tedy máme v registru EAX hodnotu 76543210h, pak přímo přístupná přes registr AX bude hodnota 3210h. Pro představu: Pouze vezmeme hodnotu 76543210h a rozdělíme ji na polovinu: 7654h a 3210h. K horní polovině nemáme přímý přístup, protože neexistuje žádný registr, přes který bychom si tuto hodnotu mohli vyzvednout. 16-bitové registry AX, BX, CX, DX jsou dále dělitelné na dva 8-bitové registry. 16-bitový registr AX má dva 8-bitové podregistry AH a AL. Tím jsme schopni přímo přistupovat jak k horní polovině 16-bitové hodnoty, tak k té dolní. To je mnohem výhodnější než v případě 32-bitového registru, kde tuto možnost nemáme. Pro výše zmíněnou hodnotu EAX 76543210h mají registry AH a AL hodnotu 32h a 10h (vezmeme počáteční hodnotu a rozdělíme ji na dvě 16-bitové hodnoty 7654h a 3210h, a následně hodnotu 3210h rozdělíme na dvě 8-bitové hodnoty 32h a 10h, což jsou právě hodnoty registrů AH (32h) a AL (10h)). Máme tedy následující 8-bitové registry: AH, AL, BH, BL, CH, CL, DH, DL. Teď asi většina čtenářů očekává půlení dalších registrů (tedy 16-bitových registrů SI, DI, SP, BP, IP). Tyto registry jsou však již nedělitelné. Jednoduše pro ně neexistují 8-bitové registry.
Názorně vypadá rozdělení pro registry EAX, EBX, ECX, EDX následovně:

+-----------------------------------------------+
|                       +----------------------+|
|                       |           AX         ||
|                       | +---------+---------+||
|          EAX          | |   AH    |    AL   |||
|                       | +---------+---------+||
|                       +----------------------+|
+-----------------------------------------------+

V případě registrů ESI, EDI, ESP, EBP pak následovně:

+-----------------------------------------------+
|                       +----------------------+|
|                       |                      ||       
|                       |           SI         ||
|          ESI          |                      ||
|                       |                      ||
|                       +----------------------+|
+-----------------------------------------------+

Každý 32-bitový registr si můžeme představit jako šuplík, do kterého se vejde 00000000h až FFFFFFFFh, to je desítkově 0 – 4294967295 (záměrně se vyhýbám znaménkovým hodnotám). Každý tento šuplík má zvláštní mechanismus, který se spustí v případě, kdy do tohoto šuplíku zkusíme natlačit o jednu věc víc než je jeho maximální velikost (tedy FFFFFFFFh). V tom případě dojde k aktivaci červí díry, která všechny věci okamžitě z tohoto šuplíku vycucne pryč a šuplík tak bude prázdný. A přesně to se děje i v registrech. Pokud se pokusíme k maximální hodnotě (tedy FFFFFFFFh) přičíst jedničku, dojde k takzvanému přetečení hodnoty, kdy nejvyšší bit se nemá kam zapsat, takže bude zahozen (v reálu zcela zahozen nebude, ale o tom až jindy 🙂 ) a ve registru se tak objeví nulová hodnota. Pokud se k maximální hodnotě (tedy FFFFFFFFh) pokusíme přičíst dvojku, nejvyšší bit bude zahozen a v registru se objeví hodnota 1, a tak dále.

Registry EAX, EBX, ECX, EDX a jejich podregistry se označují jako obecné registry. Registry ESI, EDI, ESP, EBP, EIP a jejich podregistry se označují jako indexové a pointerové registry. Kromě těchto registrů, se kterými budeme pracovat nejčastěji existují ještě takzvané segmentové registry. Jedná se o registry CS, DS, ES, FS, GS, SS. Tyto registry slouží k adresování konkrétních segmentů paměti. Můžeme si je představit jako město v poštovní adrese. Bydlím v Praze (segmentový registr) na Evropské 1 (obecný registr, přímá adresa nebo kombinace registr-index).

Aby toho nebylo málo, existuje ještě jedna skupina registrů. Těm se říká indikátory a mají poetické pojmenování EFLAGS. Tyto indikátory slouží k detekci určitých stavů během vykonávání programu. Příkladem může být porovnání dvou hodnot. Pokud jsou dvě hodnoty rovny, nastaví se takzvaný zero flag. My jsme pak schopni si tento zero flah přečíst a reagovat na vzniklý stav.

Zvláštní význam má registr EIP. Jako jediný není přímo zapisovatelný. Nedá se do něj přiřadit hodnota (ve skutečnosti to možné je, ale o tom až jindy). Tento registr ukazuje adresu aktuálně vykonávané instrukce. Z toho vyplývá, že tento registr se mění při každém kroku vykonávání programu bez ohledu na stav věci. Registr ESP se označuje jako stack pointer, neboli ukazatel stacku. Stack je zvláštní typ paměti, která slouží pro ukládání dat. Má tu zvláštnost, že ‚roste‘ shora dolů. To znamená, že každá hodnota, která je na stack uložena, sníží adresu stacku. Stack je struktura typu LIFO (Last In First Out). Když tedy nějakou hodnotu na stack uložíme, při vybírání vrcholu zásobníku (vrcholem zásobníku označujeme adresu s nejposlednější vloženou hodnotou) získáme poslední vloženou hodnotu. Příklad: Jestliže vložíme na zásobník hodnotu 5 a následně hodnotu 7, při výběru dat ze zásobníku získáme nejprve hodnotu 7 a následně hodnotu 5. Registr EBP je označován jako rámcový registr. Většina funkcí v assembleru vytváří takzvaný rámec. Tento rámec slouží k jasnějšímu a rychlejšímu adresování dat na zásobníku. Zjednodušeně řečeno: Některé funkce přebírají argumenty. Tyto argumenty jsou vloženy na zásobník před tím, než je vytvořen rámec funkce. Rámec funkce není nic jiného než aktuální adresa vrcholu zásobníku (obsah registru ESP). Proto se za tyto argumenty na stacku ‚zazálohuje‘ předchozí hodnota registru EBP a pak se do něj uloží hodnota ESP (tomuto rutinímu kódu se říká prolog funkce, na konci je pak potřeba obnovit původní hodnotu rámce, což je obrácený princip a označuje se jako epilog funkce). Když pak kdekoliv ve funkci budu chtít získat hodnoty argumentů, vím, že mi stačí použít hodnotu v registru EBP a přičíst k němu příslušný počet bajtů (detailněji později nebo samostudium 🙂 ). Registry ESI a EDI slouží jako indexy nebo ukazatele a nejčastěji jsou spojené s operacemi na textových řetězcích ve smyslu znakových polí. Registr ESI je zdrojový (source index – eSi) a registr EDI je cílový (destination index – eDi). Registry EAX, EBX, ECX, EDX pak slouží jako registry pro běžné výpočty. V některých případech mají svůj specifický význam, ale obecně je možné použít je pro všechno.

Pro případy, kdy potřebujeme alokovat paměť dynamicky,je tato paměť alokována na takzvaném heapu (česky haldě).

Tím bych dnešní bohapustou teorii ukončil, abych hned z rozjezdu neodradil příliš mnoho lidí 🙂 A pojďme na Crackme 🙂

Crackme
crackme1
Zdrojový kód crackme1
Dobře. Spustíme si OllyDbg (já používám výhradně verzi 1.10) a otevřeme si v něm Crackme (File->Open nebo F3). Prakticky okamžitě vidíme kód programu transformovaný do assembleru. Vypadá následovně:

00401000 >/$ B8 00000000       MOV EAX,0
00401005  |. 83F8 01           CMP EAX,1
00401008  |. 74 0C             JE SHORT crackme1.00401016
0040100A  |. B8 14304000       MOV EAX,crackme1.00403014                    ;  ASCII "Please patch me! :("
0040100F  |. B9 30000000       MOV ECX,30
00401014  |. EB 0A             JMP SHORT crackme1.00401020
00401016  |> B8 00304000       MOV EAX,crackme1.00403000                    ;  ASCII "Congrat reverser :)"
0040101B  |. B9 00000000       MOV ECX,0
00401020  |> 51                PUSH ECX                                     ; /Style
00401021  |. 68 28304000       PUSH crackme1.00403028                       ; |Title = "Crackme #1 by RubberDuck"
00401026  |. 50                PUSH EAX                                     ; |Text
00401027  |. 6A 00             PUSH 0                                       ; |hOwner = NULL
00401029  |. E8 0E000000       CALL <JMP.&user32.MessageBoxA>               ; \MessageBoxA
0040102E  |. 6A 00             PUSH 0                                       ; /ExitCode = 0
00401030  \. E8 01000000       CALL <JMP.&kernel32.ExitProcess>             ; \ExitProcess

Začneme hezky od začátku. Koukneme se do levého horního okna, což je okno CPU. V tomto okně vidíme disassemblovaný kód Crackme a vidíme i adresy jednotlivých instrukcí v paměti. Vedle adres je pak reprezentace instrukcí v hexadecimální podobě takzvaných opkódů. V pravém horním okně je seznam registrů a jejich aktuálních hodnot. Pokud při krokování programu některá hodnota registru zčervená, znamená to, že tento registr změnila instrukce na předchozím řádku. Levé dolní okno je takzvané Dump okno. Vidíme v něm hexadecimální reprezentaci dat v paměti a vedle jejich ASCII ekvivalent. V pravém dolním okně pak pozorujeme hodnoty na stacku.

crackme_1_1

Kód programu Crackme_1 otevřeného v OllyDbg

Pojďme se podívat na kód programu, aniž bychom jej zatím vykonávali. První řádek přiřazuje hodnotu 0 do registru EAX. To je přesně to, co instrukce MOV provádí. Na druhém řádku se porovnává hodnota v registru EAX s hodnotou 1. Opět, to je přesně to, co instrukce CMP provádí. Pokud jsou obě hodnoty rovny, nastaví se zero flag. Zero flag vidíme v OllyDbg v pravém sloupečku a má označení Z. Na třetím řádku se kontroluje, zda je nastaven zero flag. Pokud ano, provádění programu pokračuje na adrese uvedené vedle instrukce JE. Instrukce JE je takzvaný podmíněný skok. Podmínkou je v tomto případě právě nastavení zero flagu. Pokud nastaven je, dochází k odskoku. Pokud nastaven není, pokračuje se následujícím řádkem kódu. V tomto případě se jedná o adresu 00401016h. My víme z prvního řádku, že registr EAX je nastaven na hodnotu 0 a proto nedojde při porovnávání k nastavení zero flagu a tudíž nedojde ani ke skoku na řádku tři. Pojďme dál. Na řádku čtyři je opět instrukce MOV a přiřazuje do registru EAX jakousi hodnotu. Tato hodnota je adresa v paměti. OllyDbg je s námi tak velký kamarád, že nám dokonce úplně vpravo vypíše informaci, že na této adrese je textový řetězec „Please patch me! :(„. Kdo nevěří, může si kliknout na tento řádek pravým tlačítkem myši a zvolit Follow in dump -> Immediate Constant. V levém dolním okně se objeví náš řetězec. Na pátém řádku se do registru ECX ukládá hodnota 30h. Zatím netušíme, co tato hodnota znamená nebo k čemu slouží. Šestý řádek ukazuje instrukci JMP, což je nepodmíněný skok. Nepodmíněný skok přenáší tok programu na adresu uvedenou vedle instrukce. V našem případě 00401020h. Přemístíme se tedy na tuto adresu. Na tomto řádku se obsah registru ECX ukládá na vrchol zásobníku. Pokud se ale podíváme vpravo, uvidíme, že nám OllyDbg chce něco sdělit. Tou magickou informací je fakt, že jsme se dostali k volání Windows API funkce MessageBoxA. Koukneme se tedy do dokumentace na MSDN[17], jak je tato API funkce definovaná:

int WINAPI MessageBox(
  _In_opt_ HWND    hWnd,
  _In_opt_ LPCTSTR lpText,
  _In_opt_ LPCTSTR lpCaption,
  _In_     UINT    uType
);

API funkce MessageBoxA přebírá čtyři argumenty. První je handle rodičovského okna (to je okna, které toto okno vytvořilo), druhý je text, který se zobrazí v okně, třetí je popisek okna a čtvrtý definuje styl okna, počet tlačítek a podobně. Návratovou hodnotou funkce je kód tlačítka, které bylo zmáčknuto. Pokud se znovu podíváme na nápovědu ze strany OllyDbg zjistíme, že hodnoty jsou na stack ukládány v opačném pořadí. Toto pořadí určuje použitá volací konvence funkce (o volacích konvencích si řekneme příště). Nyní tedy již víme, k čemu se ukládala do registru ECX hodnota 30h. Ovlivňuje vzhled okna. Pokud se podíváme do dokumentace, co přesně znamená hodnota 30h, zjistíme, že se jedná o varovnou ikonu. Takže v okně bude ikona. Dále se na stack ukládá adresa popisku okna. Ten zní „Crackme #1 by RubberDuck“. Nic moc zajímavého. Na dalším řádku hodnota registru EAX ukládá na stack. Z dřívějška víme, že je v registru EAX je adresa řetězce „Please patch me! :(„. Jako poslední z argumentů se ukládá na stack handle rodiče, tady hodnota 0. Podle dokumentace je tím jasně řečeno, že okno nemá rodiče (je sirotek :'( ). Následuje samotné volání Windows API funkce MessageBoxA, které je provedeno instrukcí CALL.
Za voláním API funkce MessageBoxA se na stack ukládá hodnota 0 a volá se API funkce ExitProcess.

VOID WINAPI ExitProcess(
  _In_ UINT uExitCode
);

Podle dokumentace si snadno zjistíme, že API funkce ExitProcess přebírá jeden argument, který definuje takzvaný ExitCode. ExitCode udává, jak vykonávání programu skončilo. Hodnota 0 pak značí, že úspěšně.

crackme_1_2

Crackme_1 nám říká, že ho musíme patchnout

Shrňme si aktuální zjištění. Program zobrazí okno s textem „Please patch me! :(„, popiskem „Crackme #1 by RubberDuck“ a následně se ukončí s ExitCode 0. To, co jsme právě provedli, se nazývá statická analýza kódu. Šli jsme jednoduše řádek po řádku a vyhodnocovali je. Nyní můžeme provést to stejné za pomoci dynamické analýzy. Využijeme k tomu opět OllyDbg. Stiskneme klávesu F7 nebo F8. F7 je zkratková klávesa pro funkci Step into. F8 pak zkratková klávesa pro funkci Step over. Rozdíl mezi těmito funkcemi je ten, že při použití Step into na volání funkce dojde k přesměrování toku vykonávání do této funkce (rozuměj dojde k odskoku na začátek volané funkce). To se nemusí dost často hodit. Zvláště pak, když se jedná o skok do funkcí jako je právě MessageBox. Tato funkce je standardní systémovou funkcí Windows z DLL knihovny user32.dll a její funkcionalita je velmi dobře známa. Není tedy nutné tuto funkci procházet. Proto zvolíme funkci Step over a necháme vyhodnocení funkce na OllyDbg. Postupným mačkáním klávesy F8 projdeme celý kód a na každém řádku si můžeme zkontrolovat, zda jsme při statické analýze četli kód správně. Občas se hodí spustit vykonávání automaticky, bez nutnosti neustále mačkat klávesu F8. K tomu slouží klávesa F9 neboli funkce Run. Ta spustí program tak, jako by byl spuštěn dvojklikem přímo v systému.

Program dělá přesně to, co jsme řekli. V kódu jsme si ale všimli, že kromě dvou námi zjištěných textů existuje v programu ještě jedno. „Congrat reverser :)“. A to bude asi ten řetězec, který by se měl zobrazit pro splnění úkolu. Vraťme se znovu ke kódu a zkusme zjistit, jak bychom mohli změnit text okna. První věc, která nás napadne, je zeditovat popisek pomocí hex editoru. Je to určitá cesta, ale úplně špatná. Proč? Představte si, že by se jednalo o program s registračním formulářem. Editace textu by z něj plnou verzi neudělala 🙂 My musíme změnit tok programu tak, aby se sám dostal k tomuto řetězci. Na řádku tři je podmíněný skok, který je vázaný na výsledek porovnání na řádku dva. Jinými slovy: Pokud bude EAX roven 1, dojde k nastavení zero flagu na řádku tři dojde ke skoku k vytouženému řetězci. Takže musíme nějak zajistit, aby byla hodnota EAX a řádku dvě rovna 1. Musíme tedy upravit hodnotu na řádku jedna z nuly na jedničku. Stiskneme mezerník, který nám vyvolá okno, ve kterém je náš řádek. Přepíšeme hodnotu 0 na 1 a stiskneme Assemble. Nyní vybereme první řádek, stiskneme pravé tlačítko myši a vybereme volbu Copy to executable->Selection. Vyskočí na nás další okno s popiskem File. Klikneme do něj pravým tlačítkem myši a vybereme volbu Save file a uložíme. POZOR! Je třeba zvolit jiné jméno nebo dojde k úpravě původního programu. Pokud by během editace došlo například k nechtěnému odmazání části programu, byl by po uložení nenávratně ztracen!

crackme_1_3

Upravíme první řádek kódu

Nyní přejdeme do složky, kam jsme uložili náš upravený program a spustíme ho. Et voila! To je text, který jsme chtěli vidět 🙂

crackme_1_4

Congrat! Právě jsme úspěšně zreverzili a následně i patchli naše první crackme 🙂

To je pro tentokrát vše. Na závěr přidávám domácí úkol pro ty, kteří rádi o věcech přemýšlí: Pokuste se upravit Crackme jiným způsobem, než který byl uveden v tomto článku. Protože se jedná o skutečně krátký kód, neposkytnu ani žádný hint.

Odkazy
[ 1] – WinHex
[ 2] – HIEW
[ 3] – IDA Pro
[ 4] – OllyDbg
[ 5] – Immunity Debugger
[ 6] – WinDBG
[ 7] – Hex-Rays Decompiler
[ 8] – Boomerang Decompiler Project
[ 9] – dotPeek
[10] – ILSpy
[11] – DeDe
[12] – ProcMon
[13] – RegMon
[14] – Art of Assembly
[15] – Mistrovství v jazyce Assembler
[16] – TutorialsPoint.com
[17] – MSDN

Poděkování
MazeGen – za konzultaci a korekci

17 komentářů u „Nebojte se reverzního inženýrství I.

    1. RubberDuck Autor příspěvku

      Ahoj. Díky. Rozhodně se nebráním žádné konstruktivní kritice nebo nápadům, takže pokud něco máš, klidně napiš 🙂

  1. aaa

    „Seriál by měl být koncipován tak, aby byl i naprostý začátečník schopen po jeho absolvování samostatně aplikovat reverzní inženýrství pro své vlastní potřeby.“

    Ale patchnut si jednoduchsi program moze kazdy aj bez serialu a naopak, na tie narocnejsie to chce velmi vela casu. Casto najdenie chyby v zabezpeceni programu vyzaduje velmi netrivialne matematicke znalosti. Faktorgrupy modulo prvocislo vysvetlis lahko; efektivne hladanie kolizii v permutaciach kombinovanych s bitovymi operaciami podla nejakeho nelinearne sa vyvijajuceho stavu uz chce viac ako zaciatocnika.

    Isty vyrobca programov aspon svojho casu dodaval kernel-level driver a ked bezal debugger alebo sa kernel niekde zdrzal, tak sa zacali diat divne veci.

    Bude sa zabiehat az do takych detailov? Myslim WinDbg + RS232 debug + driver debugging tak, aby to driver nezistil a s tym suvisiace Windows kernel internals + rozumne a efektivne debugovanie niecoho, co vlastne pouziva ROP chain + dost pokrocila matika, aby sme sa nenudili.

    1. RubberDuck Autor příspěvku

      Nikde jsem nepsal, že reverzní inženýrství je jen a pouze o patchování. Stejně tak jsem nikde nepsal, že musí být reverzní inženýrství použito jen a pouze při hledání chyb v aplikacích. Aktuálně není cílem rozebírat složité věci, ale jednoduše ukázat kudy vede cesta do tohoto oboru, protože v češtině neexistuje komplexnější manuál pro začátečníky. Do jaké hloubky se pustím ještě netuším. Zatím je seriál opravdu mířen na začátečníky a hnát je rovnou do R0 mi nepříjde jako vhodná cesta.

  2. vl

    Seriál je fajn, líbí se mi doplnění praktickým příkladem, skvělé!

    Pro zájemce se znalostí angličtiny doporučuji naprosto famózní http://beginners.re/ — i Lite verze obsahuje výborné informace pro začátečníky v RE. A zdarma.

    1. RubberDuck Autor příspěvku

      Zrovna seriál od DjH je spíš soubor řešení CMEček. Teorie se dotýká sporadicky nebo rovnou vůbec. V době, kdy ten seriál psal, jsem ho s ním řešil i na IRC a bylo vidět, že mu jde spíš o kvantitu než o kvalitu. Denně sepsal třeba čtyři díly. Tím ho nechci nijak srážet nebo pomlouvat. V té době mu bylo nějakých čtrnáct let a na jeho věk to rozhodně mělo vysokou úroveň. Na stranu druhou tady byly třeba tutory od lidí kolem picassova poupěte a tam to byla zase bohapustá teorie, kde ještě autor předpokládal, že má čtenář nějaká znalosti. Je to cca mínus deset let, když jsem na ty tutoriály narazil a moc moudrý jsem z nich nebyl ani po opakovaném čtení. A proto jsem se rozhodl sepsat něco více polopatického, kde se nebudu vyhýbat teorii.
      Na t4c fórum odkazuji v sekci Doporučuji 🙂 A rozhodně ho doporučuji 🙂
      Kdyby mě to nebavilo, nebudu psaním ztrácet čas 🙂

  3. Kubik

    Ahoj, vypadá to jako skvělý seriál. Už jsem RE studoval na zahraničních webech, ale nikde jsem to nečetl takhle podrobně, jako to máš ty. Je to bomba, těším se na další díl.

  4. Martin Dráb

    Je to takový pěkný a rychlý úvod do Assembleru. Jsem zvědav na další díly. Trochu škoda, že se zřejmě neplánuješ věnovat např. architektuře AMD64/x64, ale zůstaneš u IA32. Na druhou stranu je pro začátačníky rozhodně lepší seznámit se s něčím jednodušším (alespoň zdánlivě).

    Jinak registr EFLAGS je jen jeden (jeho dolních 16 bitů se jmenuje FLAGS, jak je dobrým zvykem na IA32). Tvoje „skupina registrů“ jsou jen jeho jednotlivé příznaky, jednotlivé bity.

    U popisu registru ESP bych ještě zmínil, že se pojí s registrem SS (tzn. adresa zásobníku je SS:(E)SP), takže segmentový registr SS nejde zrovna používat, jak si zamaneš (na rozdíl od ES, FS a GS, které takhle přímo vázané nejsou). také bych stack nenazýval speciálním typem paměti, alespoň na IA32 ne. Je to spíše oblast paměti se speciálním významem, nebo datová struktura. Jinak se část paměti tvořící zásobník od ostatní paměti neliší (možná krom toho, že se data kolem vrcholu hodně používají, takže budou skoro pořád v cache).

    Každopádně dobrá práce (text o crackme jsem nečetl, takže nehodnotím)!

    1. Karel Lejska

      Co přesně znamená, že ES není „přímo vázaný“? Na ES závisí třeba STOS, na FS na Windows thread kontext…

      A jsem pro, aby si začátečník stack představil jako „speciální paměť“, tzn. že to není heap. Dalším učením by měl dojít k tomu, kde ty rozdíly vlastně jsou a že stack jde do určité míry používat jako heap a naopak.

      1. Martin Dráb

        > Co přesně znamená, že ES není „přímo vázaný“? Na ES závisí třeba
        > STOS, na FS na Windows thread kontext…

        Myslel jsem tím, že pokud změníš ES, FS či GS, nedojde k „okamžité katastrofě“, protože až na některé instrukce je procesor nepoužívá (na rozdíl od CS, DS a SS).

        Ale máš pravdu v tom, že tady zbytečně řeším detaily, které se ozřejmí v pozdějších dílech (a prozatím jejich absence asi nevadí).

    2. RubberDuck Autor příspěvku

      Vysvětovat začátečníkovi, že EFLAGS je vlastně jediný registr, kde se pouze nastavují jednotlivé bity mi nepřišlo nejvhodnější. I v odborné literatuře se používá pojem ‚stavové registry‘ (případně ‚indikátory‘), ze kterého není jasné, že se ve skutečnosti jedná pouze o jediný registr. Bližší vysvětlení/osvětlení jsem si chtěl schovat na další díl, kde bych chtěl přímo popsat, co tyto stavové registry ovlivňuje a jak se s nimi pracuje. V prvním díle čtenář tuto informaci znát nepotřeboval (až na jeden malý příklad v crackme, který ale obějít nešel). To stejné platí pro segmentové registry. Aktuálně čtenář nepotřebuje vědět, že SS registr ukazuje na stack a CS na segment kódu. Nepotřebuje to vědět, protože jsem zatím nezmínil, jak jsou vlastně data v paměti rozhozeny.

      Mým cílem není tvořit referenční příručku assembleru. To už za mě udělali jiní a rozhodně kvalitnější formou, než bych to dokázal já.

  5. Martin

    „Koukneme se do pravého horního okna, což je okno CPU. V tomto okně vidíme disassemblovaný kód Crackme a vidíme i adresy jednotlivých instrukcí v paměti. “ – Souhlasim, ze prave horni okno je CPU, ale v tomto okne nen disassemblovany kod.

    S OllyDbg nemam zkusenosti…
    Neuvedl jsi, jakou verzi OllyDbg pouzivas? Ja zkusil OllyDbg v2.01 (beta 2) a asi je jina, treba Copy to executable je schovane pod volbou Edit…kde bych jej uprimne necekal, naopak ->Selection jsem nenasel vubec. Pri pouziti Copy to executable se otevre nove okenko s upravenym kodem, ktere je nasledne mozne ulozit. Bohuzel to ale funguje jen pri uprave prvni instrukce, kdyz upravim druhou a pouziju Copy to executable na prvnim radku, tak je nove okno beze zmeny, kdyz to udelam z druheho radku, tak se zkopiruje vse od druheho radku a prvni je zapomenut….muze nekdo zkusenejsi poradit, co delam spatne?

    1. RubberDuck Autor příspěvku

      Ano, je tam chyba. Místo ‚pravého horního okna‘ tam má být ‚levé horní okno‘. Díky za upozornění.

      Co se verze OllyDbg týká: Mnou používaná verze mi z textu záhadně vypadla. Z technických a historických důvodů používám verzi 1.10. Omlouvám se a doplňuji.
      S dvojkovou verzí nemám žádné zkušenosti, takže neporadím. Ale možná bude vědět někdo jiný.

  6. Martin

    Take se mi v OllyDbg se mi nijak nepovedlo zvetsit Font.
    Options -> Options -> Appearance [Fonts] na zmenu nereaguje… netusi nekdo proc?

  7. ssmrek

    Konečne niečo o crackingu, čo nie je aspoň 10 rokov staré. Seriál sa mi veľmi páči. Vyhovuje mi ten štýl vysvetľovania “ polopate“. Prajem veľa zdaru a chuti do písania ďalších dielov.
    Zároveň dúfam, že to neskončí hneď po prebratí úplných základov, i keď nečakám, že sa z nás stanú profesionálny crackeri. No chcel by som sa dostať ďalej, ako len zistiť serial number nastavením brakpointu na hmemcpy.

    1. RubberDuck Autor příspěvku

      Díky. V plánu je toho celkem dost, ale času na realizaci je málo. Lépe řečno bylo by dost, pokud bych řešil kvantitu na úkor kvality 🙂

Napsat komentář

Vaše emailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *