if else嵌套
這次來(lái)研究if else嵌套在匯編中的表現(xiàn)形式,本次以獲取三個(gè)數(shù)中最大的數(shù)這個(gè)函數(shù)為例子,分析if else的匯編形式
求三個(gè)數(shù)中的最大值
首先貼上代碼:
#include "stdafx.h"
int result=0;
int getMax(int i,int j,int k){
if(i>j){
if(i>k){
return i;
}else{
return k;
}
}else{
if(j>k){
return j;
}else{
return k;
}
}
}
int main(int argc, char* argv[])
{
result=getMax(1,2,3);
printf("%d\n",result);
result=getMax(1,3,2);
printf("%d\n",result);
result=getMax(2,1,3);
printf("%d\n",result);
result=getMax(2,3,1);
printf("%d\n",result);
result=getMax(3,1,2);
printf("%d\n",result);
result=getMax(3,2,1);
printf("%d\n",result);
return 0;
}
先驗(yàn)證執(zhí)行的結(jié)果是正確的:
確認(rèn)可以函數(shù)是可以取出三個(gè)數(shù)的最大值的,于是開(kāi)始分析該函數(shù)
為方便觀看,將多余的驗(yàn)證刪去,直接改為
getMax(1,2,3);
匯編代碼
然后我們觀察匯編代碼
函數(shù)外部
28: getMax(1,2,3);
0040D7C8 push 3
0040D7CA push 2
0040D7CC push 1
0040D7CE call @ILT+10(func) (0040100f)
0040D7D3 add esp,0Ch
依次壓入?yún)?shù),然后調(diào)用函數(shù),最后再堆棧外平衡,重點(diǎn)在函數(shù)內(nèi)部,進(jìn)去看看
函數(shù)內(nèi)部
7: int getMax(int i,int j,int k){
0040D760 push ebp
0040D761 mov ebp,esp
0040D763 sub esp,40h
0040D766 push ebx
0040D767 push esi
0040D768 push edi
0040D769 lea edi,[ebp-40h]
0040D76C mov ecx,10h
0040D771 mov eax,0CCCCCCCCh
0040D776 rep stos dword ptr [edi]
8: if(i>j){
0040D778 mov eax,dword ptr [ebp+8]
0040D77B cmp eax,dword ptr [ebp+0Ch]
0040D77E jle getMax+32h (0040d792)
9: if(i>k){
0040D780 mov ecx,dword ptr [ebp+8]
0040D783 cmp ecx,dword ptr [ebp+10h]
0040D786 jle getMax+2Dh (0040d78d)
10: return i;
0040D788 mov eax,dword ptr [ebp+8]
0040D78B jmp getMax+42h (0040d7a2)
11: }else{
12: return k;
0040D78D mov eax,dword ptr [ebp+10h]
0040D790 jmp getMax+42h (0040d7a2)
13: }
14:
15: }else{
16: if(j>k){
0040D792 mov edx,dword ptr [ebp+0Ch]
0040D795 cmp edx,dword ptr [ebp+10h]
0040D798 jle getMax+3Fh (0040d79f)
17: return j;
0040D79A mov eax,dword ptr [ebp+0Ch]
0040D79D jmp getMax+42h (0040d7a2)
18: }else{
19: return k;
0040D79F mov eax,dword ptr [ebp+10h]
20: }
21: }
22: }
0040D7A2 pop edi
0040D7A3 pop esi
0040D7A4 pop ebx
0040D7A5 mov esp,ebp
0040D7A7 pop ebp
0040D7A8 ret
函數(shù)內(nèi)部有不少代碼是用來(lái)保護(hù)現(xiàn)場(chǎng) 初始化堆棧 恢復(fù)現(xiàn)場(chǎng)的,這里將其過(guò)濾掉,看判斷語(yǔ)句:
判斷語(yǔ)句
8: if(i>j){
0040D778 mov eax,dword ptr [ebp+8]
0040D77B cmp eax,dword ptr [ebp+0Ch]
0040D77E jle getMax+32h (0040d792)
9: if(i>k){
0040D780 mov ecx,dword ptr [ebp+8]
0040D783 cmp ecx,dword ptr [ebp+10h]
0040D786 jle getMax+2Dh (0040d78d)
10: return i;
0040D788 mov eax,dword ptr [ebp+8]
0040D78B jmp getMax+42h (0040d7a2)
11: }else{
12: return k;
0040D78D mov eax,dword ptr [ebp+10h]
0040D790 jmp getMax+42h (0040d7a2)
13: }
14:
15: }else{
16: if(j>k){
0040D792 mov edx,dword ptr [ebp+0Ch]
0040D795 cmp edx,dword ptr [ebp+10h]
0040D798 jle getMax+3Fh (0040d79f)
17: return j;
0040D79A mov eax,dword ptr [ebp+0Ch]
0040D79D jmp getMax+42h (0040d7a2)
18: }else{
19: return k;
0040D79F mov eax,dword ptr [ebp+10h]
20: }
21: }
22: }
參數(shù)分析
i>j
先來(lái)看看i>j的反匯編語(yǔ)句
0040D778 mov eax,dword ptr [ebp+8]
0040D77B cmp eax,dword ptr [ebp+0Ch]
0040D77E jle getMax+32h (0040d792)
比較第一個(gè)參數(shù)和第二個(gè)參數(shù)
jle:jump less equal,小于等于則跳轉(zhuǎn)(有符號(hào)數(shù))
跳轉(zhuǎn)地址:0040d792
16: if(j>k){
0040D792 mov edx,dword ptr [ebp+0Ch]
i>k
9: if(i>k){
0040D780 mov ecx,dword ptr [ebp+8]
0040D783 cmp ecx,dword ptr [ebp+10h]
0040D786 jle getMax+2Dh (0040d78d)
比較第一個(gè)和第三個(gè)參數(shù)
jle:jump less equal,小于等于則跳轉(zhuǎn)(有符號(hào)數(shù))
跳轉(zhuǎn)地址:0040d78d
11: }else{
12: return k;
0040D78D mov eax,dword ptr [ebp+10h]
0040D790 jmp getMax+42h (0040d7a2)
可以分析出,如果第一個(gè)參數(shù)小于等于第三個(gè)參數(shù)則跳轉(zhuǎn)到0040D78D,并將第三個(gè)參數(shù)賦值給eax作為返回值,這條線路為(k>i>j)
否則執(zhí)行返回指令,將第一個(gè)參數(shù)賦給eax作為返回值,這條線路為(i>j且i>k)
10: return i;
0040D788 mov eax,dword ptr [ebp+8]
0040D78B jmp getMax+42h (0040d7a2)
j>k
16: if(j>k){
0040D792 mov edx,dword ptr [ebp+0Ch]
0040D795 cmp edx,dword ptr [ebp+10h]
0040D798 jle getMax+3Fh (0040d79f)
比較第二個(gè)和第三個(gè)參數(shù)
jle:jump less equal,小于等于則跳轉(zhuǎn)(有符號(hào)數(shù))
跳轉(zhuǎn)地址:0040d79f
18: }else{
19: return k;
0040D79F mov eax,dword ptr [ebp+10h]
可以分析出,如果第二個(gè)參數(shù)小于等于第三個(gè)參數(shù)則跳轉(zhuǎn)到0040D79F,并將第三個(gè)參數(shù)賦值給eax作為返回值,這條線路為(i<=j<=k)
否則返回執(zhí)行返回命令,將第二個(gè)參數(shù)賦值給eax作為返回值,這條線路為(i<=j且k<=j)
17: return j;
0040D79A mov eax,dword ptr [ebp+0Ch]
0040D79D jmp getMax+42h (0040d7a2)
總結(jié)
不難發(fā)現(xiàn),三個(gè)數(shù)求最大值,只需兩兩比較就可以得出結(jié)果
分析if else的關(guān)鍵在于觀察涉及的參數(shù)和jcc語(yǔ)句
此案例中就是直接采取了cmp 外加 jle來(lái)進(jìn)行分支的選擇和跳轉(zhuǎn)
因?yàn)椴环蠗l件的才要跳轉(zhuǎn)走,所以在條件比較中,是大于的比較如i>j,所使用的匯編為jle 小于等于的比較
不按套路比較
此次案例并不能代表所有情況,實(shí)際分析要具體看情況來(lái)采取分析,有的程序可能就是不按套路出牌,先看看按套路出牌的程序,然后我們自己來(lái)模擬個(gè)不按套路的
正常套路
拿兩個(gè)數(shù)的比較為例
#include "stdafx.h"
int getMax2(int i,int j){
if(i>j){
return i;
}else{
return j;
}
}
int main(int argc, char* argv[])
{
getMax2(1,2);
return 0;
}
先看一般的匯編代碼:
9: if(i>j){
0040D778 mov eax,dword ptr [ebp+8]
0040D77B cmp eax,dword ptr [ebp+0Ch]
0040D77E jle getMax2+25h (0040d785)
10: return i;
0040D780 mov eax,dword ptr [ebp+8]
0040D783 jmp getMax2+28h (0040d788)
11: }else{
12: return j;
0040D785 mov eax,dword ptr [ebp+0Ch]
13: }
14: }
依舊是采用cmp 和 jle來(lái)進(jìn)行判斷,和套路一致
不按套路
完整代碼
#include "stdafx.h"
int __declspec(naked) myGetMax(int i,int j){
__asm{
//保留調(diào)用前堆棧
push ebp
//提升堆棧
mov ebp,esp
sub esp,0x40
//保護(hù)現(xiàn)場(chǎng)
push ebx
push esi
push edi
//初始化提升的堆棧,填充緩沖區(qū)
mov eax,0xCCCCCCCC
mov ecx,0x10
lea edi,dword ptr ds:[ebp-0x40]
rep stosd
//函數(shù)核心功能
//取出參數(shù)
mov eax,dword ptr ds:[ebp+8]
//比較參數(shù)
cmp eax,[ebp+0xC]
jge _ret
mov eax,[ebp+0xC]
_ret:
//恢復(fù)現(xiàn)場(chǎng)
pop edi
pop esi
pop ebx
//降低堆棧
mov esp,ebp
pop ebp
//返回
ret
}
}
int main(int argc, char* argv[])
{
int result=myGetMax(1,2);
printf("%d\n",result);
result=myGetMax(4,3);
printf("%d\n",result);
return 0;
}
功能代碼分析
這里截取出我們自己實(shí)現(xiàn)比較的那段代碼
//函數(shù)核心功能
//取出參數(shù)
mov eax,dword ptr ds:[ebp+8]
//比較參數(shù)
cmp eax,[ebp+0xC]
jge _ret
mov eax,[ebp+0xC]
_ret:
//恢復(fù)現(xiàn)場(chǎng)
pop edi
pop esi
pop ebx
//降低堆棧
mov esp,ebp
pop ebp
//返回
ret
首先我們這里將第一個(gè)參數(shù)賦值給eax
然后比較eax和第二個(gè)參數(shù),也就是比較第一個(gè)參數(shù)和第二個(gè)參數(shù)
這邊使用的就不是jle而是jge了
jge:jump greater equal,即大于等于則跳轉(zhuǎn)
前面已經(jīng)將第一個(gè)參數(shù)賦值給了eax,而eax又是作為返回值來(lái)傳遞的
當(dāng)?shù)谝粋€(gè)參數(shù)大于等于第二個(gè)參數(shù)時(shí),就可以直接返回了
如果不是則不跳轉(zhuǎn),執(zhí)行下面的將第二個(gè)參數(shù)賦值給eax作為返回值
這里注意到我在匯編中自己定義了一個(gè)段:_ret,來(lái)作為跳轉(zhuǎn)的地址來(lái)使用
最后測(cè)試一下結(jié)果:
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-530063.html
可以正確得到兩個(gè)數(shù)中的最大值文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-530063.html
到了這里,關(guān)于Windows逆向安全(一)之基礎(chǔ)知識(shí)(八)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!