Okay, so I decided to follow this binary exploitation course from RPI and do the challenges. It is interesting that it is run by students passionate about security and generally looks quite a promising introduction in binary exploitation, so you may want to check out the slides.
On to the challenges.
For crackme0x00a and crackme0x00b the slides pretty much give it away. I have decided to use radare2 so
$ r2 0xcrackme0x00a
> aa
> pdf @ main
...
| 0x0804851b 8d442413 lea eax, [esp + 0x13] ; 0x13
| 0x0804851f 89442404 mov dword [esp + 4], eax ; [0x4:4]=0x10101
| 0x08048523 c7042424a004. mov dword [esp], sym.pass.1685 ; [0x804a024:4]=0x64303067 ; "g00dJ0B!" @ 0x804a024
| 0x0804852a e891feffff call sym.imp.strcmp ; fcn.080483bc+0x4
| fcn.080483bc() ; sym.imp.strcmp
| 0x0804852f 85c0 test eax, eax
| ,=< 0x08048531 7521 jne 0x8048554
| | 0x08048533 c70424548604. mov dword [esp], str.Congrats_ ; [0x8048654:4]=0x676e6f43 ; "Congrats!" @ 0x8048654
| | 0x0804853a e8b1feffff call sym.imp.puts
So radare quite helpfully fetches the string contents of the password. Crackme is the same with a very small catch left as excersice for the reader.
For crackme0x01 we can use objdump
$ objdump -d crackme0x01 | less
...
8048418: 8d 45 fc lea -0x4(%ebp),%eax
804841b: 89 44 24 04 mov %eax,0x4(%esp)
804841f: c7 04 24 4c 85 04 08 movl $0x804854c,(%esp)
8048426: e8 e1 fe ff ff call 804830c <scanf@plt>
804842b: 81 7d fc 9a 14 00 00 cmpl $0x149a,-0x4(%ebp)
8048432: 74 0e je 8048442 <main+0x5e>
8048434: c7 04 24 4f 85 04 08 movl $0x804854f,(%esp)
804843b: e8 dc fe ff ff call 804831c <printf@plt>
8048440: eb 0c jmp 804844e <main+0x6a>
8048442: c7 04 24 62 85 04 08 movl $0x8048562,(%esp)
8048449: e8 ce fe ff ff call 804831c <printf@plt>
804844e: b8 00 00 00 00 mov $0x0,%eax
8048453: c9 leave
8048454: c3 ret
So we can clearly (?) see that it uses the value at -0x4(%ebp) as the second parameter to scanf at 804841b and then it checks the same memory address with 0x149a at line 804842b. If you have trouble understanding this, remember that the function parameters are passed from last to first on the stack and read the lecture slides, page 17.
Defeating crackme0x02 is just a tad trickier. We could use objdump for this but radare2 make our life a bit easier.
$ radare2 crackme0x02
> aa
> pdf @ main
| ; arg int arg_22_2 @ ebp+0x5a
| ; arg int arg_123 @ ebp+0x1ec
| ; var int local_1 @ ebp-0x4
| ; var int local_2 @ ebp-0x8
| ; var int local_3 @ ebp-0xc
.
.
.
| 0x08048418 8d45fc lea eax, [ebp-local_1]
| 0x0804841b 89442404 mov dword [esp + 4], eax ; [0x4:4]=0x10101
| 0x0804841f c704246c8504. mov dword [esp], 0x804856c ; [0x804856c:4]=0x50006425 ; "%d" @ 0x804856c
| 0x08048426 e8e1feffff call sym.imp.scanf
| sym.imp.scanf()
| 0x0804842b c745f85a0000. mov dword [ebp-local_2], 0x5a ; [0x5a:4]=0x81540000 ; 'Z'
| 0x08048432 c745f4ec0100. mov dword [ebp-local_3], 0x1ec ; [0x1ec:4]=0
| 0x08048439 8b55f4 mov edx, dword [ebp-local_3]
| 0x0804843c 8d45f8 lea eax, [ebp-local_2]
| 0x0804843f 0110 add dword [eax], edx
| 0x08048441 8b45f8 mov eax, dword [ebp-local_2]
| 0x08048444 0faf45f8 imul eax, dword [ebp-local_2]
| 0x08048448 8945f4 mov dword [ebp-local_3], eax
| 0x0804844b 8b45fc mov eax, dword [ebp-local_1]
| 0x0804844e 3b45f4 cmp eax, dword [ebp-local_3]
| ,=< 0x08048451 750e jne 0x8048461
| | 0x08048453 c704246f8504. mov dword [esp], str.Password_OK_:__n ; [0x804856f:4]=0x73736150 ; "Password OK :)." @ 0x804856f
| | 0x0804845a e8bdfeffff call sym.imp.printf
| | sym.imp.printf()
| ,==< 0x0804845f eb0c jmp 0x804846d
| || ; JMP XREF from 0x08048451 (sym.main)
| |`-> 0x08048461 c704247f8504. mov dword [esp], str.Invalid_Password__n ; [0x804857f:4]=0x61766e49 ; "Invalid Password!." @ 0x804857f
| | 0x08048468 e8affeffff call sym.imp.printf
| | sym.imp.printf()
| | ; JMP XREF from 0x0804845f (sym.main)
| `--> 0x0804846d b800000000 mov eax, 0
| 0x08048472 c9 leave
\ 0x08048473 c3 ret
As a general rule when you don't know how to proceed just break it down.
The scanf is responsible for saving our input in local_1. Every reference to local variables is made through the ebp register via an offset as stated in the beginning. Remember the stack layout from the previous link. After a bunch of instructions, the program compares our input with local_3. The instructions are quite simple. The program adds two values and then squares the result. If the result matches our input it prints "Password OK :)". Notice the reading difficulty of the operation compared to a high level programming language.
Until next time.