测试文件:https://www.lanzous.com/ib5y9cb
代码分析
1 __int64 __fastcall main(__int64 a1, char **a2, char **a3) 2 { 3 signed int i; // [rsp+8h] [rbp-68h] 4 signed int j; // [rsp+Ch] [rbp-64h] 5 __int64 v6; // [rsp+10h] [rbp-60h] 6 __int64 v7; // [rsp+18h] [rbp-58h] 7 __int64 v8; // [rsp+20h] [rbp-50h] 8 __int64 v9; // [rsp+28h] [rbp-48h] 9 __int64 v10; // [rsp+30h] [rbp-40h] 10 __int64 v11; // [rsp+40h] [rbp-30h] 11 __int64 v12; // [rsp+48h] [rbp-28h] 12 __int64 v13; // [rsp+50h] [rbp-20h] 13 __int64 v14; // [rsp+58h] [rbp-18h] 14 __int64 v15; // [rsp+60h] [rbp-10h] 15 unsigned __int64 v16; // [rsp+68h] [rbp-8h] 16 17 v16 = __readfsqword(0x28u); 18 puts("Let us play a game?"); 19 puts("you have six chances to input"); 20 puts("Come on!"); 21 v6 = 0LL; 22 v7 = 0LL; 23 v8 = 0LL; 24 v9 = 0LL; 25 v10 = 0LL; 26 for ( i = 0; i <= 5; ++i ) 27 { 28 printf("%s", "input: ", (unsigned int)i); 29 __isoc99_scanf("%d", (char *)&v6 + 4 * i); 30 } 31 v11 = 0LL; 32 v12 = 0LL; 33 v13 = 0LL; 34 v14 = 0LL; 35 v15 = 0LL; 36 for ( j = 0; j <= 4; j += 2 ) // 0,2,4 37 { 38 dword_601078 = *((_DWORD *)&v6 + j); // 下标0,2,4 39 dword_60107C = *((_DWORD *)&v6 + j + 1); // 下标1,3,5 40 sub_400686((unsigned int *)&dword_601078, &unk_601060); 41 *((_DWORD *)&v11 + j) = dword_601078; 42 *((_DWORD *)&v11 + j + 1) = dword_60107C; 43 } 44 if ( (unsigned int)sub_400770(&v11) != 1 ) 45 { 46 puts("NO NO NO~ "); 47 exit(0); 48 } 49 puts("Congratulation! "); 50 puts("You seccess half "); 51 puts("Do not forget to change input to hex and combine~ "); 52 puts("ByeBye"); 53 return 0LL; 54 } 55 /* Orphan comments: 56 a2指向v6的空间 57 2234 58 */
这段代码,对输入数字的处理,我们可以分成两部分
- 第36~43行代码,输入整型数组变换
- 第44行代码,判断变换后的数组是否满足要求
第二部分
打开sub_400770函数
__int64 __fastcall sub_400770(_DWORD *a1) { __int64 result; // rax if ( a1[2] - a1[3] != 2225223423LL || a1[3] + a1[4] != 4201428739LL || a1[2] - a1[4] != 1121399208LL ) { puts("Wrong!"); result = 0LL; } else if ( *a1 != 0xDF48EF7E || a1[5] != 0x84F30420 || a1[1] != 550153460 ) { puts("Wrong!"); result = 0LL; } else { puts("good!"); result = 1LL; } return result; }
整理信息,我们可以获取到变换后的数组a1的相关信息
a1[2] - a1[3] == 2225223423
a1[3] + a1[4] == 4201428739
a1[2] - a1[4] == 1121399208
a1[0] == 0xDF48EF7E
a1[1] == 550153460
a1[5] == 0x84F30420
用z3解方程
# -*- coding:utf-8 -*- from z3 import * a2,a3,a4 = BitVecs('a2 a3 a4',64) s = Solver() s.add(a2 - a3 == 2225223423) s.add(a3 + a4 == 4201428739) s.add(a2 - a4 == 1121399208) if s.check() == sat: m = s.model() for i in m: print("%s = %ld" % (i, m[i].as_long()))
得到:
a4 = 2652626477
a2 = 3774025685
a3 = 1548802262
第一部分
打开sub_400686函数
__int64 __fastcall sub_400686(unsigned int *a1, _DWORD *a2) { __int64 result; // rax unsigned int v3; // [rsp+1Ch] [rbp-24h] unsigned int v4; // [rsp+20h] [rbp-20h] int v5; // [rsp+24h] [rbp-1Ch] unsigned int i; // [rsp+28h] [rbp-18h] v3 = *a1; v4 = a1[1]; v5 = 0; for ( i = 0; i <= 0x3F; ++i ) { v5 += 1166789954; v3 += (v4 + v5 + 11) ^ ((v4 << 6) + *a2) ^ ((v4 >> 9) + a2[1]) ^ 0x20; v4 += (v3 + v5 + 20) ^ ((v3 << 6) + a2[2]) ^ ((v3 >> 9) + a2[3]) ^ 0x10; } *a1 = v3; result = v4; a1[1] = v4; return result; }
这就是一个利用已知数组unk_601060对我们输入的整型数组进行异或操作,因此我们只需要将整个过程逆过来,for循环那段,你将异或过程看成一个整体就行,最后就能得到输入的整型数组。
脚本
#include <iostream> #pragma warning(disable:4996) using namespace std; int main() { __int64 a[6] = { 3746099070, 550153460, 3774025685, 1548802262, 2652626477, 2230518816 }; unsigned int a2[4] = { 2,2,3,4 }; unsigned int v3, v4; int v5; for (int j = 0; j <= 4; j += 2) { v3 = a[j]; v4 = a[j + 1]; v5 = 1166789954*0x40; for (int i = 0; i <= 0x3F; ++i) { v4 -= (v3 + v5 + 20) ^ ((v3 << 6) + a2[2]) ^ ((v3 >> 9) + a2[3]) ^ 0x10; v3 -= (v4 + v5 + 11) ^ ((v4 << 6) + *a2) ^ ((v4 >> 9) + a2[1]) ^ 0x20; v5 -= 1166789954; } a[j] = v3; a[j + 1] = v4; } /*将整型数组作为字符输出,注意计算机小端排序*/ for (int i = 0; i < 6; ++i) { cout << *((char*)&a[i] + 2) << *((char*)&a[i] + 1) << * ((char*)&a[i]); } system("PAUSE"); return 0; }
get flag!
flag{re_is_great!}