好友
阅读权限20
听众
最后登录1970-1-1
|
大喜
发表于 2023-1-1 20:26
实际上,可变参数的函数,在 ida 中显示,定义的参数个数和调用参数个数是可能不一样,比如我写以下代码:
[C] 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | void func( int arg1, ...)
{
va_list ptr;
va_start (ptr, arg1);
int first = va_arg (ptr, int );
int second = va_arg (ptr, int );
int third = va_arg (ptr, int );
va_end (ptr);
printf ( "1: %d, 2: %d, 3: %d\n" , first, second, third);
return ;
}
int main()
{
func(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
func(3,4,5);
return 0;
}
|
这个代码在 ida 中就会定义和调用时参数不一样。上面的代码 ida 在反编译的时候,会将func 函数的参数原型定义为 4 个参数,ida 会显示为 int __fastcall func(__int64 a1, unsigned int a2, unsigned int a3, unsigned int a4) , 因为我在里面直接操作了栈上的 4 个数据。但是,在调用的时候, ida 会显示 传入了 10 个参数, 因为 ida 解析到你往寄存器和栈压入了十个参数。实际上,如果你把代码写成这样
[C] 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 | int iadd( int cnt, ... )
{
int sum=0;
va_list args;
va_start (args,cnt);
for ( int i=0;i<cnt;i++)
{
sum += va_arg (args, int );
}
va_end (args);
return sum;
}
int main()
{
printf ( "%d\r\n" ,iadd(4,1,2,3,4));
return 0;
}
|
ida 就会很聪明的把函数iadd的原型写成 __int64 iadd(int a1, ...){}
反编译的代码是从 汇编 推断出来的,ida 会根据你的汇编代码推断源代码,虽然由于一些反编译的手段或者时一些意外的错误,它会出错。
你这个地方,你应该看到有一条堆栈不平衡的报错 ,因为反编译出来的函数的参数列表是根据堆栈推断出来的,在这个时候,ida 可能会把局部变量和参数搞混,导致输出的参数与实际参数数量不一致,显示出来就是错误的结果。
所以,如果遇到这种情况,你就应该开始分析汇编代码,根据汇编代码判断程序的真实逻辑,所以,需要你了解函数调用约定。 cdecl stdcall fastcall ,根据每一种调用约定的传递方式分析程序的逻辑。当然,如果你能定位到被调用函数的位置,那么你可以结合被调用函数的代码一起分析,会更容易。 |
|