# 主函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
int __cdecl main(int argc, const char **argv, const char **envp)
{
bool v3; // si
__int64 *v4; // rax
unsigned __int8 *v5; // rax
unsigned __int8 *v6; // rbx
int v7; // er10
__int64 v8; // r11
void **v9; // r9
void **v10; // r8
__int64 v11; // rdi
__int64 v12; // r15
__int64 v13; // r12
__int64 v14; // rbp
int v15; // ecx
unsigned __int8 *v16; // rdx
__int64 v17; // rdi
__int64 *v18; // r14
__int64 v19; // rbp
__int64 v20; // r13
__int64 *v21; // rdi
__int64 v22; // r12
__int64 v23; // r15
__int64 v24; // rbp
__int64 v25; // rdx
__int64 v26; // rbp
__int64 v27; // rbp
__int64 v28; // r10
__int64 v29; // rdi
__int64 v30; // r8
bool v31; // dl
__int64 *v32; // rax
void **v33; // rdx
__int64 *v34; // rax
__int64 *v35; // rax
void *v36; // rcx
__int64 v38; // [rsp+20h] [rbp-68h]
void *Block[2]; // [rsp+30h] [rbp-58h] BYREF
unsigned __int64 v40; // [rsp+40h] [rbp-48h]
unsigned __int64 v41; // [rsp+48h] [rbp-40h]

v3 = 0;
v40 = 0i64;
v41 = 15i64;
LOBYTE(Block[0]) = 0;
v4 = sub_7FF793A919C0(std::cout, "I'm a first timer of Logic algebra , how about you?");
std::ostream::operator<<(v4, sub_7FF793A91B90);
sub_7FF793A919C0(std::cout, "Let's start our game,Please input your flag:");
sub_7FF793A91DE0(std::cin, Block);
std::ostream::operator<<(std::cout, sub_7FF793A91B90);
if ( v40 - 5 > 25 )
{
v35 = sub_7FF793A919C0(std::cout, "Wrong input ,no GXY{} in input words");
std::ostream::operator<<(v35, sub_7FF793A91B90);
goto LABEL_43;
}
v5 = operator new(32ui64);
v6 = v5;
if ( v5 )
{
*v5 = 0i64;
*(v5 + 1) = 0i64;
*(v5 + 2) = 0i64;
*(v5 + 3) = 0i64;
}
else
{
v6 = 0i64;
}
v7 = 0;
if ( v40 )
{
v8 = 0i64;
do
{
v9 = Block;
if ( v41 >= 16 )
v9 = Block[0];
v10 = &qword_7FF793A96048;
if ( qword_7FF793A96060 >= 16 )
v10 = qword_7FF793A96048;
v6[v8] = *(v9 + v8) ^ *(v10 + v7 % 27);
++v7;
++v8;
}
while ( v7 < v40 );
}
v11 = 0i64;
v12 = 0i64;
v13 = 0i64;
v14 = 0i64;
if ( v40 > 30 )
goto LABEL_27;
v15 = 0;
if ( v40 <= 0 )
goto LABEL_27;
v16 = v6;
do
{
v17 = *v16 + v11;
++v15;
++v16;
switch ( v15 )
{
case 8:
v14 = v17;
goto LABEL_23;
case 16:
v13 = v17;
goto LABEL_23;
case 24:
v12 = v17;
LABEL_23:
v17 = 0i64;
break;
case 32:
sub_7FF793A919C0(std::cout, "ERRO,out of range");
exit(1);
}
v11 = v17 << 8;
}
while ( v15 < v40 );
if ( v14 )
{
v18 = operator new(0x20ui64);
*v18 = v14;
v18[1] = v13;
v18[2] = v12;
v18[3] = v11;
goto LABEL_28;
}
LABEL_27:
v18 = 0i64;
LABEL_28:
v38 = v18[2];
v19 = v18[1];
v20 = *v18;
v21 = operator new(0x20ui64);
if ( IsDebuggerPresent() )
{
sub_7FF793A919C0(std::cout, "Hi , DO not debug me !");
Sleep(0x7D0u);
exit(0);
}
v22 = v19 & v20;
*v21 = v19 & v20;
v23 = v38 & ~v20;
v21[1] = v23;
v24 = ~v19;
v25 = v38 & v24;
v21[2] = v38 & v24;
v26 = v20 & v24;
v21[3] = v26;
if ( v23 != 0x11204161012i64 )
{
v21[1] = 0i64;
v23 = 0i64;
}
v27 = v23 | v22 | v25 | v26;
v28 = v18[1];
v29 = v18[2];
v30 = v25 & *v18 | v29 & (v22 | v28 & ~*v18 | ~(v28 | *v18));
v31 = 0;
if ( v30 == 0x8020717153E3013i64 )
v31 = v27 == 0x3E3A4717373E7F1Fi64;
if ( (v27 ^ v18[3]) == 0x3E3A4717050F791Fi64 )
v3 = v31;
if ( (v23 | v22 | v28 & v29) == (~*v18 & v29 | 0xC00020130082C0Ci64) && v3 )
{
v32 = sub_7FF793A919C0(std::cout, "Congratulations!flag is GXY{");
v33 = Block;
if ( v41 >= 0x10 )
v33 = Block[0];
v34 = sub_7FF793A91FD0(v32, v33, v40);
sub_7FF793A919C0(v34, "}");
j_j_free(v6);
}
else
{
sub_7FF793A919C0(std::cout, "Wrong answer!try again");
j_j_free(v6);
}
LABEL_43:
if ( v41 >= 0x10 )
{
v36 = Block[0];
if ( v41 + 1 >= 0x1000 )
{
v36 = *(Block[0] - 1);
if ( (Block[0] - v36 - 8) > 0x1F )
invalid_parameter_noinfo_noreturn();
}
j_j_free(v36);
}
return 0;
}

通过 48-49 行可以知道,输入的 flag 就是 block,然后在 76 行,block 被复制给了 v9,又在 82 行和 v10 也就是 qword_7FF793A96048 进行了一次异或,qword_7FF793A96048 点进去发现是 0,觉得不对,然后右键它点击 jump to xref,可以发现是有对它赋值的

所以 qword_7FF793A96048 就是 “i_will_check_is_debug_or_not” 这个字符串,并且输入的 flag 会和它进行一次异或,所以我们现在要知道的就是这个计算的结果,然后逆运算得出 flag 了。我们继续往下看,发现 v6=v16,v16=v17,v17=v11,v11 又等于 v18 [3],在 120 行 v11 = v17 << 8,这里对 v17 进行了位移八位,进行了一个堆叠,所以 v6 就相当于整个 v18 串起来。

再往下看,168 行有一个 if 语句,条件通过就会通过程序,说明这就是最后的判断条件了,而且判断条件中涉及到了 v18 数组,再看看 145-167 行,这里全是一些赋值语句,最后赋的值也是写出来了的,这些最后全都可以用 v18 [0],v18 [1],v18 [2],v18 [3] 来表示,也就可以组成一个多元一次方程组,求解这个方程组可以用 python 的 z3 模块来求解,通过这样就可以得到 v18 的值了,这样就可以通过异或得到 flag,所以我们现在要做的就是理清这个方程组并解出来,脚本如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 from z3 import *

x,y,z,w=BitVecs('x y z w',64)

s=Solver()

s.add((~x)&z==1176889593874)
s.add(((z&~x)|(x&y)|(z&(~y))|(x&(~y)))^w==4483974543195470111)
s.add(((z&~y)&x|z&((x&y)|y&~x|~(y|x)))==577031497978884115)
s.add(((z&~x)|(x&y)|(z&~y)|(x&~y))==4483974544037412639)
s.add(((z&(~x)) | (x&y) | y & z) == (((~x)& z)|864693332579200012))

s.check()
m = s.model()

print(m)

for i in m:
print("%s = 0x%x"%(i,m[i].as_long()))

z3 模块如何使用可以参考这个博客:python z3 库学习_小龙在山东的博客 - CSDN 博客_python z3 库

结果如下:

y = 0xc00020130082c0c
x = 0x3e3a460533286f0d
w = 0x32310600
z = 0x8020717153e3013

有了 v18 之后,我们就可以解 flag 了,脚本如下

1
2
3
4
5
6
7
8
9
a = "i_will_check_is_debug_or_not"
b =[0x3E,0x3A,0x46,0x05,0x33,0x28,0x6F,0x0D,0x8C,0x00,0x8A,0x09,0x78,0x49,
0x2C,0xAC,0x08,0x02,0x07,0x17,0x15,0x3E,0x30,0x13,0x32,0x31,0x06]
c = ''
for i in range(len(b)):
c += chr(ord(a[i]) ^ b[i])

print(c)

的出来的结果是 "We1l_D0näeéb’ _ólgebra_am_i",这肯定是不对的,然后在网上看了别人的博客,说是这道题在比赛的时候给出来了中间的部分为 "e!P0or_a"

所以最后的 flag 为:flag{We1l_D0ne!P0or_algebra_am_i}