BUUCTF Reverse/[GXYCTF2019]simple CPP
先看文件信息,是个64位的程序,且没有加壳
IDA64位打开
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 ) // v44中存储的是输入flag的长度
//
{
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 ) // flag长度小于32
{
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; // 8到15位
v20[1] = v15; // 16到23位
v20[2] = v14; // 24到31位
v20[3] = v13; // 0到7位
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 != 0x11204161012i64 )
{
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 == 0x8020717153E3013i64 )
v34 = v30 == 0x3E3A4717373E7F1Fi64;
if ( (v30 ^ v20[3]) == 0x3E3A4717050F791Fi64 )
v3 = v34;
if ( (v26 | v25 | v31 & v32) == (~*v20 & v32 | 0xC00020130082C0Ci64) && 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;
}
输入的flag存储在block中
一段段分析代码
这里将输入的字符串与 ==“i_will_check_is_debug_or_not”==进行异或
这一段将输入字符串八个字符转成16进制后拼到一起,
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: // 长度要小于32
sub_7FF616CB19C0(std::cout, "ERRO,out of range", (unsigned int)v44);
exit(1);
}
v13 = v19 << 8; // 16进制左移两位,就是将8个16进制数拼到一起
}
后面的比较条件,然后像v26、v25这些都可以用v20来表示
比如:
v26 = v42 & ~v22 = v20[2] & ~v20[0] = 0x11204161012
都这样表示后,可以转换成z3方程求解
from z3 import *
s = Solver()
v20_0,v20_1,v20_2,v20_3 = BitVecs('v20_0 v20_1 v20_2 v20_3',64)
s.add(v20_2 & ~v20_0 == 0x11204161012)
s.add( ((v20_2 & ~v20_0) | (v20_1 & v20_0) | (v20_2 & ~v20_1) | (v20_0 & ~v20_1)) == 0x3E3A4717373E7F1F)
s.add(( (v20_2 & ~v20_0)| (v20_1 & v20_0) | v20_1 & v20_2 ) == ((~v20_0 & v20_2) | 0xC00020130082C0C) )
s.add((v20_2 & ~v20_1) & v20_0 | v20_2 & ((v20_1 & v20_0) | v20_1 & ~v20_0 | ~(v20_1 | v20_0)) == 0x8020717153E3013)
s.add(v20_3 == 0x3E3A4717050F791F ^ 0x3E3A4717373E7F1F)
check = s.check()
print(check)
model = s.model()
print(model)
v20 = [4483973367147818765,937912183768591500,577031497978884115,842073600]
flag = [0] * 32
k = 0
for i in range(4):
s = str(hex(v20[i])).replace('0x','')
if i == 1 or i == 2:
s = '0' + s
print(s)
for j in range(0,len(s),2):
#print(chr(int(s[j:j+2],16)),end='')
flag[k] = (int(s[j:j+2],16))
k+=1
t = [ord(i) for i in "i_will_check_is_debug_or_not"]
print(t)
for i in range(len(t)):
flag[i] ^= t[i % 27]
#print(chr(flag[i])," ",flag[i] ,end='\n')
print(chr(flag[i]) ,end='')
输出
sat
[v20_2 = 577031497978884115,
v20_0 = 4483973367147818765,
v20_1 = 936750926617127948,
v20_3 = 842073600]
3e3a460533286f0d
0d0422297009ac8c
08020717153e3013
32310600
[105, 95, 119, 105, 108, 108, 95, 99, 104, 101, 99, 107, 95, 105, 115, 95, 100, 101, 98, 117, 103, 95, 111, 114, 95, 110, 111, 116]
We1l_D0neaAB/`ßÓlgebra_am_ii
得到 We1l_D0neaAB/`ßÓlgebra_am_ii ,但这玩意中间是乱码,我还以为方程抄错了,检查了好几遍,搜了下别的大佬博客才发现,这题有问题,找到原因是方程不止一个解,而比赛的时候给出了第二部分的结果e!P0or_a
得到最终flag: flag{We1l_D0ne!P0or_algebra_am_i}