逆向知識第八講,if語句在匯編中表達的方式
一丶if else的最簡單情況還原(無分支情況)
高級代碼:
#include "stdafx.h" int main(int argc, char* argv[]) { unsigned int nNumber = 0; scanf("%ud",&nNumber); if(argc == 0) { nNumber = 0; //第一種情況下無分支 } else { nNumber = -1; } return nNumber; }
總共兩種情況,我們看下Release中怎么優化的把(注意,優化方式選擇O2,速度優先)
匯編代碼:

可以看到我們熟悉的代碼了.也就是昨天的三目運算.
總共三行匯編代碼.
還原套路一樣,還是 代入大於0 小於0 還有==0,看看最終結果是什么.
鑒於昨天還原過代碼了,這里這屆代入,還原出高級代碼.
argc > 0的情況下 if(argc > 0) eax = -1
argc < 0的情況下 if(argc < 0) eax =-1
argc == 0的情況下 if(argc == 0) eax = 0
綜合三種情況,可以得出具體的條件了. 其中 ><這樣寫是在高級語言中不能這樣寫的,
所以得出的還原代碼為
if(argc == 0) eax =0 else eax == -1
二丶if else 的第二種情況(減少分支)
高級代碼:
// MyCode.cpp : Defines the entry point for the console application. // #include "stdafx.h" int main(int argc, char* argv[]) { unsigned int nNumber = 0; scanf("%ud",&nNumber); if(argc == nNumber) { printf("%d",nNumber / 8); } else { printf("%d",nNumber / 5); } return nNumber; }
對應匯編代碼:

這個主要涉及找上下界問題
1.地址: 1018 101C 分別保存了局部變量的值
2.地址: 1023 比較了argc和局部變量Var4的值
3.地址: 1025 jnz跳轉,因為1023地址的比較會影響標志位 由此判定, argc和var4比較,jnz(不相等)但因為匯編中是反條件,所以是相等的情況下
4.因為jnz是一個地址,所以這個地址是一個下界,那么jnz上面的比較代碼則是上界,在其內部,我們還原為if語句塊(先不用管里面具體干啥)
還原if語句塊
if(argc == var4) printf("%d",var4 / 8);
還原else語句塊
else printf("%d",var4 / 5);
在下方我們發現了相同的匯編代碼,也就是把retn放到上面去了,這個主要是為了減少分支.
三丶if else 第第三種形式,代碼外提的情況
代碼外提的情況下,主要在優化方式的選擇上,我們知道 o2(優化方式是速度優先) 現在我們改成o1(也就是體積優先了)
這個時候就會出現代碼外提.
高級代碼:
// MyCode.cpp : Defines the entry point for the console application. // #include "stdafx.h" int main(int argc, char* argv[]) { unsigned int nNumber = 0; scanf("%ud",&nNumber); if(argc == nNumber) { printf("Hello"); } else { printf("World"); } return nNumber; }
切換為o1

protect -> setting即可.
對應匯編代碼:

首先,找if else的時候,先確定上下界
地址: 101A位置 尋得了 if的上界
地址: 101E位置 尋得了 if的下界
注意: 中間划掉了兩個指令,這兩個指令是流水線優化,平棧的指令.所以沒有幫助,划掉
地址: 1025位置,其指令跳轉的地址是一個增量,那么則確定是else的下界
地址: 1027位置 尋得了else的上界
其實簡單來說,第一個跳轉位置,跳轉到哪里的一塊區域,是一個if的語句塊而跳轉的位置則是else語句塊的上界,其上面固定一個jmp(注意其地址跳轉是一個增量)那么跳轉的地址是else的下界
重點代碼外提:
我們可以看到 我們的if語句塊中 push了一個 hello,我們的else語句塊中,push了一個 word
那么除了if else 直接調用的printf,這樣也是可以的.因為參數是一樣的.平棧都是相等的.所以可以提到外面來打印輸出.
四丶多分支if elseif .... else的還原
這個其實很簡單了.如果是多分支,則尋找上界下界即可.
因為編譯器做的東西很多了.
高級代碼:
// Test.cpp : Defines the entry point for the console application. // #include "stdafx.h" int main(int argc, char* argv[]) { unsigned int nVar_4 = 5; scanf("%d", &nVar_4); // argc == 0 ? 0 : -1 if (argc == 0) { printf("argc == 0\r\n"); } else if(argc == 1) { printf("argc == 1\r\n"); } else if(argc == 2) { printf("argc == 2\r\n"); } else if(argc == 3) { printf("argc == 3\r\n"); } else { printf("else\r\n"); } printf("haha\r\n"); printf("haha\r\n"); printf("haha\r\n"); printf("haha\r\n"); printf("haha\r\n"); return nVar_4; }
對應匯編代碼:

看到這種,直接判斷為 if else if else if else這種語句,然后尋找上下界即可.
