[GXYCTF2019]simple CPP
参考博客:
https://www.cnblogs.com/LLeaves/p/13522069.html
https://blog.csdn.net/mcmuyanga/article/details/113628506
查壳,莫得,64位
载入 IDA,定位到主函数
int __cdecl main(int argc, const char **argv, const char **envp)
{
bool v3; // si
__int64 v4; // rax
__int64 v5; // r8
__int64 v6; // r8
unsigned __int8 *v7; // rax
unsigned __int8 *v8; // rbx
int v9; // er10
__int64 v10; // r11
void **v11; // r9
void **v12; // r8
__int64 v13; // rdi
__int64 v14; // r15
__int64 v15; // r12
__int64 v16; // rbp
int v17; // ecx
unsigned __int8 *v18; // rdx
__int64 v19; // rdi
__int64 *v20; // r14
__int64 v21; // rbp
__int64 v22; // r13
__int64 *v23; // rdi
__int64 v24; // r8
__int64 v25; // r12
__int64 v26; // r15
__int64 v27; // rbp
__int64 v28; // rdx
__int64 v29; // rbp
__int64 v30; // rbp
__int64 v31; // r10
__int64 v32; // rdi
__int64 v33; // r8
bool v34; // dl
__int64 v35; // rax
void **v36; // rdx
__int64 v37; // rax
__int64 v38; // r8
__int64 v39; // rax
void *v40; // rcx
__int64 v42; // [rsp+20h] [rbp-68h]
void *Block[2]; // [rsp+30h] [rbp-58h] BYREF
unsigned __int64 v44; // [rsp+40h] [rbp-48h]
unsigned __int64 v45; // [rsp+48h] [rbp-40h]
v3 = 0;
v44 = 0i64;
v45 = 15i64;
LOBYTE(Block[0]) = 0;
v4 = sub_1400019C0(std::cout, "I'm a first timer of Logic algebra , how about you?", envp);
std::ostream::operator<<(v4, sub_140001B90);
sub_1400019C0(std::cout, "Let's start our game,Please input your flag:", v5);
sub_140001DE0(std::cin, Block);
std::ostream::operator<<(std::cout, sub_140001B90);
if ( v44 - 5 > 0x19 )
{
v39 = sub_1400019C0(std::cout, "Wrong input ,no GXY{} in input words", v6);
std::ostream::operator<<(v39, sub_140001B90);
goto LABEL_43;
}
v7 = (unsigned __int8 *)operator new(0x20ui64);
v8 = v7;
if ( v7 )
{
*(_QWORD *)v7 = 0i64;
*((_QWORD *)v7 + 1) = 0i64;
*((_QWORD *)v7 + 2) = 0i64;
*((_QWORD *)v7 + 3) = 0i64;
}
else
{
v8 = 0i64;
}
v9 = 0;
if ( v44 )
{
v10 = 0i64;
do
{
v11 = Block;
if ( v45 >= 0x10 )
v11 = (void **)Block[0];
v12 = &qword_140006048;
if ( (unsigned __int64)qword_140006060 >= 0x10 )
v12 = (void **)qword_140006048;
v8[v10] = *((_BYTE *)v11 + v10) ^ *((_BYTE *)v12 + v9 % 27);
++v9;
++v10;
}
while ( v9 < v44 );
}
v13 = 0i64;
v14 = 0i64;
v15 = 0i64;
v16 = 0i64;
if ( (int)v44 > 30 )
goto LABEL_27;
v17 = 0;
if ( (int)v44 <= 0 )
goto LABEL_27;
v18 = v8;
do
{
v19 = *v18 + v13;
++v17;
++v18;
switch ( v17 )
{
case 8:
v16 = v19;
goto LABEL_23;
case 16:
v15 = v19;
goto LABEL_23;
case 24:
v14 = v19;
LABEL_23:
v19 = 0i64;
break;
case 32:
sub_1400019C0(std::cout, "ERRO,out of range", (unsigned int)v44);
exit(1);
}
v13 = v19 << 8;
}
while ( v17 < (int)v44 );
if ( v16 )
{
v20 = (__int64 *)operator new(0x20ui64);
*v20 = v16;
v20[1] = v15;
v20[2] = v14;
v20[3] = v13;
goto LABEL_28;
}
LABEL_27:
v20 = 0i64;
LABEL_28:
v42 = v20[2];
v21 = v20[1];
v22 = *v20;
v23 = (__int64 *)operator new(0x20ui64);
if ( IsDebuggerPresent() )
{
sub_1400019C0(std::cout, "Hi , DO not debug me !", v24);
Sleep(0x7D0u);
exit(0);
}
v25 = v21 & v22;
*v23 = v21 & v22;
v26 = v42 & ~v22;
v23[1] = v26;
v27 = ~v21;
v28 = v42 & v27;
v23[2] = v42 & v27;
v29 = v22 & v27;
v23[3] = v29;
if ( v26 != 1176889593874i64 )
{
v23[1] = 0i64;
v26 = 0i64;
}
v30 = v26 | v25 | v28 | v29;
v31 = v20[1];
v32 = v20[2];
v33 = v28 & *v20 | v32 & (v25 | v31 & ~*v20 | ~(v31 | *v20));
v34 = 0;
if ( v33 == 577031497978884115i64 )
v34 = v30 == 4483974544037412639i64;
if ( (v30 ^ v20[3]) == 4483974543195470111i64 )
v3 = v34;
if ( (v26 | v25 | v31 & v32) == (~*v20 & v32 | 864693332579200012i64) && v3 )
{
v35 = sub_1400019C0(std::cout, "Congratulations!flag is GXY{", v33);
v36 = Block;
if ( v45 >= 0x10 )
v36 = (void **)Block[0];
v37 = sub_140001FD0(v35, v36, v44);
sub_1400019C0(v37, "}", v38);
j_j_free(v8);
}
else
{
sub_1400019C0(std::cout, "Wrong answer!try again", v33);
j_j_free(v8);
}
LABEL_43:
if ( v45 >= 0x10 )
{
v40 = Block[0];
if ( v45 + 1 >= 0x1000 )
{
v40 = (void *)*((_QWORD *)Block[0] - 1);
if ( (unsigned __int64)(Block[0] - v40 - 8) > 0x1F )
invalid_parameter_noinfo_noreturn();
}
j_j_free(v40);
}
return 0;
}
从后往前看比较好看一些,先看看最后输出的部分
满足 if 条件里的东西就输出 flag,往上看一下 if 判断里的参数都是怎么来的
整理一下,大致如下:
v42 = v20[2]
v21 = v20[1]
v22 = v20[0]
v25 = v21 & v22
v23[0] = v21 & v22
得到:v25 = v23[0] = v21 & v22 = v20[1] & v20[0]
v26 = v42 & ~v22
v23[1] = v26
得到:v26 = v23[1] = v42 & ~v22 = v20[2] & ~v20[0]
v27 = ~v21
v28 = v42 & v27
v23[2] = v42 & v27
得到:v28 = v23[2] = v42 & v27 = v42 & ~v21 = v20[2] & ~v20[1]
v29 = v22 & v27
v23[3] = v29
得到:v29 = v23[3] = v22 & v27 = v22 & ~v21 = v20[0] & ~v20[1]
v26 = v23[1] = 1176889593874
得到:v20[2] & v20[0] = 1176889593874
v30 = v26 | v25 | v28 | v29
得到:v30 = (v20[2] & ~v20[0]) | (v20[1] & v20[0]) | (v20[2] & ~v20[1]) | (v20[0] & ~v20[1]) = 4483974544037412639
v31 = v20[1]
v32 = v20[2]
v33 = v28 & v20[0] | v32 & (v25 | v31 & ~v20[0] | ~(v31 | v20[0]))
得到:v33 = (v20[2] & ~v20[1]) & v20[0] | v20[2] & ((v20[1] & v20[0]) | v20[1] & ~v20[0] | ~(v20[1] | v20[0])) = 577031497978884115
v34 = v30 == 4483974544037412639i64
(v30 ^ v20[3]) == 4483974543195470111i64
得到:((v20[2] & ~v20[0]) | (v20[1] & v20[0]) | (v20[2] & ~v20[1]) | (v20[0] & ~v20[1])) ^ v20[3] = 4483974543195470111
然后用 z3 解方程组(x, y, z, w 分别代表 v20[0~3])
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()
for i in m:
print("%s = 0x%x"%(i,m[i].as_long()))
得到:
由于解是堆叠出来的 ,所以去掉堆叠,还原原本字符串
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()
for i in m:
print("%s = 0x%x"%(i,m[i].as_long()))
li=[]
li.append(hex(m[x].as_long())[2:].rjust(16,"0"))
li.append(hex(m[y].as_long())[2:].rjust(16,"0"))
li.append(hex(m[z].as_long())[2:].rjust(16,"0"))
li.append(hex(m[w].as_long())[2:-2])
print(li)
得到
继续往前看
可以看到 v20 的值来自 v16, v15, v14, v13,而它们的值又由别的数据计算而来,麻烦死了,一点一点看
由第 61 行上下猜测 flag 长度为 25,然后从第 89 到第 97 行将我们的输入数据与 qword_140006048 进行异或,交叉引用看到 qword_140006048 赋值的部分
猜测就是 "i_will_check_is_debug_or_not",写脚本异或一下
a = 'i_will_check_is_debug_or_not'
b=[0x3E,0x3A,0x46,0x05,0x33,0x28,0x6F,0x0D,0x0C,0x00,0x02,0x01,0x30,0x08,0x2C,0x0C,0x08,0x02,0x07,0x17,0x15,0x3E,0x30,0x13,0x32,0x31,0x06]
flag=''
for i in range(len(b)):
flag+=chr(ord(a[i]) ^ b[i])
print(flag)
解出来是:We1l_D0ndeajoa_Slgebra_am_i
然而并不,这题其实比赛的时候给出了这一部分的内容:e!P0or_a,中间那部分不知道啥意思的英文字母替换成这个就可以得到正确的flag
flag{We1l_D0ne!P0or_algebra_am_i}