CTF逆向-[NPUCTF2020]Baby Obfuscation-逆向思维编写脚本以及函数含义的逻辑理解

CTF逆向-[NPUCTF2020]Baby Obfuscation-逆向思维编写脚本以及函数含义的逻辑理解

来源:https://buuoj.cn/

内容

附件: https://pan.baidu.com/s/1jjjo11izhnEUQaLx00993w?pwd=pxdj 提取码:pxdj

答案:NPUCTF{0bfu5er}

总体思路

根据执行逻辑分析每个函数的含义

逻辑思维简化题目的代码,将其理解成较为简短的句子

逆向思维去编写脚本

详细步骤

  • 查看文件内容

    • image-20220427174235330
  • 打开以后发现主函数里面存在一些不知内容的变量和方法

    • image-20220427172507739
    • scanf("%32s", A0X2);推导 A0X2 为 v_input
    • for ( i = 0; i <= 64; ++i ) A0X3[i] = i + 1; 推导 A0X3为 index+1
    • A0X4A0X5改成arr1arr2
  • 双击打开查看这些函数的含义并给他们命名

    • F0X1为 求最大公约数(高中知识gcd函数)

    • int __cdecl F0X1(int a, int b)
      {
        if ( b )
          return F0X1(b, a % b);
        else
          return a;
      }
      
    • F0X2为 判断a和b是否都为flase

    • bool __cdecl F0X2(bool a, bool b)
      {
        return a == b && !a;
      }
      
    • F0X3也是判断a和b是否都为flase

    • bool __cdecl F0X3(bool a, bool b)
      {
        bool v2; // bl
        bool v3; // al
      
        v2 = F0X2(b, b);
        v3 = F0X2(a, a);
        return F0X2(v3, v2);
      }
      
    • F0X4可以化简,~表示去反,~a = int.MAX - a,等于a-b

    • int __cdecl F0X4(int a, int b)
      {
        return ~(~a + b); // = int.Max - (int.Max - a + b) = int.Max - int.Max + a - b = a - b
      }
      
    • F0X5为 pow(a,b),例如b=7,则二进制为111,a=5,则表达 = 5 * 5^2 * 5^4 = 5^7

    • int __cdecl F0X5(int a, int b)
      {
        int ans; // [rsp+Ch] [rbp-4h]
      
        ans = 1;
        while ( b )
        {
          if ( (b & 1) != 0 ) // 对b每一二进制位判断是否是1,是则乘上a
            ans *= a;
          a *= a; // 每移动一位 a自乘一遍
          b >>= 1;
        }
        return ans;
      }
      
  • 整理后得到如下,注意看注释内容,并跟着注释自行推导一遍。

  • int __cdecl main(int argc, const char **argv, const char **envp)
    {
      int v_equal_2; // eax
      int v4; // ebx
      int v5; // esi
      int v6; // ebx
      int v7; // ebx
      int v8; // esi
      int v9; // ebx
      int v10; // ebx
      int v11; // ebx
      int v12; // esi
      int v13; // eax
      int v14; // ebx
      int v15; // esi
      int v16; // ebx
      int v17; // eax
      bool v18; // bl
      int v19; // eax
      int v20; // esi
      int v21; // ebx
      int v22; // ebx
      int v23; // eax
      int v_equal_16; // eax
      int v_equal_1; // eax
      int v26; // ebx
      int v_index_add1[65]; // [rsp+20h] [rbp-60h] BYREF
      char v_input[1001]; // [rsp+130h] [rbp+B0h] BYREF
      int v_temp[1001]; // [rsp+520h] [rbp+4A0h] BYREF
      int v_arr2[4]; // [rsp+14D0h] [rbp+1450h]
      int v_arr1[4]; // [rsp+14E0h] [rbp+1460h]
      int v_input_len; // [rsp+14F0h] [rbp+1470h]
      int i_1; // [rsp+14F4h] [rbp+1474h]
      int v_i; // [rsp+14F8h] [rbp+1478h]
      int i; // [rsp+14FCh] [rbp+147Ch]
    
      _main();
      memset(v_temp, 0, sizeof(v_temp));
      memset(v_index_add1, 0, sizeof(v_index_add1));
      for ( i = 0; i <= 64; ++i )
        v_index_add1[i] = i + 1;
      v_arr1[0] = 2;
      v_arr1[1] = 3;
      v_arr1[2] = 4;
      v_arr1[3] = 5;
      v_arr2[0] = 2;
      v_arr2[1] = 3;
      v_arr2[2] = 4;
      v_arr2[3] = 5;
      puts("WHERE IS MY KEY!?");
      scanf("%32s", v_input);
      v_input_len = strlen(v_input);
      v_equal_2 = f_gcd(v_index_add1[v_i], v_index_add1[v_i]);
      for ( v_i = v_equal_2 / v_index_add1[v_i]; v_i <= v_input_len; ++v_i )// for(i = 1;i <= input_len;i++)
      {
        v4 = (v_index_add1[v_i] + v_index_add1[v_i + 1]) * (v_index_add1[v_i] + v_index_add1[v_i + 1]);// (i+1 + i+2)²
        if ( v4 >= f_pow_ex(2, 2) * v_index_add1[v_i] * v_index_add1[v_i + 1] )// 
                                                    // (i+1 + i+2)² >= 4 * (i+1) * (i+2)
                                                    // 4i²+12i+9 >= 4 * (i² + 3i + 2)
                                                    // 1 >= 0
                                                    // 一直成立
        {
          v5 = ~v_input[f_subtract(v_i, 1)];        // ~input[i-1]
          v6 = f_subtract(v_i, 1);
          v_temp[v_i] = ~(v5 + v_arr1[v6 % f_pow_ex(2, 2)]);// ~(~input[i-1] + arr1[0]) = input[i-1] - arr1[0]
        }
        v7 = f_gcd(v_index_add1[v_i], v_index_add1[v_i + 1]);// 1
        if ( v7 > f_gcd(v_index_add1[v_i + 1], ~(~v_index_add1[v_i + 1] + v_index_add1[v_i])) )// 
                                                    // 1 > gcd(i+2,~(~(i+2) + i+1))
                                                    // 1 > gcd(i+2,i+2 - (i+1))
                                                    // 1 > gcd(i+2,1)
                                                    // 1 > 1 永不成立
        {
          v8 = v_temp[v_i];
          v9 = f_subtract(v_i, 1);
          v_temp[v_i] = ~(~v8 + v_index_add1[v9 % f_pow_ex(2, 2)]) * v8;
        }
        v10 = v_index_add1[v_i + 1];                // i+2
        v11 = f_pow_ex(2, 1) * v10;                 // 2i + 4
        v12 = v_index_add1[v_i];                    // i+1
        v13 = f_pow_ex(2, 1);                       // 2
        v14 = f_gcd(v12 * v13, v11);                // gcd((i+1) * 2, 2i+4)
        v15 = f_pow_ex(2, 1);                       // 2
        if ( v14 == v15 * f_gcd(v_index_add1[v_i], v_index_add1[v_i + 1]) )// 
                                                    // gcd((i+1) * 2, 2i+4) == 2 * 1
                                                    // gcd(2i+2, 2i+4) == 2
                                                    // 从4,6,8,10,12,14,16,18,20..,2n里面找公约数只有2的
                                                    // 发现所有的i都符合
                                                    // 
        {
          v16 = f_subtract(v_i, 1);                 // i-1
          v_temp[v_i] ^= v_arr1[v16 % f_pow_ex(2, 2)];// v^= arr[(i-1) % 4]
        }
        v17 = f_pow_ex(g_value_3, v_index_add1[v_i]);// 
                                                    // g_value_3 = 3
                                                    // v17 = pow(3,i+1)
        v18 = v17 < v_index_add1[v_i] + 1;          // pow(3,i+1) < i+2
        v19 = f_pow_ex(2, 4);                       // 16
        if ( f_check_false_false_same(v19 >= v_i, v18) )// 
                                                    // 16 < i && pow(3,i+1) >= i+2
                                                    // i>1 && i>16
                                                    // i>16是永不成立的
        {
          v20 = ~v_input[f_subtract(v_i, 1)];       // ~input[i-1]
          v21 = f_subtract(v_i, 1);                 // i-1
          v_temp[v_i] ^= ~(v20 + v_arr1[v21 % f_pow_ex(2, 2)]);// ^= (input[i-1] - arr1[(i-1) %4])
        }
        v22 = f_pow_ex(2, 3);                       // 8
        v23 = f_gcd(v_index_add1[v_i], v_index_add1[v_i]);// 1
        v_temp[v_i] *= v22 + f_pow_ex(2, v23 / v_index_add1[v_i]);// *= 8 + 2 = 10
      }
      v_equal_16 = f_pow_ex(2, 4);                  // 16
      if ( f_subtract(v_equal_16, 1) != v_input_len )
        goto LABEL_23;
      v_equal_1 = f_gcd(v_index_add1[i_1], v_index_add1[i_1]);
      for ( i_1 = v_equal_1 / v_index_add1[i_1]; i_1 <= v_input_len; ++i_1 )// for(i=1;i<=input_len;i++)
      {
        v26 = v_temp[i_1];
        if ( v26 == f_subtract(g_data[i_1], 1) / 10 )// input[i] * 10 = (g_data[i] - 1) 
          ++::v_i;
      }
      if ( ::v_i == v_input_len )
        puts("\nPASS");
      else
    LABEL_23:
        puts("\nDENIED");
      return 0;
    }
    
  • 经过整理,得到其处理的步骤如下

  • 程序对该字符串进行处理 - 变换

    • input[i] = input[i-1] - arr1[(i-1)%4]
    • input[i] ^= arr1[(i-1) % 4]
  • 判断

    • 输入的是16位
      1. input[i] *= 10
      1. 判断 input[i] * 10 是否等于 g_data[i] -1
    • 即 input[i] * 100 == g_data[i] - 1
  • 逆向编写上述流程

    1. input[i] = (g_data[i] - 1) / 100
    2. input[i] ^= arr1[(i-1) % 4]
    3. input[i-1] = input[i] + arr1[0]
  • import struct
    
    
    g_data = '00000000791E0000791E0000352100000D170000411F000001190000ED2C0000F91100004926000081250000B52D0000B5140000E5250000312A0000D530000000000000'
    g_data = bytearray.fromhex(g_data) # 转换为字节
    g_data = [g_data[4*x:4*(x+1)] for x in range(int(len(g_data)/4))] # 按4个字节为一个数保存
    g_data = [struct.unpack('<I',x)[0] for x in g_data] # 按小端序将原始数据转换为整数
    arr1 = [2, 3, 4, 5] # 原始arr
    flag = [x for x in range(16)] # 初始化flag
    
    for i in range(1, 16):
        temp = int((g_data[i] - 1) / 100) # input[i] * 100 == g_data[i] - 1
        temp ^= arr1[(i-1) % 4] # input[i] ^= arr1[(i-1) % 4]
        temp += arr1[(i-1) % 4] # input[i] = input[i-1] - arr1[0] 即 input[i-1] = input[i] + arr1[0]
        flag[i-1] = temp
    
    flag = [chr(x) for x in flag] # 转换为字符
    flag = ''.join(flag)
    print(flag) # NPUCTF{0bfu5er}
    
    

其他文档

更多CTF逆向题通用性做法和常用工具下载参考该博文内容:CTF逆向Reverse题的玩法

相关逆向CTF题

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值