[RoarCTF2019]polyre.zip

拿到程序发现 是用了 ollvm 混淆的

利用 deflat.py 脚本对程序去混淆。

__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  signed __int64 v4; // [rsp+1E0h] [rbp-110h]
  int i; // [rsp+1E8h] [rbp-108h]
  int idx; // [rsp+1ECh] [rbp-104h]
  int v7; // [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 *input_num; // [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);
  input_num = s;
  if ( num1 >= 10 && ((num2 - 1) * num2 & 1) != 0 )
    goto LABEL_43;
  while ( 1 )
  {
    __isoc99_scanf("%s", input_num);
    idx = 0;
    if ( num1 < 10 || ((num2 - 1) * num2 & 1) == 0 )
      break;
LABEL_43:
    __isoc99_scanf("%s", input_num);
  }
  while ( 1 )
  {
    do
      v12 = idx;
    while ( num1 >= 10 && ((num2 - 1) * num2 & 1) != 0 );
    v13 = v12 < 0x40;
    while ( num1 >= 10 && ((num2 - 1) * num2 & 1) != 0 )
      ;
    if ( !v13 )
      break;
    v14 = s[idx];
    do
      v15 = v14;
    while ( num1 >= 10 && ((num2 - 1) * num2 & 1) != 0 );
    if ( v15 == 10 )
    {
      v16 = &s[idx];
      *v16 = 0;
      break;
    }
    v17 = idx + 1;
    do
      idx = v17;
    while ( num1 >= 10 && ((num2 - 1) * num2 & 1) != 0 );
  }
  for ( i = 0; ; ++i )
  {
    do
      v18 = i;
    while ( num1 >= 10 && ((num2 - 1) * num2 & 1) != 0 );
    do
      v19 = v18 < 6;
    while ( num1 >= 10 && ((num2 - 1) * num2 & 1) != 0 );
    if ( !v19 )
      break;
    do
      v20 = s;
    while ( num1 >= 10 && ((num2 - 1) * num2 & 1) != 0 );
    v4 = *&v20[8 * i];
    v7 = 0;
    while ( 1 )
    {
      v21 = v7;
      do
        v22 = v21 < 64;
      while ( num1 >= 10 && ((num2 - 1) * num2 & 1) != 0 );
      if ( !v22 )
        break;
      v23 = v4;
      v24 = v4 < 0;
      if ( v4 >= 0 )
      {
        v27 = v4;
        do
          v28 = 2 * v27;
        while ( num1 >= 10 && ((num2 - 1) * num2 & 1) != 0 );
        v4 = v28;
      }
      else
      {
        v25 = 2 * v4;
        do
          v26 = v25;
        while ( num1 >= 10 && ((num2 - 1) * num2 & 1) != 0 );
        v4 = v26 ^ 0xB0004B7679FA26B3LL;
      }
      v29 = v7;
      do
        v7 = v29 + 1;
      while ( num1 >= 10 && ((num2 - 1) * num2 & 1) != 0 );
    }
    v30 = 8 * i;
    v31 = &s1[8 * i];                           // 8字节
    if ( num1 >= 10 && ((num2 - 1) * num2 & 1) != 0 )
LABEL_55:
      *v31 = v4;
    *v31 = v4;
    if ( num1 >= 10 && ((num2 - 1) * num2 & 1) != 0 )
      goto LABEL_55;
    v32 = i + 1;
  }
  do
    v33 = memcmp(s1, &cmp_data, 0x30uLL);       // 0BC8FF26D43536296h 
                                                // 520100780530EE16h
                                                // 4DC0B5EA935F08ECh
                                                // 342B90AFD853F450h
                                                // 8B250EBCAA2C3681h
                                                // 55759F81A2C68AE4h
                                                // 0B0004B7679FA26B3h
  while ( num1 >= 10 && ((num2 - 1) * num2 & 1) != 0 );
  v34 = v33 != 0;
  while ( num1 >= 10 && ((num2 - 1) * num2 & 1) != 0 )
    ;
  if ( v34 )
    puts("Wrong!");
  else
    puts("Correct!");
  return v10;
}

混淆不是去的很完整。 但是 可以 比较明白的 看出程序的 逻辑。

这个时候 我们 可以先把 这个 加密的 具体逻辑写下来。

v12 = 0
if(v12<0x40):
    v4 = v28
    if(v4 >= 0):
        v28 = v28 * 2
    else:
        v28 = v28 * 2
        v28 = v28 ^ 0xB0004B7679FA26B3
    v12 += 1

发现是 每次 都 乘2 一共乘了 0x40次 得到的 计算结果 喝一个 数组 比较 0x30 大小。

0xbc8ff26d43536296, 
0x520100780530ee16,
0x4dc0b5ea935f08ec,
0x342b90afd853f450,
0x8b250ebcaa2c3681,
0x55759f81a2c68ae4

程序的主要逻辑是和 0xB0004B7679FA26B3 进行一个 异或。在这里,发现一个 知识。

一个奇数 异或 一个偶数 为 一个奇数, 一个奇数 异或 一个奇数 为 偶数 (程序的逻辑可以根据这个规则来写出 逆向脚本。注意每次异或 数据的长度可能发生变化)

因为加密里面 v4 是一个有符号数。所以我们在计算的时候,注意 ^ 0xB0004B7679FA26B3

会变成一个 奇数切变号,所以在每次 进行操作后要 | 0x8000000000000000 得到的值才是有效的。

EXP:

# v12 = 0
# if(v12<0x40):
#     v4 = v28
#     if(v4 >= 0):
#         v28 = v28 * 2
#     else:
#         v28 = v28 * 2
#         v28 = v28 ^ 0xB0004B7679FA26B3
#     v12 += 1

print (3^1)
print (4^1)
print (5^1)
print("------------------")
print (3^2)
print (4^2)
print (5^2)

cmp_data = [0xbc8ff26d43536296,
          0x520100780530ee16,
          0x4dc0b5ea935f08ec,
          0x342b90afd853f450,
          0x8b250ebcaa2c3681,
          0x55759f81a2c68ae4]
key = 0xB0004B7679FA26B3
data = ""

for value in cmp_data:
    for i in range(0, 64):
        tail = value & 1
        if tail == 1:
            value = value ^ key
        value = value // 2
        if tail == 1:
            value = value | 0x8000000000000000
        #print(hex(value))
    # end for
    print(hex(value))
    j = 0
    while (j < 8):
        data += chr(value & 0xFF)
        value = value >> 8
        j += 1
    # end while
#end for
print(data)

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