116
RE WORKSHOP Karel Lejska Milan Bartoš security session 2016

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

Embed Size (px)

Citation preview

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

RE WORKSHOP

Karel Lejska

Milan Bartoš

security

session 2016

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

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

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

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

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

1. část

• Crackme #1 by RubberDuck

• + opkódy instrukcí

• + x64

• + x64 verze crackme #1

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

Crackme #1 by RubberDuck

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

OllyDbg – crackme1.exe

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

OllyDbg – nastavení eventů

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

OllyDbg – nastavení výjimek

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

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

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

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

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

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

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

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

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

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

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

Skupina opkódů 0x83

• Osm aritmetických a logických instrukcí

• Operandy: r/m16/32, imm8

• Viz taky opkódy 80, 81

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

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

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

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

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

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

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

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

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

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! :("

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

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

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

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

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

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

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

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

);

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

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

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

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í

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

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

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

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

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

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

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

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

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

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

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

MessageBoxA(): RETN 10

• C2 1000 RETN 10

• 0x10 = 16

• 16/4 = 4 DWORD parametry

• Pseudooperace:

ESP = ESP + 16

EIP = *ESP

ESP = ESP + 4

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

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

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

OllyDbg assembler

• Assembluj MOV EAX, 5 na adrese 401000 (= EIP)

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

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ů

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

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

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

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

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

Shrnutí pojmů (2)

• Volání funkce: CALL – RET

• Odstraňování parametrů ze zásobníku pomocí RET

• OllyDbg assembler

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

Shrnutí instrukcí

• MOV

• CMP, SUB

• JE, Jcc

• JMP

• PUSH

• CALL

• INT3

• NOP

• ADD [EAX], AL

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

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

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

Crackme #1 (x64) by RubberDuck

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

x64dbg – nastavení eventů

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

x64dbg – crackme1_x64.exe

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

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í

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

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

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

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

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

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

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

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?

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

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

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

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

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

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

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

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

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

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

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

Ú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

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

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

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

Crackme #2 by RubberDuck

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

OllyDbg – crackme2.exe

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

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()

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

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

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

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ěť

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

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ší

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

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

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

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.“

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

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

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

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

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

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

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

Crackme #2 (x64) by RubberDuck

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

x64dbg – crackme2_x64.exe

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

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

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

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

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

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

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

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

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

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

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

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

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

Paměť stacku (1)

• OllyDbg: menu View, Memory map

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

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

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

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()

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

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]

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

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]

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

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ěť

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

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

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

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ý

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

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ů

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

Thread Information Block (2)

• V OllyDbg Memory map „Data block of main thread“

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

Thread Information Block (3)

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

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

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

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

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

SEH: ukázka

• OllyDbg assembler:

• Instalace handleru na 0040101A

• INT 3 vyvolá výjimku

• JMP způsobí zacyklení

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

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

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

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

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

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

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

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

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

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?

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

Crackme3

• Jenom naživo, slidy nejsou

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

3. část: C crackmes

• Crackmes napsané v jazyce C

• Jenom naživo, slidy nejsou

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

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);

}

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

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);

}

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

Nedokončeno

• Sorry, nestíhám

• Formát Portable Executable

• Oficiálně: PECOFF verze 8.3

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

Přídavek: formát instrukce podrobně

• Pokud lidi neodejdou, poveselit je ještě popisem formátu

instrukce

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

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

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

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

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

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

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

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

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

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

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

ModR/M: ruční disassembling 0xC0

• 85C0 TEST EAX, EAX

• ref.x86asm.net/coder32.html#modrm_byte_32

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

ModR/M: ruční diassembling 0x00

• 0000 ADD [EAX], AL

• 00 /r ADD r/m8, r8

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

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

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

Mod 00

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

Operand disp32

• crackme2:

• 00401029 FF35 95304000

PUSH DWORD PTR [403095]

• ModR/M 35

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

Mod 01 a 10

• Mod 01: přidání disp8

• Mod 10: přidání disp32

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

ModR/M: nejenom GP registry

• ModR/M kóduje i MMX, XMM, segment, control a debug

registry, ty neřešíme

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

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ě

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

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

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

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)