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>
int main(int argc, char *argv[]) {
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.
[0x7f3c8f000c30]>
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
0x7ffff02302b8
[0x00400526]> dr edi
0x00000002
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.