前面把一些基本的运算都记录完了,后面开始流程结构,其流程结构主要分为分支结构和循环结构。对于流程结构的逆向识别,主要在于首先需要识别是什么,然后识别语句体(花括号上下界位置),因为确定好了这两步后,其里面的主体内容就是前面的基本运算或者又是流程结构(递归进行逐步分解)。
对于流程结构主要就以debug版为主了,因为debug版更加利于研究其结构如何,而release中除了结构以外,还混有一些的优化,对于优化的情况,会再额外对其release进行分析。
先看分支语句,其大体上可分为if和switch,因为其两者的实现机制有稍许的不同,所以这里打算分开来记录,这一篇先记录if语句。
对于if语句主要分以下三类
单分支
双分支
多分支
下面先来看一下单分支的情况
int main(int argc, char* argv[])
{
if(argc)
{
printf("if argc");
}
printf("hello world\r\n");
return 0;
}
对应的汇编代码,这里是Release版代码,因为debug差不多所以就选择一个观察
9: if(argc)
00401028 83 7D 08 00 cmp dword ptr [ebp+8],0
0040102C 74 0D je main+2Bh (0040103b)//为零则跳转,跳转的位置是if结束
10: {
11: printf("if argc");
0040102E 68 2C 20 42 00 push offset string "if argc" (0042202c)
00401033 E8 38 00 00 00 call printf (00401070)
00401038 83 C4 04 add esp,4
12: }
13: printf("hello world\r\n");
0040103B 68 1C 20 42 00 push offset string "hello world\r\n" (0042201c)
对于上面的汇编代码,如果argc为零则进行跳转,其跳转的地址就是if语句的结束(下花括号),而上花括号就是je跳转的下一行代码开始,这样子我们就可以确定了if语句块的上下界位置了。
然后对于跳转逻辑,可以发现此处的汇编逻辑代码与我们的高级代码的逻辑是相反的,因为按照if语句的规定,满足if判定的表达式才能执行if的语句块,而汇编语言的条件跳转却是满足某条件则跳转(绕过语句块不执行),这一点是和C语言是相反的。
那么如果C语言编译可以把if和else的语句块进行相互的调换,那么是不是就能和C语言的逻辑一致呢(调换后if的执行块在下面,那么条件符合就会跳转到下面执行)。
是的,这样子理论上是可行的,只是因为C语言的根据代码行的位置来决定编译后的二进制代码的地址高低的(有时会使用标号相减来得到代码段的长度),所以C编译器不能随意改变代码行在内存中的顺序。
下面简化一下单分支的汇编情况
jxx IF_END
IF_BEGIN:
....
IF_END:
结构特性
条件跳转是增量跳转 - 向下跳
跳转的目标标号上面没有jmp
确定好if语句的上下界后,然后对其条件的反条件进行还原即可。
下面来看双分支结构的情况
int main(int argc, char* argv[])
{
if(argc)
{
printf("if if");
}
else
{
printf("else else");
}
return 0;
}
对应的汇编代码讲解
9: if(argc)
0040FB98 83 7D 08 00 cmp