[系统安全14]动态调试技巧补充-循环

循环

vc++使用三种语法来完成循环结构,分别为do..while,while,for。虽然完成的功能都是循环,但是每种语法有着不同的执行流程。

do..while循环:先执行循环体,后比较判断。
while循环:先比较判断,后执行循环体。
for循环:先初始化,再比较判断,最后执行循环体。

逆向前的知识

  • 局部变量

在OD中局部变量一般是EBP-8,EBP-C....
函数开始有push ebp、mov ebp,esp,或者也可能有ESP+xxx,但是函数开头没有push ebp之类的指令。

  • 函数传参

在OD中函数传参一般是EBP+8,EBP+c...
函数开头有push ebp、mov ebp,esp。

  • 传递参数

传递参数是【push 十六进制的值】,然后执行call指令,这里相当于调用了一个函数。

003F197E    6A 01           push 0x1    ;这是被传参的参数
003F1980    E8 46F9FFFF     call 循环.003F12CB
003F1985    83C4 04         add esp,0x4
003F1988    6A 14           push 0x14    ;这是被传参的参数
003F198A    E8 7AF7FFFF     call 循环.003F1109
003F198F    83C4 04         add esp,0x4
003F1992    6A 03           push 0x3   ;这是被传参的参数
003F1994    E8 7AF7FFFF     call 循环.003F1113 

反汇编C语言源码

#include "stdafx.h"
//for循环函数
int for_fun(int nCount)
{
	int nSum = 0;
	for (int nIndex = 0 ; nIndex<nCount;nIndex++)
	{
		nSum += nIndex;

	}
	printf(" 111111111111111  %d\n ", nSum);
	return nSum;
};

//do..while循环函数
int do_while_fun(int nCount) 
{
	int nSum = 0;
	int nIndex = 0;
	do {
		nSum += nIndex;
		nIndex++;
		//循环判断,是否结束循环体
	} while (nIndex<=nCount);
	printf(" 22222222222222222  %d\n ", nSum);
	return nSum;
}

//while循环函数
int while_fun(int nCount)
{
	int nSum = 0;
	int nIndex = 0;
	while (nIndex<nCount)
	{
		nSum += nIndex;
		nIndex++;
	}
	printf("333333333333333333 %d\n ", nSum);
	return nSum;
}
int main()
{
	for_fun(2);
	do_while_fun(20);
	while_fun(3);
    return 0;
}

do...while循环

do..while的工作流程相对比较简单,先执行加的运算,然后在cmp判断条件是否满足,然后jle到mov nSum的值给eax的地方。

003F16F0 >  55              push ebp
003F16F1    8BEC            mov ebp,esp
003F16F3    81EC D8000000   sub esp,0xD8
003F16F9    53              push ebx
003F16FA    56              push esi                                 ; 循环.<ModuleEntryPoint>
003F16FB    57              push edi                                 ; 循环.<ModuleEntryPoint>
003F16FC    8DBD 28FFFFFF   lea edi,dword ptr ss:[ebp-0xD8]
003F1702    B9 36000000     mov ecx,0x36
003F1707    B8 CCCCCCCC     mov eax,0xCCCCCCCC
003F170C    F3:AB           rep stos dword ptr es:[edi]
003F170E    C745 F8 0000000>mov dword ptr ss:[ebp-0x8],0x0           ; int nSum = 0
003F1715    C745 EC 0000000>mov dword ptr ss:[ebp-0x14],0x0          ; int nIndex = 0
003F171C    8B45 F8         mov eax,dword ptr ss:[ebp-0x8]           ; mov nSum的值给eax
003F171F    0345 EC         add eax,dword ptr ss:[ebp-0x14]          ; nIndex+nSum=eax
003F1722    8945 F8         mov dword ptr ss:[ebp-0x8],eax           ; 把nIdex+nSum的结果给eax,等价于:nSum += i;
003F1725    8B45 EC         mov eax,dword ptr ss:[ebp-0x14]
003F1728    83C0 01         add eax,0x1                              ; nIndex++
003F172B    8945 EC         mov dword ptr ss:[ebp-0x14],eax
003F172E    8B45 EC         mov eax,dword ptr ss:[ebp-0x14]          ; nIndex要赋值给eax
003F1731    3B45 08         cmp eax,dword ptr ss:[ebp+0x8]           ; +号函数传参的参数,我传参进来的是20,hex为14
003F1734  ^ 7E E6           jle short 循环.003F171C                    ; Do..while循环没有jmp,jxx只要满足条件则跳转,等价于} while (nIndex<=nCount);
003F1736    8B45 F8         mov eax,dword ptr ss:[ebp-0x8]           ; 把nSum赋值给eax
003F1739    50              push eax
003F173A    68 4C6B3F00     push 循环.003F6B4C                         ;  22222222222222222  %d\n
003F173F    E8 E1FBFFFF     call 循环.003F1325                         ; printf
003F1744    83C4 08         add esp,0x8
003F1747    8B45 F8         mov eax,dword ptr ss:[ebp-0x8]
003F174A    5F              pop edi                                  ; 循环.<ModuleEntryPoint>
003F174B    5E              pop esi                                  ; 循环.<ModuleEntryPoint>
003F174C    5B              pop ebx
003F174D    81C4 D8000000   add esp,0xD8
003F1753    3BEC            cmp ebp,esp
003F1755    E8 BEF9FFFF     call 循环.003F1118
003F175A    8BE5            mov esp,ebp
003F175C    5D              pop ebp
003F175D    C3              retn

do..while循环特征

如果遇到以下代码块,就可以判断是do...while循环,do..while在执行前无需检查就执行代码块内的语句,然后判断条件是否满足,根据条件跳转指令决定是否跳转到循环语句的首地址。

do_while 循环

        mov [xxx],0
loop:
        xxxxx
        cmp eax,xxx
        jxx loop_;

while循环

while循环和do循环正好相反,在执行循环语句块之前,必须要进行条件判断,判断比较结果后再选择是否执行循环语句块。执行完毕后再跳回到循环语句块的首地址,再进行比较,条件满足跳出循环。

011E182E    C745 F8 0000000>mov dword ptr ss:[ebp-0x8],0x0           ; int nSum = 0;
011E1835    C745 EC 0000000>mov dword ptr ss:[ebp-0x14],0x0          ; int nIndex = 0;
011E183C    8B45 EC         mov eax,dword ptr ss:[ebp-0x14]
011E183F    3B45 08         cmp eax,dword ptr ss:[ebp+0x8]           ; while(nIndex<nCount),这里是与传参进来的参数进行比对
011E1842    7D 14           jge short 循环.011E1858                    ; 满足条件jge执行,然后跳转到011E1858
011E1844    8B45 F8         mov eax,dword ptr ss:[ebp-0x8]           ; 局部变量nSum 赋值给 eax
011E1847    0345 EC         add eax,dword ptr ss:[ebp-0x14]          ; eax跟nIndex相加,结果保存在eax。
011E184A    8945 F8         mov dword ptr ss:[ebp-0x8],eax           ; nSum = nIndex+nSum
011E184D    8B45 EC         mov eax,dword ptr ss:[ebp-0x14]
011E1850    83C0 01         add eax,0x1                              ; nIndex+1,等价于nIndex++
011E1853    8945 EC         mov dword ptr ss:[ebp-0x14],eax
011E1856  ^ EB E4           jmp short 循环.011E183C                    ; 跳转回去,while条件对比的地方,把nIndex执行后的结果赋值到eax寄存器中
011E1858    8B45 F8         mov eax,dword ptr ss:[ebp-0x8]
011E185B    50              push eax

while循环特征

while循环的特征是先执行对比,在执行语句。

         mov [xxx],0
loop_
          cmp eax,xxx
           jxx loop_break;
           xxxx
          jmp loop_

for循环

for循环是三种循环结构中最复杂的一种。for循环里由赋初值,设置循环条件、设置循环步长这三条语句组成。

在反汇编指令中,一共有3条跳转指令。jmp,jge,jmp。第一条jmp指令跳转到判断循环条件是否满足的地方,执行代码块内的数据,等价于执行nSum = nSum+nIndex;第二条cmp指令对比如果满足条件修改标志位执行【jge short 循环.001617CA】跳出循环,否则不实现跳转继续向下执行。第三条jmp指令跳转到【mov eax,dword ptr ss:[ebp-0x14]】 、【add eax,0x1】,等价于执行nIndex++,执行add操作后, 再次对比条件是否满足。

0016179E    C745 F8 0000000>mov dword ptr ss:[ebp-0x8],0x0                        ; int nSum = 0;
001617A5    C745 EC 0000000>mov dword ptr ss:[ebp-0x14],0x0                       ; int nIndex = 0;
001617AC    EB 09           jmp short 循环.001617B7
001617AE    8B45 EC         mov eax,dword ptr ss:[ebp-0x14]                       ; 等价于执行nIndex++
001617B1    83C0 01         add eax,0x1
001617B4    8945 EC         mov dword ptr ss:[ebp-0x14],eax
001617B7    8B45 EC         mov eax,dword ptr ss:[ebp-0x14]                       ; nIndex赋值给eax
001617BA    3B45 08         cmp eax,dword ptr ss:[ebp+0x8]                        ; 判断循环条件是否满足,是不是需要继续循环,否则跳转到nIndex++的地址处,等价于nIndex<nCount
001617BD    7D 0B           jge short 循环.001617CA                                 ; 满足条件跳转
001617BF    8B45 F8         mov eax,dword ptr ss:[ebp-0x8]
001617C2    0345 EC         add eax,dword ptr ss:[ebp-0x14]                       ; 等价于nSum = nSum+nIndex
001617C5    8945 F8         mov dword ptr ss:[ebp-0x8],eax
001617C8  ^ EB E4           jmp short 循环.001617AE
001617CA    8B45 F8         mov eax,dword ptr ss:[ebp-0x8]
001617CD    50              push eax

for循环特征

for循环的简单特征如下,比while和do..while循环要复杂一些的地方是多了一层跳转,要执行条件值++的操作

                mov [xxx],0
                jmp jmp_cmp
loop_
                i++;
jmp_cmp
                cmp eax,xxx
                jxx loop_break;
                xxxxx
                jmp loop_
posted @ 2017-04-03 16:08  17bdw  阅读(532)  评论(0编辑  收藏  举报