I have been working on a small crackme program that I came across
in a public CTF archive. Not a big deal, just a 4KB stripped ELF that
requires a password, which would either print "nope" or "yay". It took me three
nights and a lot of objdump -d. This is a short write up of
what I actually did, mostly so I don't forget.
I began with the obvious: ran it, entered the word "password",
saw that it failed to work, and checked out the strings output. There was a
strcmp reference but the comparison string wasn't sitting in
.rodata as I had expected, which was my first clue that
something was being constructed onto the stack.
Disassembling the main function showed a small loop. It
loaded a byte at a time from a buffer, XOR'd it against a constant, and
then compared the result to the user input character by character. So the
real password wasn't stored anywhere — it was being reconstructed at
runtime from 'A' ^ 0x1A, 'B' ^ 0x2B, ....
I wrote a small Python script to undo the XOR using the constants I read
out of gdb. The first attempt spit out gibberish because I'd
misread one of the offsets — a fun reminder that one wrong byte and
everything downstream is wrong. After fixing it, the password dropped out
clean. Typed it into the binary, got my "yay", and sat there grinning at
the terminal for way too long.
What I learned from this exercise: do not rely on the strings output, get used to reading the disassembly line by line, and make sure to check your offsets before scripting the solution. The next exercise that I plan to work on will be a bit more difficult, involving some anti-debugging techniques.