逆向知识第十讲,循环在汇编中的表现形式,以及代码还原
逆向知識第十講,循環在匯編中的表現形式,以及代碼還原
一丶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的形式
轉載于:https://www.cnblogs.com/iBinary/p/7869304.html
總結
以上是生活随笔為你收集整理的逆向知识第十讲,循环在汇编中的表现形式,以及代码还原的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: windows 删除网络驱动器
- 下一篇: ViewStub延迟加载