Here's how you can do it.
Usual stuff : r2 file; aaa; [email protected]
You can see the params to scanf
pushed to stack.
| 0x08048537 8d45e4 lea eax, [local_1ch]
| 0x0804853a 50 push eax
| 0x0804853b 8d45e0 lea eax, [local_20h]
| 0x0804853e 50 push eax
| 0x0804853f 6855860408 push str.d__d ; 0x8048655 ; "%d %d" ; const char *format
| 0x08048544 e887feffff call sym.imp.__isoc99_scanf ; int scanf(const char *format)
Lets rename locals.
[0x080484eb]> afv?
Usage: afv [rbs]
| afvr[?] manipulate register based arguments
| afvb[?] manipulate bp based arguments/locals
| afvs[?] manipulate sp based arguments/locals
| afv* output r2 command to add args/locals to flagspace
| afvR [varname] list addresses where vars are accessed (READ)
| afvW [varname] list addresses where vars are accessed (WRITE)
| afva analyze function arguments/locals
| afvd name output r2 command for displaying the value of args/locals in the debugger
| afvn [new_name] ([old_name]) rename argument/local
| afvt [name] [new_type] change type for given argument/local
| afv-([name]) remove all or given var
[0x080484eb]> afvn input_1 local_20h
[0x080484eb]> afvn input_2 local_1ch
[0x080484eb]> [email protected]
Now it looks like
| 0x08048537 8d45e4 lea eax, [input_2]
| 0x0804853a 50 push eax
| 0x0804853b 8d45e0 lea eax, [input_1]
| 0x0804853e 50 push eax
| 0x0804853f 6855860408 push str.d__d ; 0x8048655 ; "%d %d" ; const char *format
| 0x08048544 e887feffff call sym.imp.__isoc99_scanf ; int scanf(const char *format)
There's a check for Correct/Incorrect
| `-> 0x08048579 837de800 cmp dword [local_18h], 0
| ,=< 0x0804857d 7412 je 0x8048591
| | 0x0804857f 83ec0c sub esp, 0xc
| | 0x08048582 685b860408 push str.Correct ; 0x804865b ; "Correct!" ; const char *s
| | 0x08048587 e824feffff call sym.imp.puts ; int puts(const char *s)
| | 0x0804858c 83c410 add esp, 0x10
| ,==< 0x0804858f eb10 jmp 0x80485a1
| || ; CODE XREF from main (0x804857d)
| |`-> 0x08048591 83ec0c sub esp, 0xc
| | 0x08048594 6864860408 push str.Incorrect ; 0x8048664 ; "Incorrect!" ; const char *s
| | 0x08048599 e812feffff call sym.imp.puts ; int puts(const char *s)
| | 0x0804859e 83c410 add esp, 0x10
If local_18h
is 1/0, Correct/Incorrect is printed out to stdout respectively. Rename local_18h
to final_flag
as it decides the final output.
[0x0804852b]> afvn final_flag local_18h
Some constants are loaded to local variables. Remember/rename them to follow in code.
| 0x0804850f c745e8010000. mov dword [final_flag], 1
| 0x08048516 c745ec2a0000. mov dword [local_14h], 0x2a ; '*' ; 42
| 0x0804851d c745f0390500. mov dword [local_10h], 0x539 ; 1337
final_flag
is initially 1 (true). Just after input, there's a check to set final_flag
to 0(false).
| 0x0804854c 8b45ec mov eax, dword [const_2a]
| 0x0804854f 35280a0000 xor eax, 0xa28
| 0x08048554 89c2 mov edx, eax
| 0x08048556 8b45e0 mov eax, dword [input_1]
| 0x08048559 39c2 cmp edx, eax
| ,=< 0x0804855b 7407 je 0x8048564
| | 0x0804855d c745e8000000. mov dword [final_flag], 0
| | ; CODE XREF from main (0x804855b)
This can be roughly translated to:
if const_2a^0xa28 != input_1:
final_flag = False
To pass this input_1 = const_2a^0xa28
>>> 0x2a^0xa28
2562
Similar check for input_2
| `-> 0x08048564 8b45f0 mov eax, dword [const_539]
| 0x08048567 f7d0 not eax
| 0x08048569 89c2 mov edx, eax
| 0x0804856b 8b45e4 mov eax, dword [input_2]
| 0x0804856e 39c2 cmp edx, eax
| ,=< 0x08048570 7407 je 0x8048579
| | 0x08048572 c745e8000000. mov dword [final_flag], 0
This can be roughly translated to:
if ~const_539 != input_2:
final_flag = False
To pass this input_2 = ~const_539
>>> ~0x539
-1338
Finally
./part2
Enter the password: 2562 -1338
Correct!
ps @ str.d__d
you get the result of%d %d
. This is all located at the address 0x0804853f.