0

I'm working on a crackme, where the objective is to find the valid password given a program. I'm using radare2 to reverse engineering the program. To do so, I need to enter a password that forces this program to bypass all the conditional jumps (jne's, jle's, jg's throughout).

Thus far, I've only concluded that the password must be 4 characters long, and the lowest 8 bits is 0x79, or ASCII character 'y' (please correct me if I'm wrong). The first N disassembled bytes (until I get stuck) are given below:

root@kali:~/Exploit_Class_NSL/Week1/Exercise4# r2 -AAAA example4 [x] Analyze all flags starting with sym. and entry0 (aa) [x] Analyze function calls (aac) [x] Analyze len bytes of instructions for references (aar) [x] Constructing a function name for fcn.* and sym.func.* functions (aan) [x] Enable constraint types analysis for variables [0x00401080]> pdf @main ;-- main: / (fcn) sym.main 201 | sym.main (int argc, char **argv, char **envp); | ; var int local_20h @ rbp-0x20 | ; var int local_14h @ rbp-0x14 | ; var int local_5h @ rbp-0x5 | ; var int local_4h @ rbp-0x4 | ; var int local_3h @ rbp-0x3 | ; var int local_2h @ rbp-0x2 | ; arg int argc @ rdi | ; arg char **argv @ rsi | ; DATA XREF from entry0 (0x40109d) | 0x00401162 55 push rbp | 0x00401163 4889e5 mov rbp, rsp | 0x00401166 4883ec20 sub rsp, 0x20 | 0x0040116a 897dec mov dword [local_14h], edi ; argc | 0x0040116d 488975e0 mov qword [local_20h], rsi ; argv | 0x00401171 488d3d8c0e00. lea rdi, qword str.enter_the_password: ; 0x402004 ; "enter the password: " | 0x00401178 b800000000 mov eax, 0 | 0x0040117d e8cefeffff call sym.imp.printf ; int printf(const char *format) | 0x00401182 488b15c72e00. mov rdx, qword [obj.stdin__GLIBC_2.2.5] ; obj.__TMC_END ; [0x404050:8]=0 | 0x00401189 488d45fb lea rax, qword [local_5h] | 0x0040118d be05000000 mov esi, 5 | 0x00401192 4889c7 mov rdi, rax | 0x00401195 e8c6feffff call sym.imp.fgets ; char *fgets(char *s, int size, FILE *stream) | 0x0040119a 488d45fb lea rax, qword [local_5h] | 0x0040119e 4889c7 mov rdi, rax | 0x004011a1 e89afeffff call sym.imp.strlen ; size_t strlen(const char *s) | 0x004011a6 4883f804 cmp rax, 4 ; 4 | ,=< 0x004011aa 7559 jne 0x401205 | | 0x004011ac 0fb645fb movzx eax, byte [local_5h] | | 0x004011b0 3c79 cmp al, 0x79 ; 'y' ; 121 | ,==< 0x004011b2 7554 jne 0x401208 | || 0x004011b4 0fb645fc movzx eax, byte [local_4h] | || 0x004011b8 0fbed0 movsx edx, al | || 0x004011bb 0fb645fd movzx eax, byte [local_3h] | || 0x004011bf 0fbec0 movsx eax, al | || 0x004011c2 01d0 add eax, edx | || 0x004011c4 3dda000000 cmp eax, 0xda ; 218 | ,===< 0x004011c9 7540 jne 0x40120b | ||| 0x004011cb 0fb645fd movzx eax, byte [local_3h] | ||| 0x004011cf 3c6c cmp al, 0x6c ; 'l' ; 108 | ,====< 0x004011d1 7e3b jle 0x40120e 

At 0x004011b4 is where I start to get stuck.

| || 0x004011b4 0fb645fc movzx eax, byte [local_4h] | || 0x004011b8 0fbed0 movsx edx, al | || 0x004011bb 0fb645fd movzx eax, byte [local_3h] | || 0x004011bf 0fbec0 movsx eax, al | || 0x004011c2 01d0 add eax, edx | || 0x004011c4 3dda000000 cmp eax, 0xda ; 218 | ,===< 0x004011c9 7540 jne 0x40120b 

Are local variables local_3h and local_4h ever initialized? If so, how? How should I go about stepping through this on my own?

I've tried toying around with different functions in r2, like afvd, e [ ], etc., but haven't gotten anywhere yet.

Any tips appreciated. Thanks!

2
  • look at the start you will see radare2 telling you what each of those local points to they are resp rbp - 2,3,4,5 1 is 6c other is 79 and the rest is an addition result Commented Apr 20, 2019 at 6:11
  • Sorry, @blabb , I don't see that... is that included in my code above? For example, I don't see reference to 0x6c before the cmp operation at 0x004011cf. FWIW, I've included all the output in my OP (through 0x004011c9) Commented Apr 20, 2019 at 6:16

2 Answers 2

3

Yes, they are initialized, albeit indirectly.

Have a look at this fragment:

 0x00401189 488d45fb lea rax, qword [local_5h] 0x0040118d be05000000 mov esi, 5 0x00401192 4889c7 mov rdi, rax 0x00401195 e8c6feffff call sym.imp.fgets ; char *fgets(char *s, int size, FILE *stream) 

Here we're calling the fgets function, passing to it the address of the local_5h as s and value 5 as size. This means that up to 5 bytes (including the terminating zero) can be read into the memory starting at local_5h, i.e. local_4h and local_3h are the second and third characters of the retrieved string.

2
  • Thanks! Is the qword in your referenced fragment a clue that more variables are being initialized? i.e., since local_5h appears to be only 0x1 wide? Wondering if I'm interpreting this correct: local_5h @ rbp-0x5, local_4h @ rbp-0x4, local_3h @ rbp-0x3, etc... Commented Apr 20, 2019 at 15:42
  • @ClarkHenry I think it's just an artifact of r2's disassembler. Since lea is taking an address and not moving any data, the size of the variable is not relevant. You could try reporting this issue to the developers. Commented Apr 20, 2019 at 15:45
0

I would say they are initialized on the stack for the local scope, as local variables for the function. My thoughts are look at the data stored on the local stack. I'm not sure if that is what you are looking for as an answer. I hope that helps.

2
  • 2
    Thanks for the feedback. Could you please elaborate a little? Would you happen to know how to do that in radare2? Would I find that in the 'entry0' or '.data' section of the disassembled program? Commented Apr 20, 2019 at 5:33
  • i haven't used it before, but I took a quick look at the documentation and this console string - pm xxs @ esp should print the stack, or possibly substitute ebp, let me know what that gives you! Commented Apr 20, 2019 at 5:44

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.