如何知道有多少参数需要函数?

时间:2014-01-18 23:06:42

标签: function assembly x86 arguments disassembly

我有这个功能:

BOOL WINAPI MyFunction(WORD a, WORD b, WORD *c, WORD *d)

拆解时,我会得到类似的东西:

PUSH EBP
MOV ESP, EBP
SUB ESP, C
...
LEAVE
RETN C

据我所知,SUB ESP, C意味着该函数的所有参数都需要12个字节,对吧?每个参数都是4个字节,并且有4个参数,所以不应该将此函数反汇编为SUB ESP, 10吗?

另外,如果我不知道函数的C头,我怎么知道每个参数的大小(不是 all 参数的大小)?

3 个答案:

答案 0 :(得分:3)

不,SUB指令只告诉您该函数需要12个字节用于其局部变量。推断参数需要查看调用此函数的代码。您将看到它在CALL指令之前设置堆栈。

在WINAPI函数(又名__stdcall)的特定情况下,RET指令为您提供信息,因为调用约定要求函数在返回之前清理堆栈。所以RET 0x0C告诉你参数需要12个字节。否则意外匹配堆栈框架大小。哪个通常意味着它需要3个参数,它取决于参数类型。 WORD大小参数被提升为32位值,因此您理论化的签名不匹配。

答案 1 :(得分:1)

如果常规调用使用堆栈(看起来像)传递参数,您可以计算出参数的数量和大小。

对于“多少”,您可以查看RET指令的操作数(如果有)(stdcall约定)。这将为您提供参数使用的字节数。当然这个数据本身就没用多少了。

您必须阅读功能代码并搜索此类[EBP + n]的内存引用,其中n是与EBP值的正偏移量。正偏移是寻址参数,负偏移是寻址局部变量(使用SUB ESP,x指令创建)

希望您能够发现所有不同的参数。如果该函数已经符合优化,则可能很难理解。

对于尺寸和类型,需要更多逆向工程。查看使用已寻址参数的说明。如果您找到类似dword ptr [ebp+n]的内容,则该参数为32位长。 word ptr [ebp+n]告诉您参数是16位长,byte ptr [ebp+n]表示字节大小参数。

对于字节和字大小的参数,最合理的选项是char/unsigned charshort/unsigned short

对于双字大小的参数,type可以是int/unsigned int/long/unsigned long,但它也可以是指针。要区分指针和普通整数,你必须进一步查看,看看从参数读取的dword是否被用作访问内存的内存地址(即它被解除引用)。

要告诉参数的有效性,您必须搜索将特定参数与其他值进行比较的代码片段,然后发出条件跳转。跳转中使用的特定条件将告诉您是否进行了比较是否考虑了符号。例如:与JA / JB / JAE / JBE条件跳转的比较表示无符号比较,因此表示无符号参数。 JG / JE / JGE / JLE的条件跳转表示比较中涉及的已签名参数。

答案 2 :(得分:0)

这取决于你的ABI。 在您的情况下,似乎您正在使用Windows x86(32位),它允许多个C调用约定。有些在寄存器中传递参数,有些则在堆栈中传递。 如果参数在堆栈上传递,它们将高于帧指针,因此从堆栈指针中减去用于为局部变量腾出空间,而不是读取函数参数。