[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}

posted @ 2022-01-12 22:45  Moominn  阅读(278)  评论(0编辑  收藏  举报