• BUUCTF Reverse/[2019红帽杯]xx


    BUUCTF Reverse/[2019红帽杯]xx

    在这里插入图片描述

    先看下文件信息:没有加壳、64位程序

    在这里插入图片描述

    看别人wp时候发现个好东东,就是这个findcrypt插件,可以看加密算法的,具体安装可以看这个IDA7.5安装findcrypt3插件

    在这里插入图片描述

    可以看到这是tea加密

    在这里插入图片描述

    先一点点分析代码,输入flag,flag的长度必须为19

     sub_7FF7A98718C0(std::cin, argv, flag);       // 输入flag
      v3 = -1i64;
      v4 = -1i64;
      do
        ++v4;
      while ( *((_BYTE *)flag + v4) );
      if ( v4 != 19 )                               // 长度为19
      {
        sub_7FF7A9871620(std::cout, "error\n");
        _exit((int)flag);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    这里给v6赋值为qwertyuiopasdfghjklzxcvbnm1234567890

    这行代码看上去挺麻烦的,一眼唬住,但是仔细看下,前面有个v9 = v5,后面又减去了个v5,所以这行代码就变成了v10 = *flag
    v10 = *((_BYTE *)v9 + (char *)flag - (char *)v5);

    这段代码比较的是输入的flag的前四个字符是否在qwertyuiopasdfghjklzxcvbnm1234567890之间,顺便把flag的前四个字符赋值给v5

     v5 = (__int128 *)operator new(5ui64);
      v6 = *(_QWORD *)&Code;
      v7 = v5;
      v8 = 0;
      v9 = v5;
      do
      {
        v10 = *((_BYTE *)v9 + (char *)flag - (char *)v5);
        v11 = 0;
        *(_BYTE *)v9 = v10;
        v12 = 0i64;
        v13 = -1i64;
        do
          ++v13;
        while ( *(_BYTE *)(v6 + v13) );
        if ( v13 )
        {
          do
          {
            if ( v10 == *(_BYTE *)(v6 + v12) )
              break;
            ++v11;
            ++v12;
          }
          while ( v11 < v13 );
        }
        v14 = -1i64;
        do
          ++v14;
        while ( *(_BYTE *)(v6 + v14) );
        if ( v11 == v14 )
          _exit(v6);
        v9 = (__int128 *)((char *)v9 + 1);
      }
      while ( (char *)v9 - (char *)v5 < 4 );
    
    • 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

    将v5扩展成16位,不足补0,前四位应该是 ‘flag’,补完后就是 ‘flag000000000000’

     v30 = *v7;
      while ( *((_BYTE *)&v30 + v15) )
      {
        if ( !*((_BYTE *)&v30 + v15 + 1) )
        {
          ++v15;
          break;
        }
        if ( !*((_BYTE *)&v30 + v15 + 2) )
        {
          v15 += 2i64;
          break;
        }
        if ( !*((_BYTE *)&v30 + v15 + 3) )
        {
          v15 += 3i64;
          break;
        }
        v15 += 4i64;
        if ( v15 >= 0x10 )
          break;
      }
      for ( i = v15 + 1; i < 0x10; ++i )
        *((_BYTE *)&v30 + i) = 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

    这一段就是给输入的flag进行xxtea加密,前面扩展的v5就是它的秘钥,然后再变换位置

     v17 = sub_7FF7A9871AB0((__int64)flag, v3, (unsigned __int8 *)&v30, &Size);// tea加密
      v18 = Size;
      v19 = v17;
      v20 = operator new(Size);
      v21 = 1;
      *v20 = v19[2];
      v22 = v20 + 1;
      v20[1] = *v19;
      v20[2] = v19[3];
      v20[3] = v19[1];
      v20[4] = v19[6];
      v20[5] = v19[4];
      v20[6] = v19[7];
      v20[7] = v19[5];
      v20[8] = v19[10];
      v20[9] = v19[8];
      v20[10] = v19[11];
      v20[11] = v19[9];
      v20[12] = v19[14];
      v20[13] = v19[12];
      v20[14] = v19[15];
      v20[15] = v19[13];
      v20[16] = v19[18];
      v20[17] = v19[16];
      v20[18] = v19[19];
      v20[19] = v19[17];
      v20[20] = v19[22];
      v20[21] = v19[20];
      v20[22] = v19[23];
    
    • 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

    xxtea里面还有一段拆分的代码,将32位的数拆分成4个8位的数

        if ( v40 )
        {
          do
          {
            v42[v13] = v11[v13 >> 2] >> (8 * (v13 & 3));
            ++v13;
          }
          while ( v13 < v40 );
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    异或

      for ( v20[23] = v19[21]; v21 < v18; ++v22 )
      {
        v23 = 0i64;
        if ( v21 / 3 > 0 )
        {
          v24 = *v22;
          do
          {
            v24 ^= v20[v23++];                      // 与前面的数异或
            *v22 = v24;
          }
          while ( v23 < v21 / 3 );
        }
        ++v21;
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    变换后的字符串要等于v30中的字符串

     *(_QWORD *)&v30 = 0xC0953A7C6B40BCCEui64;
      v25 = v20 - (_BYTE *)&v30;
      *((_QWORD *)&v30 + 1) = 0x3502F79120209BEFi64;
      v26 = 0i64;
      v31 = 0xC8021823;
      v32 = 0xFA5656E7;
      do
      {
        if ( *((_BYTE *)&v30 + v26) != *((_BYTE *)&v30 + v26 + v25) )
          _exit(v8 * v8);
        ++v8;
        ++v26;
      }
      while ( v26 < 24 );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    梳理下:
    输入flag->取前四位扩展成16位作秘钥-> xxtea加密->拆分 ->移位 ->异或

    然后写脚本挨个逆就行,先异或

    int v20[] = {  0xCE, 0xBC, 0x40, 0x6B, 0x7C, 0x3A, 0x95, 0xC0, 0xEF, 0x9B,
                            0x20, 0x20, 0x91, 0xF7, 0x02, 0x35, 0x23, 0x18, 0x02, 0xC8,
                            0xE7, 0x56, 0x56, 0xFA};
    
       for(int v22 = 23,v21 = 23; v21 >= 1; v22--)
       {
           int v23 = 0;
           if( v21 / 3 > 0)
           {
               //int v24 = v20[v22];
               do
               {
                   //v24 ^= v20[v23 ++];
                   //v20[v22] = v24;
                   v20[v22] ^= v20[v23++];
               }
               while(v23 < v21 / 3);
           }
           --v21;
       }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    移位

    int v19[25] = {0};
    
       v19[0] = v20[1];
       v19[2] = v20[0];
       v19[3] = v20[2];
       v19[1] = v20[3];
       v19[6] = v20[4];
       v19[4] = v20[5];
       v19[7] = v20[6];
       v19[5] = v20[7];
       v19[10] = v20[8];
       v19[8] = v20[9];
       v19[11] = v20[10];
       v19[9] = v20[11];
       v19[14] = v20[12];
       v19[12] = v20[13];
       v19[15] = v20[14];
       v19[13] = v20[15];
       v19[18] = v20[16];
       v19[16] = v20[17];
       v19[19] = v20[18];
       v19[17] = v20[19];
       v19[22] = v20[20];
       v19[20] = v20[21];
       v19[23] = v20[22];
       v19[21] = v20[23];
    
    • 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

    合并

        unsigned int flag[10] = {0};
        for(int i = 0 ; i < 0x18 ; i++)
        {
            //printf("%d, %d\n",i , 4 * (i / 4 + 1) - (i %  4) - 1);
            flag[i >>2] <<= 8;
            flag[i >> 2] += v19[4 * (i / 4 + 1) - i % 4 - 1];
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    xxtea解密

    xxtea秘钥是4个32位数,小端排序

    #define MX ((y ^ sum) + (z ^ key[e ^ (p & 3)])) ^ (((4 * y) ^ (z >> 5)) + ((y >> 3) ^ (16 * z)))
    #define DELTA 0x61C88647
    
    int key[5] = {0x67616c66,0x00,0x00,0x00};
    
     unsigned int sum = 0 , n = 6;
      int rounds = 52 / n + 6;
      int i,j,k;
      unsigned int z,y,e,p;
    
    
        rounds = 6 + 52/n;
        sum = rounds * DELTA * (-1);
        y = flag[0];
        do
        {
           // if(rounds < 0) break;
            e = (sum >> 2) & 3;
            for (p=n-1; p>0; p--)
            {
                z = flag[p-1];
                    //y = v2[p] -= ((y ^ sum) + (z ^ key[e ^ (p & 3)])) ^ (((4 * y) ^ (z >> 5)) + ((y >> 3) ^ (16 * z)));
                y = flag[p] -= MX;
                printf("p = %d\n",p);
            }
            z = flag[n-1];
                //y = v2[0] -= ((v2[0] ^ sum) + (z ^ key[e ^ (p & 3)])) ^ (((4 * v2[0]) ^ (z >> 5)) + ((v2[0] >> 3) ^ (16 * z)));
            y = flag[0] -= MX;
            sum += DELTA;
            printf("rounds = %d\n",rounds);
    
        }
        while(--rounds);
    
    
    
    • 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

    总代码

    #include 
    #include 
    #include 
    #include 
    #define MX ((y ^ sum) + (z ^ key[e ^ (p & 3)])) ^ (((4 * y) ^ (z >> 5)) + ((y >> 3) ^ (16 * z)))
    #define DELTA 0x61C88647
    
    int main()
    {
    
       int v20[] = {  0xCE, 0xBC, 0x40, 0x6B, 0x7C, 0x3A, 0x95, 0xC0, 0xEF, 0x9B,
                            0x20, 0x20, 0x91, 0xF7, 0x02, 0x35, 0x23, 0x18, 0x02, 0xC8,
                            0xE7, 0x56, 0x56, 0xFA};
    
       int key[5] = {0x67616c66,0x00,0x00,0x00};
    
          for(int v22 = 23,v21 = 23; v21 >= 1; v22--)
       {
           int v23 = 0;
           if( v21 / 3 > 0)
           {
        
               do
               {
                   v20[v22] ^= v20[v23++];
               }
               while(v23 < v21 / 3);
           }
           --v21;
       }
    
       int v19[25] = {0};
    
       v19[0] = v20[1];
       v19[2] = v20[0];
       v19[3] = v20[2];
       v19[1] = v20[3];
       v19[6] = v20[4];
       v19[4] = v20[5];
       v19[7] = v20[6];
       v19[5] = v20[7];
       v19[10] = v20[8];
       v19[8] = v20[9];
       v19[11] = v20[10];
       v19[9] = v20[11];
       v19[14] = v20[12];
       v19[12] = v20[13];
       v19[15] = v20[14];
       v19[13] = v20[15];
       v19[18] = v20[16];
       v19[16] = v20[17];
       v19[19] = v20[18];
       v19[17] = v20[19];
       v19[22] = v20[20];
       v19[20] = v20[21];
       v19[23] = v20[22];
       v19[21] = v20[23];
    
        unsigned int flag[10] = {0};
        for(int i = 0 ; i < 0x18 ; i++)
        {
            //printf("%d, %d\n",i , 4 * (i / 4 + 1) - (i %  4) - 1);
            flag[i >>2] <<= 8;
            flag[i >> 2] += v19[4 * (i / 4 + 1) - i % 4 - 1];
    
        }
    
    unsigned int sum = 0 , n = 6;
      int rounds = 52 / n + 6;
      int i,j,k;
      unsigned int z,y,e,p;
    
    //xxtea
    
        rounds = 6 + 52/n;
        sum = rounds * DELTA * (-1);
        y = flag[0];
        do
        {
           // if(rounds < 0) break;
            e = (sum >> 2) & 3;
            for (p=n-1; p>0; p--)
            {
                z = flag[p-1];
         
                y = flag[p] -= MX;
            }
            z = flag[n-1];
            y = flag[0] -= MX;
            sum += DELTA;
    
        }
        while(--rounds);
        //输出
       char *tmp = flag;
       for(int i = 0 ; i < 19 ; i++)
       {
           printf("%c",*tmp++);
       }
       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

    输出

    在这里插入图片描述

    最终flag:flag{CXX_and_++tea}

  • 相关阅读:
    laravel中锁以及事务的简单使用
    在互联网上少了这一步,你就别想着赚钱?
    TensorRT C# API 项目介绍:基于C#与TensorRT部署深度学习模型
    GBase8s物理日志
    C++11之新的类功能
    你的小程序可以接广告赚钱了
    leetcode:32. 最长有效括号
    Odoo丨如何在明细行中添加复选框?
    docker&kubernets篇(十七)
    [强化学习总结6] actor-critic算法
  • 原文地址:https://blog.csdn.net/ookami6497/article/details/119419860