不同存储区域的数组分析
下面对放在三个不同存储区的数组进行简要的分析
(1) 对全局数组进行分析
#include <cstdio>
#include <iostream>
using namespace std;
int global_array[3];
int main()
{
int idx = 2;
global_array[0] = 10;
global_array[1] = 20;
global_array[2] = 30;
global_array[idx] = 40;
return 0;
}
对全局数组来说,相信大家都知道是放在静态存储区的,就是说在编译时就可以获知该数组的基址,由于基址固定,编译器就可以计算出使用固定索引访问的任何数组元素的固定地址,从这一点可以看出,如果要对程序做出一些保密性措施,就可能对全局变量进行一些隐藏,具体的做法我也不知道,但尽量少定义一些比较重要的全局数组还是有好处的。
这里需要注意两点。
第一,使用常量索引访问全局数组时,在对应的反汇编代码清单中,对应的数组元素以全局变量的形式出现。换句话说,反汇编代码清单基本上不提供任何数组存在的证据。
第二,使用可变索引值将带领我们来到数组的开头,因为在计算要访问的数组元素的具体地址时,需要用到数组的基址加上相应的偏移量,此时基址即呈现出来。
从第一点来看好像对以全局数组可以进行隐藏,但在实际当中有可能恰恰相反,因为第二点可以看出对可变索引值进行访问时就能够得到数组的基址。相信大家在使用全局数组时都不会元素个数很小的,一般全局数组都是用来节省内存空间才采用的一种方法,所以说以常量索引访问全局数组几乎是不可能的。
.text:00401030 ; =============== S U B R O U T I N E =======================================
.text:00401030
.text:00401030 ; Attributes: bp-based frame
.text:00401030
.text:00401030 _main_0 proc near ; CODE XREF: _mainj
.text:00401030
.text:00401030 var_44= byte ptr -44h
.text:00401030 var_4= dword ptr -4
.text:00401030
.text:00401030 55 push ebp
.text:00401031 8B EC mov ebp, esp
.text:00401033 83 EC 44 sub esp, 44h
.text:00401036 53 push ebx
.text:00401037 56 push esi
.text:00401038 57 push edi
.text:00401039 8D 7D BC lea edi, [ebp+var_44]
.text:0040103C B9 11 00 00 00 mov ecx, 11h
.text:00401041 B8 CC CC CC CC mov eax, 0CCCCCCCCh
.text:00401046 F3 AB rep stosd
.text:00401048 C7 45 FC 02 00 00+mov [ebp+var_4], 2 //为局部
变量idx赋值为2
.text:0040104F C7 05 0C 2E 43 00+mov dword_432E0C, 0Ah //从
这里以后的三行可以看出来全局数组的地址在编译时候就能够确定,
此时的基址应该是0x00432E0C。红色标记。
.text:00401059 C7 05 10 2E 43 00+mov dword_432E10, 14h
.text:00401063 C7 05 14 2E 43 00+mov dword_432E14, 1Eh
.text:0040106D 8B 45 FC mov eax, [ebp+var_4] //把idx存储到eax寄存器中,用来进行偏移量计算。
.text:00401070 C7 04 85 0C 2E 43+mov dword_432E0C[eax*4], 28h
基址加上偏移量就可以定位数组的元素的下标。eax * 4,4表示数组元素的大小,这里千万不能够就认为是int型的,具体情况具体分析。
.text:0040107B 33 C0 xor eax, eax
.text:0040107D 5F pop edi
.text:0040107E 5E pop esi
.text:0040107F 5B pop ebx
.text:00401080 8B E5 mov esp, ebp
.text:00401082 5D pop ebp
.text:00401083 C3 retn
.text:00401083 _main_0 endp
.text:00401083
.text:00401083 ; ---------------------------------------------------------------------------
(2) 对栈分配的数组进行分析
#include <cstdio>
#include <iostream>
using namespace std;
int main()
{
int stack_array[3];
int idx = 2;
stack_array[0] = 10;
stack_array[1] = 20;
stack_array[2] = 30;
stack_array[idx] = 40;
return 0;
}
从下面的代码我们可以看出,编译器几乎以完全相同的方式处理栈分配的数组和全局分配的数组。由于在编译时候并不能够知道栈分配数组的基址,所以在程序中并没有像在全局数组中一样给出第一个元素的地址,所以对于常量索引访问数组时我们还是不能够快速判断程序中是否使用了数组,因为常量索引访问数组与局部变量的使用看不出有什么区别,但这个不用过于担心,因为常量索引访问数组是很少的。如果数组元素才几个,那还不如直接定义变量进行操作可能更简单。从下面的反汇编代码可以得到一些额外的信息,根据栈中idx的位置可以推断出,以var_C开始的数组最多包含3个元素(否则,它将覆盖idx),如果对缓冲区溢出有比较深刻的了解的话,可以很清楚的知道这里就可以使该数组溢出,并破坏其后的数据,到底需要在数组中填充多少数据,对于缓冲区溢出的判断和怎么去利用我还是菜鸟,不懂得,以后有学习之后再来补充相关的知识和应用。
.text:00401030 ; =============== S U B R O U T I N E =======================================
.text:00401030
.text:00401030 ; Attributes: bp-based frame
.text:00401030
.text:00401030 _main_0 proc near ; CODE XREF: _mainj
.text:00401030
.text:00401030 var_50= byte ptr -50h
.text:00401030 var_10= dword ptr -10h
.text:00401030 var_C= dword ptr -0Ch
.text:00401030 var_8= dword ptr -8
.text:00401030 var_4= dword ptr -4
.text:00401030
.text:00401030 55 push ebp
.text:00401031 8B EC mov ebp, esp
.text:00401033 83 EC 50 sub esp, 50h
.text:00401036 53 push ebx
.text:00401037 56 push esi
.text:00401038 57 push edi
.text:00401039 8D 7D B0 lea edi, [ebp+var_50]
.text:0040103C B9 14 00 00 00 mov ecx, 14h
.text:00401041 B8 CC CC CC CC mov eax, 0CCCCCCCCh
.text:00401046 F3 AB rep stosd
.text:00401048 C7 45 F0 02 00 00+mov [ebp+var_10], 2
.text:0040104F C7 45 F4 0A 00 00+mov [ebp+var_C], 0Ah //这里只能够用var_C来表示,并不像全局数组那样用地址表示。
.text:00401056 C7 45 F8 14 00 00+mov [ebp+var_8], 14h
.text:0040105D C7 45 FC 1E 00 00+mov [ebp+var_4], 1Eh
.text:00401064 8B 45 F0 mov eax, [ebp+var_10]
.text:00401067 C7 44 85 F4 28 00+mov [ebp+eax*4+var_C], 28h
基址加上偏移量就可以定位数组的元素的下标。eax * 4,4表示数组元素的大小,这里千万不能够就认为是int型的,具体情况具体分析。
.text:0040106F 33 C0 xor eax, eax
.text:00401071 5F pop edi
.text:00401072 5E pop esi
.text:00401073 5B pop ebx
.text:00401074 8B E5 mov esp, ebp
.text:00401076 5D pop ebp
.text:00401077 C3 retn
.text:00401077 _main_0 endp
.text:00401077
.text:00401077 ; ---------------------------------------------------------------------------
(3) 对堆分配的数组进行分析
#include <cstdio>
#include <iostream>
using namespace std;
int main()
{
int *heap_array = (int *)malloc(3 * sizeof(int));
int idx = 2;
heap_array[0] = 10;
heap_array[1] = 20;
heap_array[2] = 30;
heap_array[idx] = 40;
return 0;
}
堆分配的数组是使用一个动态内存分配函数(如C中的malloc(对应free)或者C++中的new(new是个运算符,并不是函数,这一点需要弄明白,对应delete)。从编译器的角度讲,处理堆分配的数组的主要区别在于,它必须根据内存分配函数返回的地址值,生成对数组的所有引用。
数组的起始地址(有EAX寄存器中的malloc返回)存储在局部变量heap_array中。每一次访问数组是,首先必须读取heap_array的内容,以获得数组的基址,然后再在它上面加上一个偏移值,计算出数组中对应元素的地址。对于堆分配的数组有一个非常有用的特点。如果能够确定数组的总大小和每个元素的大小,则可以计算出该数组有多少个元素,对堆分配的数组而言,传递给内存分配函数的参数(示例中式0x0C)即表示了分配给数组的字节总数,用这个除以元素大小,即可得到数组中元素的个数。
.text:00401030 ; =============== S U B R O U T I N E =======================================
.text:00401030
.text:00401030 ; Attributes: bp-based frame
.text:00401030
.text:00401030 _main_0 proc near ; CODE XREF: _mainj
.text:00401030
.text:00401030 var_48= byte ptr -48h
.text:00401030 var_8= dword ptr -8
.text:00401030 var_4= dword ptr -4
.text:00401030
.text:00401030 55 push ebp
.text:00401031 8B EC mov ebp, esp
.text:00401033 83 EC 48 sub esp, 48h
.text:00401036 53 push ebx
.text:00401037 56 push esi
.text:00401038 57 push edi
.text:00401039 8D 7D B8 lea edi, [ebp+var_48]
.text:0040103C B9 12 00 00 00 mov ecx, 12h
.text:00401041 B8 CC CC CC CC mov eax, 0CCCCCCCCh
.text:00401046 F3 AB rep stosd
.text:00401048 6A 0C push 0Ch ; Size
.text:0040104A E8 41 71 00 00 call _malloc
.text:0040104F 83 C4 04 add esp, 4
.text:00401052 89 45 FC mov [ebp+var_4], eax //eax寄存器返回数组的起始地址
.text:00401055 C7 45 F8 02 00 00+ mov [ebp+var_8], 2
.text:0040105C 8B 45 FC mov eax, [ebp+var_4]
.text:0040105F C7 00 0A 00 00 00 mov dword ptr [eax], 0Ah
.text:00401065 8B 4D FC mov ecx, [ebp+var_4]
.text:00401068 C7 41 04 14 00 00+ mov dword ptr [ecx+4], 14h
.text:0040106F 8B 55 FC mov edx, [ebp+var_4]
.text:00401072 C7 42 08 1E 00 00+ mov dword ptr [edx+8], 1Eh
.text:00401079 8B 45 F8 mov eax, [ebp+var_8]
.text:0040107C 8B 4D FC mov ecx, [ebp+var_4]
.text:0040107F C7 04 81 28 00 00+mov dword ptr [ecx+eax*4], 28h
.text:00401086 33 C0 xor eax, eax
.text:00401088 5F pop edi
.text:00401089 5E pop esi
.text:0040108A 5B pop ebx
.text:0040108B 83 C4 48 add esp, 48h
.text:0040108E 3B EC cmp ebp, esp
.text:00401090 E8 8B 8F 00 00 call __chkesp
.text:00401095 8B E5 mov esp, ebp
.text:00401097 5D pop ebp
.text:00401098 C3 retn
.text:00401098 _main_0 endp
.text:00401098
.text:00401098 ; ---------------------------------------------------------------------------
学习总结:
(1) 关于数组的使用,通过上面的分析能够得到唯一的确定结论是:只有当变量被用作数组的索引时,才最容易确定数组的存在。但其实我们可以反过来想,一般我们写程序使用数组都是用变量索引来访问数组元素的,很少有常量索引来访问数组元素,所以我们要把握重点,对于具体问题具体分析。
(2) 要访问数组中的元素,首先需要用索引乘以数组元素的大小,计算出相应元素的偏移量,然后将得到的偏移量与数组的基址相加,得到数组元素的访问地址。
对于变量索引访问数组的我们一般可以得到数组元素的大小,这一点对于分析也有一定的帮助。
转载于:https://www.cnblogs.com/StudyRush/archive/2010/10/26/1861990.html
不同存储区域的数组分析相关推荐
- 字符串的存储方式以及静态存储区域、栈、堆
下面两篇文章分析得比较详细.转自http://blog.csdn.net/yangdelong/archive/2010/04/03/5447362.aspx 文章来源 http://blog.csd ...
- C++存储区域基础概念详解
*************************************************** 更多精彩,欢迎进入:http://shop115376623.taobao.com ****** ...
- 亚马逊各类存储的比较与分析
亚马逊各类存储的比较与分析 摘要:本文通过对Amazon四大存储类型--Amazon S3.Amazon EBS.Amazon EFS.Amazon S3 Glacier分别的优劣势.适用场景和收费策 ...
- iOS开发:沙盒机制以及利用沙盒存储字符串、数组、字典等数据
iOS开发:沙盒机制以及利用沙盒存储字符串.数组.字典等数据 1.初识沙盒:(1).存储在内存中的数据,程序关闭,内存释放,数据就会丢失,这种数据是临时的.要想数据永久保存,将数据保存成文件,存储到程 ...
- C/C++变量存储区域
1.局部变量. 存放在栈中. 会在进入函数/块的时候进行分配空间, 在退出函数/块的时候释放该空间. 2.全局变量 和 静态变量. 存储在静态存储区域, 即存放在可执行文件的数据段中.data. 3. ...
- python编码与存储读取数据(数组字典)
Camp时在python2的编码上坑了不少. 理解pyhon2的编码 python2字符串类型只有两种: str类型:b'xxx'即是str类型, 是编码后的类型,len()按字节计算 unicode ...
- C语言程序的存储区域
由C语言代码(文本文件)形成可执行程序(二进制文件),需要经过编译-汇编-连接三个阶段.编译过程把C语言文本文件生成汇编程序,汇编过程把汇编程序形成二进制机器代码,连接过程则将各个源文件生成的二进制机 ...
- C语言 编写程序:请将Fibonacci数列前30项中的偶数值找出来,存储到一维数组中。其中,Fibonacci数列如下:1,1,2,3,5,8,13,21,34...该数列除前两项之外,其他任意
编写程序:请将Fibonacci数列前30项中的偶数值找出来,存储到一维数组中.其中,Fibonacci数列如下:1,1,2,3,5,8,13,21,34-该数列除前两项之外,其他任意一项都是相邻的前 ...
- android中资源文件的两种访问方式,Android_Android学习笔记-保存文件(Saving Files),Android设备有两种文件存储区域 - phpStudy...
Android学习笔记-保存文件(Saving Files) Android设备有两种文件存储区域: 内部存储和外部存储 ("internal" and "externa ...
最新文章
- x230 linux wifi,笔记本thinkpad x230i centos6.3 无线网卡完全配置
- 在移动硬盘里移动视频文件到移动硬盘 另外一个文件夹 显示正在计算_古风玩数码 篇九十六:物超所值?移动固态硬盘到底值不值?阿斯加特移动硬盘AP2上手体验_固态硬盘...
- js在上传图片前判断大小
- python乘法表左下变右上_vc++乘法表变换形式怎么变就是变成左上、右上三角形 左下、右下、等腰三角形 还有倒三角形,...
- PLSQL Developer连接oracle数据库安装及配置
- HP Z840 工作站配sSAS Raid 安装 Ubuntu 16.04 系统
- 使用Zuul和Spring Boot创建API网关
- linux nc命令测试端口,Linux和Windows下的NC(Netcat)命令测试端口连通性
- 光端机的使用注意事项详解
- python 打开excel并在屏幕上呈现_excel-检查文件是否在Python中打开
- 挑战杯获奖作品_我校学生参加河北省“挑战杯”竞赛获奖作品展示二
- Arcgis Engine 添加一个Symbol符号样式步骤
- 游戏筑基开发之利用文件函数取出配置文件(ini文件)的数据实体(C语言)
- UBUNTU上新建GIT库
- GoldenGate Enterprise Manager Plug-In(12.1.0.3.0) 部署文档
- 数据数值转换factorize和dummy
- 任务栏右键工具栏里的语言栏没有的修复.reg
- 异常:The JSP specification requires that an attribute name is preceded by whitespace
- JavaWeb在线刷题系统
- Android 调用系统相册选取视频,过滤视频(兼容小米)