This is a write up for “EZ crackme” by R3tr0BS: https://crackmes.one/crackme/5fcfb87933c5d424269a1afc
This challenge came with two files: Readme.txt and run.exe
Readme.txt contained the following:
so this is my first crackme, you need to use the password or..... do it your way,
good luck,
R3tr0.
run.exe has a hash of 3bc592f4963add05a2d28bc469b5cd6ea00b973516ba1a1fccc10f1590f26152
% sha256sum run.exe
3bc592f4963add05a2d28bc469b5cd6ea00b973516ba1a1fccc10f1590f26152 run.exe
file shows that this is a 32 bit ELF with debug_info and debugging symbols:
% file run.exe
run.exe: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, with debug_info, not stripped
I used dwarfdump to get debug_info. This shows that this sample was likely compiled with NASM 2.15.05 and had a filename of code.asm, which is interesting but doesn’t help much.
% dwarfdump run.exe
.debug_info
COMPILE_UNIT<header overall offset = 0x00000000>:
< 0><0x0000000b> DW_TAG_compile_unit
DW_AT_low_pc 0x08049000
DW_AT_high_pc 0x08049045
DW_AT_stmt_list 0x00000000
DW_AT_name code.asm
DW_AT_producer NASM 2.15.05
DW_AT_language DW_LANG_Mips_Assembler
...Snip!...
Next, I used objdump to disassemble run.exe. The output shows a small, straightforward program:
% objdump -d run.exe
run.exe: file format elf32-i386
Disassembly of section .text:
08049000 <_start>:
8049000: 5b pop %ebx
8049001: 5b pop %ebx
8049002: 5b pop %ebx
8049003: a1 00 a0 04 08 mov 0x804a000,%eax
8049008: 3b 03 cmp (%ebx),%eax
804900a: 74 02 je 804900e <_start.goodjob>
804900c: eb 18 jmp 8049026 <_start.wrong>
0804900e <_start.goodjob>:
804900e: b8 04 00 00 00 mov $0x4,%eax
8049013: bb 01 00 00 00 mov $0x1,%ebx
8049018: b9 08 a0 04 08 mov $0x804a008,%ecx
804901d: ba 0e 00 00 00 mov $0xe,%edx
8049022: cd 80 int $0x80
8049024: eb 16 jmp 804903c <_start.end>
08049026 <_start.wrong>:
8049026: b8 04 00 00 00 mov $0x4,%eax
804902b: bb 01 00 00 00 mov $0x1,%ebx
8049030: b9 16 a0 04 08 mov $0x804a016,%ecx
8049035: ba 07 00 00 00 mov $0x7,%edx
804903a: cd 80 int $0x80
0804903c <_start.end>:
804903c: b8 01 00 00 00 mov $0x1,%eax
8049041: 31 db xor %ebx,%ebx
8049043: cd 80 int $0x80
It is helpful to know the calling conventions for system calls on Linux/x86. Generally speaking, you place the number of the system call you wish to call into the EAX register, arguments in their corresponding registers, and issue an int 80 instruction to execute the call.
This is a handy reference that explains syscalls much better: http://shell-storm.org/shellcode/files/syscalls.html
With knowledge of how syscalls work and the chart above, this assembler translates into pseudo code:
if (arg == *0x804a000) {
write(1, *0x804a008, 0xe);
} else {
write(1, *0x804a016, 0x7);
}
exit(0);
On Linux, fd 1 is stdout
% grep STDOUT /usr/include/unistd.h
#define STDOUT_FILENO 1 /* Standard output. */
So this code basically writes a 14 byte (0xe) message to stdout if an argument equals whatever is in 0x804a000, otherwise it prints a 7 byte (0x7) message. After printing the appropriate message, the program exits with a value of 0.
Using gdb, it is easy to resolve what strings these are stored in the memory addresses 0x804a008, and 0x804a016:
% gdb -q run.exe
Reading symbols from run.exe...
(gdb) x/s 0x804a008
0x804a008 <goodjobText>: "You Got This!\nWrong!\n"<error: Cannot access memory at address 0x804a01d>
(gdb) x/s 0x804a016
0x804a016 <nope>: "Wrong!\n"<error: Cannot access memory at address 0x804a01d>
After revising the pseudo code with these strings, it makes much more sense:
if (arg == *0x804a000) {
write(1, "You Got This!\n", 14);
} else {
write(1, "Wrong!\n", 7);
}
exit(0);
Now, let’s see what we need to set the argument to:
(gdb) x/s 0x804a000
0x804a000 <password>: "P455w0rdYou Got This!\nWrong!\n"<error: Cannot access memory at address 0x804a01d>
Looks like “P455w0rd”. Let’s try it out:
(gdb) set args P455w0rd
(gdb) run
Starting program: /home/daniel/Downloads/run.exe P455w0rd
You Got This!
[Inferior 1 (process 56490) exited normally]
(gdb) set args wrongpass
(gdb) run
Starting program: /home/daniel/Downloads/run.exe wrongpass
Wrong!
[Inferior 1 (process 56503) exited normally]