通俗来说,我们的程序是需要转换方向的,如果不控制方向,那么我们的程序就不能做出抉择,只能一味往下执行
- if语句逆向学习
DWORD i=1;
if(1==i)
{
printf("1");
}
//1
当我们使用反汇编查看if语句流程控制的时候发现汇编里使用jne来表示1==i
if (1 == i)
003018D8 83 3D 28 A0 30 00 01 cmp dword ptr [i (030A028h)],1
if (1 == i)
003018DF 75 0D jne main+3Eh (03018EEh)
{
printf("1");
003018E1 68 30 7B 30 00 push offset string "1" (0307B30h)
003018E6 E8 60 F7 FF FF call _printf (030104Bh)
003018EB 83 C4 04 add esp,4
}
return 0;
003018EE 33 C0 xor eax,eax
}
知识点:jcc,标志寄存器,cmp指令
我们简单分析一下if语句的汇编代码,比较全局变量的i和立即数1,cmp指令
让我们回顾一下cmp指令
:该指令是比较两个操作数,实际上它相对于SUB指令,但是相减的结构并不保存到第一个操作数中,只是根据相减的结果来改变零标志位,两个操作数相等的时候,零标志位1
通过jcc判断两个值,结果就是1-1,ZF标志位为1
再回顾一下jcc中的jne
:jne-结果不为0则跳转(1减1等0,结果为0则不跳转)-zf=0
也就是说通过cmp指令比较内存和操作数,得到的结果是相等,zf零标志位为1,通过jjc判断以后不跳转,因为jne的条件是两个数相减以后不为0,然后继续执行下面的代码
如果(i【1】==1)
{
执行语句
}
我们根据jjc猜测一下,如果我们的代码是i!=1.则jcc应该是je!
让我们修改代码查看反汇编:
if (1 != i)
00E918D8 83 3D 28 A0 E9 00 01 cmp dword ptr [i (0E9A028h)],1
00E918DF 74 0D je main+3Eh (0E918EEh)
{//如同我们所分析的一样,如果!=则是通过jjc里面的je来判断
DWORD i=2;
if(1==i)
{
printf("1");
}else
if(2==i)
{
printf("2");
}
//1
下面来进行对if else的逆向分析!
if (1 == i)
009018DF 83 7D F8 01 cmp dword ptr [i],1
009018E3 75 0F jne main+44h (09018F4h)
{
printf("1");
009018E5 68 30 7B 90 00 push offset string "1" (0907B30h)
009018EA E8 5C F7 FF FF call _printf (090104Bh)
009018EF 83 C4 04 add esp,4
009018F2 EB 13 jmp main+57h (0901907h)
}
else if (2 == i)
009018F4 83 7D F8 02 cmp dword ptr [i],2
009018F8 75 0D jne main+57h (0901907h)
{
printf("2");
009018FA 68 34 7B 90 00 push offset string "2" (0907B34h)
009018FF E8 47 F7 FF FF call _printf (090104Bh)
00901904 83 C4 04 add esp,4
}
return 0;
if语句的原理就这样浮现在了眼前,多个if else不过是多层的je和jne的不停判断而已,相等就执行,不相等就跳到下面去执行!
- switch…case逆向分析
DWORD i = 2;
switch (i)
{
case 1:
printf("1");
break;
case 2:
printf("1");
break;
default:
break;
}
一个简单的switch语句
DWORD i = 2;
009D18D8 C7 45 F8 02 00 00 00 mov dword ptr [i],2
switch (i)
009D18DF 8B 45 F8 mov eax,dword ptr [i]
009D18E2 89 85 30 FF FF FF mov dword ptr [ebp-0D0h],eax
009D18E8 83 BD 30 FF FF FF 01 cmp dword ptr [ebp-0D0h],1
009D18EF 74 0B je main+4Ch (09D18FCh)
009D18F1 83 BD 30 FF FF FF 02 cmp dword ptr [ebp-0D0h],2
009D18F8 74 11 je main+5Bh (09D190Bh)
009D18FA EB 1C jmp main+68h (09D1918h)
{
case 1:
printf("1");
009D18FC 68 30 7B 9D 00 push offset string "1" (09D7B30h)
009D1901 E8 45 F7 FF FF call _printf (09D104Bh)
009D1906 83 C4 04 add esp,4
break;
009D1909 EB 0D jmp main+68h (09D1918h)
case 2:
printf("1");
009D190B 68 30 7B 9D 00 push offset string "1" (09D7B30h)
009D1910 E8 36 F7 FF FF call _printf (09D104Bh)
009D1915 83 C4 04 add esp,4
break;
default:
break;
}
让我们先清理一下不需要的信息
DWORD i = 2;
009D18D8 mov dword ptr [ebp-8],2
switch (i)
009D18DF mov eax,dword ptr [ebp-8]
009D18E2 mov dword ptr [ebp+FFFFFF30h],eax
009D18E8 cmp dword ptr [ebp+FFFFFF30h],1
009D18EF je 009D18FC
009D18F1 cmp dword ptr [ebp+FFFFFF30h],2
009D18F8 je 009D190B
009D18FA jmp 009D1918
{
case 1:
printf("1");
009D18FC push 9D7B30h
009D1901 call 009D104B
009D1906 add esp,4
break;
009D1909 jmp 009D1918
case 2:
printf("1");
009D190B push 9D7B30h
009D1910 call 009D104B
009D1915 add esp,4
break;
default:
break;
}
je很熟悉吧,在if语句的逆向中我们学习过,当比较的两个数相等的时候就跳转
通过逆向分析,我们发现switch语句,把我们的参数放到eax寄存器,然后把eax里面的值存到堆栈ebp+FFFFFF30h的位置,然后把第一个case 1和我们的参数比较,如果相等则跳转到case 1里面的代码块进行执行,如果不相等则继续执行,使用case 2和参数比较,发现相等,je的条件是两个数相等则ZF零标志位为1,然后跳转到case 2里面的代码
扩展:为什么switch…case比if…else快?
先来判断一下两个语句的判断方式:
if (1 == i)
009018DF 83 7D F8 01 cmp dword ptr [i],1
009018E3 75 0F jne main+44h (09018F4h)
else if (2 == i)
009018F4 83 7D F8 02 cmp dword ptr [i],2
009018F8 75 0D jne main+57h (0901907h)
if语句:每次执行的时候就对比一次正不正确
009D18E8 cmp dword ptr [ebp+FFFFFF30h],1
009D18EF je 009D18FC
009D18F1 cmp dword ptr [ebp+FFFFFF30h],2
009D18F8 je 009D190B
009D18FA jmp 009D1918
switch语句:先比较好,然后通过几个je不停得判断该跳转到哪,占用了大量的空间
总结:if语句通过遍历所有的比较项,把每个分支都进行一次比较。
而switch语句,则把case的值存在switch语句里面,通过判断一次参数和case的值,得出跳转的地址
一个是需要查看所有的分支,一个是提前算好了需要 跳转的地方,判断的时候直接跳转到相应的地方
switch语句通过在判断之前就写好需要跳转的地址,大量占用了空间,以达到空间换时间的概念