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

  1. Lit la section .text de façon linéaire et transforme chaque bloc lu en instruction

  2. 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/