---
# System prepended metadata

title: BluePrint

---

# BluePrint
> Chú ý: Chall chống chỉ định cho người yếu tim.

Đề bài cho ta 2 file:
```linux
❯ file blueprint.exe
blueprint.exe: PE32+ executable (console) x86-64, for MS Windows, 6 sections

~/reversing
❯ file user.json.enc
user.json.enc: data
```
Khúc này có thể tạo sẵn `user.json` vì có thể đoán rằng ctrinh nó sẽ encrypt cái file đấy.
Chạy thử file:
...
...
Chạy xong ăn cái bluescreen. Biết nói gì đây bây giờ.
Đọc thử file thì nó bị obfuscate rất nhiều chỗ.
![image](https://hackmd.io/_uploads/ByArtslZxl.png)
Vì không rev chay được nên mình bắt đầu debug. 
Đặt breakpoint ở hàm main, F9 -> Bluescreen tiếp.
Mình tìm `TLSCallBack` thì không có, nên mình đoán nó ở `init`.  Nên mình đặt breakpoint ở hàm `start`.
Sau một hồi thì mình đã tìm ra nguyên nhân ném bluescreen
![image](https://hackmd.io/_uploads/By7FPjxZxx.png)
Hàm `initterm` nó sẽ chạy hết mấy hàm từ First tới Last:
![image](https://hackmd.io/_uploads/S1ejvsxblg.png)
Hàm sus nhất ở đây là `sub_7FF79F2A1000`. Khi mình đặt breakpoint ở hàm đó rồi chạy thì đúng thật mình không ăn bluescreen. 
![image](https://hackmd.io/_uploads/SJTsusgbel.png)
Nhưng chạy xong hàm `sub_7FF79F2A42D0` thì mình ăn bluescreen, vậy thì mình debug hàm đó để tìm hiểu lí do tại sao ăn bluescreen thôi. 
Debug một hồi thì mình biết được flow nó là như này:
```
- init:

ucrtbase_malloc
GetComputerNameW
ucrtbase_free
GetMachineTypeAttribute
GetModuleHandleA(ntdll.dll)
GetProcAddress(ntdllHandle, RtlAdjustPrivilege)
RtlAdjustPrivilege 
GetProcAddress(ntdllHandle, NtRaiseHardError) 
NtRaiseHardError -> boom blue screen part 1
```
Vậy khúc đó ta đặt breakpoint ngay chỗ call cái `NtRaiseHardError` là được.
![image](https://hackmd.io/_uploads/H1rFFog-xe.png)
Rồi SetIP là nhảy qua được bước này. 
F9 tiếp -> Bluescreen.
Vậy giờ debug bình tĩnh từng bước thôi. Sau một hồi thì xác định được nguyên nhân nằm ở hàm main:
![image](https://hackmd.io/_uploads/ByoEqie-ge.png)
Để bypass thì sau khi step qua cái call thì gán `eax = 0` là đc. Ấn F9 một lần nữa... -> Bluescreen.
Lại là debug bình tĩnh từng bước:
![image](https://hackmd.io/_uploads/BJkj5je-xx.png)
Hàm này chính là lí do ăn bluescreen. Ta debug hàm này thôi.
Và đây là số breakpoint mình đã đặt cho hàm này:
![image](https://hackmd.io/_uploads/SyWxssl-le.png)
Sau khi ngồi debug thì rút ra được flow như này:
![image](https://hackmd.io/_uploads/BkQWoixZge.png)
Đọc thì có vẻ như là các hàm trong đây nó sẽ thực hiện việc encrypt, nhưng mình cần chạy tới cuối chương trình trước đã rồi quay lại phân tích sau.
Để bypass `NtQueryInformationProcess` thì khúc này set `ZF = 1` là đc:
![image](https://hackmd.io/_uploads/SkicnieWge.png)
Nếu bạn ấn F9 tiếp thì -> Bluescreen.
Hết hàm này thì còn thêm 1 cái antidebug nữa:
![image](https://hackmd.io/_uploads/BkMM6oebll.png)
Patch byte chỗ đó `= 0` là oke. Giờ ấn F9 
![image](https://hackmd.io/_uploads/HyzDTix-gx.png)
Oke giờ đã về bờ thành công. 
Tóm tắt lại flow chính:
```c
- init:
ucrtbase_malloc
GetComputerNameW
ucrtbase_free
GetMachineTypeAttribute
GetModuleHandleA(ntdll.dll)
GetProcAddress(ntdllHandle, RtlAdjustPrivilege)
RtlAdjustPrivilege 
GetProcAddress(ntdllHandle, NtRaiseHardError) 
NtRaiseHardError -> boom blue screen part 1


- main:
IsDebuggerPresent -> co debug -> boom blue screen part 2 
	+ Inside main:
		- LoadLibraryA(advapi32.dll) 
		- GetProcAddres(advapi32Handle, CryptAcquireContextA) 
		- CryptAcquireContextA 
		- RtlCopyMemory
		- CryptImportKey
		- CryptSetKeyParam
		- CryptSetKeyParam
		- RtlCopyMemory 
		- CryptEncrypt
		- GetModuleHandleA(ntdll.dll)
		- GetProcAddress(ntdllHandle, NtQueryInformationProcess)
		- GetCurrentProcess
		- NtQueryInformationProcess -> neu co debug -> boom blue screen part 3 
		- RtlCopyMemory
	+ CheckRemoteDebuggerPresent -> boom blue screen part 4 

ucrtbase_fopen("user.json.enc", "wb")
ucrtbase_fwrite -> write data encode from user.json
ucrtbase_fclose
```
Chú ý vào các hàm có prefix `Crypt`. 
![image](https://hackmd.io/_uploads/r1owk2eblx.png)
[Docs của hàm này](https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptacquirecontexta)
`R9 = 0x18` -> `dwProvType = 0x18` -> `PROV_RSA_AES`.
![image](https://hackmd.io/_uploads/H1aJe2x-gl.png)
[Docs](https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptimportkey)
Độ dài `0x1c` ? Chắc nó chỉ lấy `0x10` thôi nhỉ, nhưng lấy ở đâu ? Mình hỏi con GPT thử thì nó là cái struct ntn:
```c++
typedef struct _PLAINTEXTKEYBLOB {
  BLOBHEADER hdr;        // 8 bytes
  DWORD      keySize;    // 4 bytes (length of key)
  BYTE       keyData[];  // N bytes (key material)
} PLAINTEXTKEYBLOB;
```
Vậy 16 bytes cuối là key.
![image](https://hackmd.io/_uploads/S1zjZ3ebee.png)
Giờ tới [CryptSetKeyParam](https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptsetkeyparam), `edx = 4` là `KP_MODE`. 
Ngồi đọc 1 hồi tra tùm lum chỗ thì có vẻ như `r8` quyết định cái `MODE` này.
![image](https://hackmd.io/_uploads/Sypm72xWxl.png)
= 1 -> CBC
![image](https://hackmd.io/_uploads/HyZ9X2lWgl.png)
`edx = 1` => `KP_IV`.
Vậy mảng `r8` trỏ tới là `iv`.
![image](https://hackmd.io/_uploads/Hy23mhgZex.png)
Giờ đem decrypt thử khi có `key` và `iv` với `AES.MODE_CBC`.
![image](https://hackmd.io/_uploads/rywlEhgblg.png)

