前言
今天,通过一个有趣的案例,从反编译的角度看一下C语言中函数参数是如何传递的。
创建main.c
文件,将下面实验代码拷贝到main.c
文件中。
# main.c
#include <stdio.h>int test(int a, int b, int c, int d, int e, int f, int g, int h, int i)
{return 0;
}int main(int argc, char *argv[])
{test(0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9);return 0;
}
简单解释一些上述代码:
- 声明一个名为
test
且需要七个参数的函数,函数体内并未做任何事情。 - 在
main
函数中调用test
函数,并将十六进制的1-9作为参数传递到test
函数中。
32位程序
使用gcc -m32 main.c -o main
将main.c
编译为32位程序,使用file
命令查看结果。
使用gdb
看一下反编译结果,使用gdb main
命令加载程序。程序加载完毕后,使用命令disassemble main
对程序进行反编译
着重看一下上图红框中的内容,注意以下两点即可:
- 函数参数的传递顺序是从右向左依次传递,即先传递
0x9
,再传递0x8
,依次类推。 - 全部使用的
push
指令,将参数值压到栈中,最后调用test
函数
64位程序
使用gcc main.c -o main
将main.c
编译为32位程序,使用file
命令查看结果。
使用gdb
看一下反编译结果,使用gdb main
命令加载程序。程序加载完毕后,使用命令disassemble main
对程序进行反编译
着重看一下上图红框中的内容,注意以下两点即可:
- 函数参数的顺序与32位程序相同,依旧是从右向左依次传递,即先传递
0x9
,再传递0x8
,依次类推。 - 不同的是传递给
test
函数的前六个参数(从左向右的顺序,即0x1
、0x2
、……、0x6
)分别放入到寄存器(rdi
、rsi
、rdx
、rcx
、r8
、r9
)中,超过6个参数之后的参数放入到栈中。
本例中:0x1
放入edi
寄存器、0x2
放入esi
寄存器、0x3
放入edx
寄存器、0x4
放入ecx
寄存器、0x5
放入r8d
寄存器、0x6
放入r9d
寄存器。
注:edi
为32位寄存器,rdi
为64位寄存器,因为传递的参数不需要占据64bit
,因此编译程序时自动进行了优化。
无情的广告时间
哈哈哈哈,又到了大家喜欢的广告时间了,喜欢的话给个关注呗,公众号:编码魔坊
,谢谢您的关注!!!