VC反汇编笔记一
对几个最基础的c++和对应的反汇编罗列了下,有的有简要注释,没注释的是一些常规形态。挂在网上,随时方便参考回顾。看的时候可以参考上一篇《函数反汇编之函数创建和恢复现场》
http://www.cppblog.com/flyindark/archive/2012/01/09/163895.html
1 堆栈上分配内存
本质是在ES上分配一个空间,并用一个标识符表示起始的地址(这里是string),然后初始化的时候将常量区的内容复制到这个分配的空间上。这个ES堆栈空间用BP、SP定位。
![](/images/cppblog_com/flyindark/VC反汇编笔记/one堆栈上分配内存.png)
2 常量空间和堆栈空间
![](/images/cppblog_com/flyindark/VC反汇编笔记/2常量空间和堆栈空间.png)
3 /GS开关
3.1 SOURCE
__security_cookie
http://msdn.microsoft.com/en-us/library/ms235362(v=vs.80).aspx
/GS (Buffer Security Check)
http://msdn.microsoft.com/en-us/library/8dbf701c(v=VS.80).aspx
Detects some buffer overruns that overwrite the return address, a common technique for exploiting code that does not enforce buffer size restrictions. This is achieved by injecting security checks into the compiled code.
/GS(缓冲区安全检查)
http://msdn.microsoft.com/zh-cn/library/8dbf701c(v=vs.90).aspx
检测某些覆盖返回地址的缓冲区溢出,这是一种利用不强制缓冲区大小限制的代码的常用技术。这是通过将安全检查插入到已编译代码中完成的。
/Gs (Control Stack Checking Calls)
http://msdn.microsoft.com/en-US/library/9598wk25(v=vs.80).aspx
Controls stack probes.
/Gs(控制堆栈检查调用)
http://msdn.microsoft.com/zh-cn/library/9598wk25(v=vs.90).aspx
控制堆栈探测。
check_stack
http://msdn.microsoft.com/zh-cn/library/ybwsy5f9(v=vs.90).aspx
Instructs the compiler to turn off stack probes if off (or –) is specified, or to turn on stack probes if on (or +) is specified.
注意大小写,GS和Gs是不一样的,中文文档里有些小错误,关闭GS掉了“-”。
编译器进行判断的,像函数里定义了char数组,后面又用字符串操作函数进行了一定的操作,就说明
可能存在溢出。编译器在编译这个函数里的时候就加上security cookie的保护。
GS默认是开
/GS |
/GS- |
![](/images/cppblog_com/flyindark/VC反汇编笔记/3GS开关1.png) |
![](/images/cppblog_com/flyindark/VC反汇编笔记/3GS开关-2.png) |
GS开后,编译器插了三行代码,目的是ebp-4放了一个4字节的保护数,防止向堆栈空间的string地址中写入时越界(当然是想当然的看法,具体细节还不是很清楚)。
4 堆栈变量分配空间初始化的区别
![](/images/cppblog_com/flyindark/VC反汇编笔记/4堆栈变量分配空间初始化的区别-1.png)
![](http://www.cppblog.com/images/cppblog_com/flyindark/VC反汇编笔记/4堆栈变量分配空间初始化的区别-2.png)
曾见过争论{0}与{}那个效率更高的;这个堆栈变量的初始化竟然要这么多指令,以后256以上的空间还是需要memset了,抑或听说release时编译器可能会优化了;
5 函数调用
5.1 现象快照
![](/images/cppblog_com/flyindark/VC反汇编笔记/5函数调用-2.png)
![](/images/cppblog_com/flyindark/VC反汇编笔记/5函数调用-3.png)
![](/images/cppblog_com/flyindark/VC反汇编笔记/5函数调用-1.png)
进入调用函数前
+ &string 0x001ff8dc char [6]*
+ &string2 0x001ff8d0 char * *
ebp 0x001ff8e8 unsigned long
esp 0x001ff7dc unsigned long
+ &x 0x001ff8c4 int *
+ &y 0x001ff8b8 int *
进入调用函数第一条指令
ebp 0x001ff8e8 unsigned long
esp 0x001ff7d0 unsigned long
+ &a 0x001ff7d4 int *
+ &b 0x001ff7d8 int *
5.2 总结
l 函数名是函数地址的标识符
l 参数地址是常量空间地址,例如这里的&string2、&x、&y、&a、&b。
l 参数是从右向左的顺序传递的,先处理倒数第一个参数
l 参数传值的时候折腾了下,先将常量传到标识符(y),然后将y传递到EAX,然后将EAX压栈。跟着是第一个参数x类似。
l 调用前的参数入栈后,参数所在的地址就是调用的函数的参数的标识符。这里就免得参数被多次赋值。
l 函数返回值放到EAX里了。
l 压入了2个int参数,返回后ESP要加8。
6 返回结构体
分析返回结构体的情形
6.1 简单结构体
![](http://www.cppblog.com/images/cppblog_com/flyindark/VC反汇编笔记/6简单结构体-2.png)