本人首发在先知社区
https://xz.aliyun.com/t/4282
这是Hackergame 2018的一道题目
拿到题目,是一个压缩包,进行解压后发现是一个.exe可执行程序,双击可以正常运行
随意输入,总是会出来一个倒序的base64编码后的字符串
我们用python进行解码
得到一个假的flag 不用管他
Exeinfo PE载入可以发现是VC++写的64位程序,并且没有加壳
我们直接使用IDA x64载入
shift + F12可以看到程序中的一些字符串
我们双击正确的引用
可以看到有好多跳转
我们可以从下向上进行分析
在最近的jnz跳转处 按F5 查看伪代码
如下所示:
void __usercall sub_7FF7EBA1498F(__int64 [email protected]<rbp>) { unsigned __int8 *v1; // rax unsigned __int8 v2; // dl int v3; // eax *(a1 + 112) = a1 + 384; *(a1 + 40) = -1i64; do ++*(a1 + 40); while ( *(*(a1 + 112) + *(a1 + 40)) ); *(a1 + 64) = *(a1 + 40); qmemcpy((a1 + 800), a9eetw4DFh4xu, 0x39ui64); // qmemcpy将内存中的字符串进行拷贝 memset((a1 + 857), 0, 0x8Fui64); // memset()函数初始化了一块内存空间 类似于char getflxg[200] = { 0 } sub_7FF7EBA11590(a1 + 144, (a1 + 384), *(a1 + 64));// 进行base64加密 memset((a1 + 176), 0, 0xC8ui64); // 再初始化一块空间 *(a1 + 80) = sub_7FF7EBA11A40(a1 + 144); *(a1 + 48) = a1 + 176; *(a1 + 136) = *(a1 + 48); do { *(a1 + 32) = **(a1 + 80); **(a1 + 48) = *(a1 + 32); ++*(a1 + 80); ++*(a1 + 48); } while ( *(a1 + 32) ); strrev((a1 + 176)); // strrev用于反转字符串 memset((a1 + 592), 0, 0xC8ui64); // 又初始化了一个新的字符数组 for ( *(a1 + 36) = 0; ; ++*(a1 + 36) ) { *(a1 + 120) = a1 + 176; *(a1 + 56) = -1i64; do ++*(a1 + 56); while ( *(*(a1 + 120) + *(a1 + 56)) ); if ( *(a1 + 36) >= *(a1 + 56) ) break; *(a1 + *(a1 + 36) + 592) = *(a1 + 36) ^ *(a1 + *(a1 + 36) + 176);// 这个for循环用于将反转后的str与len(str)进行异或操作 } v1 = (a1 + 592); while ( 1 ) // 这个while循环将得到的串与内存中的进行比较 若相等,则v3等于0并且跳转到label_15 { v2 = *v1; if ( *v1 != v1[208] ) break; ++v1; if ( !v2 ) { v3 = 0; goto LABEL_15; } } v3 = -(v2 < v1[208]) | 1; LABEL_15: if ( v3 ) { sub_7FF7EBA124B0(std::cout, "\n你的flxg不正确!"); *(a1 + 'D') = 0; } else // v3=0,输出成功提示信息 { sub_7FF7EBA124B0(std::cout, "\n祝贺你,你输入的flxg是正确的!"); *(a1 + 'H') = 0; } sub_7FF7EBA11AE0(a1 + 144); JUMPOUT(&loc_7FF7EBA119F4); }
可以看到 重要的部分就在这段代码中
这个程序主要流程很简单,先将我们的输入进行标准的base64编码,接着进行翻转,将a[i]与i分别异或,最后与内存中的flag进行比较看是否一致
那我们就可以逆出来flag
双击这个字符串数组 接着shift + e 复制出来得到加密后的串
得到之后,用python解即可
import base64 enc = [0x39, 0x65, 0x45, 0x54, 0x77, 0x5F, 0x34, 0x5F, 0x64, 0x5F, 0x66, 0x68, 0x3C, 0x34, 0x58, 0x55, 0x7F, 0x43, 0x21, 0x4B, 0x7F, 0x20, 0x43, 0x76, 0x5F, 0x20, 0x4C, 0x4D, 0x7A, 0x53, 0x70, 0x7D, 0x56, 0x4D, 0x65, 0x47, 0x4C, 0x5D, 0x71, 0x43, 0x18, 0x6F, 0x47, 0x48, 0x42, 0x18, 0x1C, 0x4D, 0x74, 0x45, 0x01, 0x69, 0x00, 0x4D, 0x5B, 0x6D] aa = '' flag = '' #先求出xor之前的 for i in range(len(enc)): aa += chr(enc[i] ^ i) #print aa #9dGWsZ2XlVlc09VZoR3Xk5UaG9VVfNnbvlGdhxWd0Fmcn52bDt3Z4xmZ #翻转并base64解码 print base64.b64decode(aa[::-1]) #flxg{Congratulations_U_FiNd_the_trUe_flXg}
总结: 做这道题目时 因为是C++的 伪代码看着也会很乱 直接看不容易理解 这时候可以开启IDA动态调试 下断点进行分析