[buuctf.reverse] 115_[RCTF2019]DontEatMe

迷宫加Blowfish加密

ida打开,可以看到提示说一个鱼XXX,用findcrypt查密提示Blowfish而且有5行,估计是未改动过的原版加密

 程序比较长,大概分这两块,一块是对输入解密生成一个串,再用这个串走迷宫

int __cdecl main(int argc, const char **argv, const char **envp)
{
  ...
  char ArgList[68]; // [esp+1080h] [ebp-48h] BYREF

  memset(ArgList, 0, 0x40u);
  puts("LiHua is trapped on an isolated island. ", v43);
  puts("One day, he caught a fish.\n", v44);
  puts("Suddenly,the fish said: \"Dont eat me! I am Fish God,if you release me,as return ,you have one wish.\"\n", v45);
  puts("Li said : I want to know how to escape from this island.\n", v46);
  puts("Fish said: ", v47);
  scanf("%s", (char)ArgList);
  srand(0xDEADBEEF);
  ModuleHandleA = GetModuleHandleA("Ntdll");
  ZwSetInformationThread = GetProcAddress(ModuleHandleA, "ZwSetInformationThread");
  CurrentThread = GetCurrentThread();
  ((void (__stdcall *)(HANDLE, int, _DWORD, _DWORD))ZwSetInformationThread)(CurrentThread, 17, 0, 0);
  for ( i = 0; i < 8; ++i )
    byte_4057A8[i] = rand();
  byte_4057A8[0] = 0;
  v58[0] = 0x4853494668736966i64;
  LOBYTE(v7) = 104;
  word_4057A9 = 0x1A0F;                         // key
  word_4057AB = 0x3501;
  byte_4057AD = 0x3A;
  byte_4057AE = 0x3B;
  byte_4057AF = 0x20;
  sub_401090(v56, v7);                          // v57
  v8 = strlen(ArgList);
  v9 = v8;
  v49 = v8;
  if ( (v8 & 7) != 0 )                          // 8字节向上取整
  {
    v9 = 8 * (v8 >> 3) + 8;
    v49 = v9;
  }
  v54 = (char *)calloc(v9, 1u);
  v10 = (unsigned __int8 *)calloc(v9 / 2, 1u);
  v11 = 0;
  v51 = v10;
  if ( v9 / 2 > 0 )
  {
    v12 = ArgList;                              // 输入转16进制存
    do
    {
      sprintf(v12, "%02x", v11 + (_BYTE)v10);
      v10 = v51;
      ++v11;
      v12 += 2;
    }
    while ( v11 < v9 / 2 );
    v9 = v49;
  }
  v50 = 0;
  v55 = v9 / 16;
  if ( v9 / 16 <= 0 )
  {
    v26 = v54;
  }
  else
  {
    v13 = v10 + 2;
    v53 = v13;                                  // BlowFish加密
    do
    {
      v14 = v57;
      v52 = 16;
      v15 = v13[1] | ((*v13 | ((*(v13 - 1) | (*(v13 - 2) << 8)) << 8)) << 8);
      v16 = v13[5] | ((v13[4] | ((v13[3] | (v13[2] << 8)) << 8)) << 8);
      do
      {
        v17 = *(_DWORD *)v14 ^ v15;
        v14 -= 4;
        v18 = v17;
        v15 = v16 ^ (*(_DWORD *)&v57[4 * (unsigned __int8)v17 + 3076]
                   + (*(_DWORD *)&v57[4 * BYTE1(v17) + 2052] ^ (*(_DWORD *)&v57[4 * BYTE2(v17) + 1028]
                                                              + *(_DWORD *)&v57[4 * HIBYTE(v17) + 4])));
        v19 = v52-- == 1;
        v16 = v18;
      }
      while ( !v19 );
      v20 = v18 ^ v56[0];
      v21 = calloc(4u, 1u);
      *v21 = HIBYTE(v20);
      v21[1] = BYTE2(v20);
      v21[2] = BYTE1(v20);
      v21[3] = v20;
      v22 = v56[1];
      *(_DWORD *)&v54[8 * v50] = *(_DWORD *)v21;
      v23 = v15 ^ v22;
      v24 = calloc(4u, 1u);
      *v24 = HIBYTE(v23);
      v24[1] = BYTE2(v23);
      v25 = v23 >> 8;
      v24[3] = v23;
      v26 = v54;
      v24[2] = v25;
      *(_DWORD *)&v54[8 * v50 + 4] = *(_DWORD *)v24;
      v13 = v53 + 8;
      v53 += 8;
      ++v50;
    }
    while ( v50 < v55 );
  }
  v58[0] = 0x4D746145746E6F44i64;
  v27 = _byteswap_ushort(0x6F44u);
  v28 = _byteswap_ushort(0x746Eu);
  v29 = _byteswap_ushort(0x6145u);
  v30 = _byteswap_ushort(0x4D74u);
  v31 = &unk_40501A;
  do
  {
    *(v31 - 1) ^= v27;
    *v31 ^= v28;
    v31[1] ^= v29;
    v31[2] ^= v30;
    v31 += 4;                                   // 每次8字节
  }
  while ( (int)v31 < (int)&unk_40503A );
  v32 = dword_4053A8;
  v33 = (unsigned __int16 *)&unk_405018;        // 将018-038按位展开(低位在前)放入3A8 迷宫
  do
  {
    v34 = *v33;
    for ( j = 15; j > -1; --j )
    {
      v36 = (v34 & (1 << j)) >> j;
      *v32++ = v36;
    }
    ++v33;
  }
  while ( (int)v33 < (int)&unk_405038 );
  v37 = *v26;
  v38 = 10;
  v39 = 0;
  v40 = 5;
  if ( *v26 )
  {
    v41 = 160;
    while ( 1 )
    {
      switch ( v37 )
      {
        case 'a':
          --v40;
          break;
        case 'd':
          ++v40;
          break;
        case 's':
          ++v38;
          v41 += 16;
          break;
        case 'w':
          --v38;
          v41 -= 16;
          break;
        default:
          break;
      }
      if ( dword_4053A8[v41 + v40] == 1 )
        break;
      v37 = v26[++v39];
      if ( !v37 )
      {
        if ( v38 == 4 && v40 == 9 && v39 < 17 )
        {
          puts("Congratulations! Here is your flag: RCTF{%s}", (char)ArgList);
          return 0;
        }
        break;
      }
    }
  }
  puts("Oh no.  Dont eat me!!!!", v48);
  return 0;
}

迷宫这块相对独立,所以可以直接把这块逆向到解密后的结果

from pwn import *

data = open('DontEatMe.exe', 'rb').read()
#1迷宫部分

#45018-45038
a1 = list(data[0x3618: 0x3638])
xors = [0x6f,0x44,0x74,0x6e,0x61,0x45,0x4D,0x74]
print(a1)
for i in range(len(a1)-2):
    a1[i] ^= xors[i%8]
s = ''
for i in range(16):
    s+= bin(a1[i*2+1])[2:].rjust(8, '0')
    s+= bin(a1[i*2])[2:].rjust(8, '0')
    s+='\n'
print(s)
#ddddwwwaaawwwddd
'''
1111111111111111
1000000000111111
1011111110111111
1011111110111111
1011110000000111
1011110111110111
1011110111110111
1011110000110111
1011111110110111
1011111110110111
1000000000110111
1111101111110111
1111100000000111
1111111111111111
1111111111111111
1000101110110010
'''

得到的16位串再用Blowfish解密,8字节的key在主程序里先用rand填充后直接写入值覆盖。这人真够恶心的一共8字节分6次写。

  byte_4057A8[0] = 0;
  v58[0] = 0x4853494668736966i64;
  LOBYTE(v7) = 104;
  word_4057A9 = 0x1A0F;                         // key
  word_4057AB = 0x3501;
  byte_4057AD = 0x3A;
  byte_4057AE = 0x3B;
  byte_4057AF = 0x20;

最后调用函数解密

data = b'ddddwwwaaawwwddd'
key = b"\x00\x0F\x1A\x01\x35\x3A\x3B\x20"
import blowfish
cipher = blowfish.Cipher(key)
step = cipher.encrypt_block(data[:8]) + cipher.encrypt_block(data[8:])
print('flag{%s}'% step.hex())
#flag{db824ef8605c5235b4bbacfa2ff8e087}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值