L'anti-disassembly, ou "Cryptanalyse et Whitbox2"
Code source
Code disas
whoami
- Nofix
- Reverse, pwn, """Pentest"""
- Membre de Sentry Whale
- Rien de mieux qu'un bon vieux prog en C
- OSCP
@N0fix
TAILLE DES INSTRUCTIONS | |
---|---|
ARM - THUMB | 2 |
ARM | 4 |
INTEL
INTEL : les rappels
INTEL : les rappels, la doublette
mov dx,0x05eb
0x66
0xba
0xeb
0x05
jmp $+5
BAD INST
- Linear sweep
- Flow oriented
Algorithmes pour disas
-
Lit la section .text de façon linéaire et transforme chaque bloc lu en instruction
-
C'est tout en fait
Linear sweep
Fonctionnement
Facile à coder, utilisé un peu partout
char buffer[BUF_SIZE];
int position = 0;
while (position < BUF_SIZE) {
x86_insn_t insn;
int size = x86_disasm(buf, BUF_SIZE, 0, position, & insn);
if (size != 0) {
char disassembly_line[1024];
x86_format_insn( & insn, disassembly_line, 1024, intel_syntax);
printf("%s\n", disassembly_line);
position += size;
} else {
/* invalid/unrecognized instruction */
position++;
}
}
x86_cleanup();
Linear sweep - avantages
Linear sweep
Pourquoi c'est pas ouf
Linear sweep, pas ouf
main:
push chaine
jmp $+9
db "IDA > r2",0x7b
add dword [esp], 6
call puts
ret
08049170 <main>:
8049170: 68 1c c0 04 08 push 0x804c01c
8049175: eb 07 jmp 804917e <main+0xe>
8049177: 49 dec ecx
8049178: 44 inc esp
8049179: 41 inc ecx
804917a: 20 3e and BYTE PTR [esi],bh
804917c: 20 72 32 and BYTE PTR [edx+0x32],dh
---> 7b 83 jnp 8049104 <register_tm_clones+0x14>
8049181: 04 24 add al,0x24
8049183: 06 push es
8049184: e8 a7 fe ff ff call 8049030 <puts@plt>
8049189: c3 ret
0x7b -> premier octet de certaines instructions jmp
Linear Sweep
C'est pas ouf
Source
Désassemblé
IDA - Le vrai bro
Disassembly flow oriented
- But final : trouver un maximum de section de code référencées et les lister
- Décomposition de instructions en plusieurs types
- Utilisation ""intelligente"" du linear sweep
Disassembly flow oriented
Le but
Function Call Instructions | call getABeer |
---|---|
Return Instructions | ret (no shit) |
Sequential Flow Instuctions | pop, push, mov, etc |
---|---|
Conditional Branching Instructions | je, jne, jnz, etc |
Unconditional Branching Instructions | jmp goBoussole, jmp eax |
Disassembly flow oriented
Les types d'instructions
goBoussole:
<some unkown code yet>
__start:
push ebp,
mov esp, ebp
# ajout à la table de références, on disas la suite
jmp goBoussole
leave
ret
goBoussole |
Table des références
Disassembly flow oriented
L'exemple
Désassemblé
1. Lit une instruction
2. Si instruction de branchement, met l'adresse de la condition vraie sur une pile pour la désassembler plus tard
Table des références
goBoussole:
mov eax, 1
mov ebx, 0
int 0x80
__start:
push ebp,
mov esp, ebp
# ajout à la table de références, on disas la suite
jmp goBoussole
leave
ret
Disassembly flow oriented
Désassemblé
1. Lit une instruction
2. Si instruction de branchement, met l'adresse de la condition vraie sur une pile pour la désassembler plus tard
Flow oriented
eleve |
Table des références
SECTION .data
str_theou db "Ça me parait pas deconnant", 0
str_eleve db "Est ce que ça parait deconnant?", 0
SECTION .text
GLOBAL main
eleve:
<unkn>
theou_be_like:
<unkn>
exit:
<unkn>
main:
xor eax, eax
jz eleve
call exit
Disassembly flow oriented
Les choix des branchements
Désassemblé
1. Lit une instruction
2. Si instruction de branchement conditonnel, désassemble le FAUX par défaut
3. Push l'adresse de la condition VRAI
Flow oriented
exit |
---|
eleve |
Table des références
SECTION .data
str_theou db "Ça me parait pas deconnant", 0
str_eleve db "Est ce que ça parait deconnant?", 0
SECTION .text
GLOBAL main
eleve:
<unkn>
theou_be_like:
<unkn>
exit:
<unkn>
main:
xor eax, eax
jz eleve
call exit
Disassembly flow oriented
Les choix des branchements
Désassemblé
1. Lit une instruction
2. Si instruction de branchement conditonnel, désassemble le FAUX par défaut
3. Push l'adresse de la condition VRAI
Flow oriented
eleve |
Table des références
SECTION .data
str_theou db "Ça me parait pas deconnant", 0
str_eleve db "Est ce que ça parait deconnant?", 0
SECTION .text
GLOBAL main
eleve:
<unkn>
theou_be_like:
<unkn>
exit:
mov eax, 1 ; sys_exit
int 0x80
main:
xor eax, eax
jz eleve
call exit
Disassembly flow oriented
Les choix des branchements
Désassemblé
1. Lit une instruction
2. Si instruction de branchement conditonnel, désassemble le FAUX par défaut
3. Push l'adresse de la condition VRAI
Flow oriented
Table des références
SECTION .data
str_theou db "Ça me parait pas deconnant", 0
str_eleve db "Est ce que ça parait deconnant?", 0
SECTION .text
GLOBAL main
eleve:
push str_eleve
call puts
jmp theou_be_like
theou_be_like:
push str_theou
call puts
call exit
exit:
mov eax, 1 ; sys_exit
int 0x80
main:
xor eax, eax
jz eleve
call exit
Disassembly flow oriented
Les choix des branchements
Désassemblé
Guess what, c'est toujours pas parfait non plus
C'ÉTAIT SÛR
SECTION .text
GLOBAL main
main:
push chaine
xor eax, eax
jz beer+1
beer:
db 0xe8 # One byte
pop eax # <beer+1>
ret
Disassembly flow oriented :
1. Lit une instruction
2. Si instruction conditionnelle, fait un choix
3. Désassemble la condition fausse par défaut
4. Met l'adresse de la condition vraie sur une pile pour la désassembler plus tard
1 - Rogue byte + near jmp
Disassembly flow oriented
Attaque/Parade n°1 - Rogue byte + near jmp
Source
68 18 C0 04 08 push offset chaine ; "thegame"
31 C0 xor eax, eax
74 01 jz short near ptr beer+1
beer: ; CODE XREF: main+7↑j
E8 58 C3 66 90 call near ptr 986B54C6h
66 90 xchg ax, ax
main endp ; sp-analysis failed
1. Lit une instruction
2. Si instruction conditionnelle, fait un choix
3. Désassemble la condition fausse par défaut
4. Met l'adresse de la condition vraie sur une pile pour la désassembler plus tard
Disassembly flow oriented
Parade n°1 - Rogue byte + near jmp
SECTION .text
GLOBAL main
main:
push chaine
xor eax, eax
jz beer+1
beer:
db 0xe8 # One byte
pop eax # <beer+1>
ret
Source
Désassemblé
Les jump, l'outil du démon
Disassembly flow oriented
Parade n°1 - Rogue byte + near jmp
gdb-peda$ ni
Inconvénient : Facilement corrigeable sous IDA
Les jump, l'outil du démon
74 03 jz short near ptr loc_4011C4+1
75 01 jnz short near ptr loc_4011C4+1
loc_4011C4:
E8 58 C3 90 90 call near ptr 90D0D521h
Disassembly flow oriented
Parade n°2 - La doublette conditionnelle (variante)
Désassemblé
SECTION .text
GLOBAL main
main:
push chaine
xor eax, eax
jz beer+1
jnz beer+1
beer:
db 0xe8
pop eax ; beer+1
ret
Source
Les jump, l'outil du démon
74 03 jz short near ptr loc_4011C5
75 01 jnz short near ptr loc_4011C5
; ----------------------------------
E8 db 0E8h
; ----------------------------------
loc_4011C5: ; CODE XREF: sub_4011C0
; sub_4011C0+2j
58 pop eax
C3 retn
Disassembly flow oriented
Parade n°2 - La doublette conditionnelle (variante)
Désassemblé + modifié
Inconvénient : Facilement corrigeable sous IDA
3 - INTEL sah quel plaisir
Disassembly flow oriented
Parade n°3 - "INTEL sah quel plaisir"
3 - INTEL sah quel plaisir
main:
mov ax, 0x05eb
xor eax, eax
jz $-4
db 0xe8
push chaine
call puts
ret
Disassembly flow oriented
Parade n°3 - "INTEL sah quel plaisir"
Source
3 - INTEL sah quel plaisir
Toujours plus
Disassembly flow oriented
Parade n°3 - "INTEL sah quel plaisir"
1. Lit 0xEB et 0xFF pour former JMP-1
2. Met l'adresse à -1 sur la pile de références
3. Lit 0xC0 et essaye d'en faire une instruction
3 - INTEL sah quel plaisir
Patchable? Inconvénient?
Disassembly flow oriented
Parade n°3 - "INTEL sah quel plaisir"
Pas vraiment
3 - INTEL sah quel plaisir
(fcn) main 10
int main (int argc, char **argv, char **envp);
0x08049170 mov dx, 0x5eb ; 1515
0x08049172 jmp fcn.08049179
0x08049174 xor eax, eax
0x08049176 je 0x8049172 ; main+0x2
0x08049178 call 0xcc4ade5
|- fcn.08049179 108
fcn.08049179 (int32_t arg_28h);
; arg int32_t arg_28h @ esp+0x28
0x08049179 push loc.chaine ; 0x804c01c ;
0x0804917e call sym.imp.puts ; int puts(const char *s)
0x08049183 mov eax, 1
0x08049188 int 0x80
Cutter/r2
Disassembly flow oriented
Parade n°3 - "INTEL sah quel plaisir"
R2/CUTTER
GL & HF
beer:
call $+5 ; 1
add dword [esp], 13 ; 2
ret
db "IDA > r2"
push ebp
mov ebp, esp
push dword [ebp+8]
call puts
leave
ret
main:
push chaine
call beer
mov eax, 1
int 0x80
Disassembly flow oriented
Parade n°4 - Abusing ret
Source
1
2
Push <beer+5> sur la stack
Ajoute 13 à l'adresse pushé sur la stack
add dword [esp],13 | 4 octets |
---|---|
ret | 1 octet |
IDA > r2 | 8 octets |
< vrai début de fonction
GL & HF
Disassembly flow oriented
Parade n°4 - Abusing ret
Inconvénient : Nopable facilement
SECTION .data
chaine db "Hello world !", 0
SECTION .text
GLOBAL main
push chaine
call puts
mov eax,1
int 0x80
main:
mov eax,0xd6a951ae
xor eax, 0xdeadc0de
call eax
ret
Disassembly flow oriented
Parade n°5 - La classique, les packers
Source
5 - La classique, les packers
Disassembly flow oriented
Parade n°5 - La classique, les packers
Inconvénient : la balle de techniques pour trouver ce genre de call
Des questions?
https://slides.com/nofix/reverse-engineering/
Reverse Engineering
By Nofix
Reverse Engineering
- 1,086