BUUCTF——[SWPU2019]ReverseMe

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v3; // ecx
  int *v4; // eax
  int v5; // ecx
  int *v6; // eax
  char *v7; // esi
  int v8; // edi
  unsigned int v9; // kr00_4
  void **v10; // ecx
  __int128 *v11; // ecx
  int *v12; // ecx
  char *input_crypto2; // edx
  unsigned int v14; // edi
  int v15; // eax
  int v16; // eax
  bool v17; // cf
  unsigned __int8 v18; // al
  unsigned __int8 v19; // al
  unsigned __int8 v20; // al
  const char *v21; // edx
  int *v22; // eax
  char *v23; // eax
  int v25; // [esp-14h] [ebp-D8h]
  int v26; // [esp-10h] [ebp-D4h]
  void *input[4]; // [esp+24h] [ebp-A0h] BYREF
  int input_lenth; // [esp+34h] [ebp-90h]
  unsigned int v29; // [esp+38h] [ebp-8Ch]
  char v30[32]; // [esp+3Ch] [ebp-88h] BYREF
  int v31; // [esp+5Ch] [ebp-68h]
  __int128 input_; // [esp+60h] [ebp-64h] BYREF
  __int128 v33; // [esp+70h] [ebp-54h]
  int v34; // [esp+80h] [ebp-44h]
  char str[16]; // [esp+84h] [ebp-40h] BYREF
  int test[8]; // [esp+94h] [ebp-30h] BYREF
  int v37; // [esp+C0h] [ebp-4h]

  input_lenth = 0;
  v29 = 0xF;
  LOBYTE(input[0]) = 0;
  v37 = 1;
  v4 = printf(v3, "Please input your flag: ");
  sub_403050((int)v4);
  scanf(&dword_430068, input);
  strcpy(str, "SWPU_2019_CTF");
  if ( input_lenth == 0x20 )
  {
    test[4] = 0xBA143D17;
    test[5] = 0x1D730350;
    test[6] = 0x9404607A;
    test[7] = 0x290AF070;
    v8 = 0;
    input_ = 0i64;
    v34 = 0;
    v33 = 0i64;
    v9 = strlen(str);




    do                                          // 对input进行加密
    {
      v10 = input;
      if ( v29 >= 0x10 )
        v10 = (void **)input[0];
      *((_BYTE *)v10 + v8) ^= str[v8 % v9];
      ++v8;
    }
    while ( v8 < 0x20 );




    v11 = (__int128 *)input;                    // 这里可以推出input加密后的数据
    v7 = (char *)input[0];
    if ( v29 >= 0x10 )
      v11 = (__int128 *)input[0];
    v31 = 0;
    memset(v30, 0, sizeof(v30));
    input_ = *v11;
    v33 = v11[1];
    sub_4025C0(v25, v26, 0x100, (char *)&input_, (unsigned int)v30);
    test[0] = 0xF80F37B3;
    test[1] = 0x5DAEBCBC;
    v12 = test;
    test[2] = 0x864D5ABA;
    input_crypto2 = v30;
    test[3] = 0xD3629744;
    v14 = 0x1C;
    test[4] = 0x1624BA4F;
    test[5] = 0x1A729F0B;
    test[6] = 0x266D6865;
    test[7] = 0x67C86BBA;
    while ( 1 )
    {
      v15 = *v12;
      if ( *v12 != *(_DWORD *)input_crypto2 )
        break;
      ++v12;
      input_crypto2 += 4;
      v17 = v14 < 4;
      v14 -= 4;
      if ( v17 )
      {
        v16 = 0;
        goto LABEL_19;
      }
    }






    v17 = (unsigned __int8)v15 < (unsigned __int8)*input_crypto2;
    if ( (_BYTE)v15 == *input_crypto2
      && (v18 = *((_BYTE *)v12 + 1), v17 = v18 < (unsigned __int8)input_crypto2[1], v18 == input_crypto2[1])
      && (v19 = *((_BYTE *)v12 + 2), v17 = v19 < (unsigned __int8)input_crypto2[2], v19 == input_crypto2[2])
      && (v20 = *((_BYTE *)v12 + 3), v17 = v20 < (unsigned __int8)input_crypto2[3], v20 == input_crypto2[3]) )
    {
      v16 = 0;
    }
    else
    {
      v16 = v17 ? 0xFFFFFFFF : 1;
    }
LABEL_19:
    if ( v16 )
      v21 = "Try again!\r\n";
    else
      v21 = "Congratulations! I always knew you could do it.";
    v22 = printf((int)v12, v21);
    sub_403050((int)v22);
    system((int)"pause");
  }
  else
  {
    v6 = printf(v5, "Try again!\r\n");
    sub_403050((int)v6);
    system((int)"pause");
    v7 = (char *)input[0];
  }
  if ( v29 >= 0x10 )
  {
    v23 = v7;
    if ( v29 + 1 >= 0x1000 )
    {
      v7 = (char *)*((_DWORD *)v7 + 0xFFFFFFFF);
      if ( (unsigned int)(v23 - v7 - 4) > 0x1F )
        _invalid_parameter_noinfo_noreturn();
    }
    sub_4064DE(v7);
  }
  return 0;
}

总体下来有两个异或加密,第一个异或加密是

do                                          // 对input进行加密
    {
      v10 = input;
      if ( v29 >= 0x10 )
        v10 = (void **)input[0];
      *((_BYTE *)v10 + v8) ^= str[v8 % v9];
      ++v8;
    }
    while ( v8 < 0x20 );

这个就是逐字节异或,没啥好说的

下来就是一个函数

sub_4025C0(v25, v26, 0x100, (char *)&input_, (unsigned int)v30);

不得不说,如果仅是靠IDA去纯肉眼看,那必然是非常消耗时间的,这个函数的作用是,将input作为参数输入,然后输出v30

但是我们点进去函数细看:
 

void __cdecl sub_4025C0(int a1, int a2, int a3, char *input, unsigned int a5)
{
  int v5; // ecx
  unsigned int v6; // ebx
  int v7; // esi
  unsigned int v8; // edi
  unsigned int v9; // esi
  unsigned int v10; // edx
  char *v11; // esi
  char *v12; // ecx
  char *v13; // eax
  int v14; // ebx
  int v15; // esi
  __m128i v16; // xmm0
  __m128i v17; // xmm1
  __m128i v18; // xmm0
  __m128i v19; // xmm1
  __m128i v20; // xmm0
  __m128i v21; // xmm1
  __m128i v22; // xmm0
  __m128i v23; // xmm1
  int v24; // ebx
  char *v25; // eax
  int v26; // esi
  unsigned int v27; // edi
  int v28; // ecx
  signed int v29; // [esp+20h] [ebp-20h]
  int v30; // [esp+24h] [ebp-1Ch]
  char *Block; // [esp+28h] [ebp-18h]
  int v32[4]; // [esp+2Ch] [ebp-14h] BYREF

  v6 = a5;
  v7 = v5;
  v8 = (unsigned int)(a3 + 0x1F) >> 5;
  v30 = 4 * v8;
  Block = (char *)malloc(4 * v8);
  v32[0] = 0x92540366;
  v32[1] = 0x78;
  v32[2] = 0x92540366;
  v32[3] = 0x78;
  sub_402270(v7, v32);
  sub_4020E0();
  sub_402150();
  sub_401F80();
  v29 = 0;
  if ( v8 )
  {
    do
    {
      dword_430D94 = (2 * dword_430DA4) ^ (unsigned __int16)(dword_430DBC ^ (2 * dword_430DA4));
      dword_430D78 = (dword_430DB8 << 0x10) | ((unsigned int)dword_430DAC >> 0xF);
      v9 = (dword_430D70 << 0x10) | ((unsigned int)dword_430D90 >> 0xF);
      dword_430D8C = (dword_430D68 << 0x10) | ((unsigned int)dword_430D84 >> 0xF);
      dword_430D7C = v9;
      *(_DWORD *)&Block[4 * v29] = v9 ^ sub_402150();
      sub_401F80();
      ++v29;
    }
    while ( v29 < (int)v8 );
    v6 = a5;
  }
  v10 = 0;
  if ( v8 )
  {
    v11 = input;
    if ( v8 < 0x10 || v6 <= (unsigned int)&input[v30 - 4] && v6 + v30 - 4 >= (unsigned int)input )
    {
      v12 = Block;
    }
    else
    {
      v12 = Block;
      if ( v6 > (unsigned int)&Block[4 * v8 - 4] || v6 + v30 - 4 < (unsigned int)Block )
      {
        v13 = input + 0x10;
        v12 = Block;
        v14 = v6 + 0x20;
        v15 = Block - input;
        do
        {
          v16 = *((__m128i *)v13 + 0xFFFFFFFF);
          v13 += 0x40;
          v14 += 0x40;
          v17 = _mm_xor_si128(*(__m128i *)&Block[4 * v10], v16);
          v18 = *((__m128i *)v13 + 0xFFFFFFFC);
          *(__m128i *)(v14 - 0x60) = v17;
          v19 = _mm_xor_si128(*(__m128i *)&v13[v15 - 0x40], v18);
          v20 = *((__m128i *)v13 + 0xFFFFFFFD);
          *(__m128i *)&v13[a5 - (_DWORD)input - 0x40] = v19;
          v15 = Block - input;
          v21 = _mm_xor_si128(*(__m128i *)&Block[v14 - a5 - 0x40], v20);
          v22 = *((__m128i *)v13 + 0xFFFFFFFE);
          *(__m128i *)(v14 - 0x40) = v21;
          v23 = *(__m128i *)&Block[4 * v10 + 0x30];
          v10 += 0x10;
          *(__m128i *)(v14 - 0x30) = _mm_xor_si128(v23, v22);
        }
        while ( v10 < (v8 & 0xFFFFFFF0) );
        v6 = a5;
        v11 = input;
      }
    }
    if ( v10 < v8 )
    {
      v24 = v6 - (_DWORD)input;
      v25 = &v11[4 * v10];
      v26 = v12 - input;
      v27 = v8 - v10;
      do
      {
        v28 = *(_DWORD *)&v25[v26];
        v25 += 4;
        *(_DWORD *)&v25[v24 - 4] = *((_DWORD *)v25 + 0xFFFFFFFF) ^ v28;
        --v27;
      }
      while ( v27 );
    }
  }
  free(Block);
}

就是让人眼乱,里面还参杂着一些函数,鬼知道会不会给你来一个对v30的值的改变

这时候我们不一定要用IDA,可以用x32dbg下硬件写入断点帮我们看看具体是咋整的

 参数从右到左push进去,因此v30变量的地址就是 [ebp - 0x88],于是乎我们在这个地址下硬件写入断点

然后运行跑起来:

然后发现断在这个地方,这是一个循环,调试后很容易发现,是将input与一个固定值进行异或加密

或者说看汇编难受,可以转到IDA看

就是单纯的一个异或操作

下面是解题脚本:

#include <iostream>
#include <windows.h>
using namespace std;
unsigned char m_data[32] = {
};

char str[20] = "SWPU_2019_CTF";

unsigned int m_data3[8] = {
    0xF80F37B3, 0x5DAEBCBC, 0x864D5ABA, 0xD3629744, 0x1624BA4F, 0x1A729F0B, 0x266D6865, 0x67C86BBA
};

unsigned int m_data2[8] = {
    0xCA3E0C86, 0x19AED798, 0xA66B77E2, 0xB077A16A, 0x05379169, 0x307BF97A, 0x104B5A43, 0x28D47D86
};


unsigned int m_data4[8] = {};

char flag[32] = {};

int main()
{

    for (int i = 0; i < 8; i++)
    {
        m_data4[i] = m_data3[i] ^ m_data2[i];
    }


    for (int i = 0; i < 8; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            m_data[4 * i + j] = m_data4[i] & 0xff;
            m_data4[i] = m_data4[i] >>8;
        }
    }


    for (int i = 0; i < 0x20; i++)
    {
        flag[i] = m_data[i] ^ str[i % 13];
    }
    cout << flag << endl;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值