-
-
[原创]亲密接触-浅析堆栈变化(附上次很粗糙视频演示)
-
发表于:
2007-10-7 02:40
9258
-
[原创]亲密接触-浅析堆栈变化(附上次很粗糙视频演示)
【文章标题】: 亲密接触-堆栈变化分析篇(附上次很粗糙视频演示)
【文章作者】: CCDeath
【作者邮箱】: CCDeath@163.com
【操作平台】: 盗版中的最低版本XP
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
高手飘过....
在vc控制台输入以下程序用汇编一步步跟踪堆栈的变化。
图在这呢:
输入如下代码:
#include "stdafx.h"
int add(int a,int b)
{
int c=a+b;
return c;
}
void main()
{
int d=add(3,5);
printf("%d",d);
}
按F10,如果没看到寄存器,和地址,在下边右键。
void main()
{
//这里右键"GoToDisassembly"
....
}
来到这里.开始分析...
为什么我要保存象ebp、esi、edi寄存器值?
因为不想改变寄存器的值,但是我们在堆栈又要使用到她,没办法,保存起来。
int a=5,temp;
temp=a;----------------------等同于push a
a++;//经过一系列的运算-------等同于堆栈对这些寄存器操作
a=temp;----------------------等同于pop a
为什么我调用的函数跟进去之后又来保存ebp、esi等,真的很乱,整个堆栈变化又怎么样的呢?
{看分析图}
ebp、esp,配合一起在堆栈使用.
11: void main() 执行前 执行后
12: {
00401060 push ebp---------------------@1. ebp:0012FFC0
00401061 mov ebp,esp-----------------@2. esp:0012FF80 ebp:0012FF80(此时,她可没在栈)
00401063 sub esp,44h-----------------@3. esp:0012FF80 esp:0012FF3C{减去44H,腾出空间存放局部变量}
00401066 push ebx---------------------@4. esp:0012FF3C esp:0012FF38{减去4H,ebx的存放的大小}
00401067 push esi---------------------@5. esp:0012FF38 esp:0012FF34{同上}
00401068 push edi---------------------@6. esp:0012FF34 esp:0012FF30{同上}
00401069 lea edi,[ebp-44h]-----------@7. move edi,ebp-44h{move不支持'-'操作}
0040106C mov ecx,11h-----------------@8. 给局部变量分配空间,并初始化为0CCCCCCCCh,ecx为什么11h?
{11h*4=44h,是不是等于上面esp-44h}.在逆向C++里,ecx充当this指针的角色
00401071 mov eax,0CCCCCCCCh----------@9.
00401076 rep stos dword ptr [edi]---------@10.这是个循环操作,把eax值往edi指向的地址填充.edi+=2;
13:
14: int d=add(3,5);
00401078 push 5-----------------------@11.esp:0012FF30 esp:0012FF2C{参数二入栈}
0040107A push 3-----------------------@12.esp:0012FF2C esp:0012FF28{参数一入栈}
0040107C call @ILT+0(add) (00401005)--@13.F11跟入
00401081 add esp,8-------------------@29.esp:0012FF28 esp:0012FF30{记得上面push 3和5=4H+4H=8H}
00401084 mov dword ptr [ebp-4],eax---@30
15: printf("%d\n",d);
00401087 mov eax,dword ptr [ebp-4]
0040108A push eax
0040108B push offset string "%d" (0042210c)
00401090 call printf (0040d6c0)
00401095 add esp,8
16:
17: }
00401098 pop edi
00401099 pop esi
0040109A pop ebx
0040109B add esp,44h
0040109E cmp ebp,esp
004010A0 call __chkesp (004010b0)
004010A5 mov esp,ebp
004010A7 pop ebp
004010A8 ret
add函数
@ILT+0(?add@@YAHHH@Z):
00401005 jmp add (00401020)---------@14 同志们,敌人转移营地了...
6: int add(int a,int b) 执行前 执行后
7: {
00401020 push ebp--------------------@15 esp:0012FF24{不是28吗} esp:0012FF20
00401021 mov ebp,esp----------------@16
00401023 sub esp,44h----------------@17
00401026 push ebx--------------------@18
00401027 push esi--------------------@19
00401028 push edi--------------------@20
00401029 lea edi,[ebp-44h]----------@21
0040102C mov ecx,11h----------------@22
00401031 mov eax,0CCCCCCCCh---------@23
00401036 rep stos dword ptr [edi]--------@24
8: int c=a+b;--------------------------------我们来看下面是取参数的
00401038 mov eax,dword ptr [ebp+8]--@25
0040103B add eax,dword ptr [ebp+0Ch]@26
0040103E mov dword ptr [ebp-4],eax--@27
9: return c;
00401041 mov eax,dword ptr [ebp-4]--@28这个就是真的注册码经常保存在这里
10: }
| |
-----------------------
| |
-----------------------
| |
---------------------------------------------------------------------------------------|
| edi |
---------------------- |
| esi |
---------------------- |
| ebx |
----------------------- |
| 0CCCCCCCCh |
-----------------------esp-44--执行@17 |
| 0CCCCCCCCh |
---------------------- |
| ........ | ##### CALL函数区域入栈 ######
---------------------- |
| 0CCCCCCCCh |
---------------------- |
| 0CCCCCCCCh |
------------------------esp=ebp |
| ebp:0012FF80 |--------执行@15
---------------------- |
| 0040107C |--------执行@13{保存跳转地址}
-------------------------------------------执行@25[ebp+8]取出第一参数.不是ebp+4 |
| 3 |--------执行@12
-------------------------------------------执行@26[ebp+0C]取出第二参数 |
| 5 |--------执行@11
---------------------------------------------------------------------------------------|
| edi: 00000000 |--------执行@6
-----------------------
| esi: 00000000 |--------执行@5
-----------------------
| ebx: 7FFDC000 |--------执行@4
-----------------------
| 0CCCCCCCCh |
-----------------------esp-44--执行@3
| 0CCCCCCCCh |
-----------------------
| ........ |
-----------------------
| 0CCCCCCCCh |
-----------------------
| 0CCCCCCCCh |
------------------------esp
| ebp: 0012FFC0 |--------执行@1
-----------------------
二.c编译后内存分配情况
#include"stdio.h"
#include"stdlib.h"// malloc()函数头文件
void main()
{
int iCCD;--------------------------@1
char *pCCD=(char *)malloc(100);----@2
statci int sCCD=2;-----------------@3
char *cCCD="CCDeath";--------------@4
}
| 栈区(熟称堆栈) |--------执行@1.由上面分析,存放函数的参数值,局部变量的值等。地址高->低
-----------------------
| 堆区 |--------执行@2 分配地址:低->高,很自由很灵活.分配了100
-----------------------
| 全局区(静态区) |--------执行@3 static int a;可以限制在某个文件。int a;全局时可由多个文件共享
-----------------------
| 文字常量区 |--------执行@4.放的CCDeath+'/0'
-----------------------
| 程序代码区 |
三.堆栈与异常跟踪
C++异常底层实现是SEH来实现的.其中CSEHException类继承标准C++异常的基类exception.在
CSHException的构造函数来跟踪堆栈...进行处理...
四.经验总结:
我说的可能存在很多的错误...希望多多批评和建议...
上次的 :如何一步步编写VC完美注册机功能篇(视频做的很烂...有点大,我放在邮箱里)
链接地址:http://bbs1.pediy.com/showthread.php?t=52509
效果图 :
视频邮箱地址:CCDeath123@163.com 密码:ccd123
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
2007年10月07日 2:40:19
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课