?
类delete就不说了,有兴趣的朋友自己跟踪看看吧,提示一下:析构函数也有参数和返回值.
?
下面我们看下裸函数,裸函数从执行效率上是可以与汇编语言媲美的,然而它不太好逆过来说,我们就顺着说吧
前面说得构造函数的临时堆栈,恢复寄存器等等,有人给了个名称叫prolog和epilog
而裸函数并没有自动编译这些部分,其实说白了,裸函数相当于汇编语言中的一个标签,其调用受前面几种约定约束
此外空的裸函数是什么都不做的,非必要的不做,必要的也不做,就是什么都要自己实现,其实就是要自己汇编
当然了,裸函数不能是类的成员函数,举例中我们使用__cdecl约定,直接照搬fnDefaultCall的,不管执行效率
?
132: ret = fnNakedCall(19, 20, 21, &var1); 00401428 lea edx,[ebp-14h] 0040142B push edx 0040142C push 15h 0040142E push 14h 00401430 push 13h 00401432 call @ILT+15(fnNakedCall) (00401014) 00401437 add esp,10h 0040143A mov dword ptr [ebp-18h],eax 133:可以看出调用约定符合__cdecl的约定,那么跟踪一下看看:
?
?
68:
69: __declspec(naked) int __cdecl fnNakedCall(int arg1, short arg2, char arg3, void *arg4)
70: {
004012D0 push ebp
71: // 1. 到这里所有寄存器的值与调用前一样
72: // 2. 用变量名引用任何局部变量等同于引用主调函数变量或参数
73: // 3. 必须负责寄存器的维护, 这里函数作为__cdecl
74: __asm{
75: push ebp ; prolog begin
76: mov ebp, esp
004012D1 mov ebp,esp
77: sub esp, 50h
004012D3 sub esp,50h
78: push ebx
004012D6 push ebx
79: push esi
004012D7 push esi
80: push edi
004012D8 push edi
81: lea edi, [ebp-50h]
004012D9 lea edi,[ebp-50h]
82: mov ecx, 14h
004012DC mov ecx,14h
83: mov eax, 0CCCCCCCCh
004012E1 mov eax,0CCCCCCCCh
84: rep stos dword ptr [edi] ; prolog end
004012E6 rep stos dword ptr [edi]
85:
86: // var1 = arg1;
87: mov eax, dword ptr [ebp + 8] ; [esp + 8]
004012E8 mov eax,dword ptr [ebp+8]
88: mov dword ptr [ebp-4], eax ; [esp - 4]
004012EB mov dword ptr [ebp-4],eax
89: // var2 = arg2;
90: mov cx, word ptr [ebp + 0Ch]
004012EE mov cx,word ptr [ebp+0Ch]
91: mov word ptr [ebp - 8], cx
004012F2 mov word ptr [ebp-8],cx
92: // var3 = arg3;
93: mov dl, byte ptr [ebp + 10h]
004012F6 mov dl,byte ptr [ebp+10h]
94: mov byte ptr [ebp - 0Ch], dl
004012F9 mov byte ptr [ebp-0Ch],dl
95: // p = (int *)arg4;
96: mov eax, dword ptr [ebp + 14h]
004012FC mov eax,dword ptr [ebp+14h]
97: mov dword ptr [ebp - 10h], eax
004012FF mov dword ptr [ebp-10h],eax
98: // *p = -1;
99: mov ecx, dword ptr [ebp - 10h]
00401302 mov ecx,dword ptr [ebp-10h]
100: mov dword ptr [ecx], 0FFFFFFFFh
00401305 mov dword ptr [ecx],0FFFFFFFFh
101: // return 22;
102: mov eax, 16h ; 0x16 = 22
0040130B mov eax,16h
103:
104: pop edi ; epilog begin
00401310 pop edi
105: pop esi
00401311 pop esi
106: pop ebx
00401312 pop ebx
107: mov esp, ebp
00401313 mov esp,ebp
108: pop ebp ; epilog end
00401315 pop ebp
109: // return to caller function(do not use ret 10h)
110: ret
00401316 ret
--- No source file --------------------------------------------------------------
00401317 int 3 虽然复制过来有点错位,不过不难看出,我们的汇编代码被照搬了,用曾泰的话说:丝毫不差.
?
这就意味着,我们只要保证寄存器调用后符合调用约定,此外就可以为所欲为了
我不希望大家堕入哲学的深渊,不过我只能用这样的语句来描述:
什么都要自己做和什么都能自己做,往往是一回事,这就是辩证.
?
还记得前面说的fastcall中变量被存来存去吗,嘿嘿,用naked就可以避免,实现真正的fastcall
此外,一些常用的内联汇编的函数,也可以用这种方式输出,当然了,需要具备一定的汇编语言基础
再如,我们可以连堆栈都不构造,直接使用esp代替ebp,即省去prolog和epilog.
?
文章似乎到这里就结束了,那么知道这些有什么用呢?如果你有这样的想法,那就再好不过了,通常人知道了也就知道了
能有这样的想法,说明有学以致用的习惯或者说性格.
那么,我们就试着提出几个用处吧:
?
1. 提升调试程序的能力,更深入的找出BUG的根源,并得出更深一层的解决方法
比如莫名其妙的崩溃,缓冲区溢出,还有这种:

?
2.提升程序开发水平,比如常用的strcpy,memset等等函数,应该自己写,更好的发挥机器的性能,
法国一个科学家,用一台普通的计算机计算圆周率,其效率居然可以与一台超级计算机相媲美
单靠数学是无法完成这样的工作的.他必然对计算机的指令架构十分熟悉
?
3.对逆向和软件加密有一定程度的认知
比如单单知道eax作为返回值这一点,你就该认识到,仅用一个函数去做授权验证是很容易绕过的!
既然能想到绕过别人程序的办法,就应该想出防止别人简单绕过的方案
实际的软件加密和破解虽然并没有那么简单,不过起码有这样的一个认知,
?
说起破解,我到还想再废话一下,有些学习破解的朋友,反汇编出来,修改指令,就认为天下的软件就这么干就能破解了
对软件行业充满了失落感,那么我们来举个例子:
使用OD载入一个程序