radare2 将主函数参数 argv 显示为堆栈上指向 char 的指针,而不是指向 char 的指针

逆向工程 调试 雷达2 数据库 入口点
2021-06-14 15:15:58

好吧,最近几天我一直在研究进程命令行参数环境变量,尤其是查找main函数参数被推入堆栈的方式。

到目前为止,我已经知道某个_libc_start_main()函数负责main()在实际调用函数之前根据参数设置函数所需的一切
没有进入太多细节,我注意到,调试简单,当main程序时,main堆栈帧是不同的,我们无论是在看它radare2gdb
例如,让我们以这个极简的 C 程序为例:

int main (int argc, char *argv[], char *envp[])
{
}

只需调试它,无需任何附加参数:

与 GDB

main(我无法在不运行程序的情况下转储堆栈帧)的第一条汇编指令上设置断点后,我得到的gdb是非常明智的事情,正如人们所看到的:

(gdb) x/3xw $esp
0xffffcfbc:     0xf7db7b41          0x00000001      0xffffd054      
#                  ^                    ^               ^     
#              PC (somewhere          argc            argv             
#          in __libc_start_main())

现在通过实际检查指出的内存区域argv

(gdb) x/2xw 0xffffd054   # argv
0xffffd054:     0xffffd1ef      0x00000000
#                  ^                ^ 
#                argv[0]          argv[argc]
#           (another pointer)              

(gdb) x/s 0xffffd1ef  # argv[0]
0xffffd1ef:     "<path>/argvonstack32"
#                      ^ 
#                  Exepected program name

因此,基本上推送到main堆栈帧上的内容argvenvp(即使envp为了简单起见我没有显示转储)正是我们有权从调试器期望的内容,即指向的指针char(如所述)在main函数签名中)。

使用 Radare2

不设置断点,不运行程序直接查看栈帧,radare2显示不同的栈帧:

- offset -   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF  comment
0xffa63d10  0100 0000 1953 a6ff 0000 0000 2953 a6ff  .....S......)S..  ; esp
                ^         ^         ^       
              argc     argv[0]    argv[1]

检查时argv[0]

- offset -   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF  comment
0xffa65319  2e2f 6172 6776 6f6e 7374 6163 6b33 3200  ./argvonstack32.
0xffa65329  5348 454c 4c3d 2f62 696e 2f62 6173 6800  SHELL=/bin/bash.

这表明radare2跳过了第一个指针间接argv并将列表argv[0]...argv[argc]直接推送到main堆栈帧上。

什么解释了这种差异?

PS:正如您所看到的,我使用radare2之间的唯一区别是我运行gdb了程序,gdb而不需要实际运行它radare2来转储main堆栈帧内存。

1个回答

你是在比较橙子和苹果。

在第一个示例中,您正在查看mainC 库传递给函数的参数,它们符合 C 标准要求(char指针数组)。

在第二个示例中,您正在查看二进制文件的低级入口点来自内核的参数,它们还没有被 C 库处理。内核没有任何花哨的处理:它只是将所有字符串放在一个由零字节分隔(并以两个零结尾)的块中,并将拆分留给程序本身。通常这是__libc_start_main在调用之前或类似的函数完成的main()