前言
本次我们要介绍的是C/C++中的switch语句在编译为可执行程序后的反汇编内容
一只 DEMO
首先我们需要先写一段示例代码,作为我们的分析对象
void switch_demo(int v)
{switch(v){case 4:printf("v = 4\n");break;case 5:printf("v = 5\n");break;case 6:printf("v = 6\n");break;default:printf("other\n");}
}int main()
{int v = 6;switch_demo(v);return 0;
}
我们需要将上面的代码编译为可执行程序,然后使用x64dbg进行分析
分析
我们先来看一下反汇编的结果,这里我们只看 switch_demo 接口即可
输出打印信息部分
我们按照我们的代码结构来分析上面的反汇编内容,以帮助大家理解;首先出场的是使用printf打印输出信息的部分
我们可以看到输出部分一共有四段,先试用push向printf压入参数,也就是要通过printf打印的字符串,然后使用call 调用 printf 接口
break 部分
我们的代码中有3个break语句,分别对应上图中的3个跳转语句,用于跳转到switch结束的位置
条件判断跳转部分
该部分是 switch 中的条件判断与跳转部分也是最终要的部分,该部分的作用是使用 switch 括号中的操作数依次与case 中的值进行比较,用于决定跳转到哪部分代码
首先是 mov eax, dword ptr ss:[ebp+0x8],switch 的判断条件式通过 switch_demo 函数的参数传递进来的,所以这句话的含义是从参数中取出判断条件保存在eax寄存器中
接下来是 mov dword ptr ss:[ebp-0xC4], eax,该含义是将刚刚保存在 eax 中的参数保存到栈中,地址是 ebp-0xc4
cmp dword ptr ss:[ebp-0xC4], 0x4,这是判断的第一个case语句,和立即数4进行比较
je 0x00F21AEC,如果上面的判断结果是相等,那么就跳转到 0x00f21aec 地址处,我们从上面的反汇编内容中可以看到该处对应的是第一条case语句中的内容,并且执行完成后通过最后的 jmp 语句跳出 switch 结构,也就是代码块结尾的 break 语句
cmp dword ptr ss:[ebp-0xC4], 0x5,如果上面的判断条件不相等就会继续使用保存在栈中的操作数和立即数5进行比较,也就是第二条case语句的值
je 0x00F21AFB,如果上面的判断是相等的,就跳转至 0x00f21afb 地址处,从返回编的图中我们可以看到,该地址属于第二条case语句中的代码,并且同样执行完成后通过 jmp 语句跳出switch 结构
cmp dword ptr ss:[ebp-0xC4], 0x6,如果上面的判断结果依旧不成立,那就继续和6进行比较
je 0x00F21B0A,如果相等,则跳转至第3个case所代表的代码块
jmp 0x00F21B19,如果上面的条件全都不成立则直接跳转至地址 0x00f21b19 地址处,该地址所指向的代码段是switch 最后的 default 代码块
到此我们就完成了 switch 语句的全部分析了
结语
我们可以看到只要理解了不同代码反汇编后的结构理解起来还是很轻松的,如果使用IDA等工具直接进行反编译还可以直接转换为类似于C语言一样的反编译代码,这样分析起来就更加容易了,那么我们该如何防止别人恶意分析我们的程序呢?
程序的安全问题
这就要聊到一个十分重要的话题了,程序的安全性问题,我们的程序发布出去后如果不经过保护其他人还可以十分轻易的看到我们的代码逻辑的,理解了我们的代码逻辑也就可以对我们的程序进行篡改了
那我们要如何进行防护呢?我们可以使用 Virbox protector 工具对我们的程序进行保护,我们的程序编译完成后生成的可执行文件或库等直接拖到 Virbox protector 工具中进行一下保护,其他人就无法分析和调试我们的程序了,同时还能够防止其他人对我们的程序进行篡改