This might have a simple solution but I can't find it anywhere.

$> ./be1 11 AAAAA

With gdb, finding argv[] and argc is simple:

(gdb) print argv[0]@argc
$7 = {0xbffff872 "be1", 0xbffff89a "11", 0xbffff89d "AAAAA"}

But, how can we do this with radare2 ?


radare2 currently doesn't flags argv and argc. Yet, it shouldn't be something complicated to implement.

Although these arguments are not flagged by radare2, they can be easily be visible to us by inspecting the registers. Let's do it step by step.

Assume we have the following program:

$ cat example.c

#include <stdio.h>


   printf( "argv[1]: %s\n", argv[1]);

   return 0;

All the program is doing is to print the first argument given to it. Simple as that.

Let's compile it in gcc and open it in debug-mode with radare2 using the -d flag, and pass an argument to it:

$ gcc example.c -o example.elf
$ r2 -d example.elf ABCDEFGH
Process with PID 104 started...
= attach 104 104
bin.baddr 0x00400000
Using 0x400000
asm.bits 64
 -- Nothing to see here. Move along.

Let's quickly analyze the program using aa:

[0x7f3c8f000c30]> aa
[x] Analyze all flags starting with sym. and entry0 (aa)

Now, let's execute the program until we reach main(). We can do this by setting a breakpoint at main using db main and continue the execution until the program reaches the breakpoint using dc. Or, we can simply use dcu [addr] -- a very nice command that will continue the execution until a specific address.

[0x7f3c8f000c30]> dcu main
Continue until 0x00400526 using 1 bpsize
hit breakpoint at: 400526

radare2 stopped the execution of the program at main. Great! Let's move on and print the function:

[0x00400526]> pdf
            ;-- main:
            ;-- rax:
            ;-- rip:
╭ (fcn) sym.main 51
│   sym.main ();
│           ; var int local_10h @ rbp-0x10
│           ; var int local_4h @ rbp-0x4
│           ; DATA XREF from 0x0040044d (entry0)
│           0x00400526      55             push rbp
│           0x00400527      4889e5         mov rbp, rsp
│           0x0040052a      4883ec10       sub rsp, 0x10
│           0x0040052e      897dfc         mov dword [local_4h], edi
│           0x00400531      488975f0       mov qword [local_10h], rsi
│           0x00400535      488b45f0       mov rax, qword [local_10h]
│           0x00400539      4883c008       add rax, 8
│           0x0040053d      488b00         mov rax, qword [rax]
│           0x00400540      4889c6         mov rsi, rax
│           0x00400543      bfe4054000     mov edi, str.argv_1_:__s    ; 0x4005e4 ; "argv[1]: %s\n"
│           0x00400548      b800000000     mov eax, 0
│           0x0040054d      e8aefeffff     call sym.imp.printf         ; int printf(const char *format)
│           0x00400552      b800000000     mov eax, 0
│           0x00400557      c9             leave
╰           0x00400558      c3             ret

As you may know, in a GCC compiled program, at main's entry, edi will hold argc and rsi (a pointer on the stack) will hold argv.

We can print their addresses like this:

[0x00400526]> dr rsi
[0x00400526]> dr edi

So the value of argc (edi) is 0x2 which is expected since the arguments are the file name and "ABCDEFGH". The address of the pointer argv (rsi) is 0x7ffff02302b8. In order to print the content of * argv (rsi) we can simply use the following command:

[0x00400526]> psb @ [rsi]
0x7ffff02304b7 ./example.elf
0x7ffff02304c4 ABCDEFGH
0x7ffff02304cd SHELL=/bin/bash
0x7ffff02304dd TERM=xterm-256color
0x7ffff02304f1 OLDPWD=<truncated>
0x7ffff023050e USER=beet
0x7ffff0230518 NAME=<truncated>

psb is used to print strings in the current block. Since at this point we know that argc equals 2, we can ignore anything that is beneath the second line of the output.

radare2 also offers you a register telescoping using drr. This way you can easily see where rsi is pointing to:

[0x00400526]> drr~rsi
   rsi 0x00007ffff1a56ab8  rsi stack R W 0x7ffff1a56cb7 -->  stack R W 0x6c706d6178652f2e (./example.elf) -->  ascii

As you can see, rsi value is 0x7ffff1a56ab8 which is pointing to an address on the stack (0x7ffff1a56cb7) that contains an ascii string "./example.elf".
~ is radare's internal grep.

Please consider open an issue to ask for this feature, or even better, implement it and send a pull-request.

  • 1
    Wow, thanks this is everything I wanted and much much more. Thanks again!
    – Corey
    Apr 25 '18 at 16:04

the info command holds all the args passed to radare2 and you can use the internal grep too to find it

:\>radare2 -Q -c "i~ref" -d cmdlnargs.exe firstarg secarg thirdarg
Spawned new process with pid 6032, tid = 3196
r_sys_pid_to_path: Cannot get module filename.= attach 6032 3196
bin.baddr 0x01330000
Using 0x1330000
Spawned new process with pid 872, tid = 2512
r_sys_pid_to_path: Cannot get module filename.asm.bits 32
referer  dbg://cmdlnargs.exe firstarg secarg thirdarg

the same command performed inside radare instead of shell

:\>radare2 -d cmdlnargs.exe firstarg secarg thirdarg
Spawned new process with pid 5356, tid = 2704
r_sys_pid_to_path: Cannot get module filename.= attach 5356 2704
bin.baddr 0x01330000
Using 0x1330000
Spawned new process with pid 5296, tid = 6036
r_sys_pid_to_path: Cannot get module filename.asm.bits 32
 -- Are you still there?
[0x779d70d8]> i~ref
referer  dbg://cmdlnargs.exe firstarg secarg thirdarg
[0x779d70d8]> q
Do you want to quit? (Y/n) y
Do you want to kill the process? (Y/n) y


Your Answer

