测试文件:https://static2.ichunqiu.com/icq/resources/fileupload//CTF/JCTF2014/re200 参考文章:https://blog.csdn.net/chenlycly/article/details/53378196 1.程序分析 检测时发现不是PE文件,但是打开16进制却发现了
测试文件:https://static2.ichunqiu.com/icq/resources/fileupload//CTF/JCTF2014/re200
参考文章:https://blog.csdn.net/chenlycly/article/details/53378196
1.程序分析
检测时发现不是PE文件,但是打开16进制却发现了MZ标识,因此我们能够判断文件中存在错误。
1.1 第一处错误
通过观察,发现指向PE文件头的地址为E9,但是实际的地址却是E8。
1.2 第二处错误
将地址修改正确之后,在010Editor打开文件,导入EXE模板
可以看到,正确的PE文件标识应该是0x00004550,但是文件中是0x00FF4550,修改FF为00
将修改后的文件保存为EXE文件
2.IDA打开
定位到main函数
1 __int64 __cdecl main_0() 2 { 3 int v0; // eax 4 __int64 v1; // rax 5 int v2; // eax 6 int v3; // ST08_4 7 int v4; // eax 8 int v5; // eax 9 int v6; // eax 10 int v7; // eax 11 int v8; // eax 12 int v9; // eax 13 int v11; // [esp-10h] [ebp-170h] 14 int v12; // [esp-Ch] [ebp-16Ch] 15 char *v13; // [esp-8h] [ebp-168h] 16 int v14; // [esp-4h] [ebp-164h] 17 int *v15; // [esp+Ch] [ebp-154h] 18 int k; // [esp+D4h] [ebp-8Ch] 19 int j; // [esp+E0h] [ebp-80h] 20 int i; // [esp+ECh] [ebp-74h] 21 char v19; // [esp+FBh] [ebp-65h] 22 int v20; // [esp+104h] [ebp-5Ch] 23 int Dst; // [esp+108h] [ebp-58h] 24 int v22; // [esp+10Ch] [ebp-54h] 25 int v23; // [esp+110h] [ebp-50h] 26 int v24; // [esp+114h] [ebp-4Ch] 27 int v25; // [esp+118h] [ebp-48h] 28 char Str1; // [esp+14Ch] [ebp-14h] 29 int v27; // [esp+14Dh] [ebp-13h] 30 int v28; // [esp+151h] [ebp-Fh] 31 char v29; // [esp+155h] [ebp-Bh] 32 33 v0 = sub_411154(std::cout, "欢迎来到数字游戏 请输入9个数字"); 34 std::basic_ostream<char,std::char_traits<char>>::operator<<(v0, std::endl); 35 Str1 = 0; 36 v27 = 0; 37 v28 = 0; 38 v29 = 0; 39 v20 = 0; 40 j_memset(&Dst, 0, 0x3Cu); 41 for ( i = 0; i < 9; ++i ) 42 std::basic_istream<char,std::char_traits<char>>::operator>>(std::cin, &v20 + i);// v20中输入9个数字 43 if ( v22 * Dst * v20 / 11 != 106 ) // 需要满足条件1 44 goto LABEL_31; 45 if ( (Dst ^ v20) != v22 - 4 ) // 需要满足条件2 46 goto LABEL_31; 47 HIDWORD(v1) = (v22 + Dst + v20) % 100; // v1的计算表达式,反向推倒,需要满足条件3 48 if ( HIDWORD(v1) != 34 ) // v1 = 34 49 goto LABEL_31; 50 if ( v23 == 80 ) // v23=80 51 { 52 for ( j = 0; j < 3; ++j ) 53 { 54 HIDWORD(v1) = (j + 1) % 3; 55 for ( *(&Str1 + j) = *((_BYTE *)&v20 + 4 * HIDWORD(v1)) + *(&v20 + j % 3); ; *(&Str1 + j) /= 2 ) 56 { 57 while ( *(&Str1 + j) < 33 ) 58 { 59 HIDWORD(v1) = j; 60 *(&Str1 + j) *= 2; 61 } 62 if ( *(&Str1 + j) <= 126 ) 63 break; 64 v1 = *(&Str1 + j); 65 } 66 } 67 if ( v24 == 94 && v25 == 98 ) // v24=94,v25=98 68 { 69 for ( k = 3; k < 9; ++k ) 70 { 71 for ( *(&Str1 + k) = *(&Str1 + (k + 1) % 3) + *(&Str1 + k % 3); ; *(&Str1 + k) /= 2 ) 72 { 73 while ( *(&Str1 + k) < 33 ) 74 *(&Str1 + k) *= 2; 75 if ( *(&Str1 + k) <= 126 ) 76 break; 77 } 78 } 79 if ( !j_strcmp(&Str1, "*&8P^bP^b") ) 80 { 81 v2 = sub_411154(std::cout, "success!"); 82 std::basic_ostream<char,std::char_traits<char>>::operator<<(v2, std::endl); 83 v14 = std::endl; // 换行 84 v13 = "abc}"; 85 v12 = v22; 86 v11 = Dst; 87 v3 = v20; 88 v15 = &v11; 89 v4 = sub_411154(std::cout, "jlflag{"); 90 v5 = std::basic_ostream<char,std::char_traits<char>>::operator<<(v4, v3); 91 v6 = std::basic_ostream<char,std::char_traits<char>>::operator<<(v5, v11); 92 v7 = std::basic_ostream<char,std::char_traits<char>>::operator<<(v6, v12); 93 v8 = sub_411154(v7, v13); 94 std::basic_ostream<char,std::char_traits<char>>::operator<<(v8, v14);// 以上输出的组合为v4 v3 v11 v12 v13 v14 95 sub_4112D0(std::cin, &v19); 96 goto LABEL_32; 97 } 98 LABEL_31: 99 v9 = sub_411154(std::cout, "please try again!"); 100 std::basic_ostream<char,std::char_traits<char>>::operator<<(v9, std::endl); 101 goto LABEL_32; 102 } 103 } 104 LABEL_32: 105 v14 = HIDWORD(v1); 106 v13 = 0; 107 return *(_QWORD *)&v13; 108 }
2.1 代码分析
通过第90~94行代码,我们知道正确的flag为组合[v4 v3 v11 v12 v13 v14],其中v4="jlflag{",v13="abc}",v14=std::endl
因此我们只需要求出v3,v11,v12即可,通过第85~87行代码,我们知道v12 = v22;v11 = Dst;v3 = v20;
我们能够通过这三个变量满足的三个表示,求出三个数的值。
3.脚本获取
for v22 in range(100): for dst in range(100): for v20 in range(100): if v22*dst*v20//11 == 106 and (v22 + dst + v20) % 100 == 34: if (dst^v20) == v22 - 4: if (v22 + dst + v20) % 100 == 34: print("jlflag{%d%d%dabc}"%(v22, dst, v20), end=‘\n‘)
jlflag{61315abc}
jlflag{61513abc}
jlflag{13615abc}
jlflag{13156abc}
jlflag{15613abc}
jlflag{15136abc}
将这6组得到的flag一组一组试,就能得到正确flag。(记得去掉jl)
4.get flag!
flag{15613abc}