Assembly Reversing Problems
These are some basic assembly reversing problems from: https://github.com/kablaa/CTF-Workshop/blob/master/Reversing/Challenges/IfThen/if_then
The purpose of these challenges is to get some experience reversing assembly code. Try to figure out what the binaries are doing. To view disassembly machine code into assembly code, you can use something like objdump
.
Hello World
First let's take a look at the assembly code:
$ objdump -D hello_world -M intel | less
After searching through for the string main
to find the main function, we see this:
080483fb <main>:
80483fb: 8d 4c 24 04 lea ecx,[esp+0x4]
80483ff: 83 e4 f0 and esp,0xfffffff0
8048402: ff 71 fc push DWORD PTR [ecx-0x4]
8048405: 55 push ebp
8048406: 89 e5 mov ebp,esp
8048408: 51 push ecx
8048409: 83 ec 04 sub esp,0x4
804840c: 83 ec 0c sub esp,0xc
804840f: 68 b0 84 04 08 push 0x80484b0
8048414: e8 b7 fe ff ff call 80482d0 <puts@plt>
8048419: 83 c4 10 add esp,0x10
804841c: b8 00 00 00 00 mov eax,0x0
8048421: 8b 4d fc mov ecx,DWORD PTR [ebp-0x4]
8048424: c9 leave
8048425: 8d 61 fc lea esp,[ecx-0x4]
8048428: c3 ret
8048429: 66 90 xchg ax,ax
804842b: 66 90 xchg ax,ax
804842d: 66 90 xchg ax,ax
804842f: 90 nop
Looking at the code, we see a function call to puts
:
push 0x80484b0
call 80482d0 <puts@plt>
Looking through the rest of the code, we really don't see much else that is interesting for our perspective. So this code probably just prints a string. When we run the binary, we see that is correct:
$ ./hello_world
hello world!
If then
We start off by viewing the assembly code with objdump
:
$ objdump -D if_then -M intel | less
After parsing through for the main
function, we see this.
080483fb <main>:
80483fb: 8d 4c 24 04 lea ecx,[esp+0x4]
80483ff: 83 e4 f0 and esp,0xfffffff0
8048402: ff 71 fc push DWORD PTR [ecx-0x4]
8048405: 55 push ebp
8048406: 89 e5 mov ebp,esp
8048408: 51 push ecx
8048409: 83 ec 14 sub esp,0x14
804840c: c7 45 f4 0a 00 00 00 mov DWORD PTR [ebp-0xc],0xa
8048413: 83 7d f4 0a cmp DWORD PTR [ebp-0xc],0xa
8048417: 75 10 jne 8048429 <main+0x2e>
8048419: 83 ec 0c sub esp,0xc
804841c: 68 c0 84 04 08 push 0x80484c0
8048421: e8 aa fe ff ff call 80482d0 <puts@plt>
8048426: 83 c4 10 add esp,0x10
8048429: b8 00 00 00 00 mov eax,0x0
804842e: 8b 4d fc mov ecx,DWORD PTR [ebp-0x4]
8048431: c9 leave
8048432: 8d 61 fc lea esp,[ecx-0x4]
8048435: c3 ret
8048436: 66 90 xchg ax,ax
8048438: 66 90 xchg ax,ax
804843a: 66 90 xchg ax,ax
804843c: 66 90 xchg ax,ax
804843e: 66 90 xchg ax,ax
We can see that it loads the value 0xa
into ebp-0xc
:
mov DWORD PTR [ebp-0xc],0xa
Immediately proceeding that, we see that it runs a cmp
instruction on it to check if it is equal. If they are not equal it will jump to main+0x2e
. Since it was just loaded with the value 0xa
, it should not make the jump:
cmp DWORD PTR [ebp-0xc],0xa
jne 8048429 <main+0x2e>
proceeding that it should make a call to puts:
sub esp,0xc
push 0x80484c0
call 80482d0 <puts@plt>
So after looking at this code, we see that it should make that puts
call. When we run it, we see that is what it does:
$ ./if_then
x = ten
Loop
Let's take a look at the assembly code:
$ objdump -D loop -M intel | less
Quickly searching for the main function, we find it:
080483fb <main>:
80483fb: 8d 4c 24 04 lea ecx,[esp+0x4]
80483ff: 83 e4 f0 and esp,0xfffffff0
8048402: ff 71 fc push DWORD PTR [ecx-0x4]
8048405: 55 push ebp
8048406: 89 e5 mov ebp,esp
8048408: 51 push ecx
8048409: 83 ec 14 sub esp,0x14
804840c: c7 45 f4 00 00 00 00 mov DWORD PTR [ebp-0xc],0x0
8048413: eb 17 jmp 804842c <main+0x31>
8048415: 83 ec 08 sub esp,0x8
8048418: ff 75 f4 push DWORD PTR [ebp-0xc]
804841b: 68 c0 84 04 08 push 0x80484c0
8048420: e8 ab fe ff ff call 80482d0 <printf@plt>
8048425: 83 c4 10 add esp,0x10
8048428: 83 45 f4 01 add DWORD PTR [ebp-0xc],0x1
804842c: 83 7d f4 13 cmp DWORD PTR [ebp-0xc],0x13
8048430: 7e e3 jle 8048415 <main+0x1a>
8048432: b8 00 00 00 00 mov eax,0x0
8048437: 8b 4d fc mov ecx,DWORD PTR [ebp-0x4]
804843a: c9 leave
804843b: 8d 61 fc lea esp,[ecx-0x4]
804843e: c3 ret
804843f: 90 nop
In this function, we can see that it will initialize a stack variable at ebp-0xc
to 0
, then jump to 0x804842c
(main+0x31
):
mov DWORD PTR [ebp-0xc],0x0
jmp 804842c <main+0x31>
Looking at the instructions at 0x804842c
we see this:
cmp DWORD PTR [ebp-0xc],0x13
jle 8048415 <main+0x1a>
We see that it compares the stack value at ebp-0xc
against 0x13
, and if it is less than or equal then it will jump to 0x8048415
(0x80483fb + 0x1a
). That brings us to a printf call:
sub esp,0x8
push DWORD PTR [ebp-0xc]
push 0x80484c0
call 80482d0 <printf@plt>
It looks like it is printing out the contents of ebp-0xc
in some sort of format string. After that we can see that it increments the value of ebp-0xc
, before doing the cmp
again:
add DWORD PTR [ebp-0xc],0x1
So right, putting all of the pieces together, now we are probably looking at a for loop that will run 20
times, and print the iteration counter each time. Something that looks similar to this:
int i = 0;
for (i = 0; i < 20; i ++)
{
printf("%d", i);
}
When we run the binary, we see that it is true:
$ ./loop
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19