/********************************************************************. | Crackme Information: | |--------------------- | | | | Name: Ada Crackme ELF | | URL: http://crackmes.de/users/darkphoenix_/ada_crackme_1_elf./ | | Author: _DarKPhoeniX_ | | | |--------------------------------------------------------------------| | | | Cracked by: pancake | | | `********************************************************************/ Description: ============ This crackme has been coded in ADA language. Objective: ========== There are no rules to defeat this crackme, so I have done the easiest and faster one. Unpacking and on-disk patching. Tools used: =========== Both tools can be downloaded at radare.nopcode.org radare - debugger, hex editor, disasembler rabin - elf information Unpacking: ========== $ BEP=entry radare dbg://./hello > !contsc 6 ; find first close syscall > !fd ; list filedescriptors 0 0x00000000 /dev/pts/9 1 0x00000000 /dev/pts/9 2 0x00000000 /dev/pts/9 3 0x00002fa3 /home/pancake/Desktop/crackme/hello 4 0x000065e2 /tmp/upxAAC3LVWAYGK > !cp /tmp/upxAAC3LVWAYGK hello.unpacked > quit Running: ======== $ ./hello.unpacked +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ######################## DarKPhoeniX crackme ######################## +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Username : foo Serial : bar HOLY SHIT! Installing required libraries: ============================== # cd /usr/lib # wget http://www.frenchreversing.info/misc/libgnarl-3.4.so.1 # wget http://www.frenchreversing.info/misc/libgnat-3.4.so.1 # ^D $ ldd hello.unpacked linux-gate.so.1 => (0xffffe000) libgnarl-3.4.so.1 => /usr/lib/libgnarl-3.4.so.1 (0xb7ede000) libgnat-3.4.so.1 => /usr/lib/libgnat-3.4.so.1 (0xb7d1f000) libpthread.so.0 => /lib/tls/i686/cmov/libpthread.so.0 (0xb7d06000) libgcc_s.so.1 => /lib/libgcc_s.so.1 (0xb7cfb000) libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb7bb1000) libm.so.6 => /lib/tls/i686/cmov/libm.so.6 (0xb7b8c000) /lib/ld-linux.so.2 (0xb7f18000) Finding the right place to patch ================================ Now we have a working unpacked binary. UPX for linux is not hard to defeat, so now we should find the place to patch. $ radare hello.unpacked > !rabin -e hello.unpacked 0x0804a880 memory 0x00002880 disk > flag entry @ 0x2880 > seek entry ; seek to entry point > pD 100 0x00002880 ebp ^= ebp 0x00002882 pop esi 0x00002883 ecx = esp 0x00002885 esp &= 0xf0 ; 240 0x00002888 push eax 0x00002889 push esp 0x0000288A push edx 0x0000288B push dword 0x804ced0 0x00002890 push dword 0x804ce7c 0x00002895 push ecx 0x00002896 push esi 0x00002897 push dword 0x804ab57 ; main 0x0000289C ^ call 0x26E0 ; ; This looks like the typical libc trampoline to main() ; So let's flag the main > f main @ 0x804ab57-0x8048000 > ;get main 0x2b57 > s main > pD 203 0x00002B57 main: 0x00002B57 push ebp 0x00002B58 ebp = esp 0x00002B5A esp -= 0x8 ; 8 0x00002B5D esp &= 0xf0 ; 240 0x00002B60 eax = 0x0 0x00002B65 eax += 0xf ; 15 0x00002B68 eax += 0xf ; 15 0x00002B6B eax >>= 0x4 ; 4 (zerofill) 0x00002B6E eax <<= 0x4 ; 4 0x00002B71 esp -= eax 0x00002B73 dword [ebp-0x4] = 0x804e2d3 0x00002B7A eax = [ebp+0x8] 0x00002B7D [0x804e600] = eax 0x00002B82 eax = [ebp+0xc] 0x00002B85 [0x804e614] = eax 0x00002B8A eax = [ebp+0x10] 0x00002B8D [0x804e604] = eax 0x00002B92 ecx = ebp 0x00002B94 ^ call 0x26F0 ; 0x00002B99 ^ call 0x2928 ; 0x00002B9E ^ call 0x2440 ; 0x00002BA3 ecx = ebp 0x00002BA5 v call 0x4834 ; main+0x1cdd ; THIS IS ADA_MAIN 0x00002BAA ^ call 0x27A0 ; 0x00002BAF ecx = ebp 0x00002BB1 ^ call 0x2520 ; 0x00002BB6 eax = [0x804e624] 0x00002BBB leave ;-- 0x00002BBC ret ;-- ; If we observe the previous disassembly we can see that ; the only known call points to an address near to main ; this is the main of ADA at 0x4834 > pz @ 0x804d0e4-0x8048000 Thanks For Registering ; So, now we have the address of the string in memory and on-disk ; Let's find a reference of it inside the code...and voila'. ; Walking down the code we can find some checks and loops quite ; obvious and we achieve the end of the checking loop after a 'jz' ... 0x0000495E ^ jz dword 0x4C47 ; main+0x20f0 ;------------------------------------------------------ 0x00004964 esp -= 0xc ; 12 0x00004967 push dword [ebp+0xffffff24] 0x0000496D ^ call 0x27C0 ; 0x00004972 eax = [ebp-0xdc] ... 0x000049A2 cmp dword [ebp-0x68], 0xabcdef 0x000049A9 setz dl 0x000049AC cmp byte [ebp-0x59], 0x0 0x000049B0 setz al 0x000049B3 eax &= edx 0x000049B5 test al, al 0x000049B7 v jz 0x49D5 ; main+0x1e7e 0x000049B9 ^ call 0x2C1A ; main+0xc3 ; ok 0x000049BE esp -= 0x8 ; 8 ; pz @ 0x804d0e4-0x8048000 = "Thanks for registering" 0x000049C1 eax = 0x804d0e4 0x000049C6 edx = 0x804d0fc 0x000049CB push edx 0x000049CC push eax 0x000049CD ^ call 0x2640 ; ada's printf ; failure 0x000049D2 esp += 0x10 ; 16 0x000049D5 esp -= 0x8 ; 8 ; pz @ 0x804d104-0x8048000 = "HOLY SHIT!" 0x000049D8 eax = 0x804d104 0x000049DD edx = 0x804d110 0x000049E2 push edx 0x000049E3 push eax 0x000049E4 ^ call 0x2640 ; ada's printf ; Hey, we got a single reference for this string on all the file. So ; The patch is just nopping the 'jz'. > wx 66 90 @ 0x49B7 ; 16 bit nop for jz Solving problems ================ When running the patched binary we found that the program doens't shows anything after entering the user and serial: $ ./unhello.2 ++++++++++++++++++++++++++++++++++++++++++ ########## DarKPhoeniX crackme ########### ++++++++++++++++++++++++++++++++++++++++++ Username : foo Serial : bar $ Uhm. lets take a careful look at the affected code after our patch: 0x000049B7 o16 nop ; mov ax,ax 0x000049B9 ^ call 0x2C1A ; --> should be nop'ed 0x000049BE esp -= 0x8 ; pz @ 0x804d0e4-0x8048000 = "Thanks for registering" 0x000049C1 eax = 0x804d0e4 0x000049C6 edx = 0x804d0fc ; contents 01 00 00 00 0x000049CB push edx ; 1 0x000049CC push eax ; "Thanks for... 0x000049CD ^ call 0x2640 ; printf ; failure ... 0x000049D2 esp += 0x10 ; --> we must write a 'ret' As we see we have a call to a subroutine (0x2c1a) before the printf. So let's try to nopit too and put a ret after the printf at 0x49d2 Patching the previous call: > wx 66 90 66 90 90 @ 0x49B9 Patching the ret: > wx c3 @ 0x49D2 And now...let's go: $ ./unhello.unpacked +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ######################## DarKPhoeniX crackme ######################## +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Username : foo Serial : bar Thanks For Registering $ Done! :D Patch overview: =============== This is a little overview of the previous patch maybe may help you to understand if you get lost in the previous chapter. $ echo pD 100 @ 0x49b3| radare hello.unpacked 0x000049B5 84c0 test al, al ; 0x000049B7 741c v jz 0x49D5 ; wx 6690 @ 0x49b7 ;------------------------------------------------------------------ 0x000049B9 e85ce2ffff ^ call 0x2C1A ; wx 6690669090 @ 0x49b9 0x000049BE 83ec08 esp -= 0x8 ; 0x000049C1 b8e4d00408 eax = 0x804d0e4 ; string "Thanks For Registering" 0x000049C6 bafcd00408 edx = 0x804d0fc ; 0x000049CB 52 push edx ; 0x000049CC 50 push eax ; 0x000049CD e86edcffff ^ call 0x2640 ; print ok string ;------------------------------------------------------------------ 0x000049D2 83c410 esp += 0x10 ; wx c3 @ 0x39d2 0x000049D5 83ec08 esp -= 0x8 ; 0x000049D8 b804d10408 eax = 0x804d104 ; string "HOLY SHIT!" 0x000049DD ba10d10408 edx = 0x804d110 ; 0x000049E2 52 push edx ; 0x000049E3 50 push eax ; 0x000049E4 e857dcffff ^ call 0x2640 ; print fail string $ echo wx 66 90 66 90 66 90 90 @ 0x49b7 | radare -vw hello.unpacked $ echo wx c3 @ 0x49d2 | radare -vw hello.unpacked Conclussion: ============ The UPX protection was really easy to bypass. The patch is so obvious but I spend some more time than required trying to find the reference to the string because of some missing features in radare. The only surprise was the need to nop two calls to make the program work properly. --pancake