逆向知识十三讲,汇编中数组的表现形式,以及还原数组
讲解数组之前,要了解数组的特性
1.数据具有连续性
2.数据类型相同
比如:
int Ary[3] = {0,1,2};
我们可以看出,上面定义的数组,数据是连续的,其中每个数据类型大小都是int类型(类型也是一样的)
汇编中识别数组:
1.地址连续
2.带有比例因子寻址 (lea reg32,[xxx + 4 *xxxx])
一丶一维数组在汇编中的表现形式
首先说下数组寻址公式,便于下面讲解
公式: 数组首地址 + sizeof(type) * n
伪代码:
int Ary[3] = {1,2,3};
Ary[N] = 1;
sizeof(type) : 这个是求数组元素的类型的,比如上面是int类型数组,我们求数组元素的类型 sizeof(Ary[0]);
n: n的取值是下标运算,比如我们要求第数组中的第一项,(元素为2,从零开始),
代入公式: Ary + sizeof(Ary[0]) * 1
= Ary +4 * 1
= Ary + 4 取内容则是元素2了.
看例子:
高级代码:
int main(int argc, char* argv[]) {int Ary[3] = {0,1,2};int i = 0;scanf("%d",&i);Ary[i] = 3; //这句话会产生数组寻址公式return Ary[i]; }
Debug下的汇编代码:
之截图重要代码
红色区域还有下面的add esp,8属于scanf上面的代码,给数组初始化等等,重要代码属于粉红框内的
1. 局部变量赋值给ecx
2.[ebp + ecx * 4 + var_c],写入了3,其中 ebp + var_c 是数组首地址, 4是sizeof(type), ecx则是n值.
由此代入我们的数组寻址公式
Ary + sizeof(type) * n
= [ebp + Var_c + 4 * ecx]
只不过比例因子寻址会变化,转为公式是一样的,其中sizeof()求出的值变为了常量.
如果喜欢汇编的这种表达形式,可以把数组公式变换一下,
变为:
Ary + (n * sizeof(type))汇编是这种的,其实是一样的.
Release下的汇编
Release下也是一样的,可能和Debug汇编不一样,但是其本质也就是数组寻址公式一样的.
Ary + sizeof(type) * n
Ary+ (n*sizeof(type))
在这里可能大家会有疑问,为什么esp + var_c是数组首地址,而不用+18h?
因为在vc6.0下,是esp寻址,而这个18h只是做调整,IDA中显示成这样是想告诉我们,我要用到Var_C,但是因为我是esp寻址,所以我要调整一下才能找到var_c
而在高版本下,则会直接ebp寻址.不重要,知道就好.
二丶二维数组在汇编下的表现形式
数组寻址公式是一样的,但不同,
1.sizeof(type)变了. type的取值变为的自己的低维
2.不光求高维,低维也要求
现在的数组寻址公式变为了:
int ary[M][C];
数组首地址 +sizeof(type[C]) * i + sizeof(type) * j; i和j是下标运算的值, 比如 ary[3][4] = 1, 3是i,j是4, 不要和MC搞混,MC是数组定义的时候的值.
其中的sizeof(type[C])变为了二维数组的低维了.
如有一个数组为:
int Ary[2][3] = {{1,2,3},{4,5,6}};
我要求4所在的位置,
我们打印的时候要输入 ary[1][0] 可以打印出4
那么我们可以通过手来计算出其位置
得出:
Ary + sizeof(type[C]) * i + sizeof(type) * j
简化公式:
Ary + C * sizeof(Type)*i + sizeof(type) * j 在Debug下会到这一步
简化公式:
ary + sizeof(type) * (i * C + j); 在Release下会优化为这一步,因为发现了公因子 sizeof(type)了,可以提出来
代入公式得到:
ary + 4 * 1 * 3 + 0
= ary + 12
也就是说数组首地址 + 12 就得出4所在的地址位置.
+12在高级语言中,因为要%4对齐,所以我们要/4
所以得出 12 / 4 = 3,那么如果是指针指向数组的首地址,那么只需要+3即可取得数组的元素4,这也是一维数组访问二维数组元素的公式.
代码:
总结一下:
首先要知道数组的寻址公式,因为维数组多了一维,所以要求出高维还要求出低纬度.而其中的type取值是取自己的低维
公式; 数组首地址 + sizeof(type[C]) * i + sizeof(type)*j 重要,必须了解
举例子了解Debug下的汇编和Release下的数组寻址公式的区别
高级代码:
int main(int argc, char* argv[]) {int Ary[2][3] = {{1,2,3},{4,5,6}};int i = 0;int j = 0;scanf("%d%d",&i,&j);Ary[i][j] = 9; //会产生数组寻址公式return 0; }
Debug下的汇编
通过我们的数组寻址公式得出
1.edx 是获取i的值
2. edx * C 相当于我们的数组中的寻址公式 sizeof(type[C]) *i 的值.
3.lea的时候 求出数组首地址 + sizeof(type[c])的值.
4.ecx得出j的值
5.eax + 4 * ecx 相当于数组首地址 + sizeof(type)*j
致此熟悉数组寻址公式看汇编代码很简单了.
所以Debug下的数组公式会变成
数组首地址 + sizeof(type[C]) * i + sizeof(type] * j
Release下的汇编
上面说过,在Release下会优化我们的原始的公式为
数组首地址 + sizeof(type) * (C * i + j)的形式
我们代入到汇编中查看.
1.eax 得出i的值
2.edx得出数组首地址的值
3.ecx的出 数组首地址 + i * 2 的值
4.add eax,ecx 重新写会eax,eax = 数组首地址 + i * 2 + i 那么可以简化为数组首地址 + i * 3即可.
5.运用数组寻址公式 [esp + var18 + 4 * eax] esp + var18得出数组首地址 + i *3 + 4
因为我们的j的取值是0,所以在Release下不是我们想象的 数组首地址 + i * 3 *4 + 0,+0优化掉了.
三丶三维数组在汇编中的表现形式
其实二维数组就介绍了高维数组怎么求了,以不变应万变.
有一个三维数组
int Ary[M][C][H]
下标操作:
ary[i][j][k] = 1;
数组寻址公式为:
Ary + sizeof(type[C][H]) * i + sizeof(type[H])*j + sizeof(type)*k 在Debug下原模原样
在Release下会优化公式为:
Ary + sizeof(type)*c*h*i + sizeof(type)*h*j + sizeof(type)*k
发现公因数继续优化
Ary + sizeof(type) * (c*h*i + h*j + k)
发现了两个h
继续简化
Ary + sizeof(type) * (h*(c*i + j) + k);
所以上面就是最终公式
高级代码:
int main(int argc, char* argv[]) {int Ary[2][3][4] = {NULL};int i = 0;int j = 0;int k = 0;scanf("%d%d%d",&i,&j,&k);Ary[i][j][k] = 9; //会产生数组寻址公式return 0; }
Debug下的反汇编代码:
公式先贴出来:
Ary + sizeof(type[C][H]) * i + sizeof(type[H])*j + sizeof(type)*k
代入公式看汇编
1.eax = i的值
2. eax * 30 ,相当于求 sizeof(type[C][H]) * i
3.求出数组首地址+eax,也就是求出了 Ary[M]的位置,给Ecx赋值
4.求出j的值
5.左移4位,相当于2^4次方也就是16 这一步相当于求 sizeof(type[H])的值
6.ary[M] + sizeof(type[H])的值得出了 ary[M][C]的值
7.求出k的值
8.数组寻址公式 ary[M][C]的值 + 4 * k的值.
在Debug下代入公式即可.
Release下的汇编
上面说了,Release下汇编会优化,也就是我们的公式会优化.
优化为:
Ary + sizeof(type) * (h*(c*i + j) + k);
根据公式代入即可.
四维数组,高维数组,数组公式同上,只不过注意两点
1.sizeof(type) type类型比如是自己的低维
2.要加一条新的公式
比如
int ary[A][B][C][D];
下标分别为
i j k l
数组公式为:
Ary + sizeof(type[B][C][D]) * i + sizeof(type[C][D]) * j + sizeof(tyep[D]) * j + sizeof(type)*k
自己优化一下即可
总结:
数组寻址公式要熟悉最简单的数组寻址公式,因为更高纬度也是从上面公式,只不过type变化了,
会了数组寻址公式,可以说你用指针指向任何一个高维数组的值,取值使用即可.因为在高维在内存中也是线性存储,也就是一维数组的表现形式.
转载于:
作者:IBinary
出处:http://www.cnblogs.com/iBinary/
转载于:https://www.cnblogs.com/gd-luojialin/p/11219880.html
逆向知识十三讲,汇编中数组的表现形式,以及还原数组相关推荐
- c6011取消对null指针的引用_COM编程攻略(二十二 IDL中的枚举,指针,数组)
上一篇: Froser:COM编程攻略(二十一 异步)zhuanlan.zhihu.com 本篇主要讲idl的一些语法特性. idl的语法和C语言非常类似,但是它扩展了一些特性,这些特性用于兼容其它 ...
- 逆向知识第十讲,循环在汇编中的表现形式,以及代码还原
逆向知识第十讲,循环在汇编中的表现形式,以及代码还原 一丶do While在汇编中的表现形式 1.1高级代码: #include "stdafx.h"int main(int ar ...
- 逆向知识第七讲,三目运算符在汇编中的表现形式,以及编译器优化方式
一丶编译器优化方式 首先说一下编译器优化方式. 1.常量折叠 2.常量传播 3.复写传播 4.公共表达式 5.去掉不可达到分支 6.顺序代替分支 7.数学变化 8.代码外提 9.减少变量. 10 强度 ...
- 汇编中的数组分配和指针
数组简介 如果各位猿友是一路跟着LZ看到这里的,那么数组的定义就非常简单了,它就是一个相同数据类型的数据集合.数组存储在一系列逻辑上连续的内存块当中,之所以说是逻辑上连续,是因为整个内存或者说存储器本 ...
- 二维数组离散程度matlab,(十八)数据分析中的一些概念
(十八)数据分析中的一些概念 HIKAI 29 SEP 2017 0 Comments 矢量.向量.标量 矢量和向量是一个东西,只是在不同领域里面用到的不同称呼.矢量常常用在物理学中,向量在数学.几何 ...
- vba 跳到下一个循环_VBA野知识分享:从一个数组中取部分值生成新数组,不使用循环的思路...
从一个数组中取部分值生成新数组,要实现此需求通常都是采用循环的方法来完成,那有没有更简易的思路呢? 借用jscript可以实现,直接取值,不用循环.例如从100000万中元素是取8000个值出来生成新 ...
- 使用汇编语言完成下列C的数组赋值,汇编中的数组分配和指针的实现代码
数组简介 如果各位猿友是一路跟着LZ看到这里的,那么数组的定义就非常简单了,它就是一个相同数据类型的数据集合.数组存储在一系列逻辑上连续的内存块当中,之所以说是逻辑上连续,是因为整个内存或者说存储器本 ...
- [unreal4入门系列之十五] UE4中的动态数组:TArray容器
为什么使用UE4提供的容器类? 如果你用过C++的STL库,你就知道STL提供了各种各样的容器/数据结构,使得你对处理很多数据的时候非常快捷高效.UE4同样也提供了类似的库,库里面的类型是以T开头的, ...
- 汇编三星题:已知数组A包含20个互不相等的字型整数,数组B包含30个互不相等的字型整数,试编制一程序把在A中而不在B中出现的整数放于数组C中。
已知数组A包含20个互不相等的字型整数,数组B包含30个互不相等的字型整数,试编制一程序把在A中而不在B中出现的整数放于数组C中. DATAS SEGMENTBUFA DW 123BH,2,3,4,5 ...
最新文章
- 根据status信息对MySQL服务器进行优化-1
- ThreadLocal 原理 以及设计思想
- 关于#pragma code_seg
- Gradle 配置spring boot启动
- 一个平行四边形可以分成四个_【八年级下】数学 平行四边形(3)菱形
- python能不能用c打开文件_C/C++/Python等 使用二进制模式打开文件与不使用二进制模式的区别...
- AKKA Inbox收件箱
- Paint方法总结(二):着色渲染器Shader
- 计算机代码大全喜欢你,微信示爱代码大全 七夕情人节微信翻译表白代码2021
- WinForm中 SplitContainer的使用
- 厦门大学2019年数学分析考研试题参考解答
- python图片,大家来找茬
- VBA,单元格处理,数据复制,格式设置,折线图,图表属性设置
- arm64服务器性能,80核ARM服务器有多恐怖 性能比64核霄龙还强
- java 获取string值_java如何获取String里面的键值对:key=valuekey=value
- matlab plotroc 画roc曲线
- 对于大流量网站的流量优化
- 微信小程序-快速上手
- html足球小游戏,趣味小游戏
- 用友u8服务器安装后系统假死,服务器打开用友U8企业应用平台没有反应的问题。-用友U8...
热门文章
- allpairs使用方法_软件测试|正交试验测试用例设计方法
- JAVA中的通配符的符号_Linux下的通配符和特殊符号用法详解
- python基本图形绘制_【Python】Python基本图形绘制-Go语言中文社区
- linux 查看软连接_linux删除原理
- 通俗易懂的讲解区块链
- mysql的limit性能优化
- 【吐血整理】用java编写一个登陆界面
- python【数据结构与算法】选数问题(指定值求和——递归)
- scikit_image
- 通配符 泛域名 linux,openssl签署自己的泛域名(通配符)证书