2.识别嵌套的if语句#include "stdio.h" int main() { int x = 1; int y = 2; if (x == y) { printf("=n"); } else { printf("!=n"); } return 0; }如上简单C的if语句,编译运行后使用IDA Pro加载可执行文件。采用图形化可以直观的看出程序执行流程,如下:
可以看出在0x00411876处cmp及jnz指令(不相等,则跳转),若var_8(x)和var_14(y)不相等则进入右侧程序框0x0041188A处(箭头绿色表示比较结果为真)。同时观察到两个执行路径只有一个会被执行且最终进入0x00411897处(该处进行平栈操作),这一点也是识别if语句的关键点。
3.识别for循环#include "stdio.h" int main() { int x = 0; int y = 1; int z = 2; if (x == y) { if (z == 0) { printf("z is zero and x = y.n"); } else { printf("z is non-zero and x = y.n"); } } else { if (z == 0) { printf("z is zero and x != y.n"); } else { printf("z is non-zero and x != y.n"); } } return 0; }把1中的代码简单的修改一下,在两个执行分支内在嵌套一层if。IDA打开可执行文件如下:
能够看出比较跳转(cmp+jnz)共有三处,但是类似1中情况,在每一处比较跳转后有两条执行路径,但最终只有一条会被执行且最终进行平栈操作。
4.识别while循环for循环总是有4个组件:初始化、比较、执行指令、递增或递减。
#include "stdio.h" int main() { int i; for (i = 0; i < 100; i++) { printf("i = %dn", i); } return 0; }简单C的for循环如上,同样使用IDA打开可执行文件:
在图中共有5个流程框,最上方是函数执行所需的条件;比较发生在0x0041186c处:将var_8与64h(十进制100)进行比较,jge表大于等于则跳转。若比较失败进入到0x0041187D处进行输出,输出完毕后进入到var_8的自增操作。识别for循环的关键点在于var_8自增操作完成后,有一条指回到jge比较框的箭头。
至此可以看出5个流程框分别对应于初始化、比较、执行指令、递增或递减以及最后的平栈操作。
5.分析switch语句while循环频繁的被恶意代码作者使用,来通过循环知道一个条件是否被满足。
#include "stdio.h" int main() { int status = 0; int result = 0; while (status == 0) { result = 1; printf("status is zero and result is %dn", result); } return 0; }如上一个简单C的while循环,使用IDA打开可执行文件如下:
while与for循环的共同点:在执行指令后都有一条指回到比较框(0x00411877处的cmp+jnz)的箭头。
while与for循环的不同点:while只有4个流程框,相对于for循环,while循环没有自增或自减操作。
6. 反汇编数组switch语句被程序员或恶意代码作者用来做一个基于字符或整数的决策。例如,后门通常使用单一的字节值从一系列动作中选择一个。switch语句通常以两种方式被编译:使用if样式或使用跳转表。
5.1 if样式
#include "stdio.h" int main() { int i = 2; switch (i) { case 1: printf("i = %d.n", i + 1); break; case 2: printf("i = %d.n", i + 2); break; case 3: printf("i = %d.n", i + 3); break; default: break; } return 0; }如上简单C的switch语句,使用IDA打开可执行文件如下:
从执行流程上来看,与if语句很类似。在0x00411865处进行赋值(int i = 2),在0x00411875处进行第一次比较(case 1),在0x0041187E、0x00411887处分别进行case2、3的比较。同时观察到在多种指令路径中只有一条能够被执行且最后执行平栈操作。
从上述分析可知,很难知道原始代码是一个switch语句还是一个if语句序列,因为一个编译过的switch语句看起来和一组if语句一样,都包含一组cmp和jcc指令。
5.2 跳转表
在5.1中的代码加入如下情况,此时编译器优化代码来避免进行过多的比较。
case 4: printf("i = %d.n", i + 4); break;使用IDA打开可执行文件后如下:
执行逻辑关系不变,但是此时基于跳转表的形式已经很明显。
数组被程序员用来定义一个相似数据项的有序集合。如下定义两个简单C的数组,两数组都是通过for循环迭代赋值。其中a数组是局部的,b数组是全局的。
#include "stdio.h" int b[5] = {10,45,7,6,5}; int main() { int i; int a[5]; for (i = 0; i < 5; i++) { a[i] = i; b[i] = i; } return 0; }使用IDA打开可执行文件如下:
整体可以看出是典型的5框架for循环,其中数组赋值部分在0x0041178D处。在汇编代码中,数组是通过一个基地址作为起始点来进行访问的。在0x00411793处可知a数组的基地址是var_24;0041179D处可知b数组基地址是dword_41A000。因为全局变量使用内存地址引用,而局部变量通过栈地址引用。



