原文出自:http://bbs.pediy.com/showthread.php?p=1183331
对于新手而言,汇编看着就头疼,更别提去OD什么东东了,我也正处于这个阶段。前两天看了《天书夜读》第一章关于main函数反汇编的解析,顿时有种茅塞顿开的感觉。再看起来汇编代码,虽然还是没有看C语言那么容易,但心情变得很轻松。这都是《天书夜读》的功劳。特此分享给菜菜同行。
目前我们写的最简单的Main函数如下:
代码:
#include "stdafx.h" int _tmain(int argc, _TCHAR* argv[]) { return 0; }
代码:
int _tmain(int argc, _TCHAR* argv[]) { 010C13A0 push ebp 010C13A1 mov ebp,esp 010C13A3 sub esp,0C0h 010C13A9 push ebx 010C13AA push esi 010C13AB push edi 010C13AC lea edi,[ebp-0C0h] 010C13B2 mov ecx,30h 010C13B7 mov eax,0CCCCCCCCh 010C13BC rep stos dword ptr es:[edi] return 0; 010C13BE xor eax,eax } 010C13C0 pop edi 010C13C1 pop esi 010C13C2 pop ebx 010C13C3 mov esp,ebp 010C13C5 pop ebp 010C13C6 ret
代码:
push ebp mov ebp,esp
代码:
xor eax,eax ret
代码:
lea edi,[ebp-0C0h]
代码:
mov ecx,30h mov eax,0CCCCCCCCh rep stos dword ptr es:[edi]
由于CPU的寄存器有限,而且操作寄存器会影响标志值,push作用是压栈,pop是退栈。即保存寄存器标志的值和寄存器本身的值,以便在函数调用完毕后恢复原有的标志值。这也是为什么我们见到在调用某个函数或者运行一个程序时,入口总是push一堆寄存器的东东,也就是这个原因。
通过上面的基础知识,我们来看看main函数的反汇编解释:
代码:
int _tmain(int argc, _TCHAR* argv[]) { 010C13A0 push ebp ;保存ebp,返回之前弹出,避免ebp被我们改动。push操作使esp减小,esp不变 010C13A1 mov ebp,esp ; ebp被用来保存这个函数执行前的esp的值,执行完毕后用ebp恢复esp ;原ebp值已经被压栈(位于栈顶),而新的ebp又恰恰指向栈顶 ;此时ebp寄存器就已经处于一个非常重要的地位,该寄存器中存储着栈中的一个地址(原ebp入栈后的栈顶) ;从该地址为基准,向上(栈底方向)能获取返回地址、参数值(假如main中有参数,“获取参数值”会比较容易理解 ;向下(栈顶方向)能获取函数局部变量值,而该地址处又存储着上一层函数调用时的ebp值 010C13A3 sub esp,0C0h ;把esp往上移动一个范围,等于在栈中开辟一片空间存储main函数的局部变量 ;由于冯诺依曼机是小端模式,所以sub操作可以理解为将esp栈顶减去,实际上是为栈增加空间 010C13A9 push ebx 010C13AA push esi 010C13AB push edi ;保存三个寄存器的值,待main结束恢复,原来的值被破坏有可能引起系统崩溃 010C13AC lea edi,[ebp-0C0h] ;把ebp-0c0h加载到edi中,目的是保存局部变量的区域 010C13B2 mov ecx,30h 010C13B7 mov eax,0CCCCCCCCh 010C13BC rep stos dword ptr es:[edi] ;从ebp-0c0h开始的局部变量空间区域初始化成全部0CCCCCCCCh(也就是int 3中断指令的机器码) ;局部变量不可能被执行,执行了就会出错。这样发生意外时执行堆栈里面的内容会引发调试中断提示开发者 return 0; 010C13BE xor eax,eax ; 返回值将放在eax返回(这就是很多软件给秒杀爆破的原因,因为eax的返回值是可以改的) } 010C13C0 pop edi 010C13C1 pop esi 010C13C2 pop ebx ; 恢复原来寄存器的值,怎么“吃”进去,怎么“吐”出来 010C13C3 mov esp,ebp ;恢复ESP栈顶指针 010C13C5 pop ebp ;恢复ebp,也就是恢复调用main函数之前各个寄存器的状态 010C13C6 ret ;将返回地址存入eip,退出主函数
参考资料:
代码:
《天数夜读:从汇编语言到windows内核编程》第一章 反汇编代码分析--函数调用 http://blog.csdn.net/dolphin98629/article/details/6047665 C语言中一个最简main函数的反汇编代码的困惑 http://tieba.baidu.com/p/1184907086