逆向知識第十講,循環在匯編中的表現形式,以及代碼還原


        逆向知識第十講,循環在匯編中的表現形式,以及代碼還原

一丶do While在匯編中的表現形式

1.1高級代碼:

  

#include "stdafx.h"

int main(int argc, char* argv[])
{
    int nSum = 0;
    int i = 0;
    do 
    {
        nSum = nSum + i;
    } while (i <=100);
    return 0;
}

高級代碼很簡單,只是一個簡單的求1~100的累加

1.2 Debug版本下的匯編表現形式

代碼定式很簡單

ADDR

  .....do While邏輯代碼塊

  xxxx 條件

  JXX  Addr

注意,在 do while中, 匯編代碼的語義和高級代碼語義是一樣的.

比如我們以前的if   jle的時候(也就是小於等於) 我們的if則會寫成  > (jg)也就是反向還原,而循環地址向上增量的條件不用取反

代碼還原:

  do

    int nVar4 = nvar4 + nvar8;

  while(nVar8 <= 100)  注意條件,jle就是jle

還需要注意的是,地址是低地址,也就是跳轉是往上跳轉的

 

1.3 Release版本下的優化

高級代碼:

  

int main(int argc, char* argv[])
{

    int nSum = 0;
    int i = 0;
    do 
    {
        nSum = nSum + i;
        i++;
    } while (i <= argc);

    printf("HelloWorld");
    printf("HelloWorld");
    printf("HelloWorld");
    printf("HelloWorld");
    printf("HelloWorld");
    printf("HelloWorld");

    return argc;
}

Release版本下的匯編代碼:

  

代碼也是最精簡的了.和Debug一樣,只不過優化為寄存器使用了.效率更快.

 

二丶while 循環在匯編中的表達形式

2.1高級代碼:

#include "stdafx.h"

int main(int argc, char* argv[])
{
    int nSum = 0;
    int i = 0;
    while(i <= 100) 
    {
        printf("%d",nSum);
        nSum = nSum + i;
    }
    return argc;
}

2.2 Debug版本下的匯編表達形式

請注意,while循環回合if else的匯編代碼類似

但是又有質的不同,在if else中, else語句塊,其JMP跳轉的地址是往增量地址跳轉的,而在while中其跳轉的地址是往減量地址跳轉的

匯編代碼定式:

LowAddr

    jxxx  HighAddr

    ....... while語句塊代碼

    JMP  LowAddr

HighAddr

可以看出,while循環有兩個跳轉

上下界的分別

jg  highaddr  找到while循環的下界

jmp  lowaddr 找到while循環的上界

注意,這里的定式我並沒有寫條件,因為條件只要會影響標志位即可,有可能不是cmp,反正能影響標志位的即可.

代碼還原:

  while(nvar8 <= 100)  (語義相反,只有do while的語義按正常還原 jg(高於),相反則是小於等於)

  {

    printf("%d",nvar4);

    nvar4 = nvar4 + nvar8;

  }

PS: 在第一個跳轉之前的所有代碼,都作為while循環中的條件

 

三丶for循環在匯編中的表達形式

3.1高級代碼:

int main(int argc, char* argv[])
{
    int nSum = 0;
    int i = 0;
    for(i = 0; i < 100;i++) 
    {
        printf("%d",nSum);
        nSum = nSum + i;
    }
    return argc;
}

 

3.2Debug下的匯編表現形式

 

  

 

 for循環因為有了 步長的概念,所以Debug下的代碼可能有點難看懂

說下代碼定式把

  JMP  forCMPaddr  跳轉到代碼比較

FOR_STEMAddr

    for_Step    其代碼是步長代碼 (i++ j++)

forCMPaddr

  for_cmp     代碼比較

  jxxx  forEndAddr  和while循環類似,跳轉到結尾,條件不成立則退出,看此跳轉則找到for循環的下界

  .....循環體

   JMP FOR_STEMADDR 執行完循環體之后,執行步長代碼.

FOR_ENDADDR

修改為代碼定式模樣

 

 代碼還原:

第一步: JMP FOR_CMP 所以找到for循環的比較代碼位置

第二步: 找到jxx For_end 找到for循環的下界.則當前位置是代碼的上界

第三步: jmp FOR_STEP 找到for循環的步長部分

for(nVar8 = 0; nVar8 < 100; nVar8++)

{

  printf("%d",nVar4);

  nVar4 = nVar4 +nVar8;

}

還原for的時候,主要是找到 比較部分,代碼步長部分.以及循環體部分.

 

          淺談Release版本下的循環

上面版本都是Debug版本下的表達形式,但是Release版本下則會優化

主要從幾方面來講解

1.減少跳轉的優化方式

2.常量傳播的優化方式

3.代碼外提的優化方式

4.強度削弱的優化方式

 

一丶While在匯編中的Release的優化

因為dowhile是最優化的方式了,所以沒有更好的優化方式了

1.1 while循環下的減少跳轉的優化方式

 首先說下為什么減少跳轉.

我們知道,do while就一個跳轉,而while在Debug版本下是兩個跳轉,for循環在Debug版本下是3個跳轉

那么如果減少了跳轉,那么則會大大的增加效率.

1.1.2高級代碼:

  

#include "stdafx.h"

int main(int argc, char* argv[])
{

    int nSum = 0;
    int i = 0;
    while(i <= argc) 
    {
        nSum = nSum + i;
        i++;
    } 

    printf("HelloWorld");
    printf("HelloWorld");
    printf("HelloWorld");
    printf("HelloWorld");
    printf("HelloWorld");
    printf("HelloWorld");

    return argc;
}

1.1.3 Release版本下的代碼

看到這個匯編代碼,我們發現jl的時候,是和if相似的.

而 jle的時候,地址是減量跳轉,則是do while的條件

那么此時我們可能會還原成 if里面包含do while

但其實,也是這樣還原的.這樣是為了減少跳轉

說下為什么減少跳轉

1.首先判斷,如果不成立,則不執行循環語句塊

2.當第一個條件成立,則循環語句塊,此時我知道你的條件是成立的,所以我只需要變為do while去循環即可.

這樣就減少跳轉了,比如我們的while循環20000次,那么跳轉就要 *2,那么此時變成if 包含do while的時候

那么此時跳轉就是 200001次,大大的優化了效率

還原代碼:

if(argc >= 0)

{

  do

    ecx = ecx + eax;

    eax ++;

  while(eax <= argc )

}

識別此類的循環要注意

1.首先if中的條件和 do while中的條件有相關性

2.注意如果是dowhile那么其地址跳轉是往減量跳轉.

當然如果你喜歡還原為while那么也是可以了

while (eax <= argc)

{

  ecx = ecx + eax;

  eax ++;

}

第一種還原方式,如果條件有相關性,則還原出的匯編代碼是和這個的二進制代碼是一摸一樣的.2.

 1.2 常量傳播下的優化方式

在常量傳播下,則直接變成了do while了.

看下高級代碼:

int nSum = 0;
    int i = 0;
    while(i < 100)
    {
        nSum = nSum + i;
        i++;
    }

常量傳播后,則i變成了常量.所以直接變成do while即可.

Release匯編

 

1.3代碼外提優化

高級代碼:

int nSum = 0;
    int i = 0;
    while(i < argc /7)
    {
        nSum = nSum + i;
        i++;
    }

其中 argc/7並沒有在循環體中使用所以可以單獨提取出來.

int temp = argc / 7;

while(i < temp)...

Release版本下的匯編代碼:

上面則是代碼外提的情況,此時還原代碼也可以還原為 if 包含do while的形式

PS: 代碼外提不支持函數

比如 

  for(i = 0; i < strlen("hello");i++) ... 其中 strlen是函數,所以不會代碼外提

二丶減少跳轉優化(For循環)

for循環在Debug版本下有三層跳轉.那么減少跳轉之后,則和上方while一樣,也變為if包含 do While了.

PS: 注意,在常量傳播下,所有的循環都變成了do while類型去執行循環了

PS: 注意,代碼外提的情況下,所有循環都變成 if 加 do while的形式,代碼放到外面執行了.

2.1高級代碼:

 int nSum = 0;
    int i = 0;
    for (i = 0; i < argc; i++)
    {
        nSum = nSum + i;
        i++;
    }

Release版本下的匯編

 

其也變成了if 包含do while循環的形式

還原代碼同上

.

             循環中的Break和Continue的區別

循環中有continue和break

其中continue是跳過當前循環進行下一次循環.

break是跳出循環體

所以我們知道了,break會跳出循環.而continue不會跳出循環.\

一丶觀看For循環的Debug版本.和Releas版本,觀察continue和break的區別.

1.1高級代碼

 int nSum = 0;
    int i = 0;
    for ( i = 0; i < argc ;i++)
    {
        nSum = nSum + i;
        if(argc == 0)
        {
            break;
        }
        else if(argc == 1)
        {
            continue;
        }
        i++;
    }

1.2Debug匯編break和Continue的表達形式.

break執行會跳出循環體,而continue則會跳轉到補償代碼執行

1.3Release版本下的匯編

也可以看出,break會跳出循環,而continue則不會跳出循環

總結:

1. do while總結

  Debug版本下

  1.do while有一次跳轉,其中跳轉的代碼是往減量地址跳轉(低地址)

  2.還原心得,因為其地址往減量跳轉,所以匯編語義與高級語言語義一樣,正常代碼還原

  Release版本下

  1.常量傳播下,直接就是do while了,和Debug版本下一樣,一次跳轉,還原方式正常跳轉

  

 2. While循環總結

  Debug版本下

  1.有兩次跳轉,代碼特別像 if else,但是又有質的不同,其中第一次跳轉其地址是往增量跳轉,第二次跳轉其地址是往減量地址跳轉(if else則都是往增量地址跳轉)

  2.還原心得,第一次跳轉之前的代碼都作為while循環中的條件,其條件是反向還原,語義相反.第一次跳轉可以找到while的下界,其當前位置則是while的上界.

    Release版本下

  1.常量傳播的優化方式下,其代碼會變成do while執行

  2.代碼外提的情況下,其代碼會變成if 包含 do while執行,其中代碼的條件外提.注意,函數不可以作為代碼外提

  3.還原心得: 如果是 if包含do while的形式,則判斷兩個條件是否有相關性.如果有相關性則可以還原成while或者自己喜好的 if +do while的形式.

  4.第一次跳轉是相反語義,第二次跳轉是正常語義.

3.for循環總結

   Debug版本下

    1.for循環因為有步長的問題,所以多一次跳轉. 其中 第一步跳轉到 條件位置處,第二此跳轉則判斷條件是否成立,不成立則退出,此時找到for的下界,當前位置可以當做if的上界.

     條件成立之后代碼繼續執行,則此時又來了一次跳轉,此跳轉跳轉到步長執行代碼

   Release版本下

  1.常量傳播方式下 代碼變為do while執行

  2.代碼外提情況下,代碼變成了 if + do while的形式 


免責聲明!

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



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