Simple Reverse 0x12(Lab - TLSCallback)

Simple Reverse 0x12(Lab - TLSCallback)

Background

課程相關影片 [C語言] function pointer的應用[四]: function pointer array

Source Code

:::spoiler IDA main function

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
int __cdecl main(int argc, const char **argv, const char **envp)
{
  __int64 v3; // rbx
  int v4; // edi
  __int64 v5; // r14
  char *v6; // rsi
  __int64 v7; // rax
  const char *v8; // rcx

  printf("Give me flag: ");
  scanf("%58s");
  v3 = 0i64;
  v4 = 0;
  v5 = 0i64;
  v6 = flag;
  do
  {
    (funcs_140001156[v4 % 3u])(&flag[v5]);
    ++v6;
    v7 = v5 & 3;
    ++v4;
    ++v5;
    *(v6 - 1) += key_140004050[v7];
  }
  while ( v4 < 58 );
  while ( flag[v3] == byte_1400022B8[v3] )
  {
    if ( ++v3 >= 58 )
    {
      v8 = "Correct!";
      goto LABEL_7;
    }
  }
  v8 = "Wrong QAO";
LABEL_7:
  puts(v8);
  return 0;
}

:::

Recon

這一題也蠻簡單的,只要有耐心分析一下就可以了

  1. 首先執行一下這隻程式,發現沒啥特別的,就和之前的題目一樣
  2. 用IDA看一下,可以發現也蠻單純的,就用function pointer array然後傳入我們輸入的flag進行一些事情再加上一個數值(來自某一個array)
  3. 仔細看一下有哪些function然後分別做了甚麼事
    1. xor 0x87 :::spoiler source
      1
      2
      3
      4
       void __fastcall do_xor(_BYTE *a1)
       {
         *a1 ^= 0x87u;
       }
      

      :::

    2. xor 0xff :::spoiler source
      1
      2
      3
      4
       void __fastcall do_inverse(_BYTE *a1)
       {
         *a1 = ~*a1;
       }
      

      :::

    3. xor 0x63 :::spoiler source
      1
      2
      3
      4
       void __fastcall do_xor_2(_BYTE *a1)
       {
         *a1 ^= 0x63u;
       }
      

      :::

  4. 陷阱

    如果直接分析這樣的code會做白工,因為這一題有tls callback function在搞事,這件事情IDA和x64dbg都有分析出來,或者是也可以用PE-Bear看一下,所以我們就朝這個方向分析一下,看起來兩者都沒有很複雜,tlscallback function 2就只是把剛剛前面的function pointer array的順序置換一下,而tlscallback function 1也只是用置換過後的function pointer array把key的數值做一些操作而已,如果看psuedo code看不太懂得話可以直接用x64dbg用肉眼跟一下(我就這樣XDD),應該也是可以很直觀的猜出這些事情 :::spoiler TLS Callback function 1 & 2 :::

  5. 用x64dbg直接動態跟code,以下的screenshot我都有加上一些comment幫助理解
    • TLSCallback相關的code
    • 三個Function pointer
    • main function
  6. 結論 在function pointer的順序是xor 0x63 $\to$ xor 0x87 $\to$ xor 0xff 在key的部分是0x21 $\to$ 0xce $\to$ 0x39 $\to$ 0x40
     xor 0x63 + 0x21
     xor 0x87 + 0xce
     xor 0xff + 0x39
     xor 0x63 + 0x40
     xor 0x87 + 0x21
     xor 0xff + 0xce
     xor 0x63 + 0x39
     ...
    

    :::info Note: 相加的部分最後只會取==低位byte==喔,所以如果減回去發現是負的,就要在加0x100導正回來 :::

  7. 開寫script

Exploit

key = [0x21, 0xCE, 0x39, 0x40]

enc_flag = [0x46, 0x99, 0xF7, 0x64, 0x1D, 0x79, 0x44, 0x22, 0xC1, 0xD3, 0x27, 0xCD, 0x31, 0xC1, 0xD9, 0x77, 0xEC, 0x7A, 0x75, 0x24, 0xBF, 0xDD, 0x24, 0xDD, 0x23, 0xB2, 0xCD, 0x7C, 0x02, 0x58, 0x46, 0x24, 0xAC, 0xD8, 0x21, 0xD1, 0x5D, 0xBC, 0xC5, 0x7C, 0x05, 0x6C, 0x48, 0x2B, 0xBB, 0xD5, 0x11, 0xCB, 0x35, 0xB6, 0xD9, 0x57, 0x0F, 0x60, 0x3F, 0x34, 0xFF, 0xEC]

def xor(index, val):
    if index % 3 == 0:
        return val ^ 0x63
    elif index % 3 == 1:
        return val ^ 0x87
    else:
        return val ^ 0xff

FLAG = []
for i in range(len(enc_flag)):

    tmp = enc_flag[i] - key[i % 4]
    if tmp < 0:
        tmp += 0x100
    tmp = xor(i, tmp)
    FLAG.append(bytes.fromhex(hex(tmp)[2:]).decode('utf-8'))

print("".join(FLAG))

Flag: FLAG{The_first_TLS_callback_function_is_called_two_times!}