in the name of zero

November 25, 2006

crp-’s 888

make it print ‘OK’, no patching please :)

Difficulty: 2 - Needs a little brain (or luck)
Platform: Unix/linux etc.
Language: Assembler

download crackme here

the first few instructions from e_entry are quite easy to follow.. we now come to the part of the crackme where real work is being done.

LOAD:08048247 loc_8048247:
LOAD:08048247                 push    18149275h
LOAD:0804824C                 sub     [esp+4+var_4], 10101010h
LOAD:08048253                 call    loc_8048259     ; push 0x08048258 on stack
LOAD:08048253 ; ---------------------------------------------------------------------------
LOAD:08048258 byte_8048258    db 74h
LOAD:08048259 ; ---------------------------------------------------------------------------
LOAD:08048259 loc_8048259:
LOAD:08048259                 add     [esp+4+var_4], 8 ; 0x0804825 + 8 = 0x08048260 (address of retn)
LOAD:08048260                 retn

the routine pushes two addresses on the stack the first of which is the address (0x08048265) the second address (0x08048258) is pushed by the call loc_8048259 instruction, which is made to point to the address of the retn instruction itself making it execute two times. it basically, updates EIP with it’s own address then updates EIP (again) with the real address where to return control.

the next block of instruction (starts at 0x08048265) saves argc on a buffer, pushes the address 0x0804286 (remember this address) on the stack and finally, does another jmp via return address modification to address 0x08048223 which takes care of setting up a signal handler for the SIGTRAP signal.

LOAD:08048223 loc_8048223:
LOAD:08048223                 xor     eax, eax
LOAD:08048225                 mov     al, 32h
LOAD:08048227                 mov     ecx, 2
LOAD:0804822C
LOAD:0804822C loc_804822C:
LOAD:0804822C                 dec     al              ; sys_signal (eax = 48)
LOAD:0804822E                 loop    loc_804822C
LOAD:08048230                 sub     ebx, ebx
LOAD:08048232                 mov     bl, 5           ; ebx = 5 = SIGTRAP
LOAD:08048234                 mov     ecx, offset loc_804820B
LOAD:08048239                 dec     ecx             ; ecx = 0x0804820A (SIGTRAP handler)

lets jump to the crackme’s SIGTRAP handler to see what it does…

LOAD:0804820A                 inc     dword_804837C		; increment handler_count
LOAD:08048210                 mov     dword_8048380, 5B54D103h	; handler_code to another variable
LOAD:0804821A                 sub     eax, eax			; eax = 0
LOAD:0804821C                 inc     eax			; eax = 1
LOAD:0804821D                 neg     eax			; eax = -1
LOAD:0804821F                 js      short loc_8048223		; setup signal() again, after every handler call.
LOAD:08048221                 int     3				; Trap to Debugger

so in a nutshell, the crackme’s own SIGTRAP handler increments a variable then stores a predefined “identification” code to another variable and then setups up the signal() routine again.. (possibly, to restart the crackme routine…)

then control transfers to address 0x0804286 (pushed before on the stack remember?) thru a “jmp via ret” technique which eventually transfers control to 0x0804829a with the registers having values eax = 0x5 and ebx = 0x000482D2. a hardcoded value (0xd4a08f90) is saved onto a buffer and then another “jmp via ret” to the next instruction immediately after the block.

now we come accross a routine (0x080482aa) that patches the address 0x000482D2 with a 0xCC (trap/tracepoint) opcode. .. more jmps happens then finally an increment to eax which holds the memory address 0x080482D1 followed by a jmp to it. now this memory address was patched before with the value 0xCC remember? the crackme is trying to invoke its own SIGTRAP handler!

let’s view that address under gdb shall we?

misha@heaven ~/crp/888 $ gdb 888
(no debugging symbols found)
Using host libthread_db library \"/lib/libthread_db.so.1\".
niela@gdb $ context-on
niela@gdb $ hb *0x080482D2
Hardware assisted breakpoint 1 at 0x80482d2
niela@gdb $ r
warning: shared library handler failed to enable breakpoint
(no debugging symbols found)
_______________________________________________________________________________
     eax:080482D2 ebx:00000005  ecx:0804820A  edx:00000000     eflags:00000206
     esi:00000000 edi:00000000  esp:BFC15774  ebp:00000000     eip:080482D2
     cs:0073  ds:007B  es:007B  fs:0000  gs:0000  ss:007B    o d I t s z a P c
[007B:BFC15774]---------------------------------------------------------[stack]
BFC157A4 : 5B 7B C1 BF  88 7B C1 BF - 97 7B C1 BF  A3 7B C1 BF [{...{...{...{..
BFC15794 : 17 77 C1 BF  27 77 C1 BF - 32 77 C1 BF  4D 7B C1 BF .w..'w..2w..M{..
BFC15784 : DB 76 C1 BF  EB 76 C1 BF - FB 76 C1 BF  05 77 C1 BF .v...v...v...w..
BFC15774 : 03 76 C1 BF  00 00 00 00 - 1B 76 C1 BF  C8 76 C1 BF .v.......v...v..
[007B:080482D2]---------------------------------------------------------[ data]
080482D2 : CC A1 80 83  04 08 85 C0 - 74 49 2D 4F  4F 50 53 FF ........tI-OOPS.
080482E2 : D0 68 66 83  04 08 68 25 - 82 04 08 68  A1 81 04 08 .hf...h%...h....
[0073:080482D2]---------------------------------------------------------[ code]
0x80482d2:      int3
0x80482d3:      mov    eax,ds:0x8048380
0x80482d8:      test   eax,eax
0x80482da:      je     0x8048325
0x80482dc:      sub    eax,0x53504f4f
0x80482e1:      call   eax
——————————————————————————
Error while running hook_stop:
Invalid type combination in ordering comparison.
	
Breakpoint 1, 0x080482d2 in ?? ()

now, inside gdb, an interrupt 3 will suspend the program being debugged and control would be given to the debugger. the question is, how would this fool debuggers such as gdb if we are not careful anyway??

i quote the gdb info page: (gdb.info)

5.3 Signals
===========


GDB has the ability to detect any occurrence of a signal in your
program. You can tell GDB in advance what to do for each kind of
signal.

When a signal stops your program, the signal is not visible to the
program until you continue. Your program sees the signal then, if
`pass’ is in effect for the signal in question _at that time_. In
other words, after GDB reports a signal, you can use the `handle’
command with `pass’ or `nopass’ to control whether your program sees
that signal when you continue.

You can also use the `signal’ command to prevent your program from
seeing a signal, or cause it to see a signal it normally would not see,
or to give it any signal at any time.

this was how i understood it:

the int 3 will send a signal (motioning for it to stop) but gdb will catch this before the crackme’s SIGTRAP handler. unless you tell debuggers such as GDB to explicitly pass a caught signal to the program being debugged upon, things could go wrong… in this case, a SIGTRAP handler not getting executed…

after the handler executes, control is then passed to address 0x08042d3, the next instruction after the 0xCC opcode.

earlier, i inspected the SIGTRAP handler and it saves a hardcoded SIGTRAP identification code to a buffer (0x08048380). i can now see that this value is being passed to eax, tested for “zero” (which means that the crackme’s own SIGTRAP handler wasn’t called). this value is subtracted by another hard code value and then finally, eax is being called. so we have:

0x05b54D103 - 0x53504F4f = 0x080481B4 (resume execution at this address)

the block (from 0x080481B4) starts off with a pop instruction, which clears the stack of the return address of the call instruction at address 0x80482e1, saving the address (0x080482e3) to a buffer.in enters a loop wherein it continously pops off the stack until it reaches a terminating NULL. granted that the argc value has already been popped off before (at address 0x08048266 specifically), the first value it will remove is actually argv[0], the crackme’s absolute pathname. it’s trying to reach the envp variables of the program.

what’s it trying to do with the envp variables?

LOAD:080481D2                 call    sub_8048052		; strlen
LOAD:080481D7                 cmp     eax, 4
LOAD:080481DC                 jl      short fixed_loc		; strlen < 4
LOAD:080481DE                 cmp     eax, 40h
LOAD:080481E3                 jg      short loc_80481CB		; strlen > 64
LOAD:080481E5                 mov     ecx, [ebx]		; strncpy(ecx, ebx, 4);
LOAD:080481E7                 and     ecx, 0FFFFFFh		; null terminate the 3 characters
LOAD:080481ED                 cmp     ecx, 79656Bh		; strcmp(ecx, “key”, 4);
LOAD:080481F3                 jnz     short loc_80481CB		; no match
LOAD:080481F5                 push    ebx			; save string on stack
LOAD:080481F6                 push    offset loc_80481CB	; return address
LOAD:080481FB                 jmp     loc_804813E		; process “key” envp variable

sub_8048052 is a custom strlen() function that initializes the address of the next envp variable to be processed before returning the actual length of the current envp variable in question. a conversion is being done based on the value of at least two “key” environment variables,. translated to C, the conversion is roughly :

	#define BTMASK	0x80000000
	#define ECX	0x0a
	
        for (i=0; i<strlen (value); i++ ) {
                if (!isdigit(value[i])) {
                        ebx = BTMASK | value[i];
                        goto fin;
                }
	
                ebx *= ECX;
                ebx += (value[i]-0x30);
        } fin: /*  ...  */

which is simply an atoi(const char *nptr).

following the code, i came across another block of that sets up yet another signal handler for the signal SIGFPE. skip analysis of the handler code at the moment and continue at address 0x0804819d.

first, a stamp (that was ‘or’ed by 1 and 2 before) is being continously tested with decrementing values starting from 3 which would state that at least two “keyX=value” pairs have been processed. the crackme then forces an FPE (floatin point exception) by doing a division by zeroat address 0x80481b1, which would trigger the SIGFPE handler.

what does the handler do?

a) it nops out the div ecx instruction at 0x080481b1
b) both key1 and key2 values are being compared to 0x1000. (must be greater)
c) key values are multiplied… product is stored at edx:eax
d) product is divided by 0x10001 quotient is eax, remainder is edx
e) remainder (edx) is decremented and zero flag determines crack state.

Comments »

The URI to TrackBack this entry is: http://gnurbs.blogsome.com/2006/11/25/crp-s-888/trackback/

No comments yet.

RSS feed for comments on this post.

Leave a comment

Line and paragraph breaks automatic, e-mail address never displayed, HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>


Get free blog up and running in minutes with Blogsome | Theme designs available here