__declspec(naked)和__asm编写实践总结

__cdecl 和 __stdcall 压栈参数顺序是一致的,但平衡堆栈方式不一样。

__cdecl调用函数方式是调用者,即函数外部平衡堆栈,一般是在函数外部调用add esp, xxxx,函数内部只需要ret返回就行

__stdcall调用函数方式是被调用,即函数内部平衡堆栈,一般在函数内部结束的时候调用ret xxx或者add esp,xxxx ; ret

在vs2005里面C++工程默认都是__cdecl,所以需要外部平衡堆栈

 

看一个实例,本来__asm里面本来原意会去取函数参数,并打印出来

 

    

但经过编译过后,汇编代码如下:

Release版本

 

00401000 > .  56              push esi                                                            ; {
00401001   .  8B35 A4204000   mov esi,dword ptr ds:[<&MSVCR80.printf>]  
00401007   .  68 F4204000     push huibianT.004020F4
0040100C   .  FFD6            call esi
0040100E   .  83C4 04         add esp,4
00401011   .  50              push eax
00401012   .  8B4424 04       mov eax,dword ptr ss:[esp+4]
00401016   .  A3 7C334000     mov dword ptr ds:[__native_startup_lockonement],eax
0040101B   .  8B4424 08       mov eax,dword ptr ss:[esp+8]
0040101F   .  A3 78334000     mov dword ptr ds:[__native_startup_stateeement],eax
00401024   .  8B4424 0C       mov eax,dword ptr ss:[esp+C]
00401028   .  A3 74334000     mov dword ptr ds:[_adjust_fdivlestatussonement],eax
0040102D   .  58              pop eax
0040102E   .  A1 74334000     mov eax,dword ptr ds:[_adjust_fdivlestatussonement]
00401033   .  8B0D 78334000   mov ecx,dword ptr ds:[__native_startup_stateeement]
00401039   .  8B15 7C334000   mov edx,dword ptr ds:[__native_startup_lockonement]
0040103F   .  50              push eax
00401040   .  51              push ecx
00401041   .  52              push edx
00401042   .  68 F8204000     push huibianT.004020F8
00401047   .  FFD6            call esi
00401049   .  68 10214000     push huibianT.00402110

0040104E   .  FF15 9C204000   call dword ptr ds:[<&MSVCR80.system>]
00401054   .  83C4 14         add esp,14
00401057   .  33C0            xor eax,eax 

00401059 > .  5E              pop esi 

0040105A   .  C3              retn

 

Release版本优化过后函数参数不知去向。

而Debug版本的TestMy函数内部的esp已经早就破坏了,[esp+0x08]已经不再表示第一个参数。


00411449    53                push ebx
0041144A    56                push esi
0041144B    57                push edi
0041144C    8DBD 40FFFFFF     lea edi,dword ptr ss:[ebp-C0]
00411452    B9 30000000       mov ecx,30
00411457    B8 CCCCCCCC       mov eax,CCCCCCCC
0041145C    F3:AB             rep stos dword ptr es:[edi]
0041145E    8BF4              mov esi,esp
00411460    68 40574100       push huibianT.00415740
00411465    FF15 C8824100     call dword ptr ds:[<&MSVCR80D.printf>]
0041146B    83C4 04           add esp,4
0041146E    3BF4              cmp esi,esp
00411470    E8 DAFCFFFF       call huibianT.0041114F
00411475    50                push eax
00411476    8B4424 04         mov eax,dword ptr ss:[esp+4]
0041147A    A3 EC744100       mov dword ptr ds:[vEsp2ggerListeningIPTORWe>::NativeDll::ProcessVer>
0041147F    8B4424 08         mov eax,dword ptr ss:[esp+8]
00411483    A3 E8744100       mov dword ptr ds:[argc1ggerListeningIPTORWe>::NativeDll::ProcessVer>
00411488    8B4424 0C         mov eax,dword ptr ss:[esp+C]                                       
0041148C    A3 E4744100       mov dword ptr ds:[argc2ggerListeningIPTORWe>::NativeDll::ProcessVer>
00411491    58                pop eax
00411492    8BF4              mov esi,esp
00411494    A1 E4744100       mov eax,dword ptr ds:[argc2ggerListeningIPTORWe>::NativeDll::Proces>
00411499    50                push eax
0041149A    8B0D E8744100     mov ecx,dword ptr ds:[argc1ggerListeningIPTORWe>::NativeDll::Proces>
04114A0    51                push ecx
004114A1    8B15 EC744100     mov edx,dword ptr ds:[vEsp2ggerListeningIPTORWe>::NativeDll::Proces>
004114A7    52                push edx
004114A8    68 A8574100       push huibianT.004157A8
004114AD    FF15 C8824100     call dword ptr ds:[<&MSVCR80D.printf>]
004114B3    83C4 10           add esp,10
004114B6    3BF4              cmp esi,esp
004114B8    E8 92FCFFFF       call huibianT.0041114F
004114BD    5F                pop edi
004114BE    5E                pop esi
004114BF    5B                pop ebx
004114C0    81C4 C0000000     add esp,0C0
004114C6    3BEC              cmp ebp,esp
004114C8    E8 82FCFFFF       call huibianT.0041114F
004114CD    8BE5              mov esp,ebp
004114CF    5D                pop ebp
004114D0    C3                retn

 

 当使用__declspec(naked)调用约定的时候,如下面

 

 

需要注意的是使用这样约定调用的时候,函数内部不会帮你处理堆栈,需要你自己来处理,也就是说不会帮你ret,需要你自己来操作。但可以内部调用其他函数,而且会帮你的其他函数平衡好堆栈,即ebp和esp不会因为操作这些函数而改变,只有当你用__asm里面进行对其进行操作,才会改变。因为默认是__cdecl,所以我处理返回是ret。 另外我这里故意将内部临时变量从static int 变为 int,发现ebp和esp也并没有做改变。汇编代码如下:

Debug版本

 

00411440 >  8BF4              mov esi,esp                                        ; {
00411442    68 40574100       push huibianT.00415740
00411447    FF15 C8824100     call dword ptr ds:[<&MSVCR80D.printf>]
0041144D    83C4 04           add esp,4
00411450    3BF4              cmp esi,esp
00411452    E8 F8FCFFFF       call huibianT.0041114F
00411457    50                push eax                                                            ; push eax
00411458    8B4424 04         mov eax,dword ptr ss:[esp+4]                     ; mov eax, [esp + 0x04]
0041145C    8945 F8           mov dword ptr ss:[ebp-8],eax                       ; mov vEsp, eax
0041145F    8B4424 08         mov eax,dword ptr ss:[esp+8]                      ; mov eax, [esp + 0x08]
00411463    8945 EC           mov dword ptr ss:[ebp-14],eax                      ; mov argc1, eax
00411466    8B4424 0C         mov eax,dword ptr ss:[esp+C]                      ; mov eax,[esp + 0x0C]
0041146A    8945 E0           mov dword ptr ss:[ebp-20],eax                      ; mov argc2, eax
0041146D    58                pop eax                                                               ; pop eax
0041146E    8BF4              mov esi,esp                                                 
00411470    8B45 E0           mov eax,dword ptr ss:[ebp-20]
00411473    50                push eax
00411474    8B4D EC           mov ecx,dword ptr ss:[ebp-14]
00411477    51                push ecx
00411478    8B55 F8           mov edx,dword ptr ss:[ebp-8]
0041147B    52                push edx
0041147C    68 A8574100       push huibianT.004157A8
00411481    FF15 C8824100     call dword ptr ds:[<&MSVCR80D.printf>]
00411487    83C4 10           add esp,10
0041148A    3BF4              cmp esi,esp
0041148C    E8 BEFCFFFF       call huibianT.0041114F
00411491    C3                retn                                               

 

当我想对函数内部的int变量赋值的时候,发现会报错,看来这种调用约定是严格保护了ebp和esp的。

那么Release版本优化会不会改变ebp和esp的值呢

 

00401000 >/$  8B35 A4204000   mov esi,dword ptr ds:[<&MSVCR80.printf>]                            
00401006  |.  68 F4204000     push huibianT.004020F4
0040100B  |.  FFD6            call esi
0040100D  |.  83C4 04         add esp,4
00401010  |.  50              push eax                                                                   ; push eax
00401011  |.  8B4424 04       mov eax,dword ptr ss:[esp+4]                                        ; mov eax, [esp + 0x04]
00401015  |.  8945 F8         mov [local.2],eax                                                   ; mov vEsp, eax
00401018  |.  8B4424 08       mov eax,dword ptr ss:[esp+8]                                        ; mov eax, [esp + 0x08]
0040101C  |.  8945 FC         mov [local.1],eax                                                   ; mov argc1, eax
0040101F  |.  8B4424 0C       mov eax,dword ptr ss:[esp+C]                                        ; mov eax,[esp + 0x0C]
00401023  |.  8945 F4         mov [local.3],eax                                                   ; mov argc2, eax
00401026  |.  58              pop eax                                                                     ; pop eax
00401027  |.  8B45 F4         mov eax,[local.3]                                                   ; printf("%x  --   %d  --  %d /n",vEsp, argc1, argc2);
0040102A  |.  8B4D FC         mov ecx,[local.1]
0040102D  |.  8B55 F8         mov edx,[local.2]
00401030  |.  50              push eax
00401031  |.  51              push ecx
00401032  |.  52              push edx
00401033  |.  68 F8204000     push huibianT.004020F8
00401038  |.  FFD6            call esi
0040103A  |.  83C4 10         add esp,10
0040103D  /.  C3              retn                                                                

 

可以看到ebp和esp都保护得相当完美。

 

现在基本可以得到结论:

在没有__declspec(naked)调用约定的函数内部操作esp和ebp是不安全的。

而在有__declspec(naked)需要自己维护堆栈,但调用其他自己的函数,堆栈不会受影响

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值