用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#
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]
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
相关:
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
关于内存地址和寄存器中的高位和低位简介(转载)
我们对内存表的高位和低位的理解就可以想做这里就是一张白纸. 我们把每个空格都当作一个位置,从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
数据的传递中 是遵循高高低低原则的 相信大家按照这个思路去理解 会更简单些~~