C语言再学习4-分支--为什么switc_case比if_else快

通俗来说,我们的程序是需要转换方向的,如果不控制方向,那么我们的程序就不能做出抉择,只能一味往下执行

  1. 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的不停判断而已,相等就执行,不相等就跳到下面去执行!



  1. 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语句通过在判断之前就写好需要跳转的地址,大量占用了空间,以达到空间换时间的概念

猜你喜欢

转载自blog.csdn.net/qq_35425243/article/details/82790792