BUUCTF-re-SimpleCPP略解

直接上伪代码

__int64 sub_140001290()
{
     
  bool v0; // si
  __int64 v1; // rax
  __int64 v2; // r8
  unsigned __int8 *v3; // rax
  unsigned __int8 *v4; // rbx
  int v5; // er10
  __int64 v6; // r11
  _BYTE *v7; // r9
  void **v8; // r8
  __int64 v9; // rdi
  __int64 v10; // r15
  __int64 v11; // r12
  __int64 v12; // rbp
  signed int v13; // ecx
  unsigned __int8 *v14; // rdx
  __int64 v15; // rdi
  __int64 *v16; // r14
  __int64 v17; // rbp
  __int64 v18; // r13
  __int64 *v19; // rdi
  __int64 v20; // r12
  __int64 v21; // r15
  __int64 v22; // rbp
  __int64 v23; // rdx
  __int64 v24; // rbp
  __int64 v25; // rbp
  __int64 v26; // r10
  __int64 v27; // rdi
  __int64 v28; // r8
  bool v29; // dl
  __int64 v30; // rax
  void *v31; // rdx
  __int64 v32; // rax
  __int64 v33; // rax
  _BYTE *v34; // rcx
  __int64 v36; // [rsp+20h] [rbp-68h]
  void *Memory; // [rsp+30h] [rbp-58h]
  unsigned __int64 v37; // [rsp+40h] [rbp-48h]
  unsigned __int64 v39; // [rsp+48h] [rbp-40h]

  v0 = 0;
  v37 = 0i64;
  v39 = 15i64;
  LOBYTE(Memory) = 0;
  v1 = sub_1400019C0(std::cout, "I'm a first timer of Logic algebra , how about you?");
  std::basic_ostream<char,std::char_traits<char>>::operator<<(v1, sub_140001B90);
  sub_1400019C0(std::cout, "Let's start our game,Please input your flag:");
  sub_140001DE0(std::cin, &Memory, v2);
  std::basic_ostream<char,std::char_traits<char>>::operator<<(std::cout, sub_140001B90);
  if ( v37 - 5 > 0x19 )
  {
     
    v33 = sub_1400019C0(std::cout, "Wrong input ,no GXY{} in input words");
    std::basic_ostream<char,std::char_traits<char>>::operator<<(v33, sub_140001B90);
    goto LABEL_45;
  }
  v3 = (unsigned __int8 *)sub_1400024C8(0x20ui64);
  v4 = v3;
  if ( v3 )
  {
     
    *(_QWORD *)v3 = 0i64;
    *((_QWORD *)v3 + 1) = 0i64;
    *((_QWORD *)v3 + 2) = 0i64;
    *((_QWORD *)v3 + 3) = 0i64;
  }
  else
  {
     
    v4 = 0i64;
  }
  v5 = 0;
  if ( v37 > 0 )
  {
     
    v6 = 0i64;
    do
    {
     
      v7 = &Memory;
      if ( v39 >= 0x10 )
        v7 = Memory;
      v8 = &Dst;
      if ( (unsigned __int64)qword_140006060 >= 0x10 )
        v8 = (void **)Dst;
      v4[v6] = v7[v6] ^ *((_BYTE *)v8 + v5++ % 27);
      ++v6;
    }
    while ( v5 < v37 );
  }
  v9 = 0i64;
  v10 = 0i64;
  v11 = 0i64;
  v12 = 0i64;
  if ( (signed int)v37 > 30 )
    goto LABEL_28;
  v13 = 0;
  if ( (signed int)v37 <= 0 )
    goto LABEL_28;                              // 输入长度在0到30之间
  v14 = v4;
  do
  {
     
    v15 = *v14 + v9;
    ++v13;
    ++v14;
    switch ( v13 )
    {
     
      case 8:
        v12 = v15;
        goto LABEL_24;
      case 16:
        v11 = v15;
        goto LABEL_24;
      case 24:
        v10 = v15;
LABEL_24:
        v15 = 0i64;
        break;
      case 32:
        sub_1400019C0(std::cout, "ERRO,out of range");
        exit(1);
        break;
    }
    v9 = v15 << 8;
  }
  while ( v13 < (signed int)v37 );              // 将v4以8个字节为单位分为v12,v11,v10,v9四部分
  if ( v12 )
  {
     
    v16 = (__int64 *)sub_1400024C8(0x20ui64);
    *v16 = v12;
    v16[1] = v11;
    v16[2] = v10;
    v16[3] = v9;
    goto LABEL_29;
  }
LABEL_28:
  v16 = 0i64;
LABEL_29:
  v36 = v16[2];
  v17 = v16[1];
  v18 = *v16;
  v19 = (__int64 *)sub_14000223C(0x20ui64);
  if ( IsDebuggerPresent() )
  {
     
    sub_1400019C0(std::cout, "Hi , DO not debug me !");
    Sleep(0x7D0u);
    exit(0);
  }
  v20 = v17 & v18;
  *v19 = v17 & v18;
  v21 = v36 & ~v18;
  v19[1] = v21;
  v22 = ~v17;
  v23 = v36 & v22;
  v19[2] = v36 & v22;
  v24 = v18 & v22;
  v19[3] = v24;                                 // 这里很多变量,但是可以发现v20==v19,v19[1]==v21......,简化了很多
  if ( v21 != 1176889593874i64 )                // 约束条件,v21 == 1176889593874i64一般都是成立的
  {
     
    v19[1] = 0i64;
    v21 = 0i64;
  }
  v25 = v21 | v20 | v23 | v24;
  v26 = v16[1];
  v27 = v16[2];
  v28 = v23 & *v16 | v27 & (v20 | v26 & ~*v16 | ~(v26 | *v16));
  v29 = 0;
  if ( v28 == 577031497978884115i64 )           // v28 == 577031497978884115i64成立
    v29 = v25 == 4483974544037412639i64;        // v25 == 4483974544037412639i64成立
  if ( (v25 ^ v16[3]) == 4483974543195470111i64 )
    v0 = v29;
  if ( (v21 | v20 | v26 & v27) != (~*v16 & v27 | 0xC00020130082C0Ci64) || v0 != 1 )
  {
     
    sub_1400019C0(std::cout, "Wrong answer!try again");
    j_j_free(v4);
  }
  else
  {
     
    v30 = sub_1400019C0(std::cout, "Congratulations!flag is GXY{");
    v31 = &Memory;
    if ( v39 >= 0x10 )
      v31 = Memory;
    v32 = sub_140001FD0(v30, v31, v37);
    sub_1400019C0(v32, "}");
    j_j_free(v4);
  }
LABEL_45:
  if ( v39 >= 0x10 )
  {
     
    v34 = Memory;
    if ( v39 + 1 >= 0x1000 )
    {
     
      v34 = (_BYTE *)*((_QWORD *)Memory - 1);
      if ( (unsigned __int64)((_BYTE *)Memory - v34 - 8) > 0x1F )
        invalid_parameter_noinfo_noreturn();
    }
    j_j_free(v34);
  }
  return 0i64;
}

动态调试猜测变量含义

BUUCTF-re-SimpleCPP略解_第1张图片
困扰我们的是v37,Dst
(v38和qword_140006060这种跳转一般没有意义)
在动态调试相关位置下断点,观察变量
BUUCTF-re-SimpleCPP略解_第2张图片
多次输入,多次观测
发现v37是输入长度,v38在输入长度较大时为1f,较小为f
同时得到Dst = i_will_check_is_debug_or_not

ida变量数据分布

v37是输入长度,那么v37到底是什么时候被改变的呢?
注意主函数的变量声明
在这里插入图片描述
我们进入sub_140001DE0(std::cin, &Memory, v2);

__int64 __fastcall sub_140001DE0(__int64 a1, _QWORD *a2, __int64 a3)
{
     
  _QWORD *v3; // rbx
  __int64 v4; // rdi
  unsigned int v5; // esi
  char v6; // r15
  __int64 v7; // r12
  __int64 v8; // rcx
  __int64 v9; // rax
  __int64 v10; // rdx
  __int64 v11; // r8
  __int64 v12; // r9
  __int64 v13; // r13
  void (__fastcall ***v14)(_QWORD, signed __int64); // rax
  _BYTE *v15; // rax
  __int64 v16; // rcx
  signed __int64 v17; // r14
  int v18; // eax
  char v19; // r8
  unsigned __int64 v20; // rcx
  unsigned __int64 v21; // rdx
  _QWORD *v22; // rax
  __int64 v23; // rcx
  char v25; // [rsp+40h] [rbp-38h]
  __int64 v26; // [rsp+48h] [rbp-30h]

  v3 = a2;                                      // 注意这里,把memory地址给了v3
  v4 = a1;
  v5 = 0;
  v6 = 0;
  v7 = a1;
  v8 = *(_QWORD *)(*(signed int *)(*(_QWORD *)a1 + 4i64) + a1 + 72);
  if ( v8 )
    (*(void (__cdecl **)(__int64, _QWORD *, __int64))(*(_QWORD *)v8 + 8i64))(v8, a2, a3);
  if ( (unsigned __int8)std::basic_istream<char,std::char_traits<char>>::_Ipfx(v4, 0i64) )
  {
     
    v9 = std::ios_base::getloc(v4 + *(signed int *)(*(_QWORD *)v4 + 4i64), &v25);
    v13 = sub_1400018C0(v9);
    if ( v26 )
    {
     
      v14 = (void (__fastcall ***)(_QWORD, signed __int64))(*(__int64 (__cdecl **)(__int64, __int64, __int64, __int64))(*(_QWORD *)v26 + 16i64))(
                                                             v26,
                                                             v10,
                                                             v11,
                                                             v12);
      if ( v14 )
        (**v14)(v14, 1i64);
    }
    v3[2] = 0i64;                               // 而v3[2]就是        v3的地址+偏移地址0x10
                                                // 就是主函数rsp+30h + 10h = rsp + 40h
                                                // 即是v37地址
    v15 = v3;
    if ( v3[3] >= 0x10ui64 )
      v15 = (_BYTE *)*v3;
    *v15 = 0;
    v16 = *(signed int *)(*(_QWORD *)v4 + 4i64);
    v17 = *(_QWORD *)(v16 + v4 + 40);
    if ( v17 <= 0 || (unsigned __int64)v17 >= 0x7FFFFFFFFFFFFFFFi64 )
      v17 = 0x7FFFFFFFFFFFFFFFi64;
    v18 = std::basic_streambuf<char,std::char_traits<char>>::sgetc(*(_QWORD *)(v16 + v4 + 72));
    while ( v17 )
    {
     
      if ( v18 == -1 )
      {
     
        v5 = 1;
        break;
      }
      v19 = v18;
      if ( *(_BYTE *)(*(_QWORD *)(v13 + 24) + 2i64 * (unsigned __int8)v18) & 0x48 )
        break;
      v20 = v3[2];
      v21 = v3[3];
      if ( v20 >= v21 )
      {
     
        sub_140001BD0(v3);
      }
      else
      {
     
        v3[2] = v20 + 1;
        v22 = v3;
        if ( v21 >= 0x10 )
          v22 = (_QWORD *)*v3;
        *((_BYTE *)v22 + v20) = v19;
        *((_BYTE *)v22 + v20 + 1) = 0;
      }
      v6 = 1;
      --v17;
      v18 = std::basic_streambuf<char,std::char_traits<char>>::snextc(*(_QWORD *)(*(signed int *)(*(_QWORD *)v4 + 4i64)
                                                                                + v4
                                                                                + 72));
    }
  }
  *(_QWORD *)(*(signed int *)(*(_QWORD *)v4 + 4i64) + v4 + 40) = 0i64;
  if ( !v6 )
    v5 |= 2u;
  std::basic_ios<char,std::char_traits<char>>::setstate(v4 + *(signed int *)(*(_QWORD *)v4 + 4i64), v5, 0i64);
  v23 = *(_QWORD *)(*(signed int *)(*(_QWORD *)v7 + 4i64) + v7 + 72);
  if ( v23 )
    (*(void (**)(void))(*(_QWORD *)v23 + 16i64))();
  return v4;
}

ida变量数据是线性的,传入一个参数,其周围数据也可以被改变

约束条件一般都是成立的,忽略一些无关紧要的函数和代码

最后上官方wp,题目后面给了v11做已知条件(

from z3 import * 
xor_str="i_will_check_is_debug_or_not" 
s = Solver()
x = BitVec('x',64)
y = BitVec('y',64)
z = BitVec('z',64)
l = BitVec('l',64)
s.add(y==0xd44335b301b2c3e)
s.add((z&(~x))==0x11204161012) 
s.add((z&~y) & x | z & ((x&y) | y & (~x) | ~(y | x))==0x8020717153E3013) 
s.add(((z&(~x)) | (x&y) | (z&(~y)) | (x&(~y))) == 0x3E3A4717373E7F1F) 
s.add((((z&(~x)) | (x&y) | (z&(~y)) | (x&(~y))) ^ l) == 0x3E3A4717050F791F) 
s.add(((z&(~x)) | (x&y) | y & z) == (((~x)& z)|0xC00020130082C0C))
if s.check() ==sat: 
	m = s.model()
	print(m) 
	flag=""
	ls=[] 
	ls.append(hex(int(str(m[x]),10))[2:].rjust(16,"0")) 
	ls.append(hex(int(str(m[y]),10))[2:].rjust(16,"0")) 
	ls.append(hex(int(str(m[z]),10))[2:].rjust(16,"0")) 
	ls.append(hex(int(str(m[l]),10))[2:-2]) 
	print(ls) 
	sum=0 
	for i in ls: 
		for j in range(0,len(i),2): 
			xx=i[j]+i[j+1] 
			flag+=chr(int(xx,16)^ord(xor_str[(sum)%27])) 
			sum+=1
	print(flag)

你可能感兴趣的:(BUUCTF-re-SimpleCPP略解)