Update (2020): Since writing this article, it has become, in a way, the go-to tutorial for learning radare2. Your feedback was amazing and I am very happy for the opportunity to teach new people about radare2.
A lot has changed since I wrote this tutorial, both with radare2 and with me. I am now, for several years, a core member in the radare2 team and a maintainer of Cutter, a modern, GUI-based, reverse engineering framework that is powered by radare2.
This is an updated version of the original tutorial. I will keep it updated every now and then to make sure it is up-to-date with the changes in radare2.
Enjoy!
Prologue
I was playing a lot with radare2 in the past years, ever since I began participating in CTFs and got deeper into RE and exploitation challenges. I found radare2 very helpful with many CTFs tasks and my solutions had shortened significantly. It’s also my go-to tool for malware analysis tasks such as configuration retrievals. Sadly, I believe that only few people are familiar with radare2. It might be because they’re afraid to break out of their comfort zone (IDA Pro, x64dbg, Ghidra, OllyDBG, gdb) or they have simply not heard of it. Either way, I honestly believe that you must include radare2 in your toolbox.
Because I got really enthusiastic about the project and I want more and more researchers to be familiar with it, use it and hopefully contribute to the project, I decided to create a series of articles and use-cases of r2. Since these articles aim to teach you the basics of radare2, its features, and capabilities, I’ll explain much more than you actually need to know in order to solve each task.
radare2
radare2 is an open-source framework for reverse engineering and binary analysis which implements a rich command-line interface for disassembling, analyzing data, patching binaries, comparing data, searching, replacing, visualizing and more. It has great scripting capabilities, it runs on all major platforms (GNU/Linux, Windows, *BSD, iOS, OSX, Solaris…) and it supports tons of architectures and file formats. But maybe above all of its features stands the ideology – radare2 is absolutely free.
This framework is composed of a set of utilities that can be used either together from r2 shell or independently – We’ll get familiar with tools such as rahash2
, rabin2
and ragg2
. Together they create one of the most powerful toolsets in the field of static and dynamic analysis, hex editing and exploitation (in the following articles I’ll dive deeper into developing exploits using radare2).
It is important to note that r2’s learning curve is pretty steep – although it has an amazing GUI called Cutter, which I co-maintain, it is still young to compete with more mature RE applications such as IDA or Ghidra. The CLI, however, including its Visual Mode, is still the core of radare2 and where its power lays. Because of its complexity, I’ll try to make things as clear and simple as I can.
Getting radare2
Installation
Radare2’s development is pretty quick – the project evolves every day. Therefore it’s recommended to use the current git version over the release one. Sometimes the release version is less stable than the current git version because of bug fixes!
git clone https://github.com/radare/radare2.git cd radare2 ./sys/install.sh
If you don’t want to install the git version or you want the binaries for another machine (Windows, OS X, iOS, etc) download the release from github.
Updating
As I said before, it is highly recommended to always use the newest version of r2 from the git repository. All you need to do to update your r2 version from the git is to execute:
./sys/install.sh
And you’ll have the latest version from git. I usually update my version of radare2 in the morning, while watching cat videos.
Uninstalling
I Can’t think of a reason for you to uninstall radare2 so early in the article but if you do want to, you can simply execute:
make uninstall make purge
Getting Started
[!] Download the first challenge from here.
Now that radare2 is installed on your system and you have downloaded the binary, we are ready to start exploring the basic usage of radare2. I’ll work on a Linux machine but most of the commands and explanations (if not all of them) would be the same for Windows machines and others.
Command Line Arguments
As most command-line utilities, the best approach to reveal the list of the possible arguments is to execute the program with the -h
flag.
r2 -h
I won’t paste here the full output. Instead, I’ll point out those which I usually use in my daily work:
Usage: r2 [-ACdfLMnNqStuvwzX] [-P patch] [-p prj] [-a arch] [-b bits] [-i file] [-s addr] [-B baddr] [-m maddr] [-c cmd] [-e k=v] file|pid|-|--|= - same as 'r2 malloc://512' -a [arch] set asm.arch -A run 'aaa' command to analyze all referenced code -b [bits] set asm.bits -B [baddr] set base address for PIE binaries -c 'cmd..' execute radare command -d debug the executable 'file' or running process 'pid' -i [file] run script file -k [OS/kern] set asm.os (linux, macos, w32, netbsd, ...) -l [lib] load plugin file -p [prj] use project, list if no arg, load if no file -w open file in write mode
Binary info
Whenever I face a new challenge, the first thing I want is to get information about the binary. Let’s extract it using one of the most powerful tools in r2 framework: rabin2
.
rabin2 allows extracting information from binary files including Sections, Headers, Imports, Strings, Entrypoints, etc. It can then export the output in several formats. rabin2 is able to understand many file formats such as ELF, PE, Mach-O, Java CLASS.
Check
man rabin2
for more information.
We’ll call rabin2 with the -I
flag which prints binary info such as operating system, language, endianness, architecture, mitigations (canary, pic, nx) and more.
$ rabin2 -I megabeets_0x1 arch x86 baddr 0x8048000 binsz 6220 bintype elf bits 32 canary false class ELF32 compiler GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609 crypto false endian little havecode true intrp /lib/ld-linux.so.2 laddr 0x0 lang c linenum true lsyms true machine Intel 80386 maxopsz 16 minopsz 1 nx false os linux pcalign 0 pic false relocs true relro partial rpath NONE sanitiz false static false stripped false subsys linux va true
As you can clearly see, our binary is a 32bit ELF file, not stripped and dynamically linked. It doesn’t have exploit mitigation – a piece of useful information for the next articles when we’ll learn to exploit using radare2.
Now let’s run it and see what the program does.Note: Although I promise you can trust me with running this crackme, it’s highly recommended not to trust me. Whenever you reverse an unknown binary, please do it inside a virtual environment where nothing can be harmed.
But you can trust me though, you have my dword 😛
$ ./megabeets_0x1 .:: Megabeets ::. Think you can make it? Nop, Wrong argument. $ ./megabeets_0x1 abcdef .:: Megabeets ::. Think you can make it? Nop, Wrong argument.
The first time we run the file we receive a message saying “Nop, Wrong argument”. Assuming we need to provide an argument for the program we run it again, this time with ‘abcdef’ as an argument. We failed again. Most likely, some password is needed in order to solve this crackme.
Let’s examine the program using radare2:
$ r2 megabeets_0x1 -- Thank you for using radare2. Have a nice night! [0x08048370]>
We started a radare2 shell and it automatically greets us with one of its fortunes. Some are funny and others are actually very useful, you can execute the fo
command to print a fortune. Now r2 shell is waiting for our commands and shows us the address in which we’re currently at (0x08048370). By default, you’ll automatically be at the entry-point address. Let’s see if it’s correct:
[0x08048370]> ie [Entrypoints] vaddr=0x08048370 paddr=0x00000370 haddr=0x00000018 hvaddr=0x08048018 type=program 1 entrypoints
The
ie
command stands for “info entrypoint”
We used the ie
command that prints the entry points of the binary. r2 commands are a succession of meaningful letters. In this example ie
stands for ‘info >> entrypoint’. Hence the commands are easy to remember once you’re familiar with radare2 capabilities. But you don’t have to remember all commands – you can simply add ?
after (almost) every letter to get information about the command and its subcommands.
[0x00000000]> i? Usage: i Get info from opened file (see rabin2's manpage) Output mode: | '*' Output in radare commands | 'j' Output in json | 'q' Simple quiet output Actions: | i|ij Show info of current file (in JSON) | iA List archs | ia Show all info (imports, exports, sections..) | ic List classes, methods and fields | iC[j] Show signature info (entitlements, ...) | id Show DWARF source lines information | idp [file.pdb] Load pdb file information | iD lang sym demangle symbolname for given language | ie Entrypoint | iE Exports (global symbols) | ih Headers (alias for iH) | ii Imports | iI Binary info | il Libraries | iM Show main address | ir List the Relocations | iR List the Resources | is List the Symbols | iS [entropy,sha1] Sections (choose which hash algorithm to use) | iSS List memory segments (maps with om) | it File hashes | iT File signature | iV Display file version info | iz|izj Strings in data sections (in JSON/Base64) | izz Search for Strings in the whole binary
The i
(info) command aims to get information from the opened file, it’s actually rabin2 (mentioned earlier) implemented in the radare2 shell. It is recommended to take a minute or two here, and explore the different sub-commands of i
, you’ll find many of these subcommands very useful for your RE journey.
Analysis
radare2 doesn’t analyze the file by default because analysis is a complex process that can take a long time, especially when dealing with large files. To read more about analysis and the choice not to perform analysis at startup you can read my answer on Stack Exchange Reverse Engineering, and visit the links I mentioned inside.
Obviously, analysis is still possible and r2 has lots of analysis types to offer. As I noted before, we can explore the analysis options by adding a question mar ?
to the a
command.
[0x08048370]> a? Usage: a [abdefFghoprxstc] [...] | a alias for aai - analysis information | a* same as afl*;ah*;ax* | aa[?] analyze all (fcns + bbs) (aa0 to avoid sub renaming) | a8 [hexpairs] analyze bytes | ab[b] [addr] analyze block at given address | abb [len] analyze N basic blocks in [len] (section.size by default) | ac[?] manage classes | aC[?] analyze function call | aCe[?] same as aC, but uses esil with abte to emulate the function | ad[?] analyze data trampoline (wip) | ad [from] [to] analyze data pointers to (from-to) | ae[?] [expr] analyze opcode eval expression (see ao) | af[?] analyze Functions | aF same as above, but using anal.depth=1 | ag[?] [options] draw graphs in various formats | ah[?] analysis hints (force opcode size, ...) | ai [addr] address information (show perms, stack, heap, ...) | aj same as a* but in json (aflj) | aL list all asm/anal plugins (e asm.arch=?) | an [name] [@addr] show/rename/create whatever flag/function is used at addr | ao[?] [len] analyze Opcodes (or emulate it) | aO[?] [len] Analyze N instructions in M bytes | ap find prelude for current offset | ar[?] like 'dr' but for the esil vm. (registers) | as[?] [num] analyze syscall using dbg.reg | av[?] [.] show vtables | ax[?] manage refs/xrefs (see also afx?)
I usually begin with executing aa
(analyse all) or aaa
. The name is misleading because there is a lot more to analyze (check aa?
) but it’s enough for most of the binaries I examined. This time we’ll start straight with aaa
to make things simpler and due to the small size of our target binary. You can also run radare2 with the -A
flag to analyze the binary straight at startup using aaa
(i.e. r2 -A megabeets_0x1
).
[0x08048370]> aaa [x] Analyze all flags starting with sym. and entry0 (aa) [x] Analyze function calls (aac) [x] Analyze len bytes of instructions for references (aar) [x] Check for objc references [x] Check for vtables [x] Type matching analysis for all functions (aaft) [x] Propagate noreturn information [x] Use -AA or aaaa to perform additional experimental analysis.
Flags
After the analysis, radare2 associates names to interesting offsets in the file such as Sections, Function, Symbols, and Strings. Those names are called ‘flags’. Flags can be grouped into ‘flag spaces’. A flag space is a namespace for flags of similar characteristics or type. To list the flag spaces run 'fs'
.
[0x08048370]> aaa [x] Analyze all flags starting with sym. and entry0 (aa) [x] Analyze function calls (aac) [x] Analyze len bytes of instructions for references (aar) [x] Check for objc references [x] Check for vtables [x] Type matching analysis for all functions (aaft) [x] Propagate noreturn information [x] Use -AA or aaaa to perform additional experimental analysis.
We can choose a flag space using fs <flagspace>
and print the flags it contains using f
. To pass several commands in a single line we can use a semicolon (i.e cmd1; cmd2; cmd3;...
).
[0x08048370]> fs imports; f 0x00000000 16 loc.imp.__gmon_start 0x08048320 6 sym.imp.strcmp 0x08048330 6 sym.imp.strcpy 0x08048340 6 sym.imp.puts 0x08048350 6 sym.imp.__libc_start_main
As we can see radare2 flagged the imports used by the binary – we can see the well-known ‘strcmp’, ‘strcpy’, ‘puts’, etc., along with their corresponding addresses. We can also list the strings flagspace:
[0x08048370]> fs strings [0x08048370]> f 0x08048700 21 str..::_Megabeets_::. 0x08048715 23 str.Think_you_can_make_it 0x0804872c 10 str.Success 0x08048736 22 str.Nop__Wrong_argument.
Now let’s get back to the default selection of flagspaces (all of them) by executing fs *
.
Strings
We see that r2 flagged some offsets as strings, some sort of variable names. Now let’s have a look at the strings themselves. There are several ways to list the strings of the file, and you should choose the one suits your goal the most.
iz
– List strings in data sectionsizz
– Search for Strings in the whole binary
[0x08048370]> iz [Strings] nth paddr vaddr len size section type string ――――――――――――――――――――――――――――――――――――――――――――――――――――――― 0 0x00000700 0x08048700 20 21 .rodata ascii \n .:: Megabeets ::. 1 0x00000715 0x08048715 22 23 .rodata ascii Think you can make it? 2 0x0000072c 0x0804872c 9 10 .rodata ascii Success!\n 3 0x00000736 0x08048736 21 22 .rodata ascii Nop, Wrong argument.\n
We already know most of these strings – we saw them when we executed our binary, remember? We didn’t see the “Success” string though, this is probably our ‘good boy‘ message. Now that we got the strings, let’s see where they’re used in the program.
[0x08048370]> axt @@ str.* main 0x8048609 [DATA] push str..::_Megabeets_::. main 0x8048619 [DATA] push str.Think_you_can_make_it main 0x8048646 [DATA] push str.Success main 0x8048658 [DATA] push str.Nop__Wrong_argument.
axt
stands for analyze x-refs to
This command reveals us more of radare2 features. The axt
command is used to “find data/code references to this address” (see ax?
). The special operator @@
is like a foreach iterator sign, used to repeat a command over a list of offsets (see @@?
), and str.*
is a wildcard for all the flags that start with str.
. This combination helps us not just to list the strings flags but also to list the function name, where they are used and the referencing instruction. Make sure to select the strings flagspace (default, use 'fs *'
) before.
Seeking
As I mentioned before, all this time we were at the entrypoint of the program, now it’s time to move on. The strings we just listed are all referenced by ‘main’. in order to navigate from offset to offset we need to use the ‘seek’ command, represented by s
. As you already know, appending ?
to (almost) every command is the answer to all your problems.
[0x08048370]> s? Usage: s # Help for the seek commands. See ?$? to see all variables | s Print current address | s.hexoff Seek honoring a base from core->offset | s:pad Print current address with N padded zeros (defaults to 8) | s addr Seek to address | s- Undo seek | s-* Reset undo seek history | s- n Seek n bytes backward | s--[n] Seek blocksize bytes backward (/=n) | s+ Redo seek | s+ n Seek n bytes forward | s++[n] Seek blocksize bytes forward (/=n) | s[j*=!] List undo seek history (JSON, =list, *r2, !=names, s==) | s/ DATA Search for next occurrence of 'DATA' | s/x 9091 Search for next occurrence of \x90\x91 | sa [[+-]a] [asz] Seek asz (or bsize) aligned to addr | sb Seek aligned to bb start | sC[?] string Seek to comment matching given string | sf Seek to next function (f->addr+f->size) | sf function Seek to address of specified function | sf. Seek to the beginning of current function | sg/sG Seek begin (sg) or end (sG) of section or file | sl[?] [+-]line Seek to line | sn/sp ([nkey]) Seek to next/prev location, as specified by scr.nkey | so [N] Seek to N next opcode(s) | sr pc Seek to register | ss Seek silently (without adding an entry to the seek history)
So basically the seek command accepts an address or math expression as an argument. The expression can be math operations, flag, or memory access operations. We want to seek to the main function, we can do it by executing s main
but let’s see first what other functions radare2 flagged for us using the afl
command (Analyze Functions List).
[0x08048370]> afl 0x08048370 1 33 entry0 0x08048350 1 6 sym.imp.__libc_start_main 0x080483b0 4 43 sym.deregister_tm_clones 0x080483e0 4 53 sym.register_tm_clones 0x08048420 3 30 sym.__do_global_dtors_aux 0x08048440 4 43 -> 40 entry.init0 0x080486e0 1 2 sym.__libc_csu_fini 0x080483a0 1 4 sym.__x86.get_pc_thunk.bx 0x0804846b 19 282 sym.rot13 0x080486e4 1 20 sym._fini 0x08048585 1 112 sym.beet 0x08048330 1 6 sym.imp.strcpy 0x08048320 1 6 sym.imp.strcmp 0x08048680 4 93 sym.__libc_csu_init 0x080485f5 5 127 main 0x080482ec 3 35 sym._init 0x08048340 1 6 sym.imp.puts
Sweet! There are the imports we saw before, some .ctors, the entrypoints, libc, main and two interesting functions named sym.beet
and sym.rot13
.
Disassembling
main function
It’s time to look at some assembly (yay!). We first need to seek to the function using s main
and then disassemble it using pdf
(Print Disassemble Function). Notice how the address at the prompt changed to the address of main
.
Tip: Using a modern OS? cool! Your console supports UTF8. Execute e scr.utf8=true
and e scr.utf8.curvy=true
to make the output looks prettier. Add these commands to the ~/.radare2rc
to set this config permanently.
Tip
Using a modern OS? cool! Your console supports UTF8. Execute e scr.utf8=true
and e scr.utf8.curvy=true
to make the output looks prettier. Add these commands to the ~/.radare2rc
file to set this config permanently.
Please Note
As I said before, the goal of this tutorial is to teach radare2 and present some of its capabilities, not to teach assembly. Therefore I will not go through the code deeply and explain what it does. The binary is really simple, you should get it even with a basic understanding of reverse engineering.
Take all the time you need and look at the output of pdf
.
[0x08048370]> s main [0x080485f5]> pdf ; DATA XREF from entry0 @ 0x8048387 int main (int32_t arg_4h); ; var int32_t var_8h @ ebp-0x8 ; arg int32_t arg_4h @ esp+0x24 0x080485f5 8d4c2404 lea ecx, [arg_4h] 0x080485f9 83e4f0 and esp, 0xfffffff0 0x080485fc ff71fc push dword [ecx - 4] 0x080485ff 55 push ebp 0x08048600 89e5 mov ebp, esp 0x08048602 53 push ebx 0x08048603 51 push ecx 0x08048604 89cb mov ebx, ecx 0x08048606 83ec0c sub esp, 0xc 0x08048609 6800870408 push str..::_Megabeets_::. ; "\n .:: Megabeets ::." ; const char *s 0x0804860e e82dfdffff call sym.imp.puts ; int puts(const char *s) 0x08048613 83c410 add esp, 0x10 0x08048616 83ec0c sub esp, 0xc 0x08048619 6815870408 push str.Think_you_can_make_it ; "Think you can make it?" ; const char *s 0x0804861e e81dfdffff call sym.imp.puts ; int puts(const char *s) 0x08048623 83c410 add esp, 0x10 0x08048626 833b01 cmp dword [ebx], 1 ╭─< 0x08048629 7e2a jle 0x8048655 │ 0x0804862b 8b4304 mov eax, dword [ebx + 4] │ 0x0804862e 83c004 add eax, 4 │ 0x08048631 8b00 mov eax, dword [eax] │ 0x08048633 83ec0c sub esp, 0xc │ 0x08048636 50 push eax │ 0x08048637 e849ffffff call sym.beet │ 0x0804863c 83c410 add esp, 0x10 │ 0x0804863f 85c0 test eax, eax ╭──< 0x08048641 7412 je 0x8048655 ││ 0x08048643 83ec0c sub esp, 0xc ││ 0x08048646 682c870408 push str.Success ; "Success!\n" ; const char *s ││ 0x0804864b e8f0fcffff call sym.imp.puts ; int puts(const char *s) ││ 0x08048650 83c410 add esp, 0x10 ╭───< 0x08048653 eb10 jmp 0x8048665 │││ ; CODE XREFS from main @ 0x8048629, 0x8048641 │╰╰─> 0x08048655 83ec0c sub esp, 0xc │ 0x08048658 6836870408 push str.Nop__Wrong_argument. ; "Nop, Wrong argument.\n" ; const char *s │ 0x0804865d e8defcffff call sym.imp.puts ; int puts(const char *s) │ 0x08048662 83c410 add esp, 0x10 │ ; CODE XREF from main @ 0x8048653 ╰───> 0x08048665 b800000000 mov eax, 0 0x0804866a 8d65f8 lea esp, [var_8h] 0x0804866d 59 pop ecx 0x0804866e 5b pop ebx 0x0804866f 5d pop ebp 0x08048670 8d61fc lea esp, [ecx - 4] 0x08048673 c3 re
From reading the assembly we can generate a quick pseudo-code:
//f any argument passed to the program AND the result of beet, given the passed argument, is true // argc is the number of arguments passed to the program // argc will be at least 1 becuase the first argument is the program name // argv is the array of parameters passed to the program if (argc > 1 && beet(argv[1]) == true) { print "success" } else { print "fail" } exit
Visual Mode & Graph Mode
radare2 is equipped with a very strong and efficient suite of Visual Modes. The Visual Mode is much more user-friendly and takes the reversing experience using r2 to a whole new level. Pressing V
will bring us to the Visual Mode screen. Use p
/P
to change between modes. At the top of the screen you can see the command which was used to generate the view. Navigate to the disassembly view using p
. To go back from a specific screen, press q
.
Here are some basic and useful actions you can perform from Visual Mode.
Help
As always in radare, pressing ?
will take you to the help screen in which you can explore the commands of the Visual Mode.
Cross-References
Use x
/X
to list the references to/from (respectively) the current offset. Use the numbers to jump to a reference.
radare2 commands
Use :command
to execute r2 commands from inside Visual Mode. This is similar to VIM.
Comment
You can add a comment using ;<comment>
followed by Enter, remove it using ;-
or even use your default text editor to add the comment using ;!
.
Mark
m<key>
can be used to mark specific offset with a key of your choice. Press '<key>
to go to your key. This helps to mark some key addresses that you’d like to quickly navigate to.
Quit
Press q
to return to r2 shell.
Visual Graphs
As in similar disassemblers, radare2 has a Graph view. You can access Visual Graph mode from your shell by running VV
, move Left/Down/Up/Right using the arrows or h
/j
/k
/l
and jump to a function using g
and the key shown next to the jump call (e.g gd
).
Tip
Enable e scr.utf8=true
and e scr.utf8.curvy=true
to make the outlines beautiful.
Use ?
to list all the commands and make sure not to miss the R
command.
Disassembling ‘beet’
After a short break from disassembling. Let’s go back to it and explore the function beet
. As we saw earlier, our binary checks the result of beet
that is called with the argument we pass to the program. We can print beet
using several methods, here are some of them:
- Seek to
beet
in r2 shell and print the function by usings sym.beet
(sym.beet
is a flag for thebeet
function. You can print the ‘sym’ flags by runningf sym.<tab>
) and then executingpdf
(print disassembled function). - Print
beet
from r2 shell without seeking by usingpdf @ sym.beet
.@
is used as a temporary seeking. i.e “print the function at offset sym.beet”. - Jump to
beet
from Visual Mode frommain
by pressing2
(the digit next to the jump call). - Jump to
beet
from Visual Graph Mode frommain
usingoc
(the letters next to thecall sym.beet
instruction).
Here’s how beet
looks like in Visual Graph Mode:
We can see that the given argument is copied to a buffer. The buffer is located at ebp - local_88h
. ‘local_88h’ is actually 0x88 which is 136 in decimal. We can see this by executing ? 0x88
. To execute r2 command from inside Visual Graph mode use :
and then write the command.
:> ? 0x88 int32 136 uint32 136 hex 0x88 octal 0210 unit 136 segment 0000:0088 string "\x88" fvalue: 136.0 float: 0.000000f double: 0.000000 binary 0b10001000 trits 0t12001
Hence, 128 bytes are allocated for the buffer in the stack, the next 4 bytes would be the saved ebp
pointer of the previous stack frame, and the next 4 bytes will be the return address, this sums up to 136.
After the buffer is filled with the given argument, it is then compared with the result of a function named sym.rot13
. Rot-13 is a famous substitution cipher used a lot in CTFs and Crackmes. The function is called with 9 hexadecimal values that seem like radare recognizes for us. In the comments of the disassembly we can see ‘Mega’, ‘beet’ and ‘s’, together constructing the string “Megabeets”.
The binary performs rot13 on “Megabeets” and then compares the result with the argument we passed using strcmp
. Luckily we don’t need to work hard because r2 framework already includes rot13 cipher in its rahash2
utility.
rahash2 compute checksums of files or strings using various algorithms.
Check
man rahash2
for more information.
[0x08048585]> !rahash2 -E rot -S s:13 -s "Megabeets\n" Zrtnorrgf
rahash2 performed rot13(“Megabeets”) and resulted with “Zrtnorrgf”. By using !
we can execute shell commands from within r2 shell as in system(3)
. We can assume that “Zrtnorrgf” is compared with our input. Let’s open the binary in debug mode with “Zrtnorrgf” as an argument using ood
(check ood?
) and see what we’ll get.
[0x08048585]> ood? Usage: ood # Debug (re)open commands | ood [args] # reopen in debug mode (with args) | oodf [file] # reopen in debug mode using the given file | oodr [rarun2] # same as dor ..;ood [0x08048585]> ood Zrtnorrgf Process with PID 26850 started... = attach 26850 26850 File dbg:///home/beet/megabeets/crackmes/megabeets_0x1 Zrtnorrgf reopened in read-write mode 26850
We opened megabeets_0x1
with an argument in the radare2 debugger. We can now execute the program using dc
which stands for “debug continue”.
[0xf7f4a120]> dc .:: Megabeets ::. Think you can make it? Success!
Woohoo! We received the success message and solved the crack me. After getting the success message we can finally say that what the binary is doing is to take the first argument we pass it and compare it with rot13(“Megabeets”) which is “Zrtnorrgf”.
You can see the full source-code of the crackme here.
Epilogue
Here the first part of our journey with radare2 is coming to an end. We learned about radare2 just in a nutshell and explored only the basics of the basics. In the next parts we’ll learn more about radare2 capabilities including scripting, malware analysis and exploitation. I’m aware that it’s hard, at first, to understand the power within radare2 or why should you put aside some of your old habits and get used working with radare2, but I promise that having radare2 in your toolbox is a very smart step whether you’re a reverse engineer, a CTF player or just security enthusiast.
Above all I want to thank my colleagues in the radare2 community for creating this amazing tool as libre and open, and devoting their time to help, improve and promote the framework.
Please post comments, or message me privately if something is wrong, not accurate, needs further explanation or you simply don’t get it. Don’t hesitate to share your thoughts with me.
Subscribe on the left if you want to get the next articles straight in your inbox.
I have no excuses now not to learn radare haha
really great tutorial
Outstanding tutorial! As a beginner to RE and r2 in general this was extremely well written and easy to follow. Am looking forward to more entries in this series!
By far the most simple and understandable tutorial of radare. Waiting for the next posts of yours, thanks1
You’re Welcome 🙂 The next post will be published at the next few weeks
The best ever seen tutorial. Thanks for this gem !
Thanks Phil! 🙂
You’re welcome, stay tuned for more
I just want to comment, that there is a error in the “unfair comparison” because you can also use a GUI in radare https://github.com/hteso/iaito
haha that’s true, there are couple of GUI(s) to radare in addition to the webUI but it’s not officially belongs to radare (yet)
I was always wondering how to see actual strings stored in the memory addresses before they are passed to some function or compared against something. This is great, I love it!
This is really quite excellent–looking forward to the next installment!
Awesome! Waiting for the next part 🙂
Hello,i did it as this blog and there comes some problems:
[0x08048370]> s main
[0x080485f5]> pdf
there is no result blow,and i can not go into Visual Graphs when i insert VV, I do not know where it is wrong, and my r2 version is :
radare2 1.4.0-git 14322 @ linux-x86-64 git.1.3.0-226-g547479dad
Hope to get your help,think you!
Hey,
Did you analyzed the binary using `aaa`?
If so, it should work.
Try the following commands in this order, maybe some would work, tell me afterwards:
First update to the most recent git version using `./sys/install.sh`, then open the file using `r2 filename` . Then execute the following commands:
`aaa` – analyzing the binary
`afl` – list the functions, make sure main or sym.main is recognized
`af @ sym.main` – analyze main function
`pdf @ sym.main` – print the main function
`V` – to enter visual mode
`space` – to toggle between visual mode and graph mode.
And please paste the full `r2 -v` result. What machine do you work on?
If still nothing works, we’ll open an issue on github.
Waiting for your response.
think you, i am success to go into Visual Graphs as your method.
now ,i am try to use r2 analysis go language program, Is there some recommendation article?
thank you ,have a nice day!
Check this talk about reversing GO malware: https://youtu.be/PRLOlY4IKeA
Hi, there
I followed along the tutorial for learning r2. I had a question on making r2 to recognize specific offset as a string.
I ran the same command. But it did not work. The graph did not get refreshed.
Reproduction Steps:
1. Go to View
`[0x08048585]> VV @ sym.beet (nodes 1 edges 0 zoom 100%) BB-OFF mouse:canvas-y movements-speed:5`
2. Press :, and run below command
`:> ahi s @@=0x080485a3 0x080485ad 0x080485b7`
3. Press q
4. Press r to refresh the graph.
Thanks.
Hey illnino, it should work. you can also try it from outside Visual Mode and then execute `pdf` to see if it changed.
There’s other way inside Visual Mode which is actually the best practice:
1. Make sure you’re in `beet` function `s sym.beet`
2. Enter Visual Mode by pressing `v` and toggle to assembly mode using `p`
3. Use`j` to scroll down until you’re on `0x080485a3` (should be sym.beet+30)
4. Press `d` to define the selected line, then `i` to set immediate base, type `s` and press enter. The line should change right after it.
5. Use `j` again to move to the next line and repeat step 4, and then again on the next line.
Hope it will be helpful,
Itay
I have forget to chmod 755 the megabeets_0x1 file before to execute it on debug mode 🙂 first. It crashes.
Thanks a lot for this article.
Regards.
Thanks! There’s a minor typo where you call rahash2, the string should be ‘Megabeets’ (no trailing new line).
Thanks for the feedback Peter! I wrote it intentionally since there’s a bug while executing it without `\n`.
But then you don’t get the correct rot13 output. If the problem is just the missing newline, what about doing something like:
!rahash2 -E rot -S s:13 -s ‘Megabeets’; !echo
‘Zrtnorrgf’
For some reason, everything works fine up until the very end, when you type “ood Zrtnorrgf”. It seems to be having permissions issues. I saw the comment about chmod 755 and tried that but my megabeets_0x1 file already had the same permissions (tried chmod 755 anyway just to be safe), I also tried chmod 777. Here’s the error I’m getting.
[0x00400835]> ood Zrtnorrgf
Could not execvp: No such file or directory
r_core_file_reopen: Cannot reopen file: dbg:///home/Pragmata/Documents/ReverseEngineering/Crackmes & CTFs/Megabeets0x1/megabeets_0x1 Zrtnorrgf with perms 0x0007, attempting to open read-only.
[0x00000000]>
Interesting, it works for me just fine on the latest version. Please make sure to update radare to its newest version if you haven’t did yet.
Seems like a bug, I’d suggest you to change the location of `megabeets_0x1`, say to `/tmp/megabeets_0x1`. Maybe the `&` sign is causing an issues.
Anyway, `ood` is used to “reopen the file in debug mode”, you can do this by yourself by simply execute `r2 -d megabeets_0x1 Zrtnorrgf`.
Hey thanks! Both solutions worked, and then I went ahead and tried removing the & sign from the directory name (just “Crackmes” is equally as descriptive, heh..) and it solved the issue entirely! This article is gold, can’t wait to read part 2, and hope to see parts 3 and 4 soon. I’m new to reverse engineering in general as well as radare2, I’m still learning assembly and olly/ida, yet you made everything clear and easy to understand. Many thanks!
Glad to her that! Part 2 is already available check it here https://www.megabeets.net/a-journey-into-radare-2-part-2
I got the same error.
The reason is the “space” in file path .
It works fine after I change the path from “dbg:///home/remnux/A-journey-into-Radare2/Part 1 – Simple crackme/megabeets_0x1” to “dbg:///home/remnux/A-journey-into-Radare2/Part1/megabeets_0x1” .
im having a problem, the “axt @@ str.*” line isn’t doing anything
Did you analyze the binary using `aa` or `aaa`? It should work just fine when the binary is analyzes
Thanks for this introduction. It is a very good job.
^_^
Thank you so much! You’re welcome!
Great tutorial! thanks!
Sure! You are welcome! 😀
The best tutorial I’ve seen of radare
Thank You!
Thank you for your kind words! 🙂
Glad you like it!
Thanks for the tutorial. Do more lessons and if possible video.
Question:
How to stop(breakpoint) the program in a certain place?
r2 -d
1) aaa
2) db main # or db sym.main, db sym.beet, db sym.rot13, …..
3) dc
The program ends, but does not stop. Saw this in the video, I try to repeat and it does not work out. Tried it in different programs.
This actually should work, you can try with the address (`db 0x40…`).
Anyway, what is your version of r2? (`r2 -v`)
1) db 0x40… – also does not work
2) r2 -v
radare2 2.8.0 0 @ linux-x86-64 git.2.8.0
commit: HEAD build: 2018-08-15__09:35:36
Updated to the new version (2.9.0) and it all worked.
Great! Glad to hear 🙂
As I always say, using latest version of r2 from Git is the best
It’s hard to read on my monitor because of the sidebar on the left. It’s wasting a lot of space. Also, it’s irritating to keep scrolling code/console parts of your tutorial horizontally left and right all the time. Zooming out completely makes it small. Can you pls fix this?
Thanks for the feedback Anutrix!
How small is your monitor? Can you please PM me on some IM app (Telegram, twitter,…)?
https://www.megabeets.net/about.html#contact
Hey, first of all I want to thank you for your nice written tutorials 🙂
I really like the colors in your r2. Are you using a custom color scheme and would you mind sharing it?
Best regard
Thank you!
To be honest, the post is way too old and I changed computers and terminals since then.
AFAIR, I didn’t use any r2 theme but instead, I changed (hooked) the terminal colors using the color settings in ConEmu
The best introduction for beginner to study understand code
The addition of GUI with explained command tree help description of command actions would
be a tremendous help to learn r2 commands as a graphical overlay pop up to help suggest and
help directions … for student beginner .. Thank you
What a great tutorial, thank you!
I expect your nexy journey. thank you
I would like to thank you for the nice tutorial!
I suggest to add the r2 version somewhere in the post. I’ve seen that they have rebind some shortcuts described in this tutorial to other keys, this would avoid some confusion.
Thank you!
would you mind noting down the changes in r2 that broke examples in the article? I’d be happy to fix this in the tutorial 🙂
One of the best radare2 tutorial!
OMG… This is best tutorial of radare2 in the world. Thank you.
Excellent tutorial, thanks a lot!
I am new to radare2 and probably missed something (or a lot) but when i put in:
radare2 -v
i get:
radare2 4.5.0 1 @ windows-x86-32 git.4.5.0
commit: 9d7eda5ec7367d1682e489e92d1be8e37e459296 build: Fri 07/17/2020__11:10:04.28
But r2 -v gets back r2 is not recognized as internal or external, etc.
Did the name changed or do i have to create some kind of aliase?
Sorry if the question is silly but i couldnot find an answer anywhere near….
Hi Pavel,
Good question! On Linux machines, radare2 binary is called “radare2.exe” and does not have the “r2” alias. You can easily create this alias on your computer.
But what about Windows?
In the example that you show: “r2 -h”, the output is exactly like that from in “radare2 -h”
Did you create an alias first?
When you run “r2 -h” on your windows installation, what output do you get? Just curious.
Thanks in advance!
file not working in my case……
sudo ./megabeets_0x1 abcdef
sudo: ./megabeets_0x1: command not found