coursera had a malware course, one of the class was to reverse engineer a binary and crack the key. I have tried to explain it here by taking baby steps using objdump in linux. The approach is trying to comeup with a pseudo code from binary. steps are objdump output, manual analysis, write pseudo code from the analysis and the finally the real code which was compiled to verify. Used gdb only for printing strings and converting hex to decimal.
====== Example 1 =======
objdump
-------
In 1_objdump file search for main
08048394 <main>:
8048394: 55 push %ebp
8048395: 89 e5 mov %esp,%ebp
8048397: b8 7b 00 00 00 mov $0x7b,%eax
804839c: 5d pop %ebp
804839d: c3 ret
804839e: 90 nop
804839f: 90 nop
study
-----
8048394: 55 push %ebp
save previous frame pointer on stack
8048395: 89 e5 mov %esp,%ebp
Intialize the frame pointer to current stack pointer sp->bp.
8048397: b8 7b 00 00 00 mov $0x7b,%eax
moving 0x7b value to eax register. 0x7b in decimal is
gdb ./a.out (using gdb for converting 123 to hex).)
(gdb) p/x 123
$1 = 0x7b
As you can see eax register is used to return values to the caller.
pseudocode
----------
main
return 123;
code
----
#include <stdio.h>
int main(int argc, char **argv)
{
return 123;
}
build
-----
gcc 1.c
objdump -d ./a.out > 1_objdump
====== Example 2 =======
080483c4 <main>:
80483c4: 55 push %ebp
80483c5: 89 e5 mov %esp,%ebp
80483c7: 83 e4 f0 and $0xfffffff0,%esp
80483ca: 83 ec 10 sub $0x10,%esp
80483cd: b8 b4 84 04 08 mov $0x80484b4,%eax
80483d2: 89 04 24 mov %eax,(%esp)
80483d5: e8 1a ff ff ff call 80482f4 <printf@plt>
80483da: b8 7b 00 00 00 mov $0x7b,%eax
80483df: c9 leave
80483e0: c3 ret
Our 0x7b is still there, there is a call to function printf. so our string
"Hello World" should pushed on stack, so eax which looks like a pointer value
is pushed onto stack before calling printf. But objdump file doesn't contain
the address contents [0x80484b4].
objdump -D ./a.out > 1_objdump
80484b4: 48 dec %eax
80484b5: 65 gs
80484b6: 6c insb (%dx),%es:(%edi)
80484b7: 6c insb (%dx),%es:(%edi)
80484b8: 6f outsl %ds:(%esi),(%dx)
80484b9: 20 57 6f and %dl,0x6f(%edi)
80484bc: 72 6c jb 804852a <__dso_handle+0x7a>
80484be: 64 fs
b ./a.out
(gdb) x/s 0x80484b4
0x80484b4 <__dso_handle+4>: "Hello World"
(gdb) x/16xb 0x80484b4
0x80484b4 <__dso_handle+4>: 0x48 0x65 0x6c 0x6c 0x6f 0x20 0x57 0x6f
0x80484bc <__dso_handle+12>: 0x72 0x6c 0x64 0x00 0x01 0x1b 0x03 0x3b
(gdb) x/16cb 0x80484b4
0x80484b4 <__dso_handle+4>: 72 'H' 101 'e' 108 'l' 108 'l' 111 'o' 32 ' ' 87 'W' 111 'o'
0x80484bc <__dso_handle+12>: 114 'r' 108 'l' 100 'd' 0 '\000' 1 '\001' 27 '\033' 3 '\003' 59 ';'
Ok, we have our "Hello world" pointer in stack before calling printf.
80483c4: 55 push %ebp
80483c5: 89 e5 mov %esp,%ebp
usual prologue
80483c7: 83 e4 f0 and $0xfffffff0,%esp
Aligning the stack to 16 bytes.
80483ca: 83 ec 10 sub $0x10,%esp
Allocating 16 bytes, only 4 bytes are needed to put arg to printf, adhering to
alignment of 16 bytes.
80483cd: b8 b4 84 04 08 mov $0x80484b4,%eax
80483d2: 89 04 24 mov %eax,(%esp)
"Hello world" pointer is pushed to eax to contents on allocated stack.
80483d5: e8 1a ff ff ff call 80482f4 <printf@plt>
80483da: b8 7b 00 00 00 mov $0x7b,%eax
80483df: c9 leave
80483e0: c3 ret
pseudocode
----------
main
printf "Hello World";
return 123;
code
----
#include <stdio.h>
int main(int argc, char **argv)
{
printf("Hello World");
return 123;
}
build
-----
gcc 1.c
objdump -d ./a.out > 1_objdump
====== Example 3 =======
08048474 <main>:
8048474: 55 push %ebp
8048475: 89 e5 mov %esp,%ebp
8048477: 83 e4 f0 and $0xfffffff0,%esp
804847a: 81 ec 20 02 00 00 sub $0x220,%esp
8048480: b8 c4 85 04 08 mov $0x80485c4,%eax
8048485: 89 04 24 mov %eax,(%esp)
8048488: e8 1b ff ff ff call 80483a8 <printf@plt>
804848d: a1 a0 97 04 08 mov 0x80497a0,%eax
8048492: 89 04 24 mov %eax,(%esp)
8048495: e8 ee fe ff ff call 8048388 <fflush@plt>
804849a: c7 44 24 08 ff 01 00 movl $0x1ff,0x8(%esp)
80484a1: 00
80484a2: 8d 44 24 14 lea 0x14(%esp),%eax
80484a6: 89 44 24 04 mov %eax,0x4(%esp)
80484aa: c7 04 24 00 00 00 00 movl $0x0,(%esp)
80484b1: e8 c2 fe ff ff call 8048378 <read@plt>
80484b6: 8d 44 24 14 lea 0x14(%esp),%eax
80484ba: 89 04 24 mov %eax,(%esp)
80484bd: e8 d6 fe ff ff call 8048398 <strlen@plt>
80484c2: 89 84 24 14 02 00 00 mov %eax,0x214(%esp)
80484c9: 8b 84 24 14 02 00 00 mov 0x214(%esp),%eax
80484d0: 83 e8 01 sub $0x1,%eax
80484d3: 0f b6 44 04 14 movzbl 0x14(%esp,%eax,1),%eax
80484d8: 3c 0a cmp $0xa,%al
80484da: 75 0f jne 80484eb <main+0x77>
80484dc: 8b 84 24 14 02 00 00 mov 0x214(%esp),%eax
80484e3: 83 e8 01 sub $0x1,%eax
80484e6: c6 44 04 14 00 movb $0x0,0x14(%esp,%eax,1)
80484eb: b8 7b 00 00 00 mov $0x7b,%eax
80484f0: c9 leave
80484f1: c3 ret
study
-----
8048474: 55 push %ebp
8048475: 89 e5 mov %esp,%ebp
8048477: 83 e4 f0 and $0xfffffff0,%esp
usual
804847a: 81 ec 20 02 00 00 sub $0x220,%espa
(gdb) p 0x220
$1 = 544
Allocating 544 bytes on stack
8048480: b8 c4 85 04 08 mov $0x80485c4,%eax
8048485: 89 04 24 mov %eax,(%esp)
8048488: e8 1b ff ff ff call 80483a8 <printf@plt>
objdump -D ./a.out > 1_objdump
shows the contents of 0x80485c4.
(gdb) x/s 0x80485c4
0x80485c4 <__dso_handle+4>: "Are you feeling lucky today? "
printf with one arg "Are you feeling lucky today? ".
804848d: a1 a0 97 04 08 mov 0x80497a0,%eax
8048492: 89 04 24 mov %eax,(%esp)
8048495: e8 ee fe ff ff call 8048388 <fflush@plt>
man fflush
(gdb) x/s 0x80497a0
0x80497a0 <stdout@@GLIBC_2.0>: ""
(gdb) p/x *0x80497a0
$6 = 0x0
so fflush is flusihing all open output streams. I think fflush(NULL).
804849a: c7 44 24 08 ff 01 00 movl $0x1ff,0x8(%esp)
80484a1: 00
80484a2: 8d 44 24 14 lea 0x14(%esp),%eax
80484a6: 89 44 24 04 mov %eax,0x4(%esp)
80484aa: c7 04 24 00 00 00 00 movl $0x0,(%esp)
80484b1: e8 c2 fe ff ff call 8048378 <read@plt>
man 2 read
ssize_t read(int fd, void *buf, size_t count);
stack is 0x1ff (511), something in stack which is at 20 (0x14) bytes , 0
so args to read are fd = 0, buf, 511.
main() stack allocated is 544 bytes of which
...
something like buf of size 524 ...(there could be other local variables,
read call is only restricted to overwrite 511)
20
0
pointer to buf
511
...
80484b6: 8d 44 24 14 lea 0x14(%esp),%eax
80484ba: 89 04 24 mov %eax,(%esp)
80484bd: e8 d6 fe ff ff call 8048398 <strlen@plt>
80484c2: 89 84 24 14 02 00 00 mov %eax,0x214(%esp)
size_t strlen(const char *s);
so strlen(buf);
(gdb) p 0x214
$8 = 532
local variables of main are
(544 = 8,4 (var1),512 (buf),20(alignment, padding (4)))
main
char buf[512]
int var1
char unknown[8]
printf("Are you feeling lucky today? ");
fflush(NULL);
read(0, buf, 511);
var1 = strlen(buf);
80484d0: 83 e8 01 sub $0x1,%eax
512 - 1 = 511
80484d3: 0f b6 44 04 14 movzbl 0x14(%esp,%eax,1),%eax
displacement(%base, %index, scale) = displacement+%base+%index*scale.
since scale is 1 it is a char array.
buf[511]
80484d8: 3c 0a cmp $0xa,%al
(gdb) p/c 0xa
$10 = 10 '\n'
if (buf[511 == '\n')
80484da: 75 0f jne 80484eb <main+0x77>
80484dc: 8b 84 24 14 02 00 00 mov 0x214(%esp),%eax
80484e3: 83 e8 01 sub $0x1,%eax
80484e6: c6 44 04 14 00 movb $0x0,0x14(%esp,%eax,1)
buf[511] = 0;
80484eb: b8 7b 00 00 00 mov $0x7b,%eax
80484f0: c9 leave
80484f1: c3 ret
pseudo code
main
char buf[512]
int var1
char unknown[8]
printf("Are you feeling lucky today? ");
fflush(NULL);
read(0, buf, 511);
var1 = strlen(buf);
if (buf[511 == '\n')
buf[511] = 0;
return 123
code
----
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
char buf[512];
int n,ret;
int (*f)(char *);
printf("Are you feeling lucky today? ");
fflush(stdout);
(void)read(0, buf, sizeof(buf)-1);
n = strlen(buf);
if (buf[n-1] == '\n')
buf[n-1] = 0;
return 123;
}
====== Example 4 =======
080484ee <main>:
80484ee: 55 push %ebp
80484ef: 89 e5 mov %esp,%ebp
80484f1: 83 e4 f0 and $0xfffffff0,%esp
80484f4: 81 ec 20 02 00 00 sub $0x220,%esp
80484fa: b8 7c 86 04 08 mov $0x804867c,%eax
80484ff: 89 04 24 mov %eax,(%esp)
8048502: e8 c1 fe ff ff call 80483c8 <printf@plt>
8048507: a1 60 98 04 08 mov 0x8049860,%eax
804850c: 89 04 24 mov %eax,(%esp)
804850f: e8 94 fe ff ff call 80483a8 <fflush@plt>
8048514: c7 44 24 08 ff 01 00 movl $0x1ff,0x8(%esp)
804851b: 00
804851c: 8d 44 24 14 lea 0x14(%esp),%eax
8048520: 89 44 24 04 mov %eax,0x4(%esp)
8048524: c7 04 24 00 00 00 00 movl $0x0,(%esp)
804852b: e8 68 fe ff ff call 8048398 <read@plt>
8048530: 8d 44 24 14 lea 0x14(%esp),%eax
8048534: 89 04 24 mov %eax,(%esp)
8048537: e8 7c fe ff ff call 80483b8 <strlen@plt>
804853c: 89 84 24 14 02 00 00 mov %eax,0x214(%esp)
8048543: 8b 84 24 14 02 00 00 mov 0x214(%esp),%eax
804854a: 83 e8 01 sub $0x1,%eax
804854d: 0f b6 44 04 14 movzbl 0x14(%esp,%eax,1),%eax
8048552: 3c 0a cmp $0xa,%al
8048554: 75 0f jne 8048565 <main+0x77>
8048556: 8b 84 24 14 02 00 00 mov 0x214(%esp),%eax
804855d: 83 e8 01 sub $0x1,%eax
8048560: c6 44 04 14 00 movb $0x0,0x14(%esp,%eax,1)
8048565: 0f b6 44 24 14 movzbl 0x14(%esp),%eax
804856a: 0f be c0 movsbl %al,%eax
804856d: 83 f8 42 cmp $0x42,%eax
8048570: 74 17 je 8048589 <main+0x9b>
8048572: 83 f8 43 cmp $0x43,%eax
8048575: 74 21 je 8048598 <main+0xaa>
8048577: 83 f8 41 cmp $0x41,%eax
804857a: 75 29 jne 80485a5 <main+0xb7>
804857c: c7 84 24 1c 02 00 00 movl $0x80484a4,0x21c(%esp)
8048583: a4 84 04 08
8048587: eb 1e jmp 80485a7 <main+0xb9>
8048589: b8 9a 86 04 08 mov $0x804869a,%eax
804858e: 89 04 24 mov %eax,(%esp)
8048591: e8 32 fe ff ff call 80483c8 <printf@plt>
8048596: eb 0f jmp 80485a7 <main+0xb9>
8048598: c7 84 24 1c 02 00 00 movl $0x80484d6,0x21c(%esp)
804859f: d6 84 04 08
80485a3: eb 02 jmp 80485a7 <main+0xb9>
80485a5: eb fe jmp 80485a5 <main+0xb7>
80485a7: b8 7b 00 00 00 mov $0x7b,%eax
80485ac: c9 leave
80485ad: c3 ret
rom 80484ee to 8048565 is
main
char buf[512]
int var1
char unknown[8]
printf("Are you feeling lucky today? ");
fflush(NULL);
read(0, buf, 511);
var1 = strlen(buf);
if (buf[511 == '\n')
buf[511] = 0;
8048565: 0f b6 44 24 14 movzbl 0x14(%esp),%eax
804856a: 0f be c0 movsbl %al,%eax
804856d: 83 f8 42 cmp $0x42,%eax
8048570: 74 17 je 8048589 <main+0x9b>
if (buf[0] == 0x42)
(gdb) x/s 0x804869a
0x804869a <__dso_handle+42>: "Hello"
printf("Hello")
8048572: 83 f8 43 cmp $0x43,%eax
8048575: 74 21 je 8048598 <main+0xaa>
if (buf[0] == 0x43)
(gdb) x 0x80484d6
0x80484d6 <foobar>: 0x83e58955
moving address of foobar to a local variable (function pointer).
8048577: 83 f8 41 cmp $0x41,%eax
804857a: 75 29 jne 80485a5 <main+0xb7>
804857c: c7 84 24 1c 02 00 00 movl $0x80484a4,0x21c(%esp)
8048583: a4 84 04 08
8048587: eb 1e jmp 80485a7 <main+0xb9>
if (buf[0] == 0x41)
(gdb) x 0x80484a4
0x80484a4 <foo>: 0x83e58955
moving address of foo to a local variable (function pointer).
8048589: b8 9a 86 04 08 mov $0x804869a,%eax
804858e: 89 04 24 mov %eax,(%esp)
8048591: e8 32 fe ff ff call 80483c8 <printf@plt>
// done with printf("Hello");
8048596: eb 0f jmp 80485a7 <main+0xb9>
8048598: c7 84 24 1c 02 00 00 movl $0x80484d6,0x21c(%esp)
804859f: d6 84 04 08
80485a3: eb 02 jmp 80485a7 <main+0xb9>
80485a5: eb fe jmp 80485a5 <main+0xb7>
Loo.....oop
switch (buf[0]) {
case 0x41:
var2 = &foo;
break;
case 0x42:
printf("Hello");
break;
case 0x43:
var2 = &foobar;
break;
default:
loop here.
}
80485a7: b8 7b 00 00 00 mov $0x7b,%eax
80485ac: c9 leave
80485ad: c3 ret
return 123;
====== Example 5 =======
08048577 <main>:
8048577: 55 push %ebp
8048578: 89 e5 mov %esp,%ebp
804857a: 57 push %edi
804857b: 83 e4 f0 and $0xfffffff0,%esp
804857e: 81 ec 30 02 00 00 sub $0x230,%esp
8048584: b8 91 87 04 08 mov $0x8048791,%eax
8048589: 89 04 24 mov %eax,(%esp)
804858c: e8 1f fe ff ff call 80483b0 <printf@plt>
8048591: a1 40 a0 04 08 mov 0x804a040,%eax
8048596: 89 04 24 mov %eax,(%esp)
8048599: e8 22 fe ff ff call 80483c0 <fflush@plt>
804859e: c7 44 24 08 ff 01 00 movl $0x1ff,0x8(%esp)
80485a5: 00
80485a6: 8d 44 24 24 lea 0x24(%esp),%eax
80485aa: 89 44 24 04 mov %eax,0x4(%esp)
80485ae: c7 04 24 00 00 00 00 movl $0x0,(%esp)
80485b5: e8 e6 fd ff ff call 80483a0 <read@plt>
80485ba: 8d 44 24 24 lea 0x24(%esp),%eax
80485be: c7 44 24 1c ff ff ff movl $0xffffffff,0x1c(%esp)
80485c5: ff
80485c6: 89 c2 mov %eax,%edx
80485c8: b8 00 00 00 00 mov $0x0,%eax
80485cd: 8b 4c 24 1c mov 0x1c(%esp),%ecx
80485d1: 89 d7 mov %edx,%edi
80485d3: f2 ae repnz scas %es:(%edi),%al
80485d5: 89 c8 mov %ecx,%eax
80485d7: f7 d0 not %eax
80485d9: 83 e8 01 sub $0x1,%eax
80485dc: 89 84 24 28 02 00 00 mov %eax,0x228(%esp)
80485e3: 8b 84 24 28 02 00 00 mov 0x228(%esp),%eax
80485ea: 83 e8 01 sub $0x1,%eax
80485ed: 0f b6 44 04 24 movzbl 0x24(%esp,%eax,1),%eax
80485f2: 3c 0a cmp $0xa,%al
80485f4: 75 0f jne 8048605 <main+0x8e>
80485f6: 8b 84 24 28 02 00 00 mov 0x228(%esp),%eax
80485fd: 83 e8 01 sub $0x1,%eax
8048600: c6 44 04 24 00 movb $0x0,0x24(%esp,%eax,1)
8048605: 0f b6 44 24 24 movzbl 0x24(%esp),%eax
804860a: 0f be c0 movsbl %al,%eax
804860d: 83 f8 42 cmp $0x42,%eax
8048610: 74 17 je 8048629 <main+0xb2>
8048612: 83 f8 43 cmp $0x43,%eax
8048615: 74 1f je 8048636 <main+0xbf>
8048617: 83 f8 41 cmp $0x41,%eax
804861a: 75 27 jne 8048643 <main+0xcc>
804861c: c7 84 24 2c 02 00 00 movl $0x804852d,0x22c(%esp)
8048623: 2d 85 04 08
8048627: eb 1c jmp 8048645 <main+0xce>
8048629: c7 84 24 2c 02 00 00 movl $0x80484c4,0x22c(%esp)
8048630: c4 84 04 08
8048634: eb 0f jmp 8048645 <main+0xce>
8048636: c7 84 24 2c 02 00 00 movl $0x804855f,0x22c(%esp)
804863d: 5f 85 04 08
8048641: eb 02 jmp 8048645 <main+0xce>
8048643: eb fe jmp 8048643 <main+0xcc>
8048645: 8d 44 24 24 lea 0x24(%esp),%eax
8048649: 83 c0 01 add $0x1,%eax
804864c: 89 04 24 mov %eax,(%esp)
804864f: 8b 84 24 2c 02 00 00 mov 0x22c(%esp),%eax
8048656: ff d0 call *%eax
8048658: 89 84 24 24 02 00 00 mov %eax,0x224(%esp)
804865f: 83 bc 24 24 02 00 00 cmpl $0x0,0x224(%esp)
8048666: 00
8048667: 74 1a je 8048683 <main+0x10c>
8048669: b8 af 87 04 08 mov $0x80487af,%eax
804866e: 8d 54 24 24 lea 0x24(%esp),%edx
8048672: 83 c2 01 add $0x1,%edx
8048675: 89 54 24 04 mov %edx,0x4(%esp)
8048679: 89 04 24 mov %eax,(%esp)
804867c: e8 2f fd ff ff call 80483b0 <printf@plt>
8048681: eb 0c jmp 804868f <main+0x118>
8048683: c7 04 24 be 87 04 08 movl $0x80487be,(%esp)
804868a: e8 41 fd ff ff call 80483d0 <puts@plt>
804868f: 8b 84 24 24 02 00 00 mov 0x224(%esp),%eax
8048696: 89 04 24 mov %eax,(%esp)
8048699: e8 52 fd ff ff call 80483f0 <exit@plt>
804869e: 90 nop
804869f: 90 nop
from 8048577 to 8048645 is similar with minor changes in switch and local
variables.
allocated stack = 0x230 (560 = 36 padding, buffer 512, var1 4,var2 4,function pointer 4)
36 (var1, var2 and function pointer are 4 bytes they are aligned to 16 bytes
so 12*3 = 36 bytes).
buf[512] 0x24(%esp)
var1
var2 0x224(%esp) NOTE: stack is gowing in reverse so this value is ret.
function pointer(fp)
(gdb) x 0x80484c4
0x80484c4 <checkkey>: "U\211\345WV\203\354\020\213E\b\211E\364\353\024\213E\364\017\266"
switch(buf[0])
case 0x41
fp = &foo;
break;
case 0x42
fp = &checkkey;
break;
case 0x43
fp = &foobar;
break;
default:
loop here
8048649: 83 c0 01 add $0x1,%eax
804864c: 89 04 24 mov %eax,(%esp)
var2 = fp(buf+1);
exit(ret);
puts at 804868a
(gdb) x/s 0x80487be
0x80487be: "[-] Nope."
[chetan@chetan reverse]$ ./reverse-ex
Are you feeling lucky today? c
^C
[chetan@chetan reverse]$ ./reverse-ex
Are you feeling lucky today? A
foo
[-] Nope.
[chetan@chetan reverse]$ ./reverse-ex
Are you feeling lucky today? B
[-] Nope.
[chetan@chetan reverse]$ ./reverse-ex
Are you feeling lucky today? C
foo
[-] Nope.
So input with B calls checkkey();
080484c4 <checkkey>:
80484c4: 55 push %ebp
80484c5: 89 e5 mov %esp,%ebp
80484c7: 57 push %edi
80484c8: 56 push %esi
80484c9: 83 ec 10 sub $0x10,%esp
80484cc: 8b 45 08 mov 0x8(%ebp),%eax
80484cf: 89 45 f4 mov %eax,-0xc(%ebp)
80484d2: eb 14 jmp 80484e8 <checkkey+0x24>
char *p = buf[1];
80484d4: 8b 45 f4 mov -0xc(%ebp),%eax
80484d7: 0f b6 00 movzbl (%eax),%eax
80484da: 89 c2 mov %eax,%edx
80484dc: 83 f2 2a xor $0x2a,%edx
80484df: 8b 45 f4 mov -0xc(%ebp),%eax
80484e2: 88 10 mov %dl,(%eax)
*p = *p^42
80484e4: 83 45 f4 01 addl $0x1,-0xc(%ebp)
p++;
80484e8: 8b 45 f4 mov -0xc(%ebp),%eax
80484eb: 0f b6 00 movzbl (%eax),%eax
80484ee: 84 c0 test %al,%al
*p check in for loop
80484f0: 75 e2 jne 80484d4 <checkkey+0x10>
for (;*p ; p++)
*p = *p ^ 0x2a; (0x2a = 42)
80484f2: 8b 45 08 mov 0x8(%ebp),%eax
80484f5: 89 c2 mov %eax,%edx
80484f7: b8 70 87 04 08 mov $0x8048770,%eax
(gdb) x/s 0x8048770
0x8048770: "KFFSE_XHKYOKXOHOFEDM^E_Y"
80484fc: b9 19 00 00 00 mov $0x19,%ecx
8048501: 89 d6 mov %edx,%esi
8048503: 89 c7 mov %eax,%edi
8048505: f3 a6 repz cmpsb %es:(%edi),%ds:(%esi)
8048507: 0f 97 c2 seta %dl
804850a: 0f 92 c0 setb %al
804850d: 89 d1 mov %edx,%ecx
804850f: 28 c1 sub %al,%cl
8048511: 89 c8 mov %ecx,%eax
8048513: 0f be c0 movsbl %al,%eax
8048516: 85 c0 test %eax,%eax
strcmp()
8048518: 75 07 jne 8048521 <checkkey+0x5d>
804851a: b8 01 00 00 00 mov $0x1,%eax
return 1 if match
804851f: eb 05 jmp 8048526 <checkkey+0x62>
8048521: b8 00 00 00 00 mov $0x0,%eax
8048526: 83 c4 10 add $0x10,%esp
8048529: 5e pop %esi
804852a: 5f pop %edi
804852b: 5d pop %ebp
804852c: c3 ret
(Given input) ^ 42 = ("KFFSE_XHKYOKXOHOFEDM^E_Y") is the check in code
(Given input) ^ 42 ^ 42 = ("KFFSE_XHKYOKXOHOFEDM^E_Y") ^ 42
(Given input) = ("KFFSE_XHKYOKXOHOFEDM^E_Y") ^ 42
So to get the Given input
#include<stdio.h>
#include<string.h>
#define KEY "KFFSE_XHKYOKXOHOFEDM^E_Y"
main()
{
char *p = KEY;
for (; *p; p++) {
printf("%c",(*p) ^ 42);
}
printf("\n");
}
gcc above code
./a.out
allyourbasearebelongtous
[chetan@chetan reverse]$ ./reverse-ex
Are you feeling lucky today? Ballyourbasearebelongtous
[-] Nope.
Bug in the code
gcc -g reverse-ex.c
gdb ./a.out
(gdb) b checkkey
Breakpoint 1 at 0x804850a: file reverse-ex.c, line 13.
(gdb) r
Breakpoint 1, checkkey (
key=0xbffff0b5 "allyourbasearebelongtous\n\377\277\265\306>")
at reverse-ex.c:13
13 char *p = key;
There are junk characters read by read() call.
Fixing the read code (man read tells this)
from
(void) read(0, buf, sizeof(buf)-1);
n = strlen(buf);
to
n = read(0, buf, sizeof(buf)-1);
//n = strlen(buf);
checking through gdb
Breakpoint 1, checkkey (key=0xbffff0b5 "allyourbasearebelongtous")
at ./reverse-ex.c:13
13 char *p = key;
[chetan@chetan reverse]$ ./a.out
Are you feeling lucky today? Ballyourbasearebelongtous
[+] WooT!: KFFSE_XHKYOKXOHOFEDM^E_Y
So the INPUT is Ballyourbasearebelongtous
code
---
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#define KEY "KFFSE_XHKYOKXOHOFEDM^E_Y"
int
checkkey(char *key)
{
char *p = key;
for (; *p; p++)
*p ^= 42;
if (!strcmp(key,KEY))
return 1;
return 0;
}
int
foo(char *data)
{
printf("foo\n");
return 0;
}
int
bar(char *data)
{
printf("bar\n");
return 0;
}
int
foobar(char *data)
{
foo(data);
return 0;
}
int
main(void)
{
char buf[512];
int n, ret;
int (*f)(char *);
//memset(buf, 0, sizeof(buf));
printf("Are you feeling lucky today? ");
fflush(stdout);
n = read(0, buf, sizeof(buf)-1);
//n = strlen(buf);
if (buf[n-1] == '\n')
buf[n-1] = 0;
switch (buf[0]) {
case 0x41:
f = &foo;
break;
case 0x42:
f = &checkkey;
break;
case 0x43:
f = &foobar;
break;
default:
loop:
goto *&&loop;
}
ret = f(buf+1);
if (ret)
printf("[+] WooT!: %s\n", buf+1);
else
printf("[-] Nope.\n");
exit(ret);
}
====== Example 1 =======
objdump
-------
In 1_objdump file search for main
08048394 <main>:
8048394: 55 push %ebp
8048395: 89 e5 mov %esp,%ebp
8048397: b8 7b 00 00 00 mov $0x7b,%eax
804839c: 5d pop %ebp
804839d: c3 ret
804839e: 90 nop
804839f: 90 nop
study
-----
8048394: 55 push %ebp
save previous frame pointer on stack
8048395: 89 e5 mov %esp,%ebp
Intialize the frame pointer to current stack pointer sp->bp.
8048397: b8 7b 00 00 00 mov $0x7b,%eax
moving 0x7b value to eax register. 0x7b in decimal is
gdb ./a.out (using gdb for converting 123 to hex).)
(gdb) p/x 123
$1 = 0x7b
As you can see eax register is used to return values to the caller.
pseudocode
----------
main
return 123;
code
----
#include <stdio.h>
int main(int argc, char **argv)
{
return 123;
}
build
-----
gcc 1.c
objdump -d ./a.out > 1_objdump
====== Example 2 =======
080483c4 <main>:
80483c4: 55 push %ebp
80483c5: 89 e5 mov %esp,%ebp
80483c7: 83 e4 f0 and $0xfffffff0,%esp
80483ca: 83 ec 10 sub $0x10,%esp
80483cd: b8 b4 84 04 08 mov $0x80484b4,%eax
80483d2: 89 04 24 mov %eax,(%esp)
80483d5: e8 1a ff ff ff call 80482f4 <printf@plt>
80483da: b8 7b 00 00 00 mov $0x7b,%eax
80483df: c9 leave
80483e0: c3 ret
Our 0x7b is still there, there is a call to function printf. so our string
"Hello World" should pushed on stack, so eax which looks like a pointer value
is pushed onto stack before calling printf. But objdump file doesn't contain
the address contents [0x80484b4].
objdump -D ./a.out > 1_objdump
80484b4: 48 dec %eax
80484b5: 65 gs
80484b6: 6c insb (%dx),%es:(%edi)
80484b7: 6c insb (%dx),%es:(%edi)
80484b8: 6f outsl %ds:(%esi),(%dx)
80484b9: 20 57 6f and %dl,0x6f(%edi)
80484bc: 72 6c jb 804852a <__dso_handle+0x7a>
80484be: 64 fs
b ./a.out
(gdb) x/s 0x80484b4
0x80484b4 <__dso_handle+4>: "Hello World"
(gdb) x/16xb 0x80484b4
0x80484b4 <__dso_handle+4>: 0x48 0x65 0x6c 0x6c 0x6f 0x20 0x57 0x6f
0x80484bc <__dso_handle+12>: 0x72 0x6c 0x64 0x00 0x01 0x1b 0x03 0x3b
(gdb) x/16cb 0x80484b4
0x80484b4 <__dso_handle+4>: 72 'H' 101 'e' 108 'l' 108 'l' 111 'o' 32 ' ' 87 'W' 111 'o'
0x80484bc <__dso_handle+12>: 114 'r' 108 'l' 100 'd' 0 '\000' 1 '\001' 27 '\033' 3 '\003' 59 ';'
Ok, we have our "Hello world" pointer in stack before calling printf.
80483c4: 55 push %ebp
80483c5: 89 e5 mov %esp,%ebp
usual prologue
80483c7: 83 e4 f0 and $0xfffffff0,%esp
Aligning the stack to 16 bytes.
80483ca: 83 ec 10 sub $0x10,%esp
Allocating 16 bytes, only 4 bytes are needed to put arg to printf, adhering to
alignment of 16 bytes.
80483cd: b8 b4 84 04 08 mov $0x80484b4,%eax
80483d2: 89 04 24 mov %eax,(%esp)
"Hello world" pointer is pushed to eax to contents on allocated stack.
80483d5: e8 1a ff ff ff call 80482f4 <printf@plt>
80483da: b8 7b 00 00 00 mov $0x7b,%eax
80483df: c9 leave
80483e0: c3 ret
pseudocode
----------
main
printf "Hello World";
return 123;
code
----
#include <stdio.h>
int main(int argc, char **argv)
{
printf("Hello World");
return 123;
}
build
-----
gcc 1.c
objdump -d ./a.out > 1_objdump
====== Example 3 =======
08048474 <main>:
8048474: 55 push %ebp
8048475: 89 e5 mov %esp,%ebp
8048477: 83 e4 f0 and $0xfffffff0,%esp
804847a: 81 ec 20 02 00 00 sub $0x220,%esp
8048480: b8 c4 85 04 08 mov $0x80485c4,%eax
8048485: 89 04 24 mov %eax,(%esp)
8048488: e8 1b ff ff ff call 80483a8 <printf@plt>
804848d: a1 a0 97 04 08 mov 0x80497a0,%eax
8048492: 89 04 24 mov %eax,(%esp)
8048495: e8 ee fe ff ff call 8048388 <fflush@plt>
804849a: c7 44 24 08 ff 01 00 movl $0x1ff,0x8(%esp)
80484a1: 00
80484a2: 8d 44 24 14 lea 0x14(%esp),%eax
80484a6: 89 44 24 04 mov %eax,0x4(%esp)
80484aa: c7 04 24 00 00 00 00 movl $0x0,(%esp)
80484b1: e8 c2 fe ff ff call 8048378 <read@plt>
80484b6: 8d 44 24 14 lea 0x14(%esp),%eax
80484ba: 89 04 24 mov %eax,(%esp)
80484bd: e8 d6 fe ff ff call 8048398 <strlen@plt>
80484c2: 89 84 24 14 02 00 00 mov %eax,0x214(%esp)
80484c9: 8b 84 24 14 02 00 00 mov 0x214(%esp),%eax
80484d0: 83 e8 01 sub $0x1,%eax
80484d3: 0f b6 44 04 14 movzbl 0x14(%esp,%eax,1),%eax
80484d8: 3c 0a cmp $0xa,%al
80484da: 75 0f jne 80484eb <main+0x77>
80484dc: 8b 84 24 14 02 00 00 mov 0x214(%esp),%eax
80484e3: 83 e8 01 sub $0x1,%eax
80484e6: c6 44 04 14 00 movb $0x0,0x14(%esp,%eax,1)
80484eb: b8 7b 00 00 00 mov $0x7b,%eax
80484f0: c9 leave
80484f1: c3 ret
study
-----
8048474: 55 push %ebp
8048475: 89 e5 mov %esp,%ebp
8048477: 83 e4 f0 and $0xfffffff0,%esp
usual
804847a: 81 ec 20 02 00 00 sub $0x220,%espa
(gdb) p 0x220
$1 = 544
Allocating 544 bytes on stack
8048480: b8 c4 85 04 08 mov $0x80485c4,%eax
8048485: 89 04 24 mov %eax,(%esp)
8048488: e8 1b ff ff ff call 80483a8 <printf@plt>
objdump -D ./a.out > 1_objdump
shows the contents of 0x80485c4.
(gdb) x/s 0x80485c4
0x80485c4 <__dso_handle+4>: "Are you feeling lucky today? "
printf with one arg "Are you feeling lucky today? ".
804848d: a1 a0 97 04 08 mov 0x80497a0,%eax
8048492: 89 04 24 mov %eax,(%esp)
8048495: e8 ee fe ff ff call 8048388 <fflush@plt>
man fflush
(gdb) x/s 0x80497a0
0x80497a0 <stdout@@GLIBC_2.0>: ""
(gdb) p/x *0x80497a0
$6 = 0x0
so fflush is flusihing all open output streams. I think fflush(NULL).
804849a: c7 44 24 08 ff 01 00 movl $0x1ff,0x8(%esp)
80484a1: 00
80484a2: 8d 44 24 14 lea 0x14(%esp),%eax
80484a6: 89 44 24 04 mov %eax,0x4(%esp)
80484aa: c7 04 24 00 00 00 00 movl $0x0,(%esp)
80484b1: e8 c2 fe ff ff call 8048378 <read@plt>
man 2 read
ssize_t read(int fd, void *buf, size_t count);
stack is 0x1ff (511), something in stack which is at 20 (0x14) bytes , 0
so args to read are fd = 0, buf, 511.
main() stack allocated is 544 bytes of which
...
something like buf of size 524 ...(there could be other local variables,
read call is only restricted to overwrite 511)
20
0
pointer to buf
511
...
80484b6: 8d 44 24 14 lea 0x14(%esp),%eax
80484ba: 89 04 24 mov %eax,(%esp)
80484bd: e8 d6 fe ff ff call 8048398 <strlen@plt>
80484c2: 89 84 24 14 02 00 00 mov %eax,0x214(%esp)
size_t strlen(const char *s);
so strlen(buf);
(gdb) p 0x214
$8 = 532
local variables of main are
(544 = 8,4 (var1),512 (buf),20(alignment, padding (4)))
main
char buf[512]
int var1
char unknown[8]
printf("Are you feeling lucky today? ");
fflush(NULL);
read(0, buf, 511);
var1 = strlen(buf);
80484d0: 83 e8 01 sub $0x1,%eax
512 - 1 = 511
80484d3: 0f b6 44 04 14 movzbl 0x14(%esp,%eax,1),%eax
displacement(%base, %index, scale) = displacement+%base+%index*scale.
since scale is 1 it is a char array.
buf[511]
80484d8: 3c 0a cmp $0xa,%al
(gdb) p/c 0xa
$10 = 10 '\n'
if (buf[511 == '\n')
80484da: 75 0f jne 80484eb <main+0x77>
80484dc: 8b 84 24 14 02 00 00 mov 0x214(%esp),%eax
80484e3: 83 e8 01 sub $0x1,%eax
80484e6: c6 44 04 14 00 movb $0x0,0x14(%esp,%eax,1)
buf[511] = 0;
80484eb: b8 7b 00 00 00 mov $0x7b,%eax
80484f0: c9 leave
80484f1: c3 ret
pseudo code
main
char buf[512]
int var1
char unknown[8]
printf("Are you feeling lucky today? ");
fflush(NULL);
read(0, buf, 511);
var1 = strlen(buf);
if (buf[511 == '\n')
buf[511] = 0;
return 123
code
----
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
char buf[512];
int n,ret;
int (*f)(char *);
printf("Are you feeling lucky today? ");
fflush(stdout);
(void)read(0, buf, sizeof(buf)-1);
n = strlen(buf);
if (buf[n-1] == '\n')
buf[n-1] = 0;
return 123;
}
====== Example 4 =======
080484ee <main>:
80484ee: 55 push %ebp
80484ef: 89 e5 mov %esp,%ebp
80484f1: 83 e4 f0 and $0xfffffff0,%esp
80484f4: 81 ec 20 02 00 00 sub $0x220,%esp
80484fa: b8 7c 86 04 08 mov $0x804867c,%eax
80484ff: 89 04 24 mov %eax,(%esp)
8048502: e8 c1 fe ff ff call 80483c8 <printf@plt>
8048507: a1 60 98 04 08 mov 0x8049860,%eax
804850c: 89 04 24 mov %eax,(%esp)
804850f: e8 94 fe ff ff call 80483a8 <fflush@plt>
8048514: c7 44 24 08 ff 01 00 movl $0x1ff,0x8(%esp)
804851b: 00
804851c: 8d 44 24 14 lea 0x14(%esp),%eax
8048520: 89 44 24 04 mov %eax,0x4(%esp)
8048524: c7 04 24 00 00 00 00 movl $0x0,(%esp)
804852b: e8 68 fe ff ff call 8048398 <read@plt>
8048530: 8d 44 24 14 lea 0x14(%esp),%eax
8048534: 89 04 24 mov %eax,(%esp)
8048537: e8 7c fe ff ff call 80483b8 <strlen@plt>
804853c: 89 84 24 14 02 00 00 mov %eax,0x214(%esp)
8048543: 8b 84 24 14 02 00 00 mov 0x214(%esp),%eax
804854a: 83 e8 01 sub $0x1,%eax
804854d: 0f b6 44 04 14 movzbl 0x14(%esp,%eax,1),%eax
8048552: 3c 0a cmp $0xa,%al
8048554: 75 0f jne 8048565 <main+0x77>
8048556: 8b 84 24 14 02 00 00 mov 0x214(%esp),%eax
804855d: 83 e8 01 sub $0x1,%eax
8048560: c6 44 04 14 00 movb $0x0,0x14(%esp,%eax,1)
8048565: 0f b6 44 24 14 movzbl 0x14(%esp),%eax
804856a: 0f be c0 movsbl %al,%eax
804856d: 83 f8 42 cmp $0x42,%eax
8048570: 74 17 je 8048589 <main+0x9b>
8048572: 83 f8 43 cmp $0x43,%eax
8048575: 74 21 je 8048598 <main+0xaa>
8048577: 83 f8 41 cmp $0x41,%eax
804857a: 75 29 jne 80485a5 <main+0xb7>
804857c: c7 84 24 1c 02 00 00 movl $0x80484a4,0x21c(%esp)
8048583: a4 84 04 08
8048587: eb 1e jmp 80485a7 <main+0xb9>
8048589: b8 9a 86 04 08 mov $0x804869a,%eax
804858e: 89 04 24 mov %eax,(%esp)
8048591: e8 32 fe ff ff call 80483c8 <printf@plt>
8048596: eb 0f jmp 80485a7 <main+0xb9>
8048598: c7 84 24 1c 02 00 00 movl $0x80484d6,0x21c(%esp)
804859f: d6 84 04 08
80485a3: eb 02 jmp 80485a7 <main+0xb9>
80485a5: eb fe jmp 80485a5 <main+0xb7>
80485a7: b8 7b 00 00 00 mov $0x7b,%eax
80485ac: c9 leave
80485ad: c3 ret
rom 80484ee to 8048565 is
main
char buf[512]
int var1
char unknown[8]
printf("Are you feeling lucky today? ");
fflush(NULL);
read(0, buf, 511);
var1 = strlen(buf);
if (buf[511 == '\n')
buf[511] = 0;
8048565: 0f b6 44 24 14 movzbl 0x14(%esp),%eax
804856a: 0f be c0 movsbl %al,%eax
804856d: 83 f8 42 cmp $0x42,%eax
8048570: 74 17 je 8048589 <main+0x9b>
if (buf[0] == 0x42)
(gdb) x/s 0x804869a
0x804869a <__dso_handle+42>: "Hello"
printf("Hello")
8048572: 83 f8 43 cmp $0x43,%eax
8048575: 74 21 je 8048598 <main+0xaa>
if (buf[0] == 0x43)
(gdb) x 0x80484d6
0x80484d6 <foobar>: 0x83e58955
moving address of foobar to a local variable (function pointer).
8048577: 83 f8 41 cmp $0x41,%eax
804857a: 75 29 jne 80485a5 <main+0xb7>
804857c: c7 84 24 1c 02 00 00 movl $0x80484a4,0x21c(%esp)
8048583: a4 84 04 08
8048587: eb 1e jmp 80485a7 <main+0xb9>
if (buf[0] == 0x41)
(gdb) x 0x80484a4
0x80484a4 <foo>: 0x83e58955
moving address of foo to a local variable (function pointer).
8048589: b8 9a 86 04 08 mov $0x804869a,%eax
804858e: 89 04 24 mov %eax,(%esp)
8048591: e8 32 fe ff ff call 80483c8 <printf@plt>
// done with printf("Hello");
8048596: eb 0f jmp 80485a7 <main+0xb9>
8048598: c7 84 24 1c 02 00 00 movl $0x80484d6,0x21c(%esp)
804859f: d6 84 04 08
80485a3: eb 02 jmp 80485a7 <main+0xb9>
80485a5: eb fe jmp 80485a5 <main+0xb7>
Loo.....oop
switch (buf[0]) {
case 0x41:
var2 = &foo;
break;
case 0x42:
printf("Hello");
break;
case 0x43:
var2 = &foobar;
break;
default:
loop here.
}
80485a7: b8 7b 00 00 00 mov $0x7b,%eax
80485ac: c9 leave
80485ad: c3 ret
return 123;
====== Example 5 =======
08048577 <main>:
8048577: 55 push %ebp
8048578: 89 e5 mov %esp,%ebp
804857a: 57 push %edi
804857b: 83 e4 f0 and $0xfffffff0,%esp
804857e: 81 ec 30 02 00 00 sub $0x230,%esp
8048584: b8 91 87 04 08 mov $0x8048791,%eax
8048589: 89 04 24 mov %eax,(%esp)
804858c: e8 1f fe ff ff call 80483b0 <printf@plt>
8048591: a1 40 a0 04 08 mov 0x804a040,%eax
8048596: 89 04 24 mov %eax,(%esp)
8048599: e8 22 fe ff ff call 80483c0 <fflush@plt>
804859e: c7 44 24 08 ff 01 00 movl $0x1ff,0x8(%esp)
80485a5: 00
80485a6: 8d 44 24 24 lea 0x24(%esp),%eax
80485aa: 89 44 24 04 mov %eax,0x4(%esp)
80485ae: c7 04 24 00 00 00 00 movl $0x0,(%esp)
80485b5: e8 e6 fd ff ff call 80483a0 <read@plt>
80485ba: 8d 44 24 24 lea 0x24(%esp),%eax
80485be: c7 44 24 1c ff ff ff movl $0xffffffff,0x1c(%esp)
80485c5: ff
80485c6: 89 c2 mov %eax,%edx
80485c8: b8 00 00 00 00 mov $0x0,%eax
80485cd: 8b 4c 24 1c mov 0x1c(%esp),%ecx
80485d1: 89 d7 mov %edx,%edi
80485d3: f2 ae repnz scas %es:(%edi),%al
80485d5: 89 c8 mov %ecx,%eax
80485d7: f7 d0 not %eax
80485d9: 83 e8 01 sub $0x1,%eax
80485dc: 89 84 24 28 02 00 00 mov %eax,0x228(%esp)
80485e3: 8b 84 24 28 02 00 00 mov 0x228(%esp),%eax
80485ea: 83 e8 01 sub $0x1,%eax
80485ed: 0f b6 44 04 24 movzbl 0x24(%esp,%eax,1),%eax
80485f2: 3c 0a cmp $0xa,%al
80485f4: 75 0f jne 8048605 <main+0x8e>
80485f6: 8b 84 24 28 02 00 00 mov 0x228(%esp),%eax
80485fd: 83 e8 01 sub $0x1,%eax
8048600: c6 44 04 24 00 movb $0x0,0x24(%esp,%eax,1)
8048605: 0f b6 44 24 24 movzbl 0x24(%esp),%eax
804860a: 0f be c0 movsbl %al,%eax
804860d: 83 f8 42 cmp $0x42,%eax
8048610: 74 17 je 8048629 <main+0xb2>
8048612: 83 f8 43 cmp $0x43,%eax
8048615: 74 1f je 8048636 <main+0xbf>
8048617: 83 f8 41 cmp $0x41,%eax
804861a: 75 27 jne 8048643 <main+0xcc>
804861c: c7 84 24 2c 02 00 00 movl $0x804852d,0x22c(%esp)
8048623: 2d 85 04 08
8048627: eb 1c jmp 8048645 <main+0xce>
8048629: c7 84 24 2c 02 00 00 movl $0x80484c4,0x22c(%esp)
8048630: c4 84 04 08
8048634: eb 0f jmp 8048645 <main+0xce>
8048636: c7 84 24 2c 02 00 00 movl $0x804855f,0x22c(%esp)
804863d: 5f 85 04 08
8048641: eb 02 jmp 8048645 <main+0xce>
8048643: eb fe jmp 8048643 <main+0xcc>
8048645: 8d 44 24 24 lea 0x24(%esp),%eax
8048649: 83 c0 01 add $0x1,%eax
804864c: 89 04 24 mov %eax,(%esp)
804864f: 8b 84 24 2c 02 00 00 mov 0x22c(%esp),%eax
8048656: ff d0 call *%eax
8048658: 89 84 24 24 02 00 00 mov %eax,0x224(%esp)
804865f: 83 bc 24 24 02 00 00 cmpl $0x0,0x224(%esp)
8048666: 00
8048667: 74 1a je 8048683 <main+0x10c>
8048669: b8 af 87 04 08 mov $0x80487af,%eax
804866e: 8d 54 24 24 lea 0x24(%esp),%edx
8048672: 83 c2 01 add $0x1,%edx
8048675: 89 54 24 04 mov %edx,0x4(%esp)
8048679: 89 04 24 mov %eax,(%esp)
804867c: e8 2f fd ff ff call 80483b0 <printf@plt>
8048681: eb 0c jmp 804868f <main+0x118>
8048683: c7 04 24 be 87 04 08 movl $0x80487be,(%esp)
804868a: e8 41 fd ff ff call 80483d0 <puts@plt>
804868f: 8b 84 24 24 02 00 00 mov 0x224(%esp),%eax
8048696: 89 04 24 mov %eax,(%esp)
8048699: e8 52 fd ff ff call 80483f0 <exit@plt>
804869e: 90 nop
804869f: 90 nop
from 8048577 to 8048645 is similar with minor changes in switch and local
variables.
allocated stack = 0x230 (560 = 36 padding, buffer 512, var1 4,var2 4,function pointer 4)
36 (var1, var2 and function pointer are 4 bytes they are aligned to 16 bytes
so 12*3 = 36 bytes).
buf[512] 0x24(%esp)
var1
var2 0x224(%esp) NOTE: stack is gowing in reverse so this value is ret.
function pointer(fp)
(gdb) x 0x80484c4
0x80484c4 <checkkey>: "U\211\345WV\203\354\020\213E\b\211E\364\353\024\213E\364\017\266"
switch(buf[0])
case 0x41
fp = &foo;
break;
case 0x42
fp = &checkkey;
break;
case 0x43
fp = &foobar;
break;
default:
loop here
8048649: 83 c0 01 add $0x1,%eax
804864c: 89 04 24 mov %eax,(%esp)
var2 = fp(buf+1);
exit(ret);
puts at 804868a
(gdb) x/s 0x80487be
0x80487be: "[-] Nope."
[chetan@chetan reverse]$ ./reverse-ex
Are you feeling lucky today? c
^C
[chetan@chetan reverse]$ ./reverse-ex
Are you feeling lucky today? A
foo
[-] Nope.
[chetan@chetan reverse]$ ./reverse-ex
Are you feeling lucky today? B
[-] Nope.
[chetan@chetan reverse]$ ./reverse-ex
Are you feeling lucky today? C
foo
[-] Nope.
So input with B calls checkkey();
080484c4 <checkkey>:
80484c4: 55 push %ebp
80484c5: 89 e5 mov %esp,%ebp
80484c7: 57 push %edi
80484c8: 56 push %esi
80484c9: 83 ec 10 sub $0x10,%esp
80484cc: 8b 45 08 mov 0x8(%ebp),%eax
80484cf: 89 45 f4 mov %eax,-0xc(%ebp)
80484d2: eb 14 jmp 80484e8 <checkkey+0x24>
char *p = buf[1];
80484d4: 8b 45 f4 mov -0xc(%ebp),%eax
80484d7: 0f b6 00 movzbl (%eax),%eax
80484da: 89 c2 mov %eax,%edx
80484dc: 83 f2 2a xor $0x2a,%edx
80484df: 8b 45 f4 mov -0xc(%ebp),%eax
80484e2: 88 10 mov %dl,(%eax)
*p = *p^42
80484e4: 83 45 f4 01 addl $0x1,-0xc(%ebp)
p++;
80484e8: 8b 45 f4 mov -0xc(%ebp),%eax
80484eb: 0f b6 00 movzbl (%eax),%eax
80484ee: 84 c0 test %al,%al
*p check in for loop
80484f0: 75 e2 jne 80484d4 <checkkey+0x10>
for (;*p ; p++)
*p = *p ^ 0x2a; (0x2a = 42)
80484f2: 8b 45 08 mov 0x8(%ebp),%eax
80484f5: 89 c2 mov %eax,%edx
80484f7: b8 70 87 04 08 mov $0x8048770,%eax
(gdb) x/s 0x8048770
0x8048770: "KFFSE_XHKYOKXOHOFEDM^E_Y"
80484fc: b9 19 00 00 00 mov $0x19,%ecx
8048501: 89 d6 mov %edx,%esi
8048503: 89 c7 mov %eax,%edi
8048505: f3 a6 repz cmpsb %es:(%edi),%ds:(%esi)
8048507: 0f 97 c2 seta %dl
804850a: 0f 92 c0 setb %al
804850d: 89 d1 mov %edx,%ecx
804850f: 28 c1 sub %al,%cl
8048511: 89 c8 mov %ecx,%eax
8048513: 0f be c0 movsbl %al,%eax
8048516: 85 c0 test %eax,%eax
strcmp()
8048518: 75 07 jne 8048521 <checkkey+0x5d>
804851a: b8 01 00 00 00 mov $0x1,%eax
return 1 if match
804851f: eb 05 jmp 8048526 <checkkey+0x62>
8048521: b8 00 00 00 00 mov $0x0,%eax
8048526: 83 c4 10 add $0x10,%esp
8048529: 5e pop %esi
804852a: 5f pop %edi
804852b: 5d pop %ebp
804852c: c3 ret
(Given input) ^ 42 = ("KFFSE_XHKYOKXOHOFEDM^E_Y") is the check in code
(Given input) ^ 42 ^ 42 = ("KFFSE_XHKYOKXOHOFEDM^E_Y") ^ 42
(Given input) = ("KFFSE_XHKYOKXOHOFEDM^E_Y") ^ 42
So to get the Given input
#include<stdio.h>
#include<string.h>
#define KEY "KFFSE_XHKYOKXOHOFEDM^E_Y"
main()
{
char *p = KEY;
for (; *p; p++) {
printf("%c",(*p) ^ 42);
}
printf("\n");
}
gcc above code
./a.out
allyourbasearebelongtous
[chetan@chetan reverse]$ ./reverse-ex
Are you feeling lucky today? Ballyourbasearebelongtous
[-] Nope.
Bug in the code
gcc -g reverse-ex.c
gdb ./a.out
(gdb) b checkkey
Breakpoint 1 at 0x804850a: file reverse-ex.c, line 13.
(gdb) r
Breakpoint 1, checkkey (
key=0xbffff0b5 "allyourbasearebelongtous\n\377\277\265\306>")
at reverse-ex.c:13
13 char *p = key;
There are junk characters read by read() call.
Fixing the read code (man read tells this)
from
(void) read(0, buf, sizeof(buf)-1);
n = strlen(buf);
to
n = read(0, buf, sizeof(buf)-1);
//n = strlen(buf);
checking through gdb
Breakpoint 1, checkkey (key=0xbffff0b5 "allyourbasearebelongtous")
at ./reverse-ex.c:13
13 char *p = key;
[chetan@chetan reverse]$ ./a.out
Are you feeling lucky today? Ballyourbasearebelongtous
[+] WooT!: KFFSE_XHKYOKXOHOFEDM^E_Y
So the INPUT is Ballyourbasearebelongtous
code
---
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#define KEY "KFFSE_XHKYOKXOHOFEDM^E_Y"
int
checkkey(char *key)
{
char *p = key;
for (; *p; p++)
*p ^= 42;
if (!strcmp(key,KEY))
return 1;
return 0;
}
int
foo(char *data)
{
printf("foo\n");
return 0;
}
int
bar(char *data)
{
printf("bar\n");
return 0;
}
int
foobar(char *data)
{
foo(data);
return 0;
}
int
main(void)
{
char buf[512];
int n, ret;
int (*f)(char *);
//memset(buf, 0, sizeof(buf));
printf("Are you feeling lucky today? ");
fflush(stdout);
n = read(0, buf, sizeof(buf)-1);
//n = strlen(buf);
if (buf[n-1] == '\n')
buf[n-1] = 0;
switch (buf[0]) {
case 0x41:
f = &foo;
break;
case 0x42:
f = &checkkey;
break;
case 0x43:
f = &foobar;
break;
default:
loop:
goto *&&loop;
}
ret = f(buf+1);
if (ret)
printf("[+] WooT!: %s\n", buf+1);
else
printf("[-] Nope.\n");
exit(ret);
}
No comments:
Post a Comment