从汇编看一个小程序的完整执行过程

用VS建立工程,写一个C文件。

代码如下:

 

  

 

这个小程序是怎样执行的呢,两个赋值的区别在于什么地方?调试一下!

 

反汇编可以看到代码如下:

#include <stdio.h>
void main()
{

012C13A0  push        ebp 
012C13A1  mov         ebp,esp
012C13A3  sub         esp,0F0h
012C13A9  push        ebx 
012C13AA  push        esi 
012C13AB  push        edi 
012C13AC  lea         edi,[ebp-0F0h]
012C13B2  mov         ecx,3Ch
012C13B7  mov         eax,0CCCCCCCCh
012C13BC  rep stos    dword ptr es:[edi]
012C13BE  mov         eax,dword ptr [___security_cookie (12C7000h)]
012C13C3  xor         eax,ebp
012C13C5  mov         dword ptr [ebp-4],eax
char a = 1;
012C13C8  mov         byte ptr [ebp-9],1
char c[] = "1234567890";
012C13CC  mov         eax,dword ptr [string "1234567890" (12C573Ch)]
012C13D1  mov         dword ptr [ebp-20h],eax
012C13D4  mov         ecx,dword ptr ds:[12C5740h]
012C13DA  mov         dword ptr [ebp-1Ch],ecx
012C13DD  mov         dx,word ptr ds:[12C5744h]
012C13E4  mov         word ptr [ebp-18h],dx
012C13E8  mov         al,byte ptr ds:[012C5746h]
012C13ED  mov         byte ptr [ebp-16h],al
char *p ="1234567890";
012C13F0  mov         dword ptr [ebp-2Ch],offset string "1234567890" (12C573Ch)
a = c[1];
012C13F7  mov         al,byte ptr [ebp-1Fh]
012C13FA  mov         byte ptr [ebp-9],al
a = p[1];
012C13FD  mov         eax,dword ptr [ebp-2Ch]
012C1400  mov         cl,byte ptr [eax+1]
012C1403  mov         byte ptr [ebp-9],cl
}
012C1406  xor         eax,eax
012C1408  push        edx 
012C1409  mov         ecx,ebp
012C140B  push        eax 
012C140C  lea         edx,[ (12C142Ch)]
012C1412  call        @ILT+130(@_RTC_CheckStackVars@8) (12C1087h)
012C1417  pop         eax 
012C1418  pop         edx 
012C1419  pop         edi 
012C141A  pop         esi 
012C141B  pop         ebx 
012C141C  mov         ecx,dword ptr [ebp-4]
012C141F  xor         ecx,ebp
012C1421  call        @ILT+25(@__security_check_cookie@4) (12C101Eh)
012C1426  mov         esp,ebp
012C1428  pop         ebp 
012C1429  ret      

 

 

逐段解释含义

 

 

012C13A0  push        ebp 
012C13A1  mov         ebp,esp
012C13A3  sub         esp,0F0h
012C13A9  push        ebx 
012C13AA  push        esi 
012C13AB  push        edi 
012C13AC  lea         edi,[ebp-0F0h]
012C13B2  mov         ecx,3Ch
012C13B7  mov         eax,0CCCCCCCCh
012C13BC  rep stos    dword ptr es:[edi]
012C13BE  mov         eax,dword ptr [___security_cookie (12C7000h)]
012C13C3  xor         eax,ebp
012C13C5  mov         dword ptr [ebp-4],eax 

首先将原栈基址压栈,以栈顶作为新的栈底,开辟出0F0h(240个字节)的空间,作为新栈,红色部分为对栈的初始化操作,用0CCCCCCCCh循环60次填充栈。绿色的代码用来设置cookie,是用来检测缓冲区溢出的(参见文后的相关知识)。如下图中003bfbb8为原来的栈基址,d70c64c7用于cookie检测。

 

 

 

char a = 1;
012C13C8  mov         byte ptr [ebp-9],1
char c[] = "1234567890";
012C13CC  mov         eax,dword ptr [string "1234567890" (12C573Ch)]
012C13D1  mov         dword ptr [ebp-20h],eax
012C13D4  mov         ecx,dword ptr ds:[12C5740h]
012C13DA  mov         dword ptr [ebp-1Ch],ecx
012C13DD  mov         dx,word ptr ds:[12C5744h]
012C13E4  mov         word ptr [ebp-18h],dx
012C13E8  mov         al,byte ptr ds:[012C5746h]
012C13ED  mov         byte ptr [ebp-16h],al

 

上述代码将a写入栈,并将“1234567890”从常量存放的地址12C573Ch(如下图所示)依次取出,放入栈(包括最后的结束符'/0')。上面一张图是写入了“1234”时的状态,此时eax寄存器中实际是“34333231H”,这跟寄存器和内存的读取顺序有关(参见相关知识)。

 

char *p ="1234567890";
012C13F0  mov         dword ptr [ebp-2Ch],offset string "1234567890" (12C573Ch)

将指针指向的地址写入栈,也即是前面提到的常量的地址。

 

a = c[1];
012C13F7  mov         al,byte ptr [ebp-1Fh]
012C13FA  mov         byte ptr [ebp-9],al

 

直接从栈中读取c[2]的值,写入到栈中a的位置。如下图。

 

先取出指针指向的地址12C573Ch,再从该地址的+1位置读取c[2]的值,写入到栈中a的位置。

 

 

 

 

最后的收尾

012C1406  xor         eax,eax
012C1408  push        edx 
012C1409  mov         ecx,ebp
012C140B  push        eax 
012C140C  lea         edx,[ (12C142Ch)]
012C1412  call        @ILT+130(@_RTC_CheckStackVars@8) (12C1087h)
012C1417  pop         eax 
012C1418  pop         edx 
012C1419  pop         edi 
012C141A  pop         esi 
012C141B  pop         ebx 
012C141C  mov         ecx,dword ptr [ebp-4]
012C141F  xor         ecx,ebp
012C1421  call        @ILT+25(@__security_check_cookie@4) (12C101Eh)
012C1426  mov         esp,ebp
012C1428  pop         ebp 
012C1429  ret     
 

 

 

call  @ILT+130(@_RTC_CheckStackVars@8) (12C1087h);call  @ILT+25(@__security_check_cookie@4) (12C101Eh)  都是VS的安全检查(展开见相关知识)。

 

 


 

 

 

 

 

相关知识:

 

指令

rep stos    dword ptr es:[edi]

rep重复操作前缀 ,stos从累加器EAX传送4个字节,到由EDI作为指针的目的串中,同时修改EDI以指向 串中的下一个单

 

元。利用重复操作可以在串在建立一串相同的值,当ECX = 0 的时候停止。此指令对标志位无影响。

 

 

原文链接:http://www.360doc.com/content/10/0521/15/1072296_28745501.shtml#

基于堆栈的缓冲区溢出检测 (/GS)
基于堆栈的缓冲区溢出检测是 Visual C++ 中提供的最陈旧最常见的防御措施。/GS 编译器标志的目标非常简单:减少恶意代码正确执行的机会。默认情况下,/GS 选项在 Visual C++ 2003 及更高版本中处于启用状态,它在运行时检测特定种类的堆栈溢出。为了进行检测,它会在函数堆栈中包括一个随机数(在堆栈的返回地址之前),当函数返回时,函数收尾代码将检查此值以确保它未进行过更改。如果它调用的 cookie 发生了变化,则执行过程将被中止。
用来设置 cookie 的函数导引代码如下所示:
sub    esp, 8
mov    eax, DWORD PTR ___security_cookie
xor    eax, esp
mov    DWORD PTR __$ArrayPad$[esp+8], eax
mov    eax, DWORD PTR _input$[esp+4]
此处显示的是用来检查 cookie 的函数收尾代码:
mov    ecx, DWORD PTR __$ArrayPad$[esp+12]
add    esp, 4
xor    ecx, esp
call    @__security_check_cookie@4
add    esp, 8

原文链接:http://msdn.microsoft.com/zh-cn/magazine/cc337897.aspx

 

相关:

深入C/C++之基于Cookie的安全检查(VS2005)

http://blog.csdn.net/masefee/archive/2009/10/05/4633305.aspx

 

深入C/C++之基于CheckStackVars的安全检查(VS2008) 

http://blog.csdn.net/masefee/archive/2010/05/28/5630154.aspx

 

 

关于内存地址和寄存器中的高位和低位简介(转载)

 

我们可以假设内存表就是一张纸. 当我输入一个数据的时候,软件就会为我们在内存中开辟一个地址,以往内存表中存放数据,如这里就是往这个地址开始写入数据:0040339C .
我们对内存表的高位和低位的理解就可以想做这里就是一张白纸. 我们把每个空格都当作一个位置,从0~1000开始计数,写在最前的就是低位,比如说写四个数,从0~3 . GAME数据的低位~高位就是从G到M.

之后呢,我们从内存表中取数据,放入寄存器中,我们可以把寄存器比做一个水桶,我们放入数据的时候肯定是把"水"先倒到水筒的底部.
如我们从内存中区GAME放入到水桶中的话 水桶中存放的数据就成了EMAG 也就是 45 4D 41 47 (注意每个字节是两个16进制的字符)
而水桶的高位和地位呢,想必大家会很明白,水桶的最上方就是高位,水桶底就是低位,所以EMAG 数据的高低位就是 E~G(E为最高位 G为最低位)


这样大家就清楚 高高低低原则了 (低位用D表示 高位用G表示)
(中心对称,高低位一致性,寄存器先从内存低位读取数据放到自己的低位,反之一样,只不过寄存器就像这里说的水桶,低位在下(/后),高位在上(/前))
D G | G D
如果把内存地址的数据 01 02 03 04 放到寄存器就是 04 03 02 01
G D | D G
如果把寄存器 的数据 04 03 02 01 放到内存地址为 01 02 03 04

数据的传递中 是遵循高高低低原则的 相信大家按照这个思路去理解 会更简单些~~
 
附:
内存 低位在前,高位在后理解:
例如整数(假设占2个字节) 278 = 00000001 00101100
存储时100101100  00000001


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值