# 主函数
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; __int64 *v4; unsigned __int8 *v5; unsigned __int8 *v6; int v7; __int64 v8; void **v9; void **v10; __int64 v11; __int64 v12; __int64 v13; __int64 v14; int v15; unsigned __int8 *v16; __int64 v17; __int64 *v18; __int64 v19; __int64 v20; __int64 *v21; __int64 v22; __int64 v23; __int64 v24; __int64 v25; __int64 v26; __int64 v27; __int64 v28; __int64 v29; __int64 v30; bool v31; __int64 *v32; void **v33; __int64 *v34; __int64 *v35; void *v36; __int64 v38; void *Block[2 ]; unsigned __int64 v40; unsigned __int64 v41; v3 = 0 ; v40 = 0 i64; v41 = 15 i64; 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(32u i64); v6 = v5; if ( v5 ) { *v5 = 0 i64; *(v5 + 1 ) = 0 i64; *(v5 + 2 ) = 0 i64; *(v5 + 3 ) = 0 i64; } else { v6 = 0 i64; } v7 = 0 ; if ( v40 ) { v8 = 0 i64; 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 = 0 i64; v12 = 0 i64; v13 = 0 i64; v14 = 0 i64; 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 = 0 i64; break ; case 32 : sub_7FF793A919C0(std ::cout , "ERRO,out of range" ); exit (1 ); } v11 = v17 << 8 ; } while ( v15 < v40 ); if ( v14 ) { v18 = operator new(0x20 ui64); *v18 = v14; v18[1 ] = v13; v18[2 ] = v12; v18[3 ] = v11; goto LABEL_28; } LABEL_27: v18 = 0 i64; LABEL_28: v38 = v18[2 ]; v19 = v18[1 ]; v20 = *v18; v21 = operator new(0x20 ui64); if ( IsDebuggerPresent() ) { sub_7FF793A919C0(std ::cout , "Hi , DO not debug me !" ); Sleep(0x7D0 u); 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 != 0x11204161012 i64 ) { v21[1 ] = 0 i64; v23 = 0 i64; } v27 = v23 | v22 | v25 | v26; v28 = v18[1 ]; v29 = v18[2 ]; v30 = v25 & *v18 | v29 & (v22 | v28 & ~*v18 | ~(v28 | *v18)); v31 = 0 ; if ( v30 == 0x8020717153E3013 i64 ) v31 = v27 == 0x3E3A4717373E7F1F i64; if ( (v27 ^ v18[3 ]) == 0x3E3A4717050F791F i64 ) v3 = v31; if ( (v23 | v22 | v28 & v29) == (~*v18 & v29 | 0xC00020130082C0C i64) && 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}