逆向知識十三講,匯編中數組的表現形式,以及還原數組


            逆向知識十三講,匯編中數組的表現形式,以及還原數組

講解數組之前,要了解數組的特性

 

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變化了,

會了數組尋址公式,可以說你用指針指向任何一個高維數組的值,取值使用即可.因為在高維在內存中也是線性存儲,也就是一維數組的表現形式.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM