参数和返回值是函数的两个重要组成部分,可以通过参数向函数传入信息,通过返回值使函数传出信息。看一段C语言代码:
#include <stdio.h>
int function(int a, int b)
{
if (a > b)
{
return a;
}
else
{
return b;
}
}
int main()
{
function(1, 2);
return 0;
}
这里定义了一个函数function(),参数是两个整型变量,返回值也是整型变量,当a的值大于b时返回a,否则返回b,很明显这个函数返回的是两个数中的较大数,然后在主函数中调用了这个函数,参数分别为1、2。编译后使用IDA进行分析,主函数的反汇编代码如下:
.text:00401020 push ebp .text:00401021 mov ebp, esp .text:00401023 push 2 ; b .text:00401025 push 1 ; a .text:00401027 call ?function@@YAHHH@Z ; function(int,int)
这里向栈中压入数据2和1,然后调用函数function(int,int)。可以猜想这样向堆栈里压入2和1就是在给被调用的过程传递参数了。这里要注意,传递参数的时候是反着来的,C语言里调用的时候是function(1, 2),等到反汇编的时候就变成先压入2,再压入1这样的了。
.
text:0040102C add esp, 8
这一句代码用来抬高栈顶,抬高栈顶是为了平衡栈桢,前面为了给被调用过程传递参数向栈中压入了两个四字节的int型变量,这里把栈顶抬高八个字节就是为了销毁传递参数的痕迹。
下面是function()函数在IDA中的分析结果:.text:0040102F xor eax, eax .text:00401031 pop ebp .text:00401032 retn
.text:00401000 ; Attributes: bp-based frame .text:00401000 .text:00401000 ; int __cdecl function(int a, int b) .text:00401000 ?function@@YAHHH@Z proc near ; CODE XREF: _main+7 p .text:00401000 .text:00401000 a = dword ptr 8 .text:00401000 b = dword ptr 0Ch .text:00401000
这里是对function()函数的参数、返回值、调用方式等信息的分析。这里说明了function()函数的调用方式为__cdecl,返回值是int型,两个参数a、b与ebp对应的偏移分别为0x08和0x0C。
.text:00401000 push ebp .text:00401001 mov ebp, esp .text:00401003 mov eax, [ebp+a] .text:00401006 cmp eax, [ebp+b] .text:00401009 jle short loc_401012 .text:0040100B mov eax, [ebp+a] .text:0040100E jmp short loc_401015 .text:00401010 jmp short loc_401015 .text:00401012 mov eax, [ebp+b] .text:00401015 pop ebp .text:00401016 retn .text:00401016 ?function@@YAHHH@Z endp
一般来说过程返回的结果都是储存在eax里的。这个函数比较两个参数a、b,如果参数a大于参数b则把参数a放到eax,跳到最后返回,如果参数a不大于参数b则把参数b放到eax中返回。