• BUUCTF Reverse/[GXYCTF2019]simple CPP


    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;
    }
    
    • 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
    • 197
    • 198
    • 199
    • 200
    • 201

    输入的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进制数拼到一起
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    后面的比较条件,然后像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='')
    
    
    • 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

    输出

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    得到 We1l_D0neaAB/`ßÓlgebra_am_ii ,但这玩意中间是乱码,我还以为方程抄错了,检查了好几遍,搜了下别的大佬博客才发现,这题有问题,找到原因是方程不止一个解,而比赛的时候给出了第二部分的结果e!P0or_a

    得到最终flag: flag{We1l_D0ne!P0or_algebra_am_i}

  • 相关阅读:
    Kafka之日志存储详解
    dspe-peg-cy7.5;磷脂-聚乙二醇-CY7.5吲哚菁绿
    Java工具库Guava并发相关工具类的使用示例
    线上展厅制作成本
    Hive中常用SerDe介绍
    Java:如何去优雅地优化接口
    动手吧,vue做个好看的按钮01
    HTML学习笔记
    1-08 移动端适配 rem+vm
    MySQL的select语句
  • 原文地址:https://blog.csdn.net/ookami6497/article/details/119375861