动静结合分析
源代码
#include <stdio.h> #include <string.h> #include <stdlib.h> void Attack() { printf("Hello!:-)\n"); exit(0); } void fun() { char s_passwd[6] = "ABCDE"; char str[6]; FILE *f_o; if(!(f_o = fopen("C:\\Program Files\\Microsoft Visual Studio\\MyProjects\\reverseProject\\Debug\\passwd.txt", "r"))) exit(0); fscanf(f_o, "%s", str); str[5] = 0; if(strcmp(str, s_passwd) == 0) printf("OK\n"); else printf("NO\n"); } int main(int argc, char const *argv[]) { fun(); return 0; } // passwd.txt(Hex) 6161 6161 6262 6262 6363 6363 6464 6464 6565 6565 3010 40
分析过程
静态分析
fun() 函数运行流程
先找到 fun 函数入口点 0x00401080 ,之后分析 fun 函数(总流程的图太模糊了,不知道当初怎么截的图)


子函数运行流程
仔细观察 fun 函数的流程,可以看到 fun 的 fopen() 分支,如果没有文件就直接 exit(0) ,程序结束。但在下面一个 if 分支,两种情况后又会继续向下执行,符合代码流程。静态分析还可以看到相应的汇编代码和虚拟地址,为动态分析提供流程指导


动态分析
fun() 函数初始化
利用 ollydbg 进行动态调试,程序运行到 0x00401096 处会把 0x0012fed8~0x0012ff28 ,51 个单位内存都置零,为 fun 函数栈帧初始化内存,fun 栈帧大小有 54 个内存单位。
0x0012fecc 为 ESP,0x0012ff2c 为 EBP ,0x0012ff2c ~ 0x0012ff80 为 Windows 内核函数的栈帧。 0x0012ff30 是 RET 地址。
shellcode 构建
初始化内存后,会在 EBP-0x8 处为 fun 函数中的变量 passwd[6] 在内存中开辟空间并置为相应的值(赋值“ABCDE” 内存中即 44434241 cccc0045)。
fscanf 函数会在 passwd[6] 往低地址的方向选择内存,即 EBP-0x14(20) 0x0012ff18 执行 fscanf 函数,这处地址的值是本函数的返回地址,为了执行完 fscanf 后能正常返回。
str 会从 0x12ff1c 开始写入,这就是我们要利用的缓冲区漏洞。所以我们对 shellcode 构建,前 20 字节可以随便写,21~24 字节要是我们寻找到的 JMP ESP 指令


shellcode 执行
进行缓冲区溢出攻击后,fun 函数栈帧及原 windows 内核函数的栈帧已被 shellcode 覆盖,fun 函数返回地址处的指令是 JMP ESP,而 fun 返回后 ESP 就是 0x0012ff34,是我们填充的 0x90 指令,此后程序按照我们的 shellcode 执行,直到执行完 shellcode 中 exitThread 函数后程序运行结束



程序运行结果
