__declspec(naked)和__asm编写实践总结
__cdecl 和 __stdcall 壓棧參數順序是一致的,但平衡堆棧方式不一樣。
__cdecl調用函數方式是調用者,即函數外部平衡堆棧,一般是在函數外部調用add esp, xxxx,函數內部只需要ret返回就行
__stdcall調用函數方式是被調用,即函數內部平衡堆棧,一般在函數內部結束的時候調用ret xxx或者add esp,xxxx ; ret
在vs2005里面C++工程默認都是__cdecl,所以需要外部平衡堆棧
?
看一個實例,本來__asm里面本來原意會去取函數參數,并打印出來
?
?//__declspec(naked) void TestMy(int c, int d) {__noop("good morning");printf("hi/n");static int vEsp, argc1, argc2;__asm{push eaxmov eax, [esp + 0x04]mov vEsp, eaxmov eax, [esp + 0x08]mov argc1, eaxmov eax,[esp + 0x0C]mov argc2, eaxpop eax}printf("%x -- %d -- %d /n",vEsp, argc1, argc2);//__asm//{// ret//} }int _tmain(int argc, _TCHAR* argv[]) {int argc1 = 1;int argc2 = 2;TestMy(argc1, argc2);system("pause");return 0; }???
但經過編譯過后,匯編代碼如下:
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)調用約定的時候,如下面
?
__declspec(naked) void TestMy(int c, int d) {__noop("good morning");printf("hi/n");int vEsp, argc1, argc2;__asm{push eaxmov eax, [esp + 0x04]mov vEsp, eaxmov eax, [esp + 0x08]mov argc1, eaxmov eax,[esp + 0x0C]mov argc2, eaxpop eax}printf("%x -- %d -- %d /n",vEsp, argc1, argc2);__asm{ret} }int _tmain(int argc, _TCHAR* argv[]) {int argc1 = 1;int argc2 = 2;TestMy(argc1, argc2);system("pause");return 0; }
?
需要注意的是使用這樣約定調用的時候,函數內部不會幫你處理堆棧,需要你自己來處理,也就是說不會幫你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)需要自己維護堆棧,但調用其他自己的函數,堆棧不會受影響
總結
以上是生活随笔為你收集整理的__declspec(naked)和__asm编写实践总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: matlab 数值格式转换,Matlab
- 下一篇: Git 忽略编译后文件