BUUCTF Reverse [RoarCTF2019]polyre

下载文件查壳,文件无壳64位

刚用ida打开的时候一脸问号,分析了半天乱七八糟于是动调,发现一直在某个地方进行循环,在百度搜索后知道这个是需要控制流平坦化。

处理文件的时候需要用到脚本,这里贴出官方给出的wp脚本。

def patch_nop(start,end):
    for i in range(start,end):
        PatchByte(i, 0x90)

def next_instr(addr):
    return addr+ItemSize(addr)
    
st = 0x0000000000401117
end = 0x0000000000402144

addr = st
while(addr<end):
    next = next_instr(addr)
    if "ds:dword_603054" in GetDisasm(addr):
        while(True):
            addr = next
            next = next_instr(addr)
            if "jnz" in GetDisasm(addr):
                dest = GetOperandValue(addr, 0)
                PatchByte(addr, 0xe9)
                PatchByte(addr+5, 0x90) 
                offset = dest - (addr + 5)
                PatchDword(addr + 1, offset)
                print("patch bcf: 0x%x"%addr)
                addr = next
                break
    else:
        addr = next

 最后可以得到处理好的代码

__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  signed __int64 v4; // [rsp+1E0h] [rbp-110h]
  signed int j; // [rsp+1E8h] [rbp-108h]
  signed int i; // [rsp+1ECh] [rbp-104h]
  signed int k; // [rsp+1ECh] [rbp-104h]
  char s1[48]; // [rsp+1F0h] [rbp-100h]
  char s[60]; // [rsp+220h] [rbp-D0h]
  unsigned int v10; // [rsp+25Ch] [rbp-94h]
  char *v11; // [rsp+260h] [rbp-90h]
  int v12; // [rsp+26Ch] [rbp-84h]
  bool v13; // [rsp+272h] [rbp-7Eh]
  unsigned __int8 v14; // [rsp+273h] [rbp-7Dh]
  int v15; // [rsp+274h] [rbp-7Ch]
  char *v16; // [rsp+278h] [rbp-78h]
  int v17; // [rsp+284h] [rbp-6Ch]
  int v18; // [rsp+288h] [rbp-68h]
  bool v19; // [rsp+28Fh] [rbp-61h]
  char *v20; // [rsp+290h] [rbp-60h]
  int v21; // [rsp+298h] [rbp-58h]
  bool v22; // [rsp+29Fh] [rbp-51h]
  __int64 v23; // [rsp+2A0h] [rbp-50h]
  bool v24; // [rsp+2AFh] [rbp-41h]
  __int64 v25; // [rsp+2B0h] [rbp-40h]
  __int64 v26; // [rsp+2B8h] [rbp-38h]
  __int64 v27; // [rsp+2C0h] [rbp-30h]
  __int64 v28; // [rsp+2C8h] [rbp-28h]
  int v29; // [rsp+2D0h] [rbp-20h]
  int v30; // [rsp+2D4h] [rbp-1Ch]
  char *v31; // [rsp+2D8h] [rbp-18h]
  int v32; // [rsp+2E0h] [rbp-10h]
  int v33; // [rsp+2E4h] [rbp-Ch]
  bool v34; // [rsp+2EBh] [rbp-5h]

  v10 = 0;
  memset(s, 0, 0x30uLL);
  memset(s1, 0, 0x30uLL);
  printf("Input:", 0LL);
  v11 = s;
  __isoc99_scanf("%s", s, (dword_603054 - 1), 3788079310LL);
  for ( i = 0; ; ++i )
  {
    v12 = i;
    v13 = i < 64;
    if ( i >= 64 )
      break;
    v14 = s[i];
    v15 = v14;
    if ( v14 == 10 )
    {
      v16 = &s[i];
      *v16 = 0;
      break;
    }
    v17 = i + 1;
  }
  for ( j = 0; ; ++j )
  {
    v18 = j;
    v19 = j < 6;
    if ( j >= 6 )
      break;
    v20 = s;
    v4 = *&s[8 * j];
    for ( k = 0; ; ++k )
    {
      v21 = k;
      v22 = k < 64;
      if ( k >= 64 )
        break;
      v23 = v4;
      v24 = v4 < 0;
      if ( v4 >= 0 )
      {
        v27 = v4;
        v28 = 2 * v4;
        v4 *= 2LL;
      }
      else
      {
        v25 = 2 * v4;
        v26 = 2 * v4;
        v4 = 2 * v4 ^ 0xB0004B7679FA26B3LL;
      }
      v29 = k;
    }
    v30 = 8 * j;
    v31 = &s1[8 * j];
    *v31 = v4;
    v32 = j + 1;
  }
  v33 = memcmp(s1, &unk_402170, 0x30uLL);
  v34 = v33 != 0;
  if ( v33 != 0 )
    puts("Wrong!");
  else
    puts("Correct!");
  return v10;
}

这部分代码使用的是crc32查表法对数据进行加密。

加密原理实际上就是CRC32算法—输入一组长度48的字符串,每8个字节分为1组,共6组。对每一组取首位,判断正负。正值,左移一位;负值,左移一位,再异或0xB0004B7679FA26B3。重复判断操作64次,得到查表法所用的表。

贴出脚本

secret = [0xBC8FF26D43536296, 0x520100780530EE16, 0x4DC0B5EA935F08EC,
          0x342B90AFD853F450, 0x8B250EBCAA2C3681, 0x55759F81A2C68AE4]
key = 0xB0004B7679FA26B3

flag = ""

# 产生CRC32查表法所用的表
for s in secret:
    for i in range(64):
        sign = s & 1
        # 判断是否为负
        if sign == 1:
            s ^= key
        s //= 2
        # 防止负值除2,溢出为正值
        if sign == 1:
            s |= 0x8000000000000000
    # 输出表
    print(hex(s))
    # 计算CRC64
    j = 0
    while j < 8:
        flag += chr(s&0xFF)
        s >>= 8
        j += 1
print(flag)

flag{6ff29390-6c20-4c56-ba70-a95758e3d1f8}

posted @ 2021-05-06 11:44  Sk2rw  阅读(222)  评论(0编辑  收藏  举报