吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2198|回复: 7
收起左侧

[经验求助] 为什么IDA里的函数参数个数在定义时和调用时不一致

[复制链接]
longzai 发表于 2023-1-1 20:26
30吾爱币

比如上面这个WStrCatN函数调用时有5个参数,但是这个函数的定义却只有两个参数,请问是为什么呢

最佳答案

查看完整内容

实际上,可变参数的函数,在 ida 中显示,定义的参数个数和调用参数个数是可能不一样,比如我写以下代码: [mw_shl_code=c,true]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); retur ...

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

大喜 发表于 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 ,根据每一种调用约定的传递方式分析程序的逻辑。当然,如果你能定位到被调用函数的位置,那么你可以结合被调用函数的代码一起分析,会更容易。
大喜 发表于 2023-1-1 21:50
因为你看他的函数调用约定 是 fastcall ,本身支持可变参数的传递。跟 c函数 printf 一样
 楼主| longzai 发表于 2023-1-3 10:50
大喜 发表于 2023-1-1 21:50
因为你看他的函数调用约定 是 fastcall ,本身支持可变参数的传递。跟 c函数 printf 一样

我百度了一下,好像说fastcall是一种传递参数方式的约定.不过可以在调用时传递不同数量的参数吗,汇编语言层面怎么识别参数数量呢
大喜 发表于 2023-1-3 16:07
longzai 发表于 2023-1-3 10:50
我百度了一下,好像说fastcall是一种传递参数方式的约定.不过可以在调用时传递不同数量的参数吗,汇编语言 ...

函数参数数量,在编译时,是确定的,所以,函数调用约定实际上只是给编译器看的,编译器会根据参数数量操作,fastcall 会将参数尽可能用寄存器传递,其余的参数,压入栈。识别参数数量,其实是要根据参数进行判断,可变数量参数的函数至少拥有一个参数,例如 printf ,传递第一个参数为 “%d %d %d ”,那么,根据解析,后面还将有 3 个参数,函数会继续读取3个参数,如果你只传递了两个参数,它也将会继续读取,例如,printf("%d %d %d", a, b); 它同样会输出三个参数不过第三个 %d 输出的值是随机的。函数执行完毕之后,如果有压栈参数,那么会 pop 响应个数的栈来平衡栈
 楼主| longzai 发表于 2023-1-3 19:55
大喜 发表于 2023-1-3 16:07
函数参数数量,在编译时,是确定的,所以,函数调用约定实际上只是给编译器看的,编译器会根据参数数量操 ...

这里的参数数量不一致是不是有问题呢,因为这里已经是编译好的程序,只是用ida反编译成c语言.
按照你所说的编译后函数参数数量是确定的,我觉得ida在反编译的时候调用的地方应该去和定义的地方去保持一致
不知道我有没有理解错你的意思,以前没接触过这部分
大喜 发表于 2023-1-3 23:31
第一个代码,ida 会显示调用 func 函数的参数为  10 个,因为你往寄存器和栈压入了10个数据,按照 fastcall 的约定来看,你就是传递了 10 个参数。就好像你去超市买东西付款,你微信给了 100 块,那么我就有理由推断你买了100快的东西,但是,实际上,你可能只买了10块钱,但是你豪横,非要给 100,但是我推断的时候,确实看到你给了 100 。而你看有一个堆栈不平衡的错误,这个错误时 ida 发现分析出来的栈不对劲,所以,这个时候分卸的结果可能时错误的,就是说,你买了 10 块钱的东西,也只给了 10块钱,但是,我看的时候,看花眼了,觉得你给了 100 块
 楼主| longzai 发表于 2023-1-4 06:23
大喜 发表于 2023-1-3 23:31
第一个代码,ida 会显示调用 func 函数的参数为  10 个,因为你往寄存器和栈压入了10个数据,按照 fastcall ...

我懂了,谢谢.沙发说的很详细,不知道为什么之前看不到
返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2025-4-13 14:09

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表