BUUCTF--Dig the way
测试文件:https://wwa.lanzous.com/iS7aDf07jof
代码分析
这道题的关键实际上是栈溢出
1 int __cdecl main(int argc, const char **argv, const char **envp) 2 { 3 int result; // eax 4 int v4; // ebx 5 size_t v5; // eax 6 int v6; // ebx 7 char v7_20[20]; // [esp+1Ch] [ebp-48h] 8 int v8; // [esp+30h] [ebp-34h] 9 int v9; // [esp+34h] [ebp-30h] 10 int v10; // [esp+38h] [ebp-2Ch] 11 int v11; // [esp+3Ch] [ebp-28h] 12 int v12; // [esp+40h] [ebp-24h] 13 int v13; // [esp+44h] [ebp-20h] 14 signed int (__cdecl *func_ptr)(int, int, int); // [esp+48h] [ebp-1Ch] 15 int (__cdecl *cfunc1)(int, int, int); // [esp+4Ch] [ebp-18h] 16 int (__cdecl *cfunc2)(int, int, int); // [esp+50h] [ebp-14h] 17 int cv17; // [esp+54h] [ebp-10h] 18 int cv18; // [esp+58h] [ebp-Ch] 19 FILE *file_ptr; // [esp+5Ch] [ebp-8h] 20 21 __main(); 22 func_ptr = func0; // cv8[12]与cv8[16]交换 23 cfunc1 = func1; // abs(cv8[4]-cv8[8])-abs(cv8[8])-abs(cv8[4])+2 24 cfunc2 = func2; // abs(cv8[12])-abs(cv8[12]+abs[8])+abs(cv8[8])+2 25 v8 = 0; 26 v9 = 1; 27 v10 = 2; 28 v11 = 3; 29 v12 = 3; 30 v13 = 4; 31 file_ptr = fopen("data", "rb"); 32 if ( !file_ptr ) 33 return -1; 34 fseek(file_ptr, 0, 2); // 将流指针指向文件末尾 35 cv18 = ftell(file_ptr); // 获取文件大小 36 fseek(file_ptr, 0, 0); // 指向文件开头 37 cv17 = ftell(file_ptr); // v17=0 38 if ( cv17 ) 39 { 40 puts("something wrong"); 41 result = 0; 42 } 43 else 44 { 45 for ( i = 0; i < cv18; ++i ) 46 { 47 v4 = i; 48 v7_20[v4] = fgetc(file_ptr); 49 } 50 v5 = strlen(v7_20); 51 if ( v5 <= cv18 ) // 循环整个data文件数据 52 { 53 cv18 = v11; // 3 54 i = 0; 55 cv17 = v13; // 4 56 while ( i <= 2 ) 57 { 58 v6 = i + 1; 59 *(&v8 + v6) = (*(&func_ptr + i))((int)&v8, v12, v13);// 返回1 60 v12 = ++i; // 1,2 61 v13 = i + 1; // 2,3 62 } 63 if ( v11 ) 64 { 65 result = -1; 66 } 67 else 68 { 69 get_key(cv18, cv17); 70 system("PAUSE"); 71 result = 0; 72 } 73 } 74 else 75 { 76 result = -1; 77 } 78 } 79 return result; 80 }
通过对程序的分析,我们可以初步的将程序分为三个部分:
- 文件数据读取
- 函数调用执行
- v11判断(需要执行get_key函数)获取flag
第三部分
这里v11需要返回0,才能执行get_key获取到flag。
第二部分
对于func0,func1,func2函数执行了如下操作
func0:v8[4*v12]与v8[4*v13]交换
func1:abs(v8[4*v12]+v8[4*v13])-abs(v8[4*v13])-abs(v8[4*v12])+2
func2:abs(v8[4*v13])-abs(v8[4*v13]+abs[4*v12])+abs(v8[4*v12])+2
观察三个函数,可以发现:
- func0在交换栈中数据的位置(v8下方第v12个变量与第v13个变量交换)
- func1的返回值正负0都可能
- func2函数的值恒大于0
循环三个函数,返回给*(&v8 + v6),实际就是将函数值分别返回给v9,v10,v11,最后一个函数在给v11赋值,但是func2的值恒大于0,因此不可能获取到flag。
我们需要利用func0函数将指向func1,func2的指针位置在栈中的位置调换,所以v12,v13需要分别等于7,8。
第一部分
这部分在读取data文件中所有的数据存入v7_20中,而恰好我们可以利用数据溢出,对v12,v13进行赋值
我们需要从第20+4*4=36字节之后开始对v12,v13赋值7,8,即
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 07 00 00 00 08 00 00 00
当我们运行时,发现
运行func1实际就是abs(v10-v11)-abs(v11)-abs(v10)+2
v10的值为2,要使得整体的值为0,则v11为-1,即0xFFFF
得到最终的date文件数据
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF FF FF FF 07 00 00 00 08 00 00 00
get flag
flag{8cda1bdb68a72a392a3968a71bdb8cda}