x86
crackmes.one (jeffli6789)
Le binaire a été écrit en ASM, il y a de fortes chances que le décompilateur Ghidra n'y arrive pas. Je vais profiter de ça pour utiliser Radare2.
Au début, le programme appelle la fonction scanf
, on remarque qu'il
prend en entrée %d
, un nombre. Une adresse mémoire est ensuite
chargée ainsi que l'adresse à plus 0xa0
.
lea rdi, [0x00000924] ; %d dans la mémoire lea rsi, [var_4h] ; l'adresse mémoire où stocker le retour utilisateur call sym.imp.__isoc99_scanf ;; ... lea rax, [0x00201025] mov edx, dword [var_4h] lea rsi, [rax + 0xa0] jmp addr_0x704 ;; ...
Il y a une boucle, où le nombre précédemment entré est check bit par
bit et, si c'est un 0 ou un 1, va changer l'emplacement mémoire
précédemment chargé avec 0x2d
ou 0x05
. À la fin de la boucle,
section..x86
est appelé. Son adresse est 0x201020
, soit l'adresse
manipulée moins 0x05
. En regardant la première ligne, on voit que ça
charge un nombre dans un registre, la suite est un tas d'instructions
incohérentes.
.addr_0x6f8: mov byte [rax], 5 add rax, 5 cmp rsi, rax je addr_0x71b .addr_0x704: mov ecx, edx sar edx, 1 and ecx, 1 test ecx, ecx jne addr_0x6f8 mov byte [rax], 0x2d add rax, 5 cmp rsi, rax jne addr_0x704 .addr_0x71b: ;; ... call section..x86 ; adresse 0x00201020
En faisant de l'analyse dynamique, une fois la boucle finie, la zone
mémoire est rempli de add
et sub
sur le registre eax
. Un check
est fait ensuite sur le registre avant de retourner dans la fonction
main
. C'est ce check qui va permettre de trouver le bon flag.
Il faut donc faire une équation avec une valeur en entrée, des valeurs à soustraire ou additioner et une valeur de sortie. Il faut donc avoir le bon calcul pour pouvoir finir ce crackme.
mov eax, 0x3df2f794 sub eax, 0x52ae22f2 add eax, 0xbf409bcc add eax, 0x46417dc1 sub eax, 0x25f7d9a1 sub eax, 0xef83a7ce add eax, 0x2dd63e8e sub eax, 0x584a1ec5 sub eax, 0x8e58e1df add eax, 0xf2705f70 add eax, 0x2e94ef1e sub eax, 0x3ca9e080 add eax, 0xa617b5df sub eax, 0x29ae9c3d sub eax, 0x7461ed52 sub eax, 0x7125faac add eax, 0x65dfffd6 add eax, 0x97f1f41c add eax, 0x6f4e0648 sub eax, 0xd803e5d0 sub eax, 0xf358f0eb sub eax, 0xbc3b30c7 add eax, 0x585685f8 sub eax, 0x2a9cc47c sub eax, 0x7f03d175 sub eax, 0xc1d942ae sub eax, 0x174c7d4f sub eax, 0xb7d004f0 sub eax, 0xbec8b077 sub eax, 0x8ce8eaa2 sub eax, 0x2510e330 sub eax, 0x4aed0eee sub eax, 0x4043cd91 cmp eax, 0x7a612770 sete al nop nop ret
A noter que ces nombres sont aléatoires.
utilise rapidement le décompilateur scanf, emplacement mémoire -> changer le type pour string et scanf "%d" donc récupérer un nombre
on va tenter un peu radare2 pour prendre en main l'outil https://www.megabeets.net/a-journey-into-radare-2-part-1/
edx -> le buffer rax -> adresse mémoire rsi -> le pointer + 0xa0 (160)
boucle : ecx <- edx edx >> 1 ecx & 1 check si ecx = 0 met 5 dans *rax sinon met 0x2d dans *rax rax+5
rabin2 -I file : information sur le fichier
r2 file
i aaa fs fs <flag> * = pour retourner à la première section f -> les affiche axt @@ str.* => trouve les références à toutes les adresses de str (@@ est un for récursif) s pour seek aka se déplacer dans le binaire s main afl pour afficher les appels de fonctions pdf pour afficher le code désassemblé VV affiche des graphs V mode visuel, p pour switch entre les modes, ; pour mettre un commentaire m pour marquer, ' pour retourner au marquage
db 0xaddr / symbole ood dc dr afficher les registres pdf montre le breakpoint et ou on se trouve