Recently I was trying to reverse a small crackme by Tosh. The challenge was to find a password by reversing the binary, bypassing the anti-debugging techniques used. Below is some data about the binary.
This is what the binary does to call the de-obfuscation routine:
This is how the bytes look after the de-obfuscation process ie after running under x86 emulator plugin
To analyse the binary under gdb pass the SIGTRAP to the process
Using GDBserver
Its fun trying to analyse binaries of this kind!
[ctf@renorobert chall]$ file ch13 ch13: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, stripped [ctf@renorobert chall]$ ./ch13 Enter the password: reno Bad password, sorry ! [ctf@renorobert chall]$ strace -i ./ch13 [ 38b7aa6dd7] execve("./ch13", ["./ch13"], [/* 48 vars */]) = 0 [ Process PID=5359 runs in 32 bit mode. ] [ 8048074] signal(SIGTRAP, 0x80480e2) = 0 (SIG_DFL) [ 8048078] --- SIGTRAP (Trace/breakpoint trap) @ 0 (0) --- [ f77f3408] sigreturn() = 0 [ 804808c] signal(SIGTRAP, 0x8048194) = 0 (SIG_DFL) [ 8048090] --- SIGTRAP (Trace/breakpoint trap) @ 0 (0) --- [ f77f3408] sigreturn() = 0 [ 80480a4] signal(SIGTRAP, 0x8048104) = 0 (SIG_DFL) [ 80480a8] --- SIGTRAP (Trace/breakpoint trap) @ 0 (0) --- [ 80481d4] write(1, "Enter the password: ", 20Enter the password: ) = 20 [ 80481dc] read(0, reno "reno\n", 128) = 5 [ f77f3408] sigreturn() = 0 [ 80480bc] signal(SIGTRAP, 0x8048138) = 0 (SIG_DFL) [ 80480c0] --- SIGTRAP (Trace/breakpoint trap) @ 0 (0) --- [ f77f3408] sigreturn() = 0 [ 80480d4] signal(SIGTRAP, 0x8048149) = 0 (SIG_DFL) [ 80480d8] --- SIGTRAP (Trace/breakpoint trap) @ 0 (0) --- [ 80481d4] write(1, "Bad password, sorry !\n", 22Bad password, sorry ! ) = 22 [ 80481e4] _exit(1) = ?Here is the disassembly in IDA
.text:08048060 ; Segment type: Pure code .text:08048060 ; Segment permissions: Read/Execute .text:08048060 _text segment para public 'CODE' use32 .text:08048060 assume cs:_text .text:08048060 ;org 8048060h .text:08048060 assume es:nothing, ss:nothing, ds:_text, fs:nothing, gs:nothing .text:08048060 .text:08048060 ; =============== S U B R O U T I N E ======================================= .text:08048060 .text:08048060 ; Attributes: noreturn .text:08048060 .text:08048060 public start .text:08048060 start proc near .text:08048060 jmp short loc_8048063 .text:08048060 ; --------------------------------------------------------------------------- .text:08048062 db 0E8h .text:08048063 ; --------------------------------------------------------------------------- .text:08048063 .text:08048063 loc_8048063: .text:08048063 mov eax, 30h .text:08048068 mov ebx, 5 .text:0804806D mov ecx, offset sub_80480E2 .text:08048072 int 80h ; LINUX - sys_signal .text:08048074 jmp short loc_8048077 .text:08048074 ; --------------------------------------------------------------------------- .text:08048076 db 0CEh .text:08048077 ; --------------------------------------------------------------------------- .text:08048077 .text:08048077 loc_8048077: .text:08048077 int 3 ; Trap to Debugger .text:08048078 jmp short loc_804807B .text:08048078 ; --------------------------------------------------------------------------- .text:0804807A db 0EBh .text:0804807B ; --------------------------------------------------------------------------- .text:0804807B .text:0804807B loc_804807B: .text:0804807B mov eax, 30h .text:08048080 mov ebx, 5 ; signo .text:08048085 mov ecx, offset dword_8048194 .text:0804808A int 80h ; LINUX - sys_signal .text:0804808C jmp short loc_804808F .text:0804808C ; --------------------------------------------------------------------------- .text:0804808E db 0E8h .text:0804808F ; --------------------------------------------------------------------------- .text:0804808F .text:0804808F loc_804808F: .text:0804808F int 3 ; Trap to Debugger .text:08048090 jmp short loc_8048093 .text:08048090 ; --------------------------------------------------------------------------- .text:08048092 db 0CEh .text:08048093 ; --------------------------------------------------------------------------- .text:08048093 .text:08048093 loc_8048093: .text:08048093 mov eax, 30h .text:08048098 mov ebx, 5 ; signo .text:0804809D mov ecx, offset dword_8048104 .text:080480A2 int 80h ; LINUX - sys_signal .text:080480A4 jmp short loc_80480A7 .text:080480A4 ; --------------------------------------------------------------------------- .text:080480A6 db 0EBh .text:080480A7 ; --------------------------------------------------------------------------- .text:080480A7 .text:080480A7 loc_80480A7: .text:080480A7 int 3 ; Trap to Debugger .text:080480A8 jmp short loc_80480AB .text:080480A8 ; --------------------------------------------------------------------------- .text:080480AA db 0E8h .text:080480AB ; --------------------------------------------------------------------------- .text:080480AB .text:080480AB loc_80480AB: .text:080480AB mov eax, 30h .text:080480B0 mov ebx, 5 ; signo .text:080480B5 mov ecx, offset dword_8048138 .text:080480BA int 80h ; LINUX - sys_signal .text:080480BC jmp short loc_80480BF .text:080480BC ; --------------------------------------------------------------------------- .text:080480BE db 0CEh .text:080480BF ; --------------------------------------------------------------------------- .text:080480BF .text:080480BF loc_80480BF: .text:080480BF int 3 ; Trap to Debugger .text:080480C0 jmp short loc_80480C3 .text:080480C0 ; --------------------------------------------------------------------------- .text:080480C2 db 0EBh .text:080480C3 ; --------------------------------------------------------------------------- .text:080480C3 .text:080480C3 loc_80480C3: .text:080480C3 mov eax, 30h .text:080480C8 mov ebx, 5 ; signo .text:080480CD mov ecx, offset byte_8048149 .text:080480D2 int 80h ; LINUX - sys_signal .text:080480D4 jmp short loc_80480D7 .text:080480D4 ; --------------------------------------------------------------------------- .text:080480D6 db 0E8h .text:080480D7 ; --------------------------------------------------------------------------- .text:080480D7 .text:080480D7 loc_80480D7: .text:080480D7 int 3 ; Trap to Debugger .text:080480D8 jmp short loc_80480DB .text:080480D8 ; --------------------------------------------------------------------------- .text:080480DA db 0E8h .text:080480DB ; --------------------------------------------------------------------------- .text:080480DB .text:080480DB loc_80480DB: .text:080480DB mov eax, 1 .text:080480E0 int 80h ; LINUX - sys_exit .text:080480E0 start endp .text:080480E0 .text:080480E2 .text:080480E2 ; =============== S U B R O U T I N E ======================================= .text:080480E2 .text:080480E2 .text:080480E2 sub_80480E2 proc near .text:080480E2 mov eax, offset dword_8048104 .text:080480E7 jmp short loc_8048101 .text:080480E9 ; --------------------------------------------------------------------------- .text:080480E9 .text:080480E9 loc_80480E9: .text:080480E9 .text:080480E9 cmp eax, 80482E8h .text:080480EE jz short locret_8048103 .text:080480F0 jmp short loc_80480F3 .text:080480F0 ; --------------------------------------------------------------------------- .text:080480F2 db 0E8h .text:080480F3 ; --------------------------------------------------------------------------- .text:080480F3 .text:080480F3 loc_80480F3: .text:080480F3 xor dword ptr [eax], 8048FC1h .text:080480F9 add eax, 4 .text:080480FC jmp short loc_80480FF .text:080480FC ; --------------------------------------------------------------------------- .text:080480FE db 0EBh .text:080480FF ; --------------------------------------------------------------------------- .text:080480FF .text:080480FF loc_80480FF: .text:080480FF jmp short loc_80480E9 .text:08048101 ; --------------------------------------------------------------------------- .text:08048101 .text:08048101 loc_8048101: .text:08048101 jmp short loc_80480E9 .text:08048103 ; --------------------------------------------------------------------------- .text:08048103 .text:08048103 locret_8048103: .text:08048103 retn .text:08048103 sub_80480E2 endp .text:08048103 .text:08048103 ; --------------------------------------------------------------------------- .text:08048104 dword_8048104 dd 8048E7Ah, 8A3936C1h, 1CBE87C5h, 0E0048FC1h, 8048F74h .text:08048104 dd 8048F7Ah, 8A5536C1h, 88BE87C5h, 0E0048FC1h, 8048F68h .text:08048104 dd 0C86DE7Ah, 43C78EC9h, 0CB048C07h .text:08048138 dword_8048138 dd 0C86DE79h, 83C0FC9h, 388489B5h, 0FDEFCF3Dh .text:08048148 db 2 .text:08048149 byte_8048149 db 37h, 55h, 8Ah .text:0804814C dd 0D9BF87C5h, 820C8B43h, 7D0FB5C9h, 8FD0FC8h, 4B4492B5h .text:0804814C dd 9BF7E2Ah, 0B1048FC1h, 0DC6h, 804997Bh, 85367C1h, 6AEC8FC1h .text:0804814C dd 0B3048FC1h, 8048FC0h, 0C856B78h, 82735C9h, 36EC8FC1h .text:0804814C dd 0E0048FC1h, 8048F88h .text:08048194 dword_8048194 dd 68BF4FF0h, 890C8B41h, 0C866B3Ah, 3B03FBC9h, 0CC70CC2h .text:08048194 dd 0ECBF7E2Ah, 330C8B43h, 0B31DFBC2h, 8048FC0h, 0C869278h .text:08048194 dd 82435C9h, 0EEC8FC1h, 0E0048FC1h, 8048FD0h, 8003702h .text:08048194 dd 88C98FC1h, 8073702h, 88C98FC1h, 8053702h, 88C98FC1h .text:08048194 dd 7C65FD86h, 7C24A3BBh, 2877E6A9h, 7C24FCA8h, 6F24EAA9h .text:08048194 dd 2860E0AEh, 7B77EEB1h, 6C76E0B6h, 4A0EAEE1h, 7824EBA0h .text:08048194 dd 7F77FCA0h, 2460FDAEh, 7A6BFCE1h, 2924F6B3h, 4151DECBh .text:08048194 dd 2825AF95h, 6B61F784h, 6A65FBB4h, 6124EAADh, 6769AFB2h .text:08048194 dd 6162E6A5h, 2924EBA4h, 7C6ACACBh, 7C24FDA4h, 7824EAA9h .text:08048194 dd 7F77FCA0h, 3260FDAEh, 8048FE1h, 1Fh dup(8048FC1h), 95CB2AC1h .text:08048194 dd 0BC8C5275h, 0A7912054h, 9FCB3B49h, 8D90A78h, 765EE0CBh .text:08048194 _text ends .text:08048194 .text:08048194 .text:08048194 end startFrom 0x08048104, the program appears as data instead of code. This part of program is protected against static analysis. First, lets figure out the de-obfuscation algorithm becuase it looks more like a self-modifying binary.
This is what the binary does to call the de-obfuscation routine:
.text:08048063 mov eax, 30h ; signal .text:08048068 mov ebx, 5 ; SIGTRAP .text:0804806D mov ecx, 0x080480E2 ; handler - de-obfuscation routine .text:08048072 int 80h ; LINUX - sys_signal .text:08048077 int 3Analysing the instructions at 0x080480E2, we can find the de-obfuscation routine:
mov eax, 0x08048104 ;loop cmp eax, 0x080482e8 if equal: ret else: xor [eax], 0x08048fc1 add eax, 4Bytes between 0x08048104 and 0x080482e4 is xor'ed with 0x08048fc1 to generate new sequence of instructions. Below is the permissions on the binary, 0x08048000-0x08049000 has read, write and execute permissions
(gdb) info target Symbols from "/Windows/E/Desktop_Recent/Recent/chall/ch13". Unix child process: Using the running image of child process 19533. While running this, GDB does not access memory from... Local exec file: `/Windows/E/Desktop_Recent/Recent/chall/ch13', file type elf32-i386. Entry point: 0x8048060 0x08048060 - 0x080482e8 is .text (gdb) shell cat /proc/19533/maps 08048000-08049000 rwxp 00000000 08:05 190663 /Windows/E/Desktop_Recent/Recent/chall/ch13 f7ffd000-f7ffe000 r-xp 00000000 00:00 0 [vdso] fffe9000-ffffe000 rwxp 00000000 00:00 0 [stack]Now we can convert the bytes to valid instructions since we know de-obfuscation routine. Interestingly I came across x86 Emulator plugin for IDA . Using this I was able to step through the code and convert the bytes to valid assembly instructions
This is how the bytes look after the de-obfuscation process ie after running under x86 emulator plugin
.text:08048104 dword_8048104 dd 1BBh, 823DB900h, 14BA0804h, 0E8000000h, 0B5h, 0BBh .text:08048104 dd 8251B900h, 80BA0804h, 0E8000000h, 0A9h, 48251BBh, 4BC30108h .text:08048104 dd 0C30003C6h .text:08048138 dword_8048138 dd 48251B8h, 388008h, 30800674h, 0F5EB40FCh .text:08048148 db 0C3h .text:08048149 byte_8048149 db 0B8h, 51h, 82h .text:0804814C dd 0D1BB0804h, 8A080482h, 750B3A08h, 0F98009h, 43401D74h .text:0804814C dd 1BBF1EBh, 0B9000000h, 8048207h, 16BAh, 57E800h, 62E80000h .text:0804814C dd 0BB000000h, 1, 481E4B9h, 23BA08h, 3EE80000h, 0E8000000h .text:0804814C dd 49h .text:08048194 dword_8048194 dd 60BBC031h, 81080480h, 482E4FBh, 33077408h, 4C38303h .text:08048194 dd 0E4BBF1EBh, 3B080482h, 0BB197403h, 1, 4821DB9h, 20BA08h .text:08048194 dd 6E80000h, 0E8000000h, 11h, 4B8C3h, 80CD0000h, 3B8C3h .text:08048194 dd 80CD0000h, 1B8C3h, 80CD0000h, 74617247h, 74202C7Ah .text:08048194 dd 20736968h, 74207369h, 67206568h, 20646F6Fh, 73736170h .text:08048194 dd 64726F77h, 420A2120h, 70206461h, 77737361h, 2C64726Fh .text:08048194 dd 726F7320h, 21207972h, 4955510Ah, 20212054h, 63657845h .text:08048194 dd 62617475h, 6920656Ch, 6F6D2073h, 69666964h, 21206465h .text:08048194 dd 746E450Ah, 74207265h, 70206568h, 77737361h, 3A64726Fh .text:08048194 dd 20h, 1Fh dup(0), 9DCFA500h, 0B488DDB4h, 0AF95AF95h .text:08048194 dd 97CFB488h, 0DD85B9h, 7E5A6F0Ah .text:080482E8 align 1000h .text:080482E8 _text endsConvert these bytes to instructions using IDA's Analyse selected area option.
.text:08048104 loc_8048104: .text:08048104 .text:08048104 mov ebx, 1 .text:08048109 mov ecx, offset aEnterThePasswo ; "Enter the password: " .text:0804810E mov edx, 14h .text:08048113 call sub_80481CD .text:08048118 mov ebx, 0 .text:0804811D mov ecx, 8048251h .text:08048122 mov edx, 80h .text:08048127 call sub_80481D5 .text:0804812C mov ebx, 8048251h .text:08048131 add ebx, eax .text:08048133 dec ebx .text:08048134 mov byte ptr [ebx], 0 .text:08048137 retn .text:08048138 ; --------------------------------------------------------------------------- .text:08048138 .text:08048138 loc_8048138: .text:08048138 mov eax, 8048251h .text:0804813D .text:0804813D loc_804813D: .text:0804813D cmp byte ptr [eax], 0 .text:08048140 jz short locret_8048148 .text:08048142 xor byte ptr [eax], 0FCh .text:08048145 inc eax .text:08048146 jmp short loc_804813D .text:08048148 ; --------------------------------------------------------------------------- .text:08048148 .text:08048148 locret_8048148: .text:08048148 retn .text:08048149 ; --------------------------------------------------------------------------- .text:08048149 .text:08048149 loc_8048149: .text:08048149 mov eax, 8048251h .text:0804814E mov ebx, offset aEAIXpxpiCE .text:08048153 .text:08048153 loc_8048153: .text:08048153 mov cl, [eax] .text:08048155 cmp cl, [ebx] .text:08048157 jnz short loc_8048162 .text:08048159 cmp cl, 0 .text:0804815C jz short loc_804817B .text:0804815E inc eax .text:0804815F inc ebx .text:08048160 jmp short loc_8048153 .text:08048162 ; --------------------------------------------------------------------------- .text:08048162 .text:08048162 loc_8048162: .text:08048162 mov ebx, 1 .text:08048167 mov ecx, (offset loc_8048206+1) .text:0804816C mov edx, 16h .text:08048171 call sub_80481CD .text:08048176 call sub_80481DD .text:0804817B ; --------------------------------------------------------------------------- .text:0804817B .text:0804817B loc_804817B: .text:0804817B mov ebx, 1 .text:08048180 mov ecx, offset loc_80481E4 .text:08048185 mov edx, 23h .text:0804818A call sub_80481CD .text:0804818F call sub_80481DD .text:08048194 ; --------------------------------------------------------------------------- .text:08048194 .text:08048194 loc_8048194: .text:08048194 xor eax, eax .text:08048196 mov ebx, offset start .text:0804819B .text:0804819B loc_804819B: .text:0804819B cmp ebx, offset loc_80482E4 .text:080481A1 jz short loc_80481AA .text:080481A3 xor eax, [ebx] .text:080481A5 add ebx, 4 .text:080481A8 jmp short loc_804819B .text:080481AA ; --------------------------------------------------------------------------- .text:080481AA .text:080481AA loc_80481AA: .text:080481AA mov ebx, offset loc_80482E4 .text:080481AF cmp eax, [ebx] .text:080481B1 jz short locret_80481CC .text:080481B3 mov ebx, 1 .text:080481B8 mov ecx, offset loc_804821D .text:080481BD mov edx, 20h .text:080481C2 call sub_80481CD .text:080481C7 call sub_80481DD .text:080481CC ; --------------------------------------------------------------------------- .text:080481CC .text:080481CC locret_80481CC: .text:080481CC retn .text:080481CD .text:080481CD ; =============== S U B R O U T I N E ======================================= .text:080481CD .text:080481CD .text:080481CD sub_80481CD proc near .text:080481CD .text:080481CD mov eax, 4 .text:080481D2 int 80h ; LINUX - sys_write .text:080481D4 retn .text:080481D4 sub_80481CD endp .text:080481D4 .text:080481D5 .text:080481D5 ; =============== S U B R O U T I N E ======================================= .text:080481D5 .text:080481D5 .text:080481D5 sub_80481D5 proc near .text:080481D5 mov eax, 3 .text:080481DA int 80h ; LINUX - sys_read .text:080481DC retn .text:080481DC sub_80481D5 endp .text:080481DC .text:080481DD .text:080481DD ; =============== S U B R O U T I N E ======================================= .text:080481DD .text:080481DD ; Attributes: noreturn .text:080481DD .text:080481DD sub_80481DD proc near .text:080481DD .text:080481DD mov eax, 1 .text:080481E2 int 80h ; LINUX - sys_exit .text:080481E2 sub_80481DD endpAfter analysing the instructions, the address range from 0x080481e4 to 0x0804823d looks more like data. Undefine this range and convert it to string using IDA
.text:080481E4 aGratzThisIsThe db 'Gratz, this is the good password !',0Ah .text:080481E4 db 'Bad password, sorry !',0Ah .text:080481E4 db 'QUIT ! Executable is modified !',0Ah .text:080481E4 db 'Enter the password: 'Hardcoded bytes at 0x080482d1
.text:080482D1 unk_80482D1 db 0A5h .text:080482D2 db 0CFh .text:080482D3 db 9Dh .text:080482D4 db 0B4h .text:080482D5 db 0DDh .text:080482D6 db 88h .text:080482D7 db 0B4h .text:080482D8 db 95h .text:080482D9 db 0AFh .text:080482DA db 95h .text:080482DB db 0AFh .text:080482DC db 88h .text:080482DD db 0B4h .text:080482DE db 0CFh .text:080482DF db 97h .text:080482E0 db 0B9h .text:080482E1 db 85h .text:080482E2 db 0DDh .text:080482E3 db 0Below is the function of binary:
mov eax, 0x30 mov ebx, 0x5 mov ecx, 0x080480e2 int 0x80 ; 0x080480e2 ; De-obfuscation routine mov eax, 0x08048104 ;loop cmp eax, 0x080482e8 if equal: ret else: xor [eax], 0x08048fc1 add eax, 4 mov eax, 0x30 mov ebx, 0x5 mov ecx, 0x08048194 int 0x80 ; 0x08048194 ; Verification routine xor eax, eax mov ebx, 0x08048060 ; loop cmp ebx, 0x080482e4 if equal: mov ebx, 0x080482e4 cmp eax, [ebx] if equal: ret else: mov ebx, 1 mov ecx, 0x0804821d mov edx, 0x20 call write ; QUIT ! Executable is modified ! call exit xor eax, [ebx] add ebx,4 mov eax, 0x30 mov ebx, 0x5 mov ecx, 0x08048104 int 0x80 ; 0x08048104 ; Accept password routine mov ebx, 1 mov ecx, "Enter the password: " mov edx, 0x14 call write mov ebx, 0 mov ecx, 0x08048251 mov edx, 0x80 call read mov ebx, 0x08048251 add ebx, eax dec ebx mov [ebx], 0x0 ; NUL terminate ret mov eax, 0x30 mov ebx, 0x5 mov ecx, 0x08048138 int 0x80 ; 0x08048138 mov eax, 0x08048251 ; loop cmp byte ptr [eax], 0 if equal: ret xor byte ptr [eax], 0x0fc inc eax mov eax, 0x30 ; Verify password routine mov ebx, 0x5 mov ecx, 0x08048149 int 0x80 ; 0x08048149 mov eax, 0x08048251 ; User input after xor mov ebx, 0x080482d1 ; Hard coded bytes ; loop mov cl, [eax] cmp cl, [ebx] jnz 0x08048162 ; Bad password, sorry ! cmp cl, 0 jz 0x0804817b ; Gratz, this is the good password ! inc eax inc ebxI wrote a simple python script to find the valid password.
#!/usr/bin/env python bytes = [0xa5, 0xcf, 0x9d, 0xb4, 0xdd, 0x88, 0xb4, 0x95, 0xaf, 0x95, 0xaf, 0x88, 0xb4, 0xcf, 0x97, 0xb9, 0x85, 0xdd] key = 0xfc password = '' for i in bytes: password += chr(i ^ key) print password
[ctf@renorobert chall]$ python ch13.py Y3aH!tHiSiStH3kEy! [ctf@renorobert chall]$ ./ch13 Enter the password: Y3aH!tHiSiStH3kEy! Gratz, this is the good password !Using GDB
To analyse the binary under gdb pass the SIGTRAP to the process
[ctf@renorobert chall]$ gdb -q ./ch13 Reading symbols from /Windows/E/Desktop_Recent/Recent/chall/ch13...(no debugging symbols found)...done. (gdb) handle SIGTRAP pass SIGTRAP is used by the debugger. Are you sure you want to change it? (y or n) y Signal Stop Print Pass to program Description SIGTRAP Yes Yes Yes Trace/breakpoint trapNow the binary will execute normally as we run it outside debugger.
Using GDBserver
[ctf@renorobert chall]$ gdbserver --remote-debug 127.0.0.1:6666 ./ch13 Process ./ch13 created; pid = 4833 Listening on port 6666Now use remote debugger option in IDA and attach to the process. Now after the de-obfuscation routine is called, we can inspect the memory and convert the raw bytes to instructions using IDA Analyze selected area option.
Its fun trying to analyse binaries of this kind!
Thanks for the write up. I struggled a bit with this but your write up helped me solving and understanding this better
ReplyDeletegreat!
ReplyDelete