打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
【新提醒】[教程]逆向反汇编第三课

说完利用堆栈传递参数了,下面该说说使用寄存器传递参数的话题了.寄存器传递传输的方式并没有一个标准,所有与平台相关的方法都是由IDE(也就是编译器)开发人员制定的.尽管没有统一的标准,但绝大多数编译器提供商都在不对兼容性声明的情况下,遵循相应的规范,吉fastcall规范._fastcall顾名思义,特点就是快,因为他是靠寄存器来传递参数的.
不同编译器实现的fastcall稍有不同,如Microsoft Visual C++编译器采用fastcall规范传递参数时,最左边的两个不大于4个字节(DWORD)的参数分别放在ecx和edx寄存器.当寄存器用完后,就要使用堆栈,其余参数仍然按照从右到左的顺序压入堆栈,被调用的函数在返回前清理传送参数的堆栈.浮点值员指针和int64类型总是通过对战来传递的.而Borland Delphi/C++编译器总是通过将寄存器来传递参数的,其最左边的三个不大于4个字节(DWORD)的参数分别放在eax edx 和 ecx寄存器,寄存器用完后,参数按照从左到右的PASCAL方式来压栈.另外一款编译器Watcom C总是通过寄存器来传递参数的,严格为每一个参数分配一个寄存器,默认时第一个参数用eax,第二个参数用edx,第三个参数用ebx,第四个参数用 ecx,如果寄存器用完了,就会用堆栈来传递参数.Watcom C可以由程序员指定任意一个寄存器传递参数,因此,其参数实际上可能通过任何寄存器进行传递.
来看一个手动指定fastcall调用参数的实例:
C源码如下:

欢迎来到Bysimont编程技术论坛学习 www.bysimont.com 因你而精彩
  1. int _fastcall Add(char,long,int,int);
  2. main(void)
  3. {
  4. Add(1,2,3,4);
  5. return 0;
  6. }
  7. int _fastcall Add(char a,long b,int c,int d);
  8. {
  9. return (a+b+c+d);
  10. }

这个反汇编后的代码

欢迎来到Bysimont编程技术论坛学习 www.bysimont.com 因你而精彩
  1. 00401000 /$ 55 push ebp
  2. 00401001 |. 8BEC mov ebp, esp
  3. 00401003 |. 6A 04 push 4 ; 后面两个参数从右到左入栈,先压入a
  4. 00401005 |. 6A 03 push 3 ; 再将第三个参数数值3入栈
  5. 00401007 |. BA 02000000 mov edx, 2 ; 再将第二个参数数值2放入edx
  6. 0040100C |. B1 01 mov cl, 1 ; 传递第一个参数(字符类型的变量是8位大小)
  7. 0040100E |. E8 04000000 call fastcall.00401017 ; 调用Add()函数
  8. 00401013 |. 33C0 xor eax, eax
  9. 00401015 |. 5D pop ebp
  10. 00401016 /. C3 retn
  11. 00401017 /$ 55 push ebp
  12. 00401018 |. 8BEC mov ebp, esp
  13. 0040101A |. 83EC 08 sub esp, 8 ; 为局部变量分配8个字节
  14. 0040101D 8955 F8 mov dword ptr ss:[ebp-8], edx ; 第二个参数放到局部变量[ebp-08]中
  15. 00401020 884D FC mov byte ptr ss:[ebp-4], cl ; 第一个参数放到局部变量[ebp-4]中
  16. 00401023 |. 0FBE45 FC movsx eax, byte ptr ss:[ebp-4] ; 将字符型数据扩展成一个双字
  17. 00401027 |. 0345 F8 add eax, dword ptr ss:[ebp-8] ; 将左边2个参数相加
  18. 0040102A |. 0345 08 add eax, dword ptr ss:[ebp+8] ; 相加之后的和(放到eax中)再加第三个参数
  19. 0040102D |. 0345 0C add eax, dword ptr ss:[ebp+C] ; 最后再将eax的结果加上第四个参数
  20. 00401030 |. 8BE5 mov esp, ebp
  21. 00401032 |. 5D pop ebp
  22. 00401033 /. C2 0800 retn 8

另一个调用规范thiscall也用到了寄存器传递参数.thiscall是C++中的非静态类成员函数的默认调用约定,对象的每个函数隐含接受this 参数.采用thiscall约定时,函数参数按照从右到左的顺序入栈,被调用的函数在返回前清理传送参数的栈,只是另外通过寄存器ecx传送一个额外的参数:this指针.
定义一个类,并在类中定义一个成员函数:

欢迎来到Bysimont编程技术论坛学习 www.bysimont.com 因你而精彩
  1. class CSun
  2. {
  3. public:
  4. int Add(int a,int b) //实际Add原型如下形式:Addd(this,int a,intb)
  5. {
  6. return (a+b)
  7. }
  8. };
  9. void main()
  10. {
  11. CSum sum;
  12. sum.Add(1,2);
  13. }
  14. 看看他反汇编后的代码:
  15. [code]
  16. 00401004 |. 6A 02 push 2 ; 传递第三个参数
  17. 00401006 |. 6A 01 push 1 ; 传递第二个参数
  18. 00401008 |. 8D4D FC lea ecx, dword ptr ss:[ebp-4] ; this指针通过ECX寄存器传递
  19. 0040100B |. E8 10000000 call VF.00401020 ; 调用函数sum.Add(1,2)
  20. 00401010 |. 8BE5 mov esp, ebp
  21. 00401012 |. 5D pop ebp
  22. 00401013 /. C3 retn
  23. sum.Add()函数实现部分反汇编代码:
  24. 00401020 /$ 55 push ebp
  25. 00401021 |. 8BEC mov ebp, esp
  26. 00401023 |. 51 push ecx
  27. 00401024 |. 894D FC mov dword ptr ss:[ebp-4], ecx
  28. 00401027 |. 8B45 08 mov eax, dword ptr ss:[ebp+8]
  29. 0040102A |. 0345 0C add eax, dword ptr ss:[ebp+C]
  30. 0040102D |. 8BE5 mov esp, ebp
  31. 0040102F |. 5D pop ebp
  32. 00401030 /. C2 0800 retn 8

我就不过多分析了,和前面差不多.

欢迎来到Bysimont编程技术论坛学习 www.bysimont.com 因你而精彩
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
C语言中函数参数入栈的顺序
_cdecl 和_stdcall
函数调用约定与函数名称修饰规则(一)
带你玩转Visual Studio——调用约定__cdecl、__stdcall和__fastcall
C语言函数调用栈(二)
linux内核中的fastcall和asmlinkage宏
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服