讲解数组之前,要了解数组的特性

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

逆向知识十三讲,汇编中数组的表现形式,以及还原数组相关推荐

  1. c6011取消对null指针的引用_COM编程攻略(二十二 IDL中的枚举,指针,数组)

    上一篇: Froser:COM编程攻略(二十一 异步)​zhuanlan.zhihu.com 本篇主要讲idl的一些语法特性. idl的语法和C语言非常类似,但是它扩展了一些特性,这些特性用于兼容其它 ...

  2. 逆向知识第十讲,循环在汇编中的表现形式,以及代码还原

    逆向知识第十讲,循环在汇编中的表现形式,以及代码还原 一丶do While在汇编中的表现形式 1.1高级代码: #include "stdafx.h"int main(int ar ...

  3. 逆向知识第七讲,三目运算符在汇编中的表现形式,以及编译器优化方式

    一丶编译器优化方式 首先说一下编译器优化方式. 1.常量折叠 2.常量传播 3.复写传播 4.公共表达式 5.去掉不可达到分支 6.顺序代替分支 7.数学变化 8.代码外提 9.减少变量. 10 强度 ...

  4. 汇编中的数组分配和指针

    数组简介 如果各位猿友是一路跟着LZ看到这里的,那么数组的定义就非常简单了,它就是一个相同数据类型的数据集合.数组存储在一系列逻辑上连续的内存块当中,之所以说是逻辑上连续,是因为整个内存或者说存储器本 ...

  5. 二维数组离散程度matlab,(十八)数据分析中的一些概念

    (十八)数据分析中的一些概念 HIKAI 29 SEP 2017 0 Comments 矢量.向量.标量 矢量和向量是一个东西,只是在不同领域里面用到的不同称呼.矢量常常用在物理学中,向量在数学.几何 ...

  6. vba 跳到下一个循环_VBA野知识分享:从一个数组中取部分值生成新数组,不使用循环的思路...

    从一个数组中取部分值生成新数组,要实现此需求通常都是采用循环的方法来完成,那有没有更简易的思路呢? 借用jscript可以实现,直接取值,不用循环.例如从100000万中元素是取8000个值出来生成新 ...

  7. 使用汇编语言完成下列C的数组赋值,汇编中的数组分配和指针的实现代码

    数组简介 如果各位猿友是一路跟着LZ看到这里的,那么数组的定义就非常简单了,它就是一个相同数据类型的数据集合.数组存储在一系列逻辑上连续的内存块当中,之所以说是逻辑上连续,是因为整个内存或者说存储器本 ...

  8. [unreal4入门系列之十五] UE4中的动态数组:TArray容器

    为什么使用UE4提供的容器类? 如果你用过C++的STL库,你就知道STL提供了各种各样的容器/数据结构,使得你对处理很多数据的时候非常快捷高效.UE4同样也提供了类似的库,库里面的类型是以T开头的, ...

  9. 汇编三星题:已知数组A包含20个互不相等的字型整数,数组B包含30个互不相等的字型整数,试编制一程序把在A中而不在B中出现的整数放于数组C中。

    已知数组A包含20个互不相等的字型整数,数组B包含30个互不相等的字型整数,试编制一程序把在A中而不在B中出现的整数放于数组C中. DATAS SEGMENTBUFA DW 123BH,2,3,4,5 ...

最新文章

  1. 根据status信息对MySQL服务器进行优化-1
  2. ThreadLocal 原理 以及设计思想
  3. 关于#pragma code_seg
  4. Gradle 配置spring boot启动
  5. 一个平行四边形可以分成四个_【八年级下】数学 平行四边形(3)菱形
  6. python能不能用c打开文件_C/C++/Python等 使用二进制模式打开文件与不使用二进制模式的区别...
  7. AKKA Inbox收件箱
  8. Paint方法总结(二):着色渲染器Shader
  9. 计算机代码大全喜欢你,微信示爱代码大全 七夕情人节微信翻译表白代码2021
  10. WinForm中 SplitContainer的使用
  11. 厦门大学2019年数学分析考研试题参考解答
  12. python图片,大家来找茬
  13. VBA,单元格处理,数据复制,格式设置,折线图,图表属性设置
  14. arm64服务器性能,80核ARM服务器有多恐怖 性能比64核霄龙还强
  15. java 获取string值_java如何获取String里面的键值对:key=valuekey=value
  16. matlab plotroc 画roc曲线
  17. 对于大流量网站的流量优化
  18. 微信小程序-快速上手
  19. html足球小游戏,趣味小游戏
  20. 用友u8服务器安装后系统假死,服务器打开用友U8企业应用平台没有反应的问题。-用友U8...

热门文章

  1. allpairs使用方法_软件测试|正交试验测试用例设计方法
  2. JAVA中的通配符的符号_Linux下的通配符和特殊符号用法详解
  3. python基本图形绘制_【Python】Python基本图形绘制-Go语言中文社区
  4. linux 查看软连接_linux删除原理
  5. 通俗易懂的讲解区块链
  6. mysql的limit性能优化
  7. 【吐血整理】用java编写一个登陆界面
  8. python【数据结构与算法】选数问题(指定值求和——递归)
  9. scikit_image
  10. 通配符 泛域名 linux,openssl签署自己的泛域名(通配符)证书