SlideShare ist ein Scribd-Unternehmen logo
1 von 116
Downloaden Sie, um offline zu lesen
RE
WORKSHOP
Karel Lejska
Milan Bartoš
security
session 2016
Pojetí workshopu
• Solidní základy pro reverzování
• Windows: tradiční platforma pro reverzery
• OllyDbg: nejoblíbenější debugger
• x64dbg: částečná náhrada za nedokončený 64-bit
OllyDbg, postupy bývají stejné
• Slidy pro pozdější studium
Podklady
• Nebojte se reverzního inženýrství I.
• Nebojte se reverzního inženýrství II.
• Nebojte se reverzního inženýrství III.
• x86asm.net/links
• ref.x86asm.net/coder32.html
• ref.x86asm.net/coder64.html
• Poděkování Lukáši „RubberDuck“ Čižmarovi
• Security Cave
1. část
• Crackme #1 by RubberDuck
• + opkódy instrukcí
• + x64
• + x64 verze crackme #1
1. workshop - nástroje
• 32bitový debugger OllyDbg
• OllyDbg 2.01
• 64bitový debugger x64dbg
• x64dbg snapshot_2016-01-21_02-44
Crackme #1 by RubberDuck
OllyDbg – crackme1.exe
OllyDbg – nastavení eventů
OllyDbg – nastavení výjimek
crackme1.exe – 1. instrukce MOV
• 00401000 B8 00000000 MOV EAX, 0
• 1. sloupec – virtuální adresa 00401000
• 2. sloupec – operační kód – opcode B8 00000000
• 3. sloupec – instrukce MOV EAX, 0
• OllyDbg disassembler: Intel syntax, MASM příchuť
• OllyDbg AT&T syntaxe:
MOVL $0, %EAX
1. instrukce podrobně
• B8 00000000 MOV EAX, 0
• Mnemonic MOV
• Cílový 32bitový operand EAX
• Zdrojový 32bitový operand 0x0
• Jednobajtový primární opkód 0xB8
• ref.x86asm.net/coder32.html#xB8
• Skupina opkódů B8+r MOV r16/32, imm16/32
• 32bitová konstanta 0x00000000
• Intel jí říká immediate value
IA-32 general-purpose registers
• Osm 32bitových všeobecných registrů, kód 0-7 (3 bity)
EAX ECX EDX EBX ESP EBP ESI EDI
0 1 2 3 4 5 6 7
General-purpose registers - příklady
• EAX = 44332211 – 32 bitů, velikost DWORD
• AX: 2211 – 16 bitů, velikost WORD
• AL: 11 – dolních 8 bitů, velikost BYTE
• AH: 22 – horních 8 bitů, velikost BYTE
• EBP = 40302010
• BP: 2010
• Horní WORD nemá název a nejde ho adresovat
• Pozn. 4 bitům (půlbajt) se říká nibble
Crackme1.exe – 2. instrukce CMP
• 00401005 83F8 01 CMP EAX, 1
• Mnemonic CMP
• Cílový 32bitový operand EAX
• Zdrojový 32bitový operand 0x1
• Jednobajtový primární opkód 0x83
• ref.x86asm.net/coder32.html#x83
• Skupina opkódů 83
• ModR/M byte F8 = 11111000bin
• zatím to víc neřešíme
• 8bitová přímá (immediate) hodnota 0x01
Skupina opkódů 0x83
• Osm aritmetických a logických instrukcí
• Operandy: r/m16/32, imm8
• Viz taky opkódy 80, 81
2. instrukce podrobně
• CMP: compare two operands
• CMP nemění žádný operand
• Operace CMP = operace SUB
• SUB: subtract two operands
• SUB EAX, 1: EAX = EAX - 1
• CMP nastavuje šest stavových příznaků (status flags):
CF, PF, AF, ZF, SF, OF
• Viz instrukční reference:
• Příznaky jsou uloženy v registru EFlags
Registr EFlags, operace CMP
• Šest stavových příznaků v bitech 0, 2, 4, 6, 7 a 11
• Hromada jiných, ty teď neřešíme
• CMP nastaví ZF (Zero Flag), pokud mají operandy
stejnou hodnotu
• Stejně jako SUB nastaví ZF, pokud je výsledek odečítání
nula
crackme1.exe – 3. instrukce JE
• 00401008 74 0C JE SHORT 00401016
• Jednobajtový primární opkód 0x74
• ref.x86asm.net/coder32.html#x74
• Mnemonic JE: Jump if Equal
• Mnemonic JZ: Jump if Zero
• SHORT znamená skok v rozmezí -128 a +127 bajtů
• Skupina opkódů 70-7F: 16 podmíněných skoků Jcc
• 8-bit relative offset 0x0C
• Relativní offset se přičítá k registru EIP
3. instrukce JE a reg. EIP podrobně
• EIP: Instruction Pointer Register
• EIP obsahuje virtuální adresu následující instrukce, tzn. v
době spouštění instrukce JE je EIP 40100A
• Operace:
if (ZF == 1)
EIP = EIP + sign extended rel8
• Kalkulace návěští (label) skoku: adresa instrukce JE je
401008, je dlouhá 2 bajty:
401008 + 2 + 0C = 401016
crackme1.exe – 4. instrukce MOV
• 0040100A B8 14304000
MOV EAX, OFFSET 00403014
• Viz 1. instrukce MOV
• OFFSET: MASM příchuť, důsledek analýzy – OllyDbg
rozeznal, že jde o adresu, ne o nahodilou hodnotu
• Na adrese 403014 je řetězec "Please patch me! :("
crackme1.exe – 5. instrukce MOV
• 0040100F B9 30000000 MOV ECX, 30
• Viz 1. instrukce MOV
• Připomenutí: opkód B9 = B8+r, kód ECX je 1
crackme1.exe – 6. instrukce JMP
• 00401014 EB 0A JMP SHORT 00401020
• ref.x86asm.net/coder32.html#xEB: JMP rel8
• Mnemonic JMP: Unconditional Jump
• SHORT znamená skok v rozmezí -128 a +127 bajtů
• 8-bit relative offset 0x0A
• Relativní offset se přičítá k registru EIP
• Kalkulace návěští skoku: 401014 + 2 + 0A = 401020
crackme1.exe – 9. instrukce PUSH
• 00401020 51 PUSH ECX
• ref.x86asm.net/coder32.html#x50: 50+r PUSH r16/32
• Skupina opkódů 50-57
• Uloží hodnotu operandu na zásobník ve dvou krocích:
ESP = ESP – 4
*ESP = ECX
• Zásobník je zatím prostě nějaká paměť, víc to neřešíme
• OllyDbg: zásobník je vidět vpravo dole
Parametry WinAPI MessageBoxA()
• Prototyp funkce z MSDN:
int WINAPI MessageBox(
_In_opt_ HWND hWnd,
_In_opt_ LPCTSTR lpText,
_In_opt_ LPCTSTR lpCaption,
_In_ UINT uType
);
Parametry WinAPI MessageBoxA()
• Odpovídající instrukce PUSH
51 PUSH ECX ; uType
68 28304000 PUSH OFFSET 403028 ; lpCaption
50 PUSH EAX ; lpText
6A 00 PUSH 0 ; hWnd
Volací konvence stdcall
• Konvence je vidět v prototypu:
• int WINAPI MessageBox();
• WinDef.h (Windows SDKs):
• #define WINAPI __stdcall
• MSDN stdcall calling convention
• Parametry jsou uložené zprava doleva
• Zásobník čistí volaná funkce
• Návratová hodnota je v registru EAX
• Registry EAX, ECX a EDX může volaná funkce změnit, ostatní
musí zachovat
• stdcall používá většina WinAPI funkcí
Další formy instrukce PUSH
• PUSH immediate value: buď 32bitová hodnota, nebo
znaménkově rozšířený imm8 na 32 bitů
68 28304000 PUSH OFFSET 403028
6A 00 PUSH 0
crackme1.exe – 13. instrukce CALL
• 00401029 E8 0E000000
CALL <jmp.&user32.MessageBoxA>
• Trochu jinak:
• CALL 0040103C
• Jednobajtový primární opkód E8 CALL rel16/32
• Operace:
PUSH EIP
JMP 0040103C
• Tento CALL volá MessageBoxA() nepřímo přes JMP
umístěný na konci kódu, je to záležitost importování
funkcí a assembleru MASM, toto teď neřešíme
Volání funkce: pár CALL - RET
CALL func
...
func:
...
RET ; taky „RETN“
• Operace CALL:
• ESP = ESP – 4
• *ESP = EIP
• JMP func
• Operace RET:
• EIP = *ESP
• ESP = ESP + 4
OllyDbg: základní akce
• Step into (klávesa F7): dojde k přechodu na návěští CALL
• Step over (klávesa F8): krokování pokračuje až po
návratu z CALL
• Run (klávesa F9): spustí debugovaný program, tzn.
nekrokuje ho
• Restart (Ctrl+F2): zabije aktuální session a načte
debugovaný program znovu; dobrá věc, pokud
krokováním dojdu donikam a potřebuju začít znovu
Disassembling MessageBoxA()
8BFF mov edi, edi
55 push ebp
8BEC mov ebp, esp
6A 00 push 0
FF75 14 push dword ptr [ebp+14]
FF75 10 push dword ptr [ebp+10]
FF75 0C push dword ptr [ebp+0C]
FF75 08 push dword ptr [ebp+8]
E8 A0FFFFFF call MessageBoxExA
5D pop ebp
C2 1000 retn 10
MessageBoxA(): RETN 10
• C2 1000 RETN 10
• 0x10 = 16
• 16/4 = 4 DWORD parametry
• Pseudooperace:
ESP = ESP + 16
EIP = *ESP
ESP = ESP + 4
crackme1.exe – 15. instrukce CALL
• 00401030 E8 01000000
CALL <jmp.&kernel32.ExitProcess>
• Trochu jinak:
• CALL 00401036
• Viz předchozí instrukce CALL
• Jde o ukončení procesu: funkce ExitProcess() v
knihovně kernel32.dll
• I když nikdy nedojde k návratu, stejně se použivá CALL a
ne JMP
OllyDbg assembler
• Assembluj MOV EAX, 5 na adrese 401000 (= EIP)
OllyDbg assembler
• Např. nekonečná smyčka – instrukce MOV, SUB a JMP:
1. Assembluj MOV EAX, 5 na adrese 401000 (= EIP)
2. Assembluj SUB EAX, 1 na adrese 401005
3. Assembluj JMP 401005 na adrese 401008
• Změny se obarví červeně, super věc na učení se opkódů
Instrukce INT3; NOP; ADD [EAX], AL
• CC INT3
• Výplň kódu (i dat) na místech, kam se nemá dostat řízení
• Způsobí ladící výjimku; tu teď neřešíme
• 90 NOP
• No OPeration
• Výplň pro zarovnání kódu
• 0000 ADD [EAX], AL
• Podezřelá instrukce
• Inicializační hodnota při alokaci paměti, nejde o kód
Shrnutí pojmů (1)
• Virtuální adresa
• Opkód, primární opkód
• Mnemonic instrukce
• Operand instrukce
• Intel syntaxe vs. AT&T syntaxe
• Osm všeobecných registrů
• Velikosti: DWORD, WORD, BYTE
• Orientace v primárních opkódech
• Registr EFlags, šest stavových příznaků, příznak ZF
• Registr EIP, kalkulace návěští skoku
• Volací konvence stdcall
Shrnutí pojmů (2)
• Volání funkce: CALL – RET
• Odstraňování parametrů ze zásobníku pomocí RET
• OllyDbg assembler
Shrnutí instrukcí
• MOV
• CMP, SUB
• JE, Jcc
• JMP
• PUSH
• CALL
• INT3
• NOP
• ADD [EAX], AL
Problémy s označením architektury
• Hromada zjednodušujících názvů pro komplikovanou
architekturu:
• Intel
• IA-32 architecture
• Intel64 architecture (nový „64-bit mode“)
• IA-64 je úplně jiná (mrtvá) architektura
• AMD64 architecture
• x86 architecture, „legacy mode“
• 64-bit x86 architecture (nový „Long Mode“)
• Microsoft
• x86
• x64
Crackme #1 (x64) by RubberDuck
x64dbg – nastavení eventů
x64dbg – crackme1_x64.exe
crackme1_x64: 1. instrukce SUB
• 000000013FC0100 48 83 EC 08 SUB RSP, 8
• Vypadá jako alokace 8 bajtů na zásobníku
• Ve skutečnosti zarovnání zásobníku na 16 bajtů,
vynucené volací konvencí (viz následující slajdy)
• Komplikace při programování v assembleru
• Jednobajtový primární operační znak 0x83
• ref.x86asm.net/coder64.html#x83
• Nová věc: prefix 48 REX.W
• ref.x86asm.net/coder64.html#x48
• Nejčastější REX.W zvětší velikost operandu na 64 bitů
• REX prefixy na x86 neexistují
64-bit registers
• Šestnáct 64bitových všeobecných registrů, kód 0-15
(4 bity)
RAX RCX RDX RBX RSP RBP RSI RDI
0 1 2 3 4 5 6 7
R8 R9 R10 R11 R12 R13 R14 R15
8 9 10 11 12 13 14 15
• 64bitový instrukční ukazatel RIP
64-bit general-purpose registers
• RAX = 8877665544332211, velikost QWORD
• EAX: 44332211
• AX: 2211
• AL: 11
• AH: 22
• RSP – ESP – SP – SPL
• RBP – EBP – BP – BPL
• RSI – ESI – SI – SIL
• RDI – EDI – DI – DIL
• R15 - R15D - R15W - R15B
• Horní DWORD nejde adresovat a nemá název
crackme1_x64: 5. instrukce MOVABS
• 000000013FC0100 48 B8 1430C03F01000000
MOVABS RAX, 13FC03014
• Jednobajtový primární opkód 0xB8
• Prefix 48 REX.W
• Mnemonic MOVABS neexistuje, jde o MOV
• lidová tvořivost, odpovídá to správnějšímu OFFSET v OllyDbg
crackme1_x64: volání MessageBoxA
• Předávání parametrů je zhruba vidět:
SUB RSP, 20
MOV RCX, 0 ; hWnd
MOV RDX, RAX ; lpText
MOVABS R8, 13FC03028 ; lpCaption
MOV R9, RBX ; uType
CALL <crackme1_x64.MessageBoxA>
ADD RSP, 20
• První 4 parametry jdou vždycky do registrů RCX, RDX,
R8 a R9
• Ale co ten SUB/ADD RSP, 20?
Volací konvence fastcall (1)
• Pozor, nejde o x86 fastcall, i když je podobný
• Ještě jednou, konvence bývá vidět v prototypu:
• int WINAPI MessageBox();
• WinDef.h (Windows SDKs): #define WINAPI
• tentokrát je to „prázdná“ hodnota, všechno je fastcall (s výjimkami)
• MSDN x64 fastcall calling convention
• První 4 parametry jdou vždycky do registrů RCX, RDX, R8 a R9,
ostatní na zásobník
• Zásobník čistí volaná funkce
• Návratová hodnota je v registru RAX
• Registry RAX, RCX, RDX, R8, R9, R10 a R11 může volaná funkce
změnit, ostatní musí zachovat
Volací konvence fastcall (2)
• První 4 parametry jsou v registrech, ale na zásobníku
musí být tak jako tak alokovaný prostor, další jdou na
zásobník jako u stdcall
• Alokace a uvolnění 4 parametrů pomocí
SUB/ADD RSP, 20
• 0x20 = 32 = 4*8
fastcall a zarovnání zásobníku
• MSDN: The stack will always be maintained 16-byte
aligned
• Vstupní bod programu je vlastně vstupní bod funkce
main()
• Volání funkce zruší zarovnání na 16 bytů:
1. Před provedením CALL je zásobník zarovnaný na 16
bytů
2. CALL provede PUSH RIP (8 bytů)
3. Na vstupu do funkce je potřeba zásobník znovu
zarovnat pomocí SUB RSP, 8
crackme1_x64: volání ExitProcess
• ExitProcess() má jenom jeden parametr, ale na zásobníku
je potřeba vždycky alokovat 4 parametry:
SUB RSP, 20 ; 4*QWORD
MOV ECX, 0
CALL crackme1_x64.RtlExitUserProcess
Shrnutí pojmů (x64)
• 16 64bitových všeobecných registrů
• 64bitová virtuální paměť, registr RIP
• Velikost QWORD
• Volací konvence fastcall
• Zarovnání zásobníku
• Prefixy REX
Úkoly
1. Crackněte crackme1 (x86 i x64) podle návodu v článku
Nebojte se reverzního inženýrství I.
2. Crackněte crackme1 ještě jinak než podle návodu
3. Pokud v crackme1 změníte instrukci CMP na SUB, jaký
vliv to bude mít na funkčnost programu?
4. Vytvořte přímo v OllyDbg assembleru co nejkratší kód,
který způsobí vyčerpání paměti zásobníku
2. část
• Crackme #2 by RubberDuck
• + opkódy instrukcí
• + x64 verze crackme #2
• Stack, heap, virtual memory
• Memory model, TEB (TIB)
• Exception handling
• Entry point, kód, data
• Importy
• Binární formát instrukce
Crackme #2 by RubberDuck
OllyDbg – crackme2.exe
crackme2.exe – 1. instrukce PUSH
• 00401000 6A F5 PUSH -0B
• ref.x86asm.net/coder32.html#x6A
• 6A PUSH (sign extended) imm8
• imm8: 8bitová immediate value
• Takže jinak (velikost položky na zásobníku je DWORD):
• PUSH FFFFFFF5
• Je to první parametr volání WinAPI funkce
GetStdHandle()
GetStdHandle()
• MSDN: Retrieves a handle to the specified standard
device (standard input, standard output, or standard
error).
HANDLE WINAPI GetStdHandle(
_In_ DWORD nStdHandle
);
• Potřebujeme návratovou hodnotu HANDLE
• winnt.h (Microsoft SDKs):
• typedef void *HANDLE;
• Volací konvence stdcall: návratová hodnota je v EAX, ta
je uložena pomocí následující instrukce na později
crackme2.exe – 3. instrukce MOV
• 00401007 A3 95304000 MOV [403095], EAX
• ref.x86asm.net/coder32.html#xA3
• A3 MOV moffs16/32, eAX
• Opkódy A0-A3
• speciální forma MOV mezi AL/AX/EAX a pamětí
• Registr eAX (tzn. AX nebo EAX):
• accumulator, historicky optimalizovaný pro častý přístup
• Spousta opkódů podporujících accumulator, umožňujících
kratší kódování instrukcí (viz třeba 0x04, 0x05, 0x0C, ...)
• Dědictví historie, dnes nemá podstatný význam
• moffs - memory offset: konstatní hodnota adresuje paměť
crackme2.exe – 3. instrukce MOV
• MOV [403095], EAX
• 0x403095 = 4206741 = nezarovnaná paměť při ukládání
DWORD hodnoty
• Architektura x86 nevynucuje zarovnání paměti na určitou
hodnotu
• Pozor, architektura x64 typicky (dá se to vypnout na
úrovni OS) vyžaduje zarovnání paměti na „přirozenou“
hodnotu, tzn. DWORD je potřeba uložit na adresu
zarovnanou na 4 byty atd.
• Připomenutí: 64-bit Windows navíc vynucuje zarovnání
zásobníku na 16 bytů (ještě z jiných důvodů)
• Přístup k zarovnané paměti je rychlejší
crackme2.exe – 10. a 11. instr. PUSH
• 00401024 68 00304000
PUSH OFFSET 00403000
• 00401029 FF35 95304000
PUSH DWORD PTR [403095]
• ref.x86asm.net/coder32.html#xFF
• Skupina různých instrukcí
• FF /6 PUSH r/m16/32
• ModR/M byte 0x35 (viz dál)
• DWORD PTR: označení velikosti odkazované hodnoty
crackme2.exe – porovnání hesel
• WriteConsoleA(): vypíše výzvu k zadání hesla
• ReadConsoleA(): přečte zadané heslo
• lstrcmp(): WinAPI funkce porovnávající řetězce,
podobná funkci ze standardní C knihovny
int WINAPI lstrcmp(
_In_ LPCTSTR lpString1,
_In_ LPCTSTR lpString2
);
• „If the strings are equal, the return value is zero.“
crackme2.exe – vyhodnocení hesla
• 85C0 TEST EAX, EAX
• Zvláštní případ na vyhodnocení nulové hodnoty v registru
• Opkódy 84 a 85: TEST r/m, r
• ModR/M byte C0
• TEST: logical compare
• TEST nemění žádný operand
• Operace TEST = operace AND
• TEST nastavuje šest stavových příznaků, viz:
• Smysl dávají tři: SF, ZF a PF
• 0 AND 0 = 0 → nastaví se ZF
crackme1.exe – vyhodnocení CMP
• crackme1:
83F8 01 CMP EAX, 1
74 0C JE SHORT 00401016
• crackme2:
85C0 TEST EAX, EAX
74 1E JZ SHORT 00401081
• TEST EAX, EAX má kratší opkód než CMP EAX, 0
• Zajímavost: OllyDbg disassembler vyhodnotil, že
vhodnější je mnemonic JZ
Binární formát instrukce (opkód)
• Teoreticky:
• Formát instrukce je jenom jeden (ignorujeme VEX)
• Instrukce se skládá z 6 částí
• Primární opkód se vyskytuje vždycky, ostatní volitelně
1. Prefix(y)
2. Primární opkód: 1, 2 nebo 3 byty, volitelně +3 bity
3. ModR/M byte
4. SIB byte (zatím neřešíme)
5. Displacement / memory offset
6. Immediate
Crackme #2 (x64) by RubberDuck
x64dbg – crackme2_x64.exe
crackme2_x64: úvod
• Zarovnání zásobníku na 16 bytů
• 48 83 EC 08 sub rsp, 8
• Volání GetStdHandle, uložení 64bitové HANDLE
• 48 83 EC 20 sub rsp, 20
• B9 F5 FF FF FF mov ecx, FFFFFFF5
• E8 3C 01 00 00 call <crackme2_x64.GetStdHandle>
• 48 83 C4 20 add rsp, 20
• 48 89 05 7E 20 00 00 mov qword ptr [7FF60549309B], rax
crackme2_x64: RIP-rel addressing
• 48 89 05 7E200000 MOV [7FF60549309B], RAX
• Operand vypadá jako disp64, ale ten neexistuje
• Jde o RIP-relative addressing:
• ref.x86asm.net/coder64.html#modrm_byte_32_64
• Ve skutečnosti:
• 48 89 05 7E200000 MOV [RIP+207E], RAX
Crackme2_x64: WriteConsoleA()
• WriteConsoleA() má pět parametrů
• Alokace jakoby 6 parametrů na zásobníku
• 1 QWORD navíc je zase zarovnání na 16 bytů
48 83EC 30 sub rsp, 30 ; 48dec = 6*QWORD
48 8B0D 5A200000 mov rcx, [7FF60549309B]
48 BA ... movabs rdx, crackme2_x64.7FF605493000
41 B8 31 00 00 00 mov r8d, 31
49 B9 ... movabs r9, crackme2_x64.7FF605493093
48 C7 44 24 20000000 mov qword ptr [rsp+20], 0
E8 F1000000 call <crackme2_x64.WriteConsoleA>
48 83C4 30 add rsp, 30
x64 stack a volání WriteConsoleA()
• Stack po SUB RSP, 30:
RSP+28: zarovnání
RSP+20: parameter lpReserved
RSP+18: R9 home: parametr lpNumberOfCharsWritten
RSP+10: R8 home: parametr nNumberOfCharsToWrite
RSP+08: RDX home: parametr *lpBuffer
RSP+00: RCX home: parametr hConsoleOutput
Stack: rychlá dočasná paměť
• LIFO (Last In First Out)
• Roste směrem k nižším adresám
• rSP: Stack Pointer register; pod ním je všechno volatile
• rSP ukazuje na platnou položku, ne pod
• Alokace jednoho DWORD: rSP = rSP – 4
• Jazyk C: alokace automatic variables probíhá na stacku
• Páry instrukcí
• CALL – RET; PUSH – CALL – RET imm16
• PUSH – POP
• INT – IRET (doručení přerušení a návrat z přerušení)
• Každý thread má svůj stack
Stack frame – „rámec funkce“
• Problém: rSP se často mění
• rBP: stack frame register
push ebp ; EBP je nonvolatile (stdcall convention)
mov ebp, esp
sub esp, x ; alokace automatic variables
... ; konec prologu
mov eax, [ebp+y] ; výběr parametru funkce
mov [ebp-z], eax ; inicializace automatické proměnné
... ; začátek epilogu
mov esp, ebp ; uvolnění proměnných – ukončení scope
pop ebp ; obnova nonvolatile registru
ret
Paměť stacku (1)
• OllyDbg: menu View, Memory map
Paměť stacku (2)
• Počáteční hodnota ESP při startu procesu: 1A0000
• Velikost alokovaná systémem: 3000 (12 KB, 3 stránky)
• Hodnota ESP na entry pointu: 19FF84
• Tzn. nějaká inicializace a zavolání kódu programu zabralo
31 položek (DWORDs) na stacku
• Za alokovaným zásobníkem na adrese 19B000 je guard
page (několik) o velikosti 2000 (8 KB, 2 stránky)
• Další guard pages jsou od adresy 95000 o velikosti B000
(44 KB)
• Vyčerpání stacku nastane na adrese A3000
• Konkrétní hodnoty se liší podle aplikace a podle verze OS
Stack a guard page
• Cílem je při inicializaci procesu alokovat jenom tolik
stacku, aby stačil po celou dobu jeho života
• Další paměť se alokuje dynamicky „na požádání“ čtením
nebo zápisem pod alokovanou paměť
• Exception zachytí memory manager, alokuje další stránku
• Paměť zasobníku nemusí alokovat jenom zvláštní
instrukce, ale i přímý přístup k rSP, např. SUB ESP, 100
• Alokace příliš velkých bloků paměti může obejít guard
pages, je proto potřeba provádět stack probe nebo použít
_alloca()
Velikost položky na 32-bit zásobníku
• Vždycky DWORD
• Zarovnání se (na Windows) neočekává
• Příklady:
• PUSH 11223344
• PUSH EAX
• PUSH DWORD PTR [EAX]
• Jde ale i WORD:
• PUSH 1122
• PUSH AX
• PUSH WORD PTR [EAX]
Velikost položky na 64-bit zásobníku
• Vždycky QWORD
• Pozor, Windows očekává zarovnání zásobníku na 16 bytů
před voláním (CALL) funkce
• Příklady:
• PUSH 11223344 (jde jenom sign extended imm32)
• PUSH RAX
• PUSH QWORD PTR [RAX]
• Paradox: nejde DWORD, ale WORD ano:
• PUSH EAX
• PUSH AX
• PUSH 1122
• PUSH WORD PTR [RAX]
Heap („hromada“)
• Vysokoúrovňový memory management
• Heap má svůj HANDLE
• Proces má víc heaps najednou
• Windows loader vytvoří default Process heap
• WinAPI: HeapAlloc (GlobalAlloc, LocalAlloc)
• C runtime heap: malloc, operator new
• Viz Sysinternals VMMap
Manipulace s virtuální pamětí
• Nízkoúrovňový přístup přímo ke stránkám paměti
• 4KB stránka
• Rezervace virtuálních adres (reserve)
• Alokace virtuálních adres (commit)
• VirtualAlloc, VirtualQuery
• VirtualProtect: dynamická generace a spuštění kódu
• Virtuální paměť = nefyzická paměť
Přístupné virtuální adresy
• Proces nemůže přistupovat ke všem existujícím adresám
(neplatí pro drivery)
• OllyDbg to dokáže částečně zobrazit
• 32-bit Windows:
• část prostoru musí zůstat systému
• první 2 GB paměti (adresy 0x00000000 až 0x7FFFFFFF)
• 4-gigabyte tuning (aka /3GB switch): prvním 3 GB paměti
(0x00000000 až 0xBFFFFFFF)
• 64-bit Windows:
• 32-bit proces: vždy celé 4 GB, bez ohledu na další nastavení
• 64-bit proces: teoreticky všechny 64-bit adresy, prakticky omezení
systémem, např. Windows 7 - 192 GB, Windows 10 - 2 TB
Paměťový model (memory model)
• Flat memory model
• Všechno se řeší přes stránkování (paging)
• Kontinuální (nesegmentovaný) virtuální paměťový prostor,
tzn. všechny segmenty mají bázi 0, viz OllyDbg
• Zjednodušeně: paměť začíná od adresy 0 až po nejvyšší
hodnotu (danou systémem)
• Reziduum segmentace: paměť TEB (TIB)
• 32-bit Windows: adresace pomocí FS segmentu
• SEH chain: FS:[0]
• 64-bit Windows: GS segment; FS je nevyužitý
Thread Information Block (1)
• aka Thread Environment Block
• Nedokumentovaná struktura (Bingem jde vygooglit)
• Všechny informace o threadu
• 32-bit Windows
• adresace pomocí segmentu FS
• OllyDbg: FS 0053 32bit 3C0000(FFF)
• 64-bit Windows
• adresace pomocí segmentu GS
• x64Dbg neumí zobrazit báze segmentů
Thread Information Block (2)
• V OllyDbg Memory map „Data block of main thread“
Thread Information Block (3)
Structured Exception Handling (1)
• Jenom 32-bit Windows
• FS:[0] pointer na:
EXCEPTION_REGISTRATION STRUCT
prev DWORD ? ; předchozí handler
handler DWORD ? ; aktuální handler
EXCEPTION_REGISTRATION ENDS
• OllyDbg: View – VEH/SEH chain
SEH (2)
• Instalace vlastního handleru do řetězce handlerů:
push pointer_to_exception_handler
push dword ptr fs:[0]
mov fs:[0], esp
• Odinstalace:
pop dword ptr fs:[0]
add esp, 4
SEH: ukázka
• OllyDbg assembler:
• Instalace handleru na 0040101A
• INT 3 vyvolá výjimku
• JMP způsobí zacyklení
Table-based exception handling
• 64bitový Windows nezná SEH
• Table-based exception handling je popsaný v datech,
neinstaluje se během spouštění kódu
Entry point, kód, importy, data
• PE header je taky v paměti
• Entry point určuje PE header
• Kód, importy, data atd. načtené ze sekcí v souboru
Importy
• „.rdata“ sekce: read-only initialized data
• Knihovny, které program používá
• OllyDbg: View – Executable modules
• User-mode systémové knihovny načtené těsně pod
hranicí 2 GB
Shrnutí instrukcí
• MOV
• CMP, SUB
• TEST, AND
• JE, Jcc
• JMP
• PUSH, POP
• CALL, RET
• Adresace paměti pomocí [moffs] a [disp32]
• INT3
• NOP
• ADD [EAX], AL
Domácí úkoly
1. Crackněte crackme2, jakobyste neznali heslo
3. Pokud nahradíme instrukci TEST za AND, jak se změní
chování crackme2?
4. Jakou jinou logickou instrukci se stejnými operandy a
stejným testováním výsledku bysme mohli k
vyhodnocení použít?
Crackme3
• Jenom naživo, slidy nejsou
3. část: C crackmes
• Crackmes napsané v jazyce C
• Jenom naživo, slidy nejsou
Dekompilace crackme2 (asm verze)
void __cdecl start(UINT a1)
{
hConsoleOutput = GetStdHandle(0xFFFFFFF5);
hConsoleInput = GetStdHandle(0xFFFFFFF6);
WriteConsoleA(hConsoleOutput, aCrackme2ByRubb, 0x2Bu, &Ncw, 0);
ReadConsoleA(hConsoleInput, String1, 0x14u, &NumberOfCharsRead, 0);
if ( lstrcmpA(String1, String2) )
WriteConsoleA(hConsoleOutput, aNo_ThisIsnTGoo, 0x22u, & Ncw, 0);
else
WriteConsoleA(hConsoleOutput, aGoodJobCracker, 0x15u, & Ncw, 0);
ExitProcess(a1);
}
Dekompilace crackme3 (asm verze)
--Ncr;
if ( (signed int)--Ncr <= 3 || Ncr > 0xE )
WriteConsoleA(hConsoleOutput, aLoginMustHaveM, 0x39u, &Ncw, 0);
else
{
WriteConsoleA(hConsoleOutput, aInsertPassword, 0x12u, &Ncw, 0);
ReadConsoleA(hConsoleInput, String1, 0x64u, &Ncr, 0);
for ( i = &unk_4030AB; *i; ++i )
{
sub_40117C((unsigned __int8)*i, (int)&word_40318B);
*v0 = word_40318B;
}
String1[sub_401170((int)String1) - 2] = 0;
sub_4011AE((int)v0, v1, (int)String1);
if ( lstrcmpA(String1, String2) )
WriteConsoleA(hConsoleOutput, aNo_ThisIsnTGoo, 0x22u, &Ncw, 0);
else
WriteConsoleA(hConsoleOutput, aGoodJobCracker, 0x15u, &Ncw, 0);
}
Díky za pozornost!
karel@defendio.net
milan@defendio.net
RubberDuck@security-portal.cz
Nedokončeno
• Sorry, nestíhám
• Formát Portable Executable
• Oficiálně: PECOFF verze 8.3
Přídavek: formát instrukce podrobně
• Pokud lidi neodejdou, poveselit je ještě popisem formátu
instrukce
Jenom jednobajtový primární opkód
• 90 NOP – No OPeration
• CC INT3
• 50+r PUSH r
• 5 horních bitů opkód (01010), 3 dolní bity kód registru
• Příklady:
• 01010 000 PUSH rAX
• 01010 001 PUSH rCX
• 01010 010 PUSH rDX
• 01010 111 PUSH rDI
Registr zakódovaný v opkódu + imm
• B8+r MOV r32/64, imm32/64
• BA 10203040 MOV EDX, 40302010
• Registrů na x64 je 16, tzn. jsou potřeba 4 bity pro kód
• Přístup k novým registrům pomocí prefixu REX.B
41 BA 10203040 MOV R10D, 40302010
• Přístup k operandům r64, imm64 pomocí prefixu REX.W:
48 BA 1020304050607080
MOV RDX, 8070605040302010
• Kombinace - prefix REX.WB:
49 BA 1020304050607080
MOV R10, 8070605040302010
REX prefixy
• Opkódy 40-4F
• ref.x86asm.net/coder64.html#x40
• x64: 16 registrů, ale jednotlivých 8bitových částí je 20...
• Opkód 40 - „plain“ REX prefix přepíná:
AH CH DH BH bez jakéhokoliv REX prefixu
SPL BPL SIL DIL s jakýmkoliv REX prefixem
ModR/M byte
• 2 bity 7-6: pole Mod
• 3 bity 5-3: kód registru nebo 3-bit opcode extension
• 3 bity 2-0: kód registru nebo kód paměťového operandu
ModR/M byte: operandy reg, reg
• 85C0 TEST EAX, EAX
• Obecně:
• 85 /r TEST r/m16/32, r16/32
• /r v manuálech značí přítomnost ModR/M byte
• ModR/M C0: 11‘000‘000
• Mod 11: operand R/M je registr
• Reg 000: EAX
• R/M 000: EAX
ModR/M: ruční disassembling 0xC0
• 85C0 TEST EAX, EAX
• ref.x86asm.net/coder32.html#modrm_byte_32
ModR/M: ruční diassembling 0x00
• 0000 ADD [EAX], AL
• 00 /r ADD r/m8, r8
Reg/Opcode obsahuje 3-bit opkód
• crackme1:
• 83F8 01 CMP EAX, 1
• Obecně:
• ref.x86asm.net/coder32.html#x83
• 83 /7 CMP r/m16/32, imm8
• /digit značí ModR/M byte s 3bitovou opcode extension
• F8 = 11‘111‘000
• Mod 11: R/M kóduje registr
• Reg/Opcode 111: opcode extension 7
• R/M 000: registr EAX
Mod 00
Operand disp32
• crackme2:
• 00401029 FF35 95304000
PUSH DWORD PTR [403095]
• ModR/M 35
Mod 01 a 10
• Mod 01: přidání disp8
• Mod 10: přidání disp32
ModR/M: nejenom GP registry
• ModR/M kóduje i MMX, XMM, segment, control a debug
registry, ty neřešíme
Motivace pro ruční disassembling
• Chyby a lidová tvořivost v disassemblerech
• Disassembler někdy není po ruce
• Patchování, hlavně když není dost místa
• Shellcode: „cení se každý ušetřený bajt, který neohrozí
funkčnost shellcodu“
• Dis/assemblování z hlavy v hospodě
Shrnutí opkódů
• A0-A3: zvláštní skupina opkódů, jsou další
• rAX: operace s „accumulator“ často využívají vlastní
kratší opkódy
• Jenom jeden formát instrukce
• Jednobajtový opkód (NOP)
• Jednobajtový opkód + kód registru
• Některé REX prefixy
• Kompletní ModR/M byte
• Displacement, memory offset
• Immediate
Trocha historie
• Původně se registr
SP nedal pro
adresaci paměti
vůbec použít (8086)
• Vyřešilo to přidání
SIB byte později
(80286)

Weitere ähnliche Inhalte

Andere mochten auch

Zabezpečení nejen SSH na serveru pomocí Fail2Ban a jednoduchého honeypotu. / ...
Zabezpečení nejen SSH na serveru pomocí Fail2Ban a jednoduchého honeypotu. / ...Zabezpečení nejen SSH na serveru pomocí Fail2Ban a jednoduchého honeypotu. / ...
Zabezpečení nejen SSH na serveru pomocí Fail2Ban a jednoduchého honeypotu. / ...Security Session
 
Getting your hands dirty: How to Analyze the Behavior of Malware Traffic / SE...
Getting your hands dirty: How to Analyze the Behavior of Malware Traffic / SE...Getting your hands dirty: How to Analyze the Behavior of Malware Traffic / SE...
Getting your hands dirty: How to Analyze the Behavior of Malware Traffic / SE...Security Session
 
The LLDB Debugger in FreeBSD by Ed Maste
The LLDB Debugger in FreeBSD by Ed MasteThe LLDB Debugger in FreeBSD by Ed Maste
The LLDB Debugger in FreeBSD by Ed Masteeurobsdcon
 
#ochranadat pred sebou samotným / MATEJ ZACHAR [SAFETICA TECHNOLOGIES S.R.O.]
#ochranadat pred sebou samotným / MATEJ ZACHAR [SAFETICA TECHNOLOGIES S.R.O.]#ochranadat pred sebou samotným / MATEJ ZACHAR [SAFETICA TECHNOLOGIES S.R.O.]
#ochranadat pred sebou samotným / MATEJ ZACHAR [SAFETICA TECHNOLOGIES S.R.O.]Security Session
 
Co vše skrývá síťový provoz a jak detekovat kybernetické hrozby? / MARTIN ŠKO...
Co vše skrývá síťový provoz a jak detekovat kybernetické hrozby? / MARTIN ŠKO...Co vše skrývá síťový provoz a jak detekovat kybernetické hrozby? / MARTIN ŠKO...
Co vše skrývá síťový provoz a jak detekovat kybernetické hrozby? / MARTIN ŠKO...Security Session
 
Введение в реверс-инжиниринг вредоносного ПО - Сергей Харюк
Введение в реверс-инжиниринг вредоносного ПО - Сергей ХарюкВведение в реверс-инжиниринг вредоносного ПО - Сергей Харюк
Введение в реверс-инжиниринг вредоносного ПО - Сергей ХарюкHackIT Ukraine
 
Practical Malware Analysis: Ch 9: OllyDbg
Practical Malware Analysis: Ch 9: OllyDbgPractical Malware Analysis: Ch 9: OllyDbg
Practical Malware Analysis: Ch 9: OllyDbgSam Bowne
 
Introduction to Debuggers
Introduction to DebuggersIntroduction to Debuggers
Introduction to DebuggersSaumil Shah
 
Kernel mode vs user mode in linux
Kernel mode vs user mode in linuxKernel mode vs user mode in linux
Kernel mode vs user mode in linuxSiddique Ibrahim
 

Andere mochten auch (11)

Zabezpečení nejen SSH na serveru pomocí Fail2Ban a jednoduchého honeypotu. / ...
Zabezpečení nejen SSH na serveru pomocí Fail2Ban a jednoduchého honeypotu. / ...Zabezpečení nejen SSH na serveru pomocí Fail2Ban a jednoduchého honeypotu. / ...
Zabezpečení nejen SSH na serveru pomocí Fail2Ban a jednoduchého honeypotu. / ...
 
Getting your hands dirty: How to Analyze the Behavior of Malware Traffic / SE...
Getting your hands dirty: How to Analyze the Behavior of Malware Traffic / SE...Getting your hands dirty: How to Analyze the Behavior of Malware Traffic / SE...
Getting your hands dirty: How to Analyze the Behavior of Malware Traffic / SE...
 
The LLDB Debugger in FreeBSD by Ed Maste
The LLDB Debugger in FreeBSD by Ed MasteThe LLDB Debugger in FreeBSD by Ed Maste
The LLDB Debugger in FreeBSD by Ed Maste
 
Dissecting BetaBot
Dissecting BetaBotDissecting BetaBot
Dissecting BetaBot
 
#ochranadat pred sebou samotným / MATEJ ZACHAR [SAFETICA TECHNOLOGIES S.R.O.]
#ochranadat pred sebou samotným / MATEJ ZACHAR [SAFETICA TECHNOLOGIES S.R.O.]#ochranadat pred sebou samotným / MATEJ ZACHAR [SAFETICA TECHNOLOGIES S.R.O.]
#ochranadat pred sebou samotným / MATEJ ZACHAR [SAFETICA TECHNOLOGIES S.R.O.]
 
Co vše skrývá síťový provoz a jak detekovat kybernetické hrozby? / MARTIN ŠKO...
Co vše skrývá síťový provoz a jak detekovat kybernetické hrozby? / MARTIN ŠKO...Co vše skrývá síťový provoz a jak detekovat kybernetické hrozby? / MARTIN ŠKO...
Co vše skrývá síťový provoz a jak detekovat kybernetické hrozby? / MARTIN ŠKO...
 
Введение в реверс-инжиниринг вредоносного ПО - Сергей Харюк
Введение в реверс-инжиниринг вредоносного ПО - Сергей ХарюкВведение в реверс-инжиниринг вредоносного ПО - Сергей Харюк
Введение в реверс-инжиниринг вредоносного ПО - Сергей Харюк
 
Anti Debugging
Anti DebuggingAnti Debugging
Anti Debugging
 
Practical Malware Analysis: Ch 9: OllyDbg
Practical Malware Analysis: Ch 9: OllyDbgPractical Malware Analysis: Ch 9: OllyDbg
Practical Malware Analysis: Ch 9: OllyDbg
 
Introduction to Debuggers
Introduction to DebuggersIntroduction to Debuggers
Introduction to Debuggers
 
Kernel mode vs user mode in linux
Kernel mode vs user mode in linuxKernel mode vs user mode in linux
Kernel mode vs user mode in linux
 

Ähnlich wie Základy reverse engineeringu a assembleru / KAREL LEJSKA, MILAN BARTOŠ [DEFENDIO]

Mikro­kontrolér s Wi-Fi za $3! nejen pro IOT
Mikro­kontrolér s Wi-Fi za $3! nejen pro IOTMikro­kontrolér s Wi-Fi za $3! nejen pro IOT
Mikro­kontrolér s Wi-Fi za $3! nejen pro IOTAdam Hořčica
 
Czech Oracle Solaris Administrators Day 2011 - DTrace
Czech Oracle Solaris Administrators Day 2011 - DTrace Czech Oracle Solaris Administrators Day 2011 - DTrace
Czech Oracle Solaris Administrators Day 2011 - DTrace Martin Cerveny
 
CZNIC: Správa internetu, routing a IPv6
CZNIC: Správa internetu, routing a IPv6CZNIC: Správa internetu, routing a IPv6
CZNIC: Správa internetu, routing a IPv6Tomáš Holas
 
Řečové technologie ve věku zlaté horečky DNN
Řečové technologie ve věku zlaté horečky DNNŘečové technologie ve věku zlaté horečky DNN
Řečové technologie ve věku zlaté horečky DNNYtica
 
Analýza zaváděcího sektoru a procesu bootování Windows 8.1
Analýza zaváděcího sektoru a procesu bootování Windows 8.1Analýza zaváděcího sektoru a procesu bootování Windows 8.1
Analýza zaváděcího sektoru a procesu bootování Windows 8.1Security Session
 
Slovak Sun Training Day 2010 - DTrace
Slovak Sun Training Day 2010 - DTraceSlovak Sun Training Day 2010 - DTrace
Slovak Sun Training Day 2010 - DTraceMartin Cerveny
 
Elm - Funkcionální nebe pro webové vývojáře
Elm - Funkcionální nebe pro webové vývojářeElm - Funkcionální nebe pro webové vývojáře
Elm - Funkcionální nebe pro webové vývojářeTomáš Látal
 
Rodina protokolů TCP/IP, téma 5: Protokol IPv4
Rodina protokolů TCP/IP, téma 5: Protokol IPv4Rodina protokolů TCP/IP, téma 5: Protokol IPv4
Rodina protokolů TCP/IP, téma 5: Protokol IPv4Jiří Peterka
 
Arduino naplno (Arduino Day 2015)
Arduino naplno (Arduino Day 2015)Arduino naplno (Arduino Day 2015)
Arduino naplno (Arduino Day 2015)Adam Hořčica
 

Ähnlich wie Základy reverse engineeringu a assembleru / KAREL LEJSKA, MILAN BARTOŠ [DEFENDIO] (13)

Mikro­kontrolér s Wi-Fi za $3! nejen pro IOT
Mikro­kontrolér s Wi-Fi za $3! nejen pro IOTMikro­kontrolér s Wi-Fi za $3! nejen pro IOT
Mikro­kontrolér s Wi-Fi za $3! nejen pro IOT
 
Czech Oracle Solaris Administrators Day 2011 - DTrace
Czech Oracle Solaris Administrators Day 2011 - DTrace Czech Oracle Solaris Administrators Day 2011 - DTrace
Czech Oracle Solaris Administrators Day 2011 - DTrace
 
CZNIC: Správa internetu, routing a IPv6
CZNIC: Správa internetu, routing a IPv6CZNIC: Správa internetu, routing a IPv6
CZNIC: Správa internetu, routing a IPv6
 
Bes07
Bes07Bes07
Bes07
 
Řečové technologie ve věku zlaté horečky DNN
Řečové technologie ve věku zlaté horečky DNNŘečové technologie ve věku zlaté horečky DNN
Řečové technologie ve věku zlaté horečky DNN
 
JPEG
JPEGJPEG
JPEG
 
Analýza zaváděcího sektoru a procesu bootování Windows 8.1
Analýza zaváděcího sektoru a procesu bootování Windows 8.1Analýza zaváděcího sektoru a procesu bootování Windows 8.1
Analýza zaváděcího sektoru a procesu bootování Windows 8.1
 
Slovak Sun Training Day 2010 - DTrace
Slovak Sun Training Day 2010 - DTraceSlovak Sun Training Day 2010 - DTrace
Slovak Sun Training Day 2010 - DTrace
 
Elm - Funkcionální nebe pro webové vývojáře
Elm - Funkcionální nebe pro webové vývojářeElm - Funkcionální nebe pro webové vývojáře
Elm - Funkcionální nebe pro webové vývojáře
 
IoT Hackathon
IoT HackathonIoT Hackathon
IoT Hackathon
 
Rodina protokolů TCP/IP, téma 5: Protokol IPv4
Rodina protokolů TCP/IP, téma 5: Protokol IPv4Rodina protokolů TCP/IP, téma 5: Protokol IPv4
Rodina protokolů TCP/IP, téma 5: Protokol IPv4
 
WARC 1.1 je skoro tady - co přinese nová verze?
WARC 1.1 je skoro tady - co přinese nová verze?WARC 1.1 je skoro tady - co přinese nová verze?
WARC 1.1 je skoro tady - co přinese nová verze?
 
Arduino naplno (Arduino Day 2015)
Arduino naplno (Arduino Day 2015)Arduino naplno (Arduino Day 2015)
Arduino naplno (Arduino Day 2015)
 

Mehr von Security Session

Insights of a brute-forcing botnet / VERONICA VALEROS [CISCO]
Insights of a brute-forcing botnet / VERONICA VALEROS [CISCO]Insights of a brute-forcing botnet / VERONICA VALEROS [CISCO]
Insights of a brute-forcing botnet / VERONICA VALEROS [CISCO]Security Session
 
Softwarove protektory / KAREL LEJSKA, MILAN BARTOŠ [DEFENDIO]
Softwarove protektory / KAREL LEJSKA, MILAN BARTOŠ [DEFENDIO]Softwarove protektory / KAREL LEJSKA, MILAN BARTOŠ [DEFENDIO]
Softwarove protektory / KAREL LEJSKA, MILAN BARTOŠ [DEFENDIO]Security Session
 
Wintel Hell: průvodce devíti kruhy Dantova technologického pekla / MARTIN HRO...
Wintel Hell: průvodce devíti kruhy Dantova technologického pekla / MARTIN HRO...Wintel Hell: průvodce devíti kruhy Dantova technologického pekla / MARTIN HRO...
Wintel Hell: průvodce devíti kruhy Dantova technologického pekla / MARTIN HRO...Security Session
 
Robots against robots: How a Machine Learning IDS detected a novel Linux Botn...
Robots against robots: How a Machine Learning IDS detected a novel Linux Botn...Robots against robots: How a Machine Learning IDS detected a novel Linux Botn...
Robots against robots: How a Machine Learning IDS detected a novel Linux Botn...Security Session
 
Exploitace – od minulosti po současnost - Jan Kopecký
Exploitace – od minulosti po současnost - Jan KopeckýExploitace – od minulosti po současnost - Jan Kopecký
Exploitace – od minulosti po současnost - Jan KopeckýSecurity Session
 
Kontrola uživatelských účtů ve Windows a jak ji obejít - Martin Dráb
Kontrola uživatelských účtů ve Windows a jak ji obejít - Martin DrábKontrola uživatelských účtů ve Windows a jak ji obejít - Martin Dráb
Kontrola uživatelských účtů ve Windows a jak ji obejít - Martin DrábSecurity Session
 
Research in Liveness Detection - Martin Drahanský
Research in Liveness Detection - Martin DrahanskýResearch in Liveness Detection - Martin Drahanský
Research in Liveness Detection - Martin DrahanskýSecurity Session
 
Dolování dat z řeči pro bezpečnostní aplikace - Jan Černocký
Dolování dat z řeči pro bezpečnostní aplikace - Jan ČernockýDolování dat z řeči pro bezpečnostní aplikace - Jan Černocký
Dolování dat z řeči pro bezpečnostní aplikace - Jan ČernockýSecurity Session
 
Co se skrývá v datovém provozu? - Pavel Minařík
Co se skrývá v datovém provozu? - Pavel MinaříkCo se skrývá v datovém provozu? - Pavel Minařík
Co se skrývá v datovém provozu? - Pavel MinaříkSecurity Session
 
Jak odesílat zprávy, když někdo vypne Internet - Pavel Táborský
Jak odesílat zprávy, když někdo vypne Internet - 	Pavel TáborskýJak odesílat zprávy, když někdo vypne Internet - 	Pavel Táborský
Jak odesílat zprávy, když někdo vypne Internet - Pavel TáborskýSecurity Session
 
Two Years with botnet Asprox - Michal Ambrož
Two Years with botnet Asprox - Michal AmbrožTwo Years with botnet Asprox - Michal Ambrož
Two Years with botnet Asprox - Michal AmbrožSecurity Session
 
Falsifikace biometricke charakteristiky a detekce zivosti
Falsifikace biometricke charakteristiky a detekce zivostiFalsifikace biometricke charakteristiky a detekce zivosti
Falsifikace biometricke charakteristiky a detekce zivostiSecurity Session
 
Detekcia kompromitacie z pohladu pracovnika bezpecnosti
Detekcia kompromitacie z pohladu pracovnika bezpecnostiDetekcia kompromitacie z pohladu pracovnika bezpecnosti
Detekcia kompromitacie z pohladu pracovnika bezpecnostiSecurity Session
 
Dejiny podvodov v bitcoinovom svete
Dejiny podvodov v bitcoinovom sveteDejiny podvodov v bitcoinovom svete
Dejiny podvodov v bitcoinovom sveteSecurity Session
 
Ako sa nestat internetovym podvodnikom
Ako sa nestat internetovym podvodnikomAko sa nestat internetovym podvodnikom
Ako sa nestat internetovym podvodnikomSecurity Session
 
Decentralized society and Bitcoin contracts
Decentralized society and Bitcoin contractsDecentralized society and Bitcoin contracts
Decentralized society and Bitcoin contractsSecurity Session
 

Mehr von Security Session (20)

Insights of a brute-forcing botnet / VERONICA VALEROS [CISCO]
Insights of a brute-forcing botnet / VERONICA VALEROS [CISCO]Insights of a brute-forcing botnet / VERONICA VALEROS [CISCO]
Insights of a brute-forcing botnet / VERONICA VALEROS [CISCO]
 
Softwarove protektory / KAREL LEJSKA, MILAN BARTOŠ [DEFENDIO]
Softwarove protektory / KAREL LEJSKA, MILAN BARTOŠ [DEFENDIO]Softwarove protektory / KAREL LEJSKA, MILAN BARTOŠ [DEFENDIO]
Softwarove protektory / KAREL LEJSKA, MILAN BARTOŠ [DEFENDIO]
 
Wintel Hell: průvodce devíti kruhy Dantova technologického pekla / MARTIN HRO...
Wintel Hell: průvodce devíti kruhy Dantova technologického pekla / MARTIN HRO...Wintel Hell: průvodce devíti kruhy Dantova technologického pekla / MARTIN HRO...
Wintel Hell: průvodce devíti kruhy Dantova technologického pekla / MARTIN HRO...
 
Robots against robots: How a Machine Learning IDS detected a novel Linux Botn...
Robots against robots: How a Machine Learning IDS detected a novel Linux Botn...Robots against robots: How a Machine Learning IDS detected a novel Linux Botn...
Robots against robots: How a Machine Learning IDS detected a novel Linux Botn...
 
Prezentace brno
Prezentace brnoPrezentace brno
Prezentace brno
 
OSINT and beyond
OSINT and beyondOSINT and beyond
OSINT and beyond
 
Exploitace – od minulosti po současnost - Jan Kopecký
Exploitace – od minulosti po současnost - Jan KopeckýExploitace – od minulosti po současnost - Jan Kopecký
Exploitace – od minulosti po současnost - Jan Kopecký
 
Kontrola uživatelských účtů ve Windows a jak ji obejít - Martin Dráb
Kontrola uživatelských účtů ve Windows a jak ji obejít - Martin DrábKontrola uživatelských účtů ve Windows a jak ji obejít - Martin Dráb
Kontrola uživatelských účtů ve Windows a jak ji obejít - Martin Dráb
 
Research in Liveness Detection - Martin Drahanský
Research in Liveness Detection - Martin DrahanskýResearch in Liveness Detection - Martin Drahanský
Research in Liveness Detection - Martin Drahanský
 
Dolování dat z řeči pro bezpečnostní aplikace - Jan Černocký
Dolování dat z řeči pro bezpečnostní aplikace - Jan ČernockýDolování dat z řeči pro bezpečnostní aplikace - Jan Černocký
Dolování dat z řeči pro bezpečnostní aplikace - Jan Černocký
 
Turris - Robert Šefr
Turris - Robert ŠefrTurris - Robert Šefr
Turris - Robert Šefr
 
Co se skrývá v datovém provozu? - Pavel Minařík
Co se skrývá v datovém provozu? - Pavel MinaříkCo se skrývá v datovém provozu? - Pavel Minařík
Co se skrývá v datovém provozu? - Pavel Minařík
 
Jak odesílat zprávy, když někdo vypne Internet - Pavel Táborský
Jak odesílat zprávy, když někdo vypne Internet - 	Pavel TáborskýJak odesílat zprávy, když někdo vypne Internet - 	Pavel Táborský
Jak odesílat zprávy, když někdo vypne Internet - Pavel Táborský
 
Two Years with botnet Asprox - Michal Ambrož
Two Years with botnet Asprox - Michal AmbrožTwo Years with botnet Asprox - Michal Ambrož
Two Years with botnet Asprox - Michal Ambrož
 
Falsifikace biometricke charakteristiky a detekce zivosti
Falsifikace biometricke charakteristiky a detekce zivostiFalsifikace biometricke charakteristiky a detekce zivosti
Falsifikace biometricke charakteristiky a detekce zivosti
 
Nehacknutelny web
Nehacknutelny webNehacknutelny web
Nehacknutelny web
 
Detekcia kompromitacie z pohladu pracovnika bezpecnosti
Detekcia kompromitacie z pohladu pracovnika bezpecnostiDetekcia kompromitacie z pohladu pracovnika bezpecnosti
Detekcia kompromitacie z pohladu pracovnika bezpecnosti
 
Dejiny podvodov v bitcoinovom svete
Dejiny podvodov v bitcoinovom sveteDejiny podvodov v bitcoinovom svete
Dejiny podvodov v bitcoinovom svete
 
Ako sa nestat internetovym podvodnikom
Ako sa nestat internetovym podvodnikomAko sa nestat internetovym podvodnikom
Ako sa nestat internetovym podvodnikom
 
Decentralized society and Bitcoin contracts
Decentralized society and Bitcoin contractsDecentralized society and Bitcoin contracts
Decentralized society and Bitcoin contracts
 

Základy reverse engineeringu a assembleru / KAREL LEJSKA, MILAN BARTOŠ [DEFENDIO]

  • 2. Pojetí workshopu • Solidní základy pro reverzování • Windows: tradiční platforma pro reverzery • OllyDbg: nejoblíbenější debugger • x64dbg: částečná náhrada za nedokončený 64-bit OllyDbg, postupy bývají stejné • Slidy pro pozdější studium
  • 3. Podklady • Nebojte se reverzního inženýrství I. • Nebojte se reverzního inženýrství II. • Nebojte se reverzního inženýrství III. • x86asm.net/links • ref.x86asm.net/coder32.html • ref.x86asm.net/coder64.html • Poděkování Lukáši „RubberDuck“ Čižmarovi • Security Cave
  • 4. 1. část • Crackme #1 by RubberDuck • + opkódy instrukcí • + x64 • + x64 verze crackme #1
  • 5. 1. workshop - nástroje • 32bitový debugger OllyDbg • OllyDbg 2.01 • 64bitový debugger x64dbg • x64dbg snapshot_2016-01-21_02-44
  • 6. Crackme #1 by RubberDuck
  • 10. crackme1.exe – 1. instrukce MOV • 00401000 B8 00000000 MOV EAX, 0 • 1. sloupec – virtuální adresa 00401000 • 2. sloupec – operační kód – opcode B8 00000000 • 3. sloupec – instrukce MOV EAX, 0 • OllyDbg disassembler: Intel syntax, MASM příchuť • OllyDbg AT&T syntaxe: MOVL $0, %EAX
  • 11. 1. instrukce podrobně • B8 00000000 MOV EAX, 0 • Mnemonic MOV • Cílový 32bitový operand EAX • Zdrojový 32bitový operand 0x0 • Jednobajtový primární opkód 0xB8 • ref.x86asm.net/coder32.html#xB8 • Skupina opkódů B8+r MOV r16/32, imm16/32 • 32bitová konstanta 0x00000000 • Intel jí říká immediate value
  • 12. IA-32 general-purpose registers • Osm 32bitových všeobecných registrů, kód 0-7 (3 bity) EAX ECX EDX EBX ESP EBP ESI EDI 0 1 2 3 4 5 6 7
  • 13. General-purpose registers - příklady • EAX = 44332211 – 32 bitů, velikost DWORD • AX: 2211 – 16 bitů, velikost WORD • AL: 11 – dolních 8 bitů, velikost BYTE • AH: 22 – horních 8 bitů, velikost BYTE • EBP = 40302010 • BP: 2010 • Horní WORD nemá název a nejde ho adresovat • Pozn. 4 bitům (půlbajt) se říká nibble
  • 14. Crackme1.exe – 2. instrukce CMP • 00401005 83F8 01 CMP EAX, 1 • Mnemonic CMP • Cílový 32bitový operand EAX • Zdrojový 32bitový operand 0x1 • Jednobajtový primární opkód 0x83 • ref.x86asm.net/coder32.html#x83 • Skupina opkódů 83 • ModR/M byte F8 = 11111000bin • zatím to víc neřešíme • 8bitová přímá (immediate) hodnota 0x01
  • 15. Skupina opkódů 0x83 • Osm aritmetických a logických instrukcí • Operandy: r/m16/32, imm8 • Viz taky opkódy 80, 81
  • 16. 2. instrukce podrobně • CMP: compare two operands • CMP nemění žádný operand • Operace CMP = operace SUB • SUB: subtract two operands • SUB EAX, 1: EAX = EAX - 1 • CMP nastavuje šest stavových příznaků (status flags): CF, PF, AF, ZF, SF, OF • Viz instrukční reference: • Příznaky jsou uloženy v registru EFlags
  • 17. Registr EFlags, operace CMP • Šest stavových příznaků v bitech 0, 2, 4, 6, 7 a 11 • Hromada jiných, ty teď neřešíme • CMP nastaví ZF (Zero Flag), pokud mají operandy stejnou hodnotu • Stejně jako SUB nastaví ZF, pokud je výsledek odečítání nula
  • 18. crackme1.exe – 3. instrukce JE • 00401008 74 0C JE SHORT 00401016 • Jednobajtový primární opkód 0x74 • ref.x86asm.net/coder32.html#x74 • Mnemonic JE: Jump if Equal • Mnemonic JZ: Jump if Zero • SHORT znamená skok v rozmezí -128 a +127 bajtů • Skupina opkódů 70-7F: 16 podmíněných skoků Jcc • 8-bit relative offset 0x0C • Relativní offset se přičítá k registru EIP
  • 19. 3. instrukce JE a reg. EIP podrobně • EIP: Instruction Pointer Register • EIP obsahuje virtuální adresu následující instrukce, tzn. v době spouštění instrukce JE je EIP 40100A • Operace: if (ZF == 1) EIP = EIP + sign extended rel8 • Kalkulace návěští (label) skoku: adresa instrukce JE je 401008, je dlouhá 2 bajty: 401008 + 2 + 0C = 401016
  • 20. crackme1.exe – 4. instrukce MOV • 0040100A B8 14304000 MOV EAX, OFFSET 00403014 • Viz 1. instrukce MOV • OFFSET: MASM příchuť, důsledek analýzy – OllyDbg rozeznal, že jde o adresu, ne o nahodilou hodnotu • Na adrese 403014 je řetězec "Please patch me! :("
  • 21. crackme1.exe – 5. instrukce MOV • 0040100F B9 30000000 MOV ECX, 30 • Viz 1. instrukce MOV • Připomenutí: opkód B9 = B8+r, kód ECX je 1
  • 22. crackme1.exe – 6. instrukce JMP • 00401014 EB 0A JMP SHORT 00401020 • ref.x86asm.net/coder32.html#xEB: JMP rel8 • Mnemonic JMP: Unconditional Jump • SHORT znamená skok v rozmezí -128 a +127 bajtů • 8-bit relative offset 0x0A • Relativní offset se přičítá k registru EIP • Kalkulace návěští skoku: 401014 + 2 + 0A = 401020
  • 23. crackme1.exe – 9. instrukce PUSH • 00401020 51 PUSH ECX • ref.x86asm.net/coder32.html#x50: 50+r PUSH r16/32 • Skupina opkódů 50-57 • Uloží hodnotu operandu na zásobník ve dvou krocích: ESP = ESP – 4 *ESP = ECX • Zásobník je zatím prostě nějaká paměť, víc to neřešíme • OllyDbg: zásobník je vidět vpravo dole
  • 24. Parametry WinAPI MessageBoxA() • Prototyp funkce z MSDN: int WINAPI MessageBox( _In_opt_ HWND hWnd, _In_opt_ LPCTSTR lpText, _In_opt_ LPCTSTR lpCaption, _In_ UINT uType );
  • 25. Parametry WinAPI MessageBoxA() • Odpovídající instrukce PUSH 51 PUSH ECX ; uType 68 28304000 PUSH OFFSET 403028 ; lpCaption 50 PUSH EAX ; lpText 6A 00 PUSH 0 ; hWnd
  • 26. Volací konvence stdcall • Konvence je vidět v prototypu: • int WINAPI MessageBox(); • WinDef.h (Windows SDKs): • #define WINAPI __stdcall • MSDN stdcall calling convention • Parametry jsou uložené zprava doleva • Zásobník čistí volaná funkce • Návratová hodnota je v registru EAX • Registry EAX, ECX a EDX může volaná funkce změnit, ostatní musí zachovat • stdcall používá většina WinAPI funkcí
  • 27. Další formy instrukce PUSH • PUSH immediate value: buď 32bitová hodnota, nebo znaménkově rozšířený imm8 na 32 bitů 68 28304000 PUSH OFFSET 403028 6A 00 PUSH 0
  • 28. crackme1.exe – 13. instrukce CALL • 00401029 E8 0E000000 CALL <jmp.&user32.MessageBoxA> • Trochu jinak: • CALL 0040103C • Jednobajtový primární opkód E8 CALL rel16/32 • Operace: PUSH EIP JMP 0040103C • Tento CALL volá MessageBoxA() nepřímo přes JMP umístěný na konci kódu, je to záležitost importování funkcí a assembleru MASM, toto teď neřešíme
  • 29. Volání funkce: pár CALL - RET CALL func ... func: ... RET ; taky „RETN“ • Operace CALL: • ESP = ESP – 4 • *ESP = EIP • JMP func • Operace RET: • EIP = *ESP • ESP = ESP + 4
  • 30. OllyDbg: základní akce • Step into (klávesa F7): dojde k přechodu na návěští CALL • Step over (klávesa F8): krokování pokračuje až po návratu z CALL • Run (klávesa F9): spustí debugovaný program, tzn. nekrokuje ho • Restart (Ctrl+F2): zabije aktuální session a načte debugovaný program znovu; dobrá věc, pokud krokováním dojdu donikam a potřebuju začít znovu
  • 31. Disassembling MessageBoxA() 8BFF mov edi, edi 55 push ebp 8BEC mov ebp, esp 6A 00 push 0 FF75 14 push dword ptr [ebp+14] FF75 10 push dword ptr [ebp+10] FF75 0C push dword ptr [ebp+0C] FF75 08 push dword ptr [ebp+8] E8 A0FFFFFF call MessageBoxExA 5D pop ebp C2 1000 retn 10
  • 32. MessageBoxA(): RETN 10 • C2 1000 RETN 10 • 0x10 = 16 • 16/4 = 4 DWORD parametry • Pseudooperace: ESP = ESP + 16 EIP = *ESP ESP = ESP + 4
  • 33. crackme1.exe – 15. instrukce CALL • 00401030 E8 01000000 CALL <jmp.&kernel32.ExitProcess> • Trochu jinak: • CALL 00401036 • Viz předchozí instrukce CALL • Jde o ukončení procesu: funkce ExitProcess() v knihovně kernel32.dll • I když nikdy nedojde k návratu, stejně se použivá CALL a ne JMP
  • 34. OllyDbg assembler • Assembluj MOV EAX, 5 na adrese 401000 (= EIP)
  • 35. OllyDbg assembler • Např. nekonečná smyčka – instrukce MOV, SUB a JMP: 1. Assembluj MOV EAX, 5 na adrese 401000 (= EIP) 2. Assembluj SUB EAX, 1 na adrese 401005 3. Assembluj JMP 401005 na adrese 401008 • Změny se obarví červeně, super věc na učení se opkódů
  • 36. Instrukce INT3; NOP; ADD [EAX], AL • CC INT3 • Výplň kódu (i dat) na místech, kam se nemá dostat řízení • Způsobí ladící výjimku; tu teď neřešíme • 90 NOP • No OPeration • Výplň pro zarovnání kódu • 0000 ADD [EAX], AL • Podezřelá instrukce • Inicializační hodnota při alokaci paměti, nejde o kód
  • 37. Shrnutí pojmů (1) • Virtuální adresa • Opkód, primární opkód • Mnemonic instrukce • Operand instrukce • Intel syntaxe vs. AT&T syntaxe • Osm všeobecných registrů • Velikosti: DWORD, WORD, BYTE • Orientace v primárních opkódech • Registr EFlags, šest stavových příznaků, příznak ZF • Registr EIP, kalkulace návěští skoku • Volací konvence stdcall
  • 38. Shrnutí pojmů (2) • Volání funkce: CALL – RET • Odstraňování parametrů ze zásobníku pomocí RET • OllyDbg assembler
  • 39. Shrnutí instrukcí • MOV • CMP, SUB • JE, Jcc • JMP • PUSH • CALL • INT3 • NOP • ADD [EAX], AL
  • 40. Problémy s označením architektury • Hromada zjednodušujících názvů pro komplikovanou architekturu: • Intel • IA-32 architecture • Intel64 architecture (nový „64-bit mode“) • IA-64 je úplně jiná (mrtvá) architektura • AMD64 architecture • x86 architecture, „legacy mode“ • 64-bit x86 architecture (nový „Long Mode“) • Microsoft • x86 • x64
  • 41. Crackme #1 (x64) by RubberDuck
  • 44. crackme1_x64: 1. instrukce SUB • 000000013FC0100 48 83 EC 08 SUB RSP, 8 • Vypadá jako alokace 8 bajtů na zásobníku • Ve skutečnosti zarovnání zásobníku na 16 bajtů, vynucené volací konvencí (viz následující slajdy) • Komplikace při programování v assembleru • Jednobajtový primární operační znak 0x83 • ref.x86asm.net/coder64.html#x83 • Nová věc: prefix 48 REX.W • ref.x86asm.net/coder64.html#x48 • Nejčastější REX.W zvětší velikost operandu na 64 bitů • REX prefixy na x86 neexistují
  • 45. 64-bit registers • Šestnáct 64bitových všeobecných registrů, kód 0-15 (4 bity) RAX RCX RDX RBX RSP RBP RSI RDI 0 1 2 3 4 5 6 7 R8 R9 R10 R11 R12 R13 R14 R15 8 9 10 11 12 13 14 15 • 64bitový instrukční ukazatel RIP
  • 46. 64-bit general-purpose registers • RAX = 8877665544332211, velikost QWORD • EAX: 44332211 • AX: 2211 • AL: 11 • AH: 22 • RSP – ESP – SP – SPL • RBP – EBP – BP – BPL • RSI – ESI – SI – SIL • RDI – EDI – DI – DIL • R15 - R15D - R15W - R15B • Horní DWORD nejde adresovat a nemá název
  • 47. crackme1_x64: 5. instrukce MOVABS • 000000013FC0100 48 B8 1430C03F01000000 MOVABS RAX, 13FC03014 • Jednobajtový primární opkód 0xB8 • Prefix 48 REX.W • Mnemonic MOVABS neexistuje, jde o MOV • lidová tvořivost, odpovídá to správnějšímu OFFSET v OllyDbg
  • 48. crackme1_x64: volání MessageBoxA • Předávání parametrů je zhruba vidět: SUB RSP, 20 MOV RCX, 0 ; hWnd MOV RDX, RAX ; lpText MOVABS R8, 13FC03028 ; lpCaption MOV R9, RBX ; uType CALL <crackme1_x64.MessageBoxA> ADD RSP, 20 • První 4 parametry jdou vždycky do registrů RCX, RDX, R8 a R9 • Ale co ten SUB/ADD RSP, 20?
  • 49. Volací konvence fastcall (1) • Pozor, nejde o x86 fastcall, i když je podobný • Ještě jednou, konvence bývá vidět v prototypu: • int WINAPI MessageBox(); • WinDef.h (Windows SDKs): #define WINAPI • tentokrát je to „prázdná“ hodnota, všechno je fastcall (s výjimkami) • MSDN x64 fastcall calling convention • První 4 parametry jdou vždycky do registrů RCX, RDX, R8 a R9, ostatní na zásobník • Zásobník čistí volaná funkce • Návratová hodnota je v registru RAX • Registry RAX, RCX, RDX, R8, R9, R10 a R11 může volaná funkce změnit, ostatní musí zachovat
  • 50. Volací konvence fastcall (2) • První 4 parametry jsou v registrech, ale na zásobníku musí být tak jako tak alokovaný prostor, další jdou na zásobník jako u stdcall • Alokace a uvolnění 4 parametrů pomocí SUB/ADD RSP, 20 • 0x20 = 32 = 4*8
  • 51. fastcall a zarovnání zásobníku • MSDN: The stack will always be maintained 16-byte aligned • Vstupní bod programu je vlastně vstupní bod funkce main() • Volání funkce zruší zarovnání na 16 bytů: 1. Před provedením CALL je zásobník zarovnaný na 16 bytů 2. CALL provede PUSH RIP (8 bytů) 3. Na vstupu do funkce je potřeba zásobník znovu zarovnat pomocí SUB RSP, 8
  • 52. crackme1_x64: volání ExitProcess • ExitProcess() má jenom jeden parametr, ale na zásobníku je potřeba vždycky alokovat 4 parametry: SUB RSP, 20 ; 4*QWORD MOV ECX, 0 CALL crackme1_x64.RtlExitUserProcess
  • 53. Shrnutí pojmů (x64) • 16 64bitových všeobecných registrů • 64bitová virtuální paměť, registr RIP • Velikost QWORD • Volací konvence fastcall • Zarovnání zásobníku • Prefixy REX
  • 54. Úkoly 1. Crackněte crackme1 (x86 i x64) podle návodu v článku Nebojte se reverzního inženýrství I. 2. Crackněte crackme1 ještě jinak než podle návodu 3. Pokud v crackme1 změníte instrukci CMP na SUB, jaký vliv to bude mít na funkčnost programu? 4. Vytvořte přímo v OllyDbg assembleru co nejkratší kód, který způsobí vyčerpání paměti zásobníku
  • 55. 2. část • Crackme #2 by RubberDuck • + opkódy instrukcí • + x64 verze crackme #2 • Stack, heap, virtual memory • Memory model, TEB (TIB) • Exception handling • Entry point, kód, data • Importy • Binární formát instrukce
  • 56. Crackme #2 by RubberDuck
  • 58. crackme2.exe – 1. instrukce PUSH • 00401000 6A F5 PUSH -0B • ref.x86asm.net/coder32.html#x6A • 6A PUSH (sign extended) imm8 • imm8: 8bitová immediate value • Takže jinak (velikost položky na zásobníku je DWORD): • PUSH FFFFFFF5 • Je to první parametr volání WinAPI funkce GetStdHandle()
  • 59. GetStdHandle() • MSDN: Retrieves a handle to the specified standard device (standard input, standard output, or standard error). HANDLE WINAPI GetStdHandle( _In_ DWORD nStdHandle ); • Potřebujeme návratovou hodnotu HANDLE • winnt.h (Microsoft SDKs): • typedef void *HANDLE; • Volací konvence stdcall: návratová hodnota je v EAX, ta je uložena pomocí následující instrukce na později
  • 60. crackme2.exe – 3. instrukce MOV • 00401007 A3 95304000 MOV [403095], EAX • ref.x86asm.net/coder32.html#xA3 • A3 MOV moffs16/32, eAX • Opkódy A0-A3 • speciální forma MOV mezi AL/AX/EAX a pamětí • Registr eAX (tzn. AX nebo EAX): • accumulator, historicky optimalizovaný pro častý přístup • Spousta opkódů podporujících accumulator, umožňujících kratší kódování instrukcí (viz třeba 0x04, 0x05, 0x0C, ...) • Dědictví historie, dnes nemá podstatný význam • moffs - memory offset: konstatní hodnota adresuje paměť
  • 61. crackme2.exe – 3. instrukce MOV • MOV [403095], EAX • 0x403095 = 4206741 = nezarovnaná paměť při ukládání DWORD hodnoty • Architektura x86 nevynucuje zarovnání paměti na určitou hodnotu • Pozor, architektura x64 typicky (dá se to vypnout na úrovni OS) vyžaduje zarovnání paměti na „přirozenou“ hodnotu, tzn. DWORD je potřeba uložit na adresu zarovnanou na 4 byty atd. • Připomenutí: 64-bit Windows navíc vynucuje zarovnání zásobníku na 16 bytů (ještě z jiných důvodů) • Přístup k zarovnané paměti je rychlejší
  • 62. crackme2.exe – 10. a 11. instr. PUSH • 00401024 68 00304000 PUSH OFFSET 00403000 • 00401029 FF35 95304000 PUSH DWORD PTR [403095] • ref.x86asm.net/coder32.html#xFF • Skupina různých instrukcí • FF /6 PUSH r/m16/32 • ModR/M byte 0x35 (viz dál) • DWORD PTR: označení velikosti odkazované hodnoty
  • 63. crackme2.exe – porovnání hesel • WriteConsoleA(): vypíše výzvu k zadání hesla • ReadConsoleA(): přečte zadané heslo • lstrcmp(): WinAPI funkce porovnávající řetězce, podobná funkci ze standardní C knihovny int WINAPI lstrcmp( _In_ LPCTSTR lpString1, _In_ LPCTSTR lpString2 ); • „If the strings are equal, the return value is zero.“
  • 64. crackme2.exe – vyhodnocení hesla • 85C0 TEST EAX, EAX • Zvláštní případ na vyhodnocení nulové hodnoty v registru • Opkódy 84 a 85: TEST r/m, r • ModR/M byte C0 • TEST: logical compare • TEST nemění žádný operand • Operace TEST = operace AND • TEST nastavuje šest stavových příznaků, viz: • Smysl dávají tři: SF, ZF a PF • 0 AND 0 = 0 → nastaví se ZF
  • 65. crackme1.exe – vyhodnocení CMP • crackme1: 83F8 01 CMP EAX, 1 74 0C JE SHORT 00401016 • crackme2: 85C0 TEST EAX, EAX 74 1E JZ SHORT 00401081 • TEST EAX, EAX má kratší opkód než CMP EAX, 0 • Zajímavost: OllyDbg disassembler vyhodnotil, že vhodnější je mnemonic JZ
  • 66. Binární formát instrukce (opkód) • Teoreticky: • Formát instrukce je jenom jeden (ignorujeme VEX) • Instrukce se skládá z 6 částí • Primární opkód se vyskytuje vždycky, ostatní volitelně 1. Prefix(y) 2. Primární opkód: 1, 2 nebo 3 byty, volitelně +3 bity 3. ModR/M byte 4. SIB byte (zatím neřešíme) 5. Displacement / memory offset 6. Immediate
  • 67. Crackme #2 (x64) by RubberDuck
  • 69. crackme2_x64: úvod • Zarovnání zásobníku na 16 bytů • 48 83 EC 08 sub rsp, 8 • Volání GetStdHandle, uložení 64bitové HANDLE • 48 83 EC 20 sub rsp, 20 • B9 F5 FF FF FF mov ecx, FFFFFFF5 • E8 3C 01 00 00 call <crackme2_x64.GetStdHandle> • 48 83 C4 20 add rsp, 20 • 48 89 05 7E 20 00 00 mov qword ptr [7FF60549309B], rax
  • 70. crackme2_x64: RIP-rel addressing • 48 89 05 7E200000 MOV [7FF60549309B], RAX • Operand vypadá jako disp64, ale ten neexistuje • Jde o RIP-relative addressing: • ref.x86asm.net/coder64.html#modrm_byte_32_64 • Ve skutečnosti: • 48 89 05 7E200000 MOV [RIP+207E], RAX
  • 71. Crackme2_x64: WriteConsoleA() • WriteConsoleA() má pět parametrů • Alokace jakoby 6 parametrů na zásobníku • 1 QWORD navíc je zase zarovnání na 16 bytů 48 83EC 30 sub rsp, 30 ; 48dec = 6*QWORD 48 8B0D 5A200000 mov rcx, [7FF60549309B] 48 BA ... movabs rdx, crackme2_x64.7FF605493000 41 B8 31 00 00 00 mov r8d, 31 49 B9 ... movabs r9, crackme2_x64.7FF605493093 48 C7 44 24 20000000 mov qword ptr [rsp+20], 0 E8 F1000000 call <crackme2_x64.WriteConsoleA> 48 83C4 30 add rsp, 30
  • 72. x64 stack a volání WriteConsoleA() • Stack po SUB RSP, 30: RSP+28: zarovnání RSP+20: parameter lpReserved RSP+18: R9 home: parametr lpNumberOfCharsWritten RSP+10: R8 home: parametr nNumberOfCharsToWrite RSP+08: RDX home: parametr *lpBuffer RSP+00: RCX home: parametr hConsoleOutput
  • 73. Stack: rychlá dočasná paměť • LIFO (Last In First Out) • Roste směrem k nižším adresám • rSP: Stack Pointer register; pod ním je všechno volatile • rSP ukazuje na platnou položku, ne pod • Alokace jednoho DWORD: rSP = rSP – 4 • Jazyk C: alokace automatic variables probíhá na stacku • Páry instrukcí • CALL – RET; PUSH – CALL – RET imm16 • PUSH – POP • INT – IRET (doručení přerušení a návrat z přerušení) • Každý thread má svůj stack
  • 74. Stack frame – „rámec funkce“ • Problém: rSP se často mění • rBP: stack frame register push ebp ; EBP je nonvolatile (stdcall convention) mov ebp, esp sub esp, x ; alokace automatic variables ... ; konec prologu mov eax, [ebp+y] ; výběr parametru funkce mov [ebp-z], eax ; inicializace automatické proměnné ... ; začátek epilogu mov esp, ebp ; uvolnění proměnných – ukončení scope pop ebp ; obnova nonvolatile registru ret
  • 75. Paměť stacku (1) • OllyDbg: menu View, Memory map
  • 76. Paměť stacku (2) • Počáteční hodnota ESP při startu procesu: 1A0000 • Velikost alokovaná systémem: 3000 (12 KB, 3 stránky) • Hodnota ESP na entry pointu: 19FF84 • Tzn. nějaká inicializace a zavolání kódu programu zabralo 31 položek (DWORDs) na stacku • Za alokovaným zásobníkem na adrese 19B000 je guard page (několik) o velikosti 2000 (8 KB, 2 stránky) • Další guard pages jsou od adresy 95000 o velikosti B000 (44 KB) • Vyčerpání stacku nastane na adrese A3000 • Konkrétní hodnoty se liší podle aplikace a podle verze OS
  • 77. Stack a guard page • Cílem je při inicializaci procesu alokovat jenom tolik stacku, aby stačil po celou dobu jeho života • Další paměť se alokuje dynamicky „na požádání“ čtením nebo zápisem pod alokovanou paměť • Exception zachytí memory manager, alokuje další stránku • Paměť zasobníku nemusí alokovat jenom zvláštní instrukce, ale i přímý přístup k rSP, např. SUB ESP, 100 • Alokace příliš velkých bloků paměti může obejít guard pages, je proto potřeba provádět stack probe nebo použít _alloca()
  • 78. Velikost položky na 32-bit zásobníku • Vždycky DWORD • Zarovnání se (na Windows) neočekává • Příklady: • PUSH 11223344 • PUSH EAX • PUSH DWORD PTR [EAX] • Jde ale i WORD: • PUSH 1122 • PUSH AX • PUSH WORD PTR [EAX]
  • 79. Velikost položky na 64-bit zásobníku • Vždycky QWORD • Pozor, Windows očekává zarovnání zásobníku na 16 bytů před voláním (CALL) funkce • Příklady: • PUSH 11223344 (jde jenom sign extended imm32) • PUSH RAX • PUSH QWORD PTR [RAX] • Paradox: nejde DWORD, ale WORD ano: • PUSH EAX • PUSH AX • PUSH 1122 • PUSH WORD PTR [RAX]
  • 80. Heap („hromada“) • Vysokoúrovňový memory management • Heap má svůj HANDLE • Proces má víc heaps najednou • Windows loader vytvoří default Process heap • WinAPI: HeapAlloc (GlobalAlloc, LocalAlloc) • C runtime heap: malloc, operator new • Viz Sysinternals VMMap
  • 81. Manipulace s virtuální pamětí • Nízkoúrovňový přístup přímo ke stránkám paměti • 4KB stránka • Rezervace virtuálních adres (reserve) • Alokace virtuálních adres (commit) • VirtualAlloc, VirtualQuery • VirtualProtect: dynamická generace a spuštění kódu • Virtuální paměť = nefyzická paměť
  • 82. Přístupné virtuální adresy • Proces nemůže přistupovat ke všem existujícím adresám (neplatí pro drivery) • OllyDbg to dokáže částečně zobrazit • 32-bit Windows: • část prostoru musí zůstat systému • první 2 GB paměti (adresy 0x00000000 až 0x7FFFFFFF) • 4-gigabyte tuning (aka /3GB switch): prvním 3 GB paměti (0x00000000 až 0xBFFFFFFF) • 64-bit Windows: • 32-bit proces: vždy celé 4 GB, bez ohledu na další nastavení • 64-bit proces: teoreticky všechny 64-bit adresy, prakticky omezení systémem, např. Windows 7 - 192 GB, Windows 10 - 2 TB
  • 83. Paměťový model (memory model) • Flat memory model • Všechno se řeší přes stránkování (paging) • Kontinuální (nesegmentovaný) virtuální paměťový prostor, tzn. všechny segmenty mají bázi 0, viz OllyDbg • Zjednodušeně: paměť začíná od adresy 0 až po nejvyšší hodnotu (danou systémem) • Reziduum segmentace: paměť TEB (TIB) • 32-bit Windows: adresace pomocí FS segmentu • SEH chain: FS:[0] • 64-bit Windows: GS segment; FS je nevyužitý
  • 84. Thread Information Block (1) • aka Thread Environment Block • Nedokumentovaná struktura (Bingem jde vygooglit) • Všechny informace o threadu • 32-bit Windows • adresace pomocí segmentu FS • OllyDbg: FS 0053 32bit 3C0000(FFF) • 64-bit Windows • adresace pomocí segmentu GS • x64Dbg neumí zobrazit báze segmentů
  • 85. Thread Information Block (2) • V OllyDbg Memory map „Data block of main thread“
  • 87. Structured Exception Handling (1) • Jenom 32-bit Windows • FS:[0] pointer na: EXCEPTION_REGISTRATION STRUCT prev DWORD ? ; předchozí handler handler DWORD ? ; aktuální handler EXCEPTION_REGISTRATION ENDS • OllyDbg: View – VEH/SEH chain
  • 88. SEH (2) • Instalace vlastního handleru do řetězce handlerů: push pointer_to_exception_handler push dword ptr fs:[0] mov fs:[0], esp • Odinstalace: pop dword ptr fs:[0] add esp, 4
  • 89. SEH: ukázka • OllyDbg assembler: • Instalace handleru na 0040101A • INT 3 vyvolá výjimku • JMP způsobí zacyklení
  • 90. Table-based exception handling • 64bitový Windows nezná SEH • Table-based exception handling je popsaný v datech, neinstaluje se během spouštění kódu
  • 91. Entry point, kód, importy, data • PE header je taky v paměti • Entry point určuje PE header • Kód, importy, data atd. načtené ze sekcí v souboru
  • 92. Importy • „.rdata“ sekce: read-only initialized data • Knihovny, které program používá • OllyDbg: View – Executable modules • User-mode systémové knihovny načtené těsně pod hranicí 2 GB
  • 93. Shrnutí instrukcí • MOV • CMP, SUB • TEST, AND • JE, Jcc • JMP • PUSH, POP • CALL, RET • Adresace paměti pomocí [moffs] a [disp32] • INT3 • NOP • ADD [EAX], AL
  • 94. Domácí úkoly 1. Crackněte crackme2, jakobyste neznali heslo 3. Pokud nahradíme instrukci TEST za AND, jak se změní chování crackme2? 4. Jakou jinou logickou instrukci se stejnými operandy a stejným testováním výsledku bysme mohli k vyhodnocení použít?
  • 96. 3. část: C crackmes • Crackmes napsané v jazyce C • Jenom naživo, slidy nejsou
  • 97. Dekompilace crackme2 (asm verze) void __cdecl start(UINT a1) { hConsoleOutput = GetStdHandle(0xFFFFFFF5); hConsoleInput = GetStdHandle(0xFFFFFFF6); WriteConsoleA(hConsoleOutput, aCrackme2ByRubb, 0x2Bu, &Ncw, 0); ReadConsoleA(hConsoleInput, String1, 0x14u, &NumberOfCharsRead, 0); if ( lstrcmpA(String1, String2) ) WriteConsoleA(hConsoleOutput, aNo_ThisIsnTGoo, 0x22u, & Ncw, 0); else WriteConsoleA(hConsoleOutput, aGoodJobCracker, 0x15u, & Ncw, 0); ExitProcess(a1); }
  • 98. Dekompilace crackme3 (asm verze) --Ncr; if ( (signed int)--Ncr <= 3 || Ncr > 0xE ) WriteConsoleA(hConsoleOutput, aLoginMustHaveM, 0x39u, &Ncw, 0); else { WriteConsoleA(hConsoleOutput, aInsertPassword, 0x12u, &Ncw, 0); ReadConsoleA(hConsoleInput, String1, 0x64u, &Ncr, 0); for ( i = &unk_4030AB; *i; ++i ) { sub_40117C((unsigned __int8)*i, (int)&word_40318B); *v0 = word_40318B; } String1[sub_401170((int)String1) - 2] = 0; sub_4011AE((int)v0, v1, (int)String1); if ( lstrcmpA(String1, String2) ) WriteConsoleA(hConsoleOutput, aNo_ThisIsnTGoo, 0x22u, &Ncw, 0); else WriteConsoleA(hConsoleOutput, aGoodJobCracker, 0x15u, &Ncw, 0); }
  • 100. Nedokončeno • Sorry, nestíhám • Formát Portable Executable • Oficiálně: PECOFF verze 8.3
  • 101. Přídavek: formát instrukce podrobně • Pokud lidi neodejdou, poveselit je ještě popisem formátu instrukce
  • 102. Jenom jednobajtový primární opkód • 90 NOP – No OPeration • CC INT3 • 50+r PUSH r • 5 horních bitů opkód (01010), 3 dolní bity kód registru • Příklady: • 01010 000 PUSH rAX • 01010 001 PUSH rCX • 01010 010 PUSH rDX • 01010 111 PUSH rDI
  • 103. Registr zakódovaný v opkódu + imm • B8+r MOV r32/64, imm32/64 • BA 10203040 MOV EDX, 40302010 • Registrů na x64 je 16, tzn. jsou potřeba 4 bity pro kód • Přístup k novým registrům pomocí prefixu REX.B 41 BA 10203040 MOV R10D, 40302010 • Přístup k operandům r64, imm64 pomocí prefixu REX.W: 48 BA 1020304050607080 MOV RDX, 8070605040302010 • Kombinace - prefix REX.WB: 49 BA 1020304050607080 MOV R10, 8070605040302010
  • 104. REX prefixy • Opkódy 40-4F • ref.x86asm.net/coder64.html#x40 • x64: 16 registrů, ale jednotlivých 8bitových částí je 20... • Opkód 40 - „plain“ REX prefix přepíná: AH CH DH BH bez jakéhokoliv REX prefixu SPL BPL SIL DIL s jakýmkoliv REX prefixem
  • 105. ModR/M byte • 2 bity 7-6: pole Mod • 3 bity 5-3: kód registru nebo 3-bit opcode extension • 3 bity 2-0: kód registru nebo kód paměťového operandu
  • 106. ModR/M byte: operandy reg, reg • 85C0 TEST EAX, EAX • Obecně: • 85 /r TEST r/m16/32, r16/32 • /r v manuálech značí přítomnost ModR/M byte • ModR/M C0: 11‘000‘000 • Mod 11: operand R/M je registr • Reg 000: EAX • R/M 000: EAX
  • 107. ModR/M: ruční disassembling 0xC0 • 85C0 TEST EAX, EAX • ref.x86asm.net/coder32.html#modrm_byte_32
  • 108. ModR/M: ruční diassembling 0x00 • 0000 ADD [EAX], AL • 00 /r ADD r/m8, r8
  • 109. Reg/Opcode obsahuje 3-bit opkód • crackme1: • 83F8 01 CMP EAX, 1 • Obecně: • ref.x86asm.net/coder32.html#x83 • 83 /7 CMP r/m16/32, imm8 • /digit značí ModR/M byte s 3bitovou opcode extension • F8 = 11‘111‘000 • Mod 11: R/M kóduje registr • Reg/Opcode 111: opcode extension 7 • R/M 000: registr EAX
  • 110. Mod 00
  • 111. Operand disp32 • crackme2: • 00401029 FF35 95304000 PUSH DWORD PTR [403095] • ModR/M 35
  • 112. Mod 01 a 10 • Mod 01: přidání disp8 • Mod 10: přidání disp32
  • 113. ModR/M: nejenom GP registry • ModR/M kóduje i MMX, XMM, segment, control a debug registry, ty neřešíme
  • 114. Motivace pro ruční disassembling • Chyby a lidová tvořivost v disassemblerech • Disassembler někdy není po ruce • Patchování, hlavně když není dost místa • Shellcode: „cení se každý ušetřený bajt, který neohrozí funkčnost shellcodu“ • Dis/assemblování z hlavy v hospodě
  • 115. Shrnutí opkódů • A0-A3: zvláštní skupina opkódů, jsou další • rAX: operace s „accumulator“ často využívají vlastní kratší opkódy • Jenom jeden formát instrukce • Jednobajtový opkód (NOP) • Jednobajtový opkód + kód registru • Některé REX prefixy • Kompletní ModR/M byte • Displacement, memory offset • Immediate
  • 116. Trocha historie • Původně se registr SP nedal pro adresaci paměti vůbec použít (8086) • Vyřešilo to přidání SIB byte později (80286)