OK, enough of praising r2, lets start reversing this stuff. First, you have to know your enemy:
[0x00 avatao]$ rabin2 -I reverse4 pic false canary true nx true crypto false va true intrp /lib64/ld-linux-x86-64.so.2 bintype elf class ELF64 lang c arch x86 bits 64 machine AMD x86-64 architecture os linux subsys linux endian little stripped true static false linenum false lsyms false relocs false rpath NONE binsz 8620
r2 tip: rabin2 is one of the handy tools that comes with radare2. It can be used to extract information (imports, symbols, libraries, etc.) about binary executables. As always, check the help (rabin2 -h)!
So, its a dynamically linked, stripped, 64bit Linux executable - nothing fancy here. Let's try to run it:
[0x00 avatao]$ ./reverse4 ? Size of data: 2623 pamparam Wrong! [0x00 avatao]$ "\x01\x00\x00\x00" | ./reverse4 Size of data: 1
OK, so it reads a number as a size from the standard input first, than reads further, probably "size" bytes/characters, processes this input, and outputs either "Wrong!", nothing or something else, presumably our flag. But do not waste any more time monkeyfuzzing the executable, let's fire up r2, because in asm we trust!
[0x00 avatao]$ r2 -A reverse4 -- Heisenbug: A bug that disappears or alters its behavior when one attempts to probe or isolate it. [0x00400720]>
r2 tip: The -A switch runs aaa command at start to analyze all referenced code, so we will have functions, strings, XREFS, etc. right at the beginning. As usual, you can get help with ?.
It is a good practice to create a project, so we can save our progress, and we can come back at a later time:
[0x00400720]> Ps avatao_reverse4 avatao_reverse4 [0x00400720]>
r2 tip: You can save a project using Ps [file], and load one using Po [file]. With the -p option, you can load a project when starting r2.
We can list all the strings r2 found:
[0x00400720]> fs strings [0x00400720]> f 0x00400e98 7 str.Wrong_ 0x00400e9f 27 str.We_are_in_the_outer_space_ 0x00400f80 18 str.Size_of_data:__u_n 0x00400f92 23 str.Such_VM__MuCH_reV3rse_ 0x00400fa9 16 str.Use_everything_ 0x00400fbb 9 str.flag.txt 0x00400fc7 26 str.You_won__The_flag_is:__s_n 0x00400fe1 21 str.Your_getting_closer_ [0x00400720]>
r2 tip: r2 puts so called flags on important/interesting offsets, and organizes these flags into flagspaces (strings, functions, symbols, etc.) You can list all flagspaces using fs, and switch the current one using fs [flagspace] (the default is *, which means all the flagspaces). The command f prints all flags from the currently selected flagspace(s).
OK, the strings looks interesting, especially the one at 0x00400f92. It seems to hint that this crackme is based on a virtual machine. Keep that in mind!
These strings could be a good starting point if we were talking about a real-life application with many-many features. But we are talking about a crackme, and they tend to be small and simple, and focused around the problem to be solved. So I usually just take a look at the entry point(s) and see if I can figure out something from there. Nevertheless, I'll show you how to find where these strings are used:
[0x00400720]> axt @@=`f~` d 0x400cb5 mov edi, str.Size_of_data:__u_n d 0x400d1d mov esi, str.Such_VM__MuCH_reV3rse_ d 0x400d4d mov edi, str.Use_everything_ d 0x400d85 mov edi, str.flag.txt d 0x400db4 mov edi, str.You_won__The_flag_is:__s_n d 0x400dd2 mov edi, str.Your_getting_closer_
r2 tip: We can list crossreferences to addresses using the axt [addr] command (similarly, we can use axf to list references from the address). The @@ is an iterator, it just runs the command once for every arguments listed.
The argument list in this case comes from the command f~. It lists the strings from the executable with f, and uses the internal grep command ~ to select only the first column () that contains the strings' addresses.