Function 如何知道一个函数有多少个参数?

Function 如何知道一个函数有多少个参数?,function,assembly,x86,arguments,disassembly,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 据我所知,子ESP,C意味着函数的所有参数都需要12个字节,对吗?每个参数都是4字节的,有4个参数,所以这个函数不应该被反汇编为子ESP,10 另外,如果我不知道函数的C头,我如何知道每个参数的大小(不是所有参数的大小)?这取决于您的ABI

我有这个功能:

BOOL WINAPI MyFunction(WORD a, WORD b, WORD *c, WORD *d)
分解时,我得到如下结果:

PUSH EBP
MOV ESP, EBP
SUB ESP, C
...
LEAVE
RETN C
据我所知,
子ESP,C
意味着函数的所有参数都需要12个字节,对吗?每个参数都是4字节的,有4个参数,所以这个函数不应该被反汇编为
子ESP,10


另外,如果我不知道函数的C头,我如何知道每个参数的大小(不是所有参数的大小)?

这取决于您的ABI。 在您的例子中,似乎您正在使用Windowsx86(32位),它允许几种C调用约定。一些在寄存器中传递参数,另一些在堆栈上传递参数。 如果参数在堆栈上传递,则它们将位于帧指针上方,因此从堆栈指针中减去参数将用于为局部变量留出空间,而不是读取函数参数。

这取决于您的ABI。 在您的例子中,似乎您正在使用Windowsx86(32位),它允许几种C调用约定。一些在寄存器中传递参数,另一些在堆栈上传递参数。
如果参数在堆栈上传递,则它们将位于帧指针上方,因此从堆栈指针中减去参数将用于为局部变量留出空间,而不是读取函数参数。

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


在WINAPI函数(又称uu stdcall)的特定情况下,RET指令会提供信息,因为调用约定要求函数在返回堆栈之前清理堆栈。因此RET 0x0C告诉您参数需要12个字节。否则,可能会与堆栈帧大小意外匹配。这通常意味着它需要3个参数,这取决于参数类型。字号参数将升级为32位值,因此您理论化的签名不匹配。

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


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

如果约定调用使用堆栈(看起来)传递参数,您可以计算出有多少个参数以及它们的大小

对于“多少”,可以查看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 char
short/unsigned short

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


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

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

对于“多少”,可以查看RET指令的操作数(如果有)(stdcall约定)。这将给出参数正在使用的字节数。当然,这些数据本身并没有多大用处

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

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

对于尺寸和类型,需要更多的逆向工程。查看使用寻址参数的说明。如果你找到什么,李