---
# System prepended metadata

title: PTITCTF (Revese Rust Challenges)

---

# PTITCTF (Revese Rust Challenges)
## Phân tích tổng quát:
- Đầu tiên mình sẽ xác định loại file này là gì.
![image](https://hackmd.io/_uploads/SyDaJuBkex.png)
- Nó chính là file `PE(Windown)` được compiler bằng ngôn ngữ Rust.
- Tiếp theo mình sẽ tiến hành phân tích tĩnh trên IDA.
```rust=
int __fastcall main(int argc, const char **argv, const char **envp)
{
  return sub_140002480(sub_1400030E0, argc, argv, 0LL);
}
```
- Nhìn tổng quan thì hàm main() chả có gì ngoài việc return về thằng ```sub_140002480(sub_1400030E0, argc, argv, 0LL)```.
- Ta hiểu qua rằng nó sẽ run kèm theo đối số.
- VD: `./chall.exe <flag>`
- Mình sẽ xem thằng `sub_140002480()` này làm gì.
```rust=
// Hidden C++ exception states: #wind=1 #try_helpers=1
__int64 __fastcall sub_140002480(__int64 a1, __int64 a2, __int64 a3, char a4)
{
  _QWORD v5[4]; // [rsp+38h] [rbp-30h] BYREF
  char v6; // [rsp+5Fh] [rbp-9h]

  v5[1] = a1;
  v5[2] = a2;
  v5[3] = a3;
  v6 = a4;
  v5[0] = a1;
  return sub_140007C60(v5, &unk_1400207B0);
}
```
```rust=
// Hidden C++ exception states: #wind=1 #try_helpers=1
__int64 __fastcall sub_140007C60(__int64 a1, __int64 a2)
{
  __int64 v4; // rax
  __int64 v6; // rdx
  __int64 v7; // rsi
  __int64 v8; // rdx
  __int64 v9; // rdx
  ULONG StackSizeInBytes[2]; // [rsp+20h] [rbp-60h] BYREF
  __int64 v11; // [rsp+50h] [rbp-30h] BYREF
  __int64 v12; // [rsp+60h] [rbp-20h]
  __int64 v13; // [rsp+68h] [rbp-18h]
  __int64 v14; // [rsp+78h] [rbp-8h]
  __int64 v15; // [rsp+80h] [rbp+0h] BYREF
  __int64 v16; // [rsp+90h] [rbp+10h] BYREF
  __int64 v17; // [rsp+98h] [rbp+18h] BYREF

  v14 = -2LL;
  AddVectoredExceptionHandler(0, Handler);
  StackSizeInBytes[0] = 20480;
  SetThreadStackGuarantee(StackSizeInBytes);
  GetCurrentThread();
  off_14002C028();
  try
  {
    *(_QWORD *)StackSizeInBytes = 0LL;
    v4 = sub_140008210(StackSizeInBytes);
  }
  catch ( __int64 v17 )
  {
    sub_14001E550(v17);
    goto LABEL_9;
  }
  catch ( ... )
  {
    sub_14001E550(0LL);
    goto LABEL_9;
  }
  try
  {
    sub_140008020(v4);
    v7 = (*(int (__fastcall **)(__int64))(a2 + 40))(a1);
  }
  catch ( __int64 v16 )
  {
    v12 = sub_14001E550(v16);
    v13 = v8;
    goto LABEL_5;
  }
  catch ( ... )
  {
    v12 = sub_14001E550(0LL);
    v13 = v9;
LABEL_5:
    if ( *(_QWORD *)v13 )
      (*(void (__fastcall **)(__int64))v13)(v12);
    v6 = *(_QWORD *)(v13 + 8);
    v7 = 101LL;
    if ( v6 )
      sub_140005FE0(v12, v6, *(_QWORD *)(v13 + 16));
  }
  try
  {
    if ( dword_14002C144 != 4 )
    {
      LOBYTE(v11) = 1;
      *(_QWORD *)StackSizeInBytes = &v11;
      sub_14001E890(StackSizeInBytes);
    }
  }
  catch ( __int64 v15 )
  {
    sub_14001E550(v15);
    goto LABEL_9;
  }
  catch ( ... )
  {
    sub_14001E550(0LL);
LABEL_9:
    sub_140006730();
  }
  return v7;
}
```
- Càng vào sâu thì chả có manh mỗi gì nên mình sẽ quay lại thằng ```sub_1400030E0()```.

```rust=
// Hidden C++ exception states: #wind=2
__int64 sub_1400030E0()
{
  __int64 v0; // rax
  __int64 v1; // rdx
  __int64 v2; // rdx
  __int64 v3; // rax
  __int64 v4; // rdx
  __int64 v5; // rax
  __int64 v6; // rdx
  int *v7; // rdx
  int v9; // [rsp+2Ch] [rbp-54h]
  unsigned __int64 v10; // [rsp+98h] [rbp+18h]
  __int64 v11; // [rsp+A8h] [rbp+28h]
  _QWORD v12[2]; // [rsp+D0h] [rbp+50h] BYREF
  _BYTE v13[48]; // [rsp+E0h] [rbp+60h] BYREF
  _OWORD v14[2]; // [rsp+110h] [rbp+90h] BYREF
  _BYTE v15[24]; // [rsp+138h] [rbp+B8h] BYREF
  _BYTE v16[32]; // [rsp+150h] [rbp+D0h] BYREF
  _BYTE v17[48]; // [rsp+170h] [rbp+F0h] BYREF
  _OWORD v18[2]; // [rsp+1A0h] [rbp+120h] BYREF
  _BYTE v19[48]; // [rsp+1C8h] [rbp+148h] BYREF
  _BYTE v20[24]; // [rsp+1F8h] [rbp+178h] BYREF
  _QWORD v21[2]; // [rsp+210h] [rbp+190h] BYREF
  _BYTE *v22; // [rsp+220h] [rbp+1A0h]
  char v23; // [rsp+22Fh] [rbp+1AFh] BYREF
  _DWORD v24[34]; // [rsp+230h] [rbp+1B0h]
  _QWORD v25[3]; // [rsp+2B8h] [rbp+238h] BYREF
  _BYTE v26[24]; // [rsp+2D0h] [rbp+250h] BYREF
  _QWORD v27[3]; // [rsp+2E8h] [rbp+268h] BYREF
  unsigned __int64 v28; // [rsp+300h] [rbp+280h]
  int *v29; // [rsp+308h] [rbp+288h]
  _BYTE v30[48]; // [rsp+310h] [rbp+290h] BYREF
  _BYTE v31[48]; // [rsp+340h] [rbp+2C0h] BYREF
  __int64 v32; // [rsp+370h] [rbp+2F0h]
  unsigned __int64 v33; // [rsp+378h] [rbp+2F8h]
  int v34; // [rsp+384h] [rbp+304h]
  _BYTE *v35; // [rsp+388h] [rbp+308h]
  int v36; // [rsp+394h] [rbp+314h]
  __int128 v37; // [rsp+398h] [rbp+318h]
  __int64 v38; // [rsp+3A8h] [rbp+328h]
  __int64 (__fastcall *v39)(); // [rsp+3B0h] [rbp+330h]
  __int64 v40; // [rsp+3B8h] [rbp+338h]
  __int128 v41; // [rsp+3C0h] [rbp+340h]
  _QWORD *v42; // [rsp+3D0h] [rbp+350h]
  __int64 (__fastcall *v43)(); // [rsp+3D8h] [rbp+358h]
  _QWORD *v44; // [rsp+3E0h] [rbp+360h]
  __int64 v45; // [rsp+3E8h] [rbp+368h]

  v45 = -2LL;
  v12[0] = asc_14002092E;
  v12[1] = 3598LL;
  v42 = v12;
  v43 = sub_140003AA0;
  v44 = v12;
  *&v41 = v12;
  *(&v41 + 1) = sub_140003AA0;
  v14[1] = v41;
  v14[0] = v41;
  sub_140003AD0(v13, &unk_140021740, v14);
  sub_14000A340(v13);
  sub_140008970();
  sub_140005F60(v15, v16);
  if ( sub_140005670(v15) != 2 )
  {
    v38 = sub_140005800(v15, 0LL, &off_140021818);
    v39 = sub_140004FE0;
    v40 = v38;
    *&v37 = v38;
    *(&v37 + 1) = sub_140004FE0;
    v18[1] = v37;
    v18[0] = v37;
    sub_140003AD0(v17, &off_1400217F8, v18);
    sub_14000A450(v17);
    sub_14000C820(1LL);
  }
  v11 = sub_140005800(v15, 1LL, &off_140021770);
  v32 = v11;
  v10 = sub_140004FA0();
  if ( v10 < 4 )
    sub_14001FA30(&off_140021788);
  if ( v10 != 34 )
  {
    sub_140003B20(v19, &off_1400217D8);
    sub_14000A450(v19);
    sub_14000C820(1LL);
  }
  sub_140005440(v20);
  v0 = sub_140004FC0(v11);
  v21[0] = sub_140005D40(v0, v1);
  v21[1] = v2;
  while ( 1 )
  {
    v22 = sub_140005E60(v21);
    if ( !v22 )
      break;
    v35 = v22;
    v23 = *v22;
    v36 = sub_140003710(&v23, 1LL);
    sub_140005680(v20);
  }
  v24[0] = -1184252295;
  v24[1] = -1107002784;
  v24[2] = -587065671;
  v24[3] = -1107002784;
  v24[4] = 1037565863;
  v24[5] = -1107002784;
  v24[6] = 1304234792;
  v24[7] = 366298937;
  v24[8] = 1255198513;
  v24[9] = 1842515611;
  v24[10] = 30677878;
  v24[11] = -2082672713;
  v24[12] = 2013832146;
  v24[13] = 701932520;
  v24[14] = -186917087;
  v24[15] = 1993550816;
  v24[16] = 701932520;
  v24[17] = -630205792;
  v24[18] = -69523947;
  v24[19] = 701932520;
  v24[20] = 1304234792;
  v24[21] = 1812594589;
  v24[22] = -2082672713;
  v24[23] = 1842515611;
  v24[24] = 2013832146;
  v24[25] = -1730327860;
  v24[26] = 453955339;
  v24[27] = 701932520;
  v24[28] = 1466425173;
  v24[29] = -227710402;
  v24[30] = -2068763730;
  v24[31] = 1790921346;
  v24[32] = -1637089325;
  v24[33] = -55123444;
  v3 = sub_1400057A0(v20);
  v5 = sub_140005910(v3, v4);
  sub_140005CB0(v26, v5, v6);
  sub_140001FC0(v25, v26);
  v27[0] = v25[0];
  v27[1] = v25[1];
  v27[2] = v25[2];
  while ( 1 )
  {
    v28 = sub_140001ED0(v27);
    v29 = v7;
    if ( !v7 )
      break;
    v33 = v28;
    v9 = *v29;
    v34 = *v29;
    if ( v28 >= 0x22 )
      sub_14001F590(v28, 34LL, &off_1400217B8);
    if ( v9 != v24[v28] )
    {
      sub_140003B20(v30, &off_1400217D8);
      sub_14000A340(v30);
      sub_14000C820(1LL);
    }
  }
  sub_140003B20(v31, &off_1400217A8);
  sub_14000A340(v31);
  sub_140002A10(v20);
  return sub_140002C90(v15);
}
```
- Đây rồi có vẻ đây là hàm xử lý chính vì mình có thấy chuỗi data target sau khi encode.
- Nhìn sơ qua thì flag nhập vào nó sẽ xử lý bằng cách nào đó rồi return về thằng `v9` rồi nó sẽ đi so sánh với thằng data target.
- Nhưng `v9` nó có liên quan đến `v7` nhưng mình không thấy nó `v7` được tham chiếu từ đâu.
- Mình nghĩ rằng nó sẽ có một hàm xử lý riêng trước đó.
- Thì ra nó ở đây.

```rust=
 if ( v10 != 34 )
  {
    sub_140003B20(v19, &off_1400217D8);
    sub_14000A450(v19);
    sub_14000C820(1LL);
  }
  sub_140005440(v20);
  v0 = sub_140004FC0(v11);
  v21[0] = sub_140005D40(v0, v1);
  v21[1] = v2;
  while ( 1 )
  {
    v22 = sub_140005E60(v21);
    if ( !v22 )
      break;
    v35 = v22;
    v23 = *v22;
    v36 = sub_140003710(&v23, 1LL);
    sub_140005680(v20);
  }
```
- Ở đây thằng `v10` là len của flag sẽ là `34`.
- Tiếp tục thằng `while` sẽ xử lý mã hóa flag, tại thằng ```v36 = sub_140003710(&v23, 1LL);```.
- Mình sẽ xem thử nó làm gì.
```rust=
__int64 __fastcall sub_140003710(__int64 a1, __int64 a2)
{
  __int64 v2; // rdx
  unsigned __int64 v3; // rdx
  __int64 v4; // rdx
  int v5; // edx
  int v7; // edx
  unsigned __int64 v8; // [rsp+38h] [rbp-490h]
  _DWORD v11[256]; // [rsp+50h] [rbp-478h] BYREF
  _QWORD v12[2]; // [rsp+450h] [rbp-78h] BYREF
  __int64 v13; // [rsp+460h] [rbp-68h]
  unsigned __int64 v14; // [rsp+468h] [rbp-60h]
  unsigned int v15; // [rsp+470h] [rbp-58h]
  _DWORD v16[2]; // [rsp+474h] [rbp-54h] BYREF
  int v17; // [rsp+47Ch] [rbp-4Ch]
  int v18; // [rsp+480h] [rbp-48h]
  unsigned int v19; // [rsp+484h] [rbp-44h]
  _QWORD v20[2]; // [rsp+488h] [rbp-40h] BYREF
  char *v21; // [rsp+498h] [rbp-30h]
  __int64 v22; // [rsp+4A0h] [rbp-28h]
  __int64 v23; // [rsp+4A8h] [rbp-20h]
  char v24; // [rsp+4B7h] [rbp-11h]
  __int64 v25; // [rsp+4B8h] [rbp-10h]
  unsigned __int64 v26; // [rsp+4C0h] [rbp-8h]

  v22 = a1;
  v23 = a2;
  memset(v11, 0, sizeof(v11));
  v12[0] = sub_140002550(0LL, 256LL);
  v12[1] = v2;
  while ( 1 )
  {
    v13 = sub_140002500(v12);
    v14 = v3;
    if ( !v13 )
      break;
    v8 = v14;
    v26 = v14;
    v15 = v14;
    v16[0] = sub_140002540(0LL, 8LL);
    v16[1] = v5;
    while ( 1 )
    {
      v17 = sub_140002520(v16);
      v18 = v7;
      if ( !v17 )
        break;
      if ( (v15 & 1) != 0 )
        v15 = (v15 >> 1) ^ 0xEDB88320;
      else
        v15 >>= 1;
    }
    if ( v8 >= 0x100 )
      sub_14001F590(v8, 256LL, &off_140021848);
    v11[v8] = v15;
  }
  v19 = -1;
  v20[0] = sub_140005D40(a1, a2);
  v20[1] = v4;
  while ( 1 )
  {
    v21 = sub_140005E60(v20);
    if ( !v21 )
      break;
    v24 = *v21;
    v25 = (v24 ^ v19);
    v19 = v11[v25] ^ (v19 >> 8);
  }
  return ~v19;
}
```
- Thuật toán cũng khá lạ nên mình sẽ tìm hiểu.
- Đây là đường link github của một người lạ nói về thuật toán này
https://gist.github.com/timepp/1f678e200d9e0f2a043a9ec6b3690635
- Nó là thuật toán `CRC 32` hiểu đơn giản là nó sẽ tạo một bảng chữ cái tưng ứng với từng 8bit hex cho mỗi ký tự theo cách của nó.
- Vậy thằng này khi chuyển về hex sẽ tương ứng với từng ký tự flag theo thứ tự
```rust=
 v24[0] = -1184252295;
  v24[1] = -1107002784;
  v24[2] = -587065671;
  v24[3] = -1107002784;
  v24[4] = 1037565863;
  v24[5] = -1107002784;
  v24[6] = 1304234792;
  v24[7] = 366298937;
  v24[8] = 1255198513;
  v24[9] = 1842515611;
  v24[10] = 30677878;
  v24[11] = -2082672713;
  v24[12] = 2013832146;
  v24[13] = 701932520;
  v24[14] = -186917087;
  v24[15] = 1993550816;
  v24[16] = 701932520;
  v24[17] = -630205792;
  v24[18] = -69523947;
  v24[19] = 701932520;
  v24[20] = 1304234792;
  v24[21] = 1812594589;
  v24[22] = -2082672713;
  v24[23] = 1842515611;
  v24[24] = 2013832146;
  v24[25] = -1730327860;
  v24[26] = 453955339;
  v24[27] = 701932520;
  v24[28] = 1466425173;
  v24[29] = -227710402;
  v24[30] = -2068763730;
  v24[31] = 1790921346;
  v24[32] = -1637089325;
  v24[33] = -55123444;
```

## Solution
- Và cách làm của mình sẽ viết script python tạo ra một bảng chữ các bằng 8bits hex tương ứng sau đó mapping thằng target này vào và lấy flag.

> Script solve
```python=
def crc32(data: bytes) -> int:
    table = []
    for i in range(256):
        crc = i
        for _ in range(8):
            if crc & 1:
                crc = (crc >> 1) ^ 0xEDB88320
            else:
                crc >>= 1
        table.append(crc)
    crc = 0xFFFFFFFF
    for byte in data:
        crc = table[(byte ^ crc) & 0xFF] ^ (crc >> 8)

    return ~crc & 0xFFFFFFFF 
target = [
    0xB969BE79, 0xBE047A60, 0xDD0216B9, 0xBE047A60, 0x3DD7FFA7, 0xBE047A60,
    0x4DBD0B28, 0x15D54739, 0x4AD0CF31, 0x6DD28E9B, 0x01D41B76, 0x83DCEFB7,
    0x7808A3D2, 0x29D6A3E8, 0xF4DBDF21, 0x76D32BE0, 0x29D6A3E8, 0xDA6FD2A0,
    0xFBDB2615, 0x29D6A3E8, 0x4DBD0B28, 0x6C09FF9D, 0x83DCEFB7, 0x6DD28E9B,
    0x7808A3D2, 0x98DD4ACC, 0x1B0ECF0B, 0x29D6A3E8, 0x5767DF55, 0xF26D6A3E,
    0x84B12BAE, 0x6ABF4A82, 0x9E6BFFD3, 0xFCB6E20C
]
charset = b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789{}_"
result = b""
for t in target:
    found = False
    for c in charset:
        if crc32(bytes([c])) == t:
            result += bytes([c])
            found = True
            break
    if not found:
        result += b"?"

print("Flag:", result.decode(errors="replace"))
```

> Flag: PTITCTF{B3g1n_0f_My_Fr13nds_Ru57?}