# RingZero See No Evil
Đây là writeup của tôi về bài See No Evil ở trên RingZero.
## Part 1
Trong quá trình debug tôi thấy có một thứ lạ đó chính là sau khi chạy xong cái lệnh in cái chữ `Level 1` thay vì trả về giá trị là 0 hoặc là 1 do nhiệm vụ của nó chỉ là in ra thì nó lại trả về giá trị là `7FF68B95AFE0`
Tôi tra cứu thì cái hàm này là liên quan tới việc thực hiện hash sha-1
```
DWORD *__fastcall sub_7FF68B932490(const BYTE *a1, DWORD a2)
{
HCRYPTHASH phHash; // [rsp+30h] [rbp-28h] BYREF
HCRYPTPROV phProv; // [rsp+38h] [rbp-20h] BYREF
DWORD *v5; // [rsp+40h] [rbp-18h]
v5 = (DWORD *)sub_7FF68B931150(0x10ui64);
phProv = 0i64;
phHash = 0i64;
CryptAcquireContextA(&phProv, 0i64, 0i64, 1u, 0xF0000000);
CryptCreateHash(phProv, 0x8003u, 0i64, 0, &phHash);
CryptHashData(phHash, a1, a2, 0);
CryptGetHashParam(phHash, 2u, *(BYTE **)v5, v5 + 2, 0);
CryptReleaseContext(phProv, 0);
CryptDestroyHash(phHash);
return v5;
}
```
Ở trong hàm in ra flag
```python
void __fastcall fn_printFlag(int a1)
{
_QWORD **v1; // [rsp+20h] [rbp-18h]
DWORD *v2; // [rsp+28h] [rbp-10h]
v2 = sub_7FF68B932490((const BYTE *)&qword_7FF68B971EB8[a1 - 1], 8u);
v1 = sub_7FF68B931240(v2, (char *)*(&off_7FF68B970D30 + a1 - 1), 0x28ui64);
printf("Your flag is at 0x%016IX\n", *v1);
sub_7FF68B9311E0((__int64)v1);
sub_7FF68B9311E0((__int64)v2);
}
```
Thực hiện debug file thì ta sẽ ra được địa chỉ của flag nhảy vào địa chỉ đó thì ta sẽ có được flag
```
part 1: FLAG-JDGIkhGvlCcoojXduitQuZKpGv
```
## Part 2
Ở phần này tôi gặp phải một vấn đề khó khăn hơn thuật toán của chương trình đi như sau
```python
__int64 fn_AntiDebugLevelTwo()
{
sub_1400031F0(&qword_140041F00, "[*] Level 2... ");
CreateThread(0i64, 0i64, (LPTHREAD_START_ROUTINE)StartAddress, 0i64, 0, 0i64);
WaitForSingleObject(hEvent, 0xFFFFFFFF);
return fn_PrintFlag(2);
}
```
Cái khó của chương trình chính là việc tạo ra một cái thread với function thực hiện là `StartAddress` có nội dung như sau
```python
void __fastcall __noreturn StartAddress(LPVOID lpThreadParameter)
{
__int64 v1; // rdx
__int64 v2; // rcx
__int64 v3; // r8
while ( 1 )
{
if ( *(_QWORD *)((char *)GetProcessHeap() + 116) )
{
OutputDebugStringA("Heap Corruption Detected.");
MEMORY[0](v2, v1, v3);
}
qword_140041EB8[1] = 0x481257362EFB5820i64;
SetEvent(hEvent);
}
}
```
Chương trình thực hiện chạy một vòng lặp vô hạn trong đó có một cái biến cần thiết để có thể giải mã được ra flag `qword_140041EB8[1] = 0x481257362EFB5820i64`
Tôi cố tìm cách để mà chương trình có thể chèn thêm data vào trong một cái mảng nhưng không ổn cho lắm tôi đi theo hướng tiếp theo là có thể tôi sẽ phải chỉnh lại cái giá trị truyền vào cho cái `WaitForSingleObject` tuy nhiên cũng không được khi mà tôi bị gặp cái lỗi này
```python
0: The instruction at 0x0 referenced memory at 0x0. The memory could not be executed -> 0000000000000000 (exc.code c0000005, tid 3280)
```
Giờ lại ngồi nghĩ hướng khác đây trong lúc tôi ngồi phân tích output ở ida thì tôi thấy là có một cái như này
```python
Debugged application message: Heap Corruption Detected.
```
Nói chung là do cái thuật toán `GetProcessHeap()` tôi sẽ đi theo hướng là patch lại cái phần `jnz` để chương trình nhảy trực tiếp vào cái seed flag là được

Và tôi ra được flag tiếp theo
```
Part 2: FLAG-VMOkKL86JbTuhEViFvxyao4H2k
```
## Part 3
Ở phần này có vẻ căng thẳng hơn đoạn code nó thực hiện là như sau
```python
void __noreturn fn_AntiDebugLevelThree()
{
CreateThread(0i64, 0i64, sub_7FF60D715FF0, 0i64, 0, 0i64);
__debugbreak();
}
```
Thực hiện gọi tới hàm `sub_7FF60D715FF0` bằng việc thực hiện tạo ra một cái thread và có cả cái một cái hàm `__debugbreak()` cái này tương đương với `int 3` trong assembly một phương thức dùng để thực hiện anti debug
Bên trong hàm `sub_7FF60D715FF0` là như sau
```python
void __fastcall __noreturn sub_7FF60D715FF0(LPVOID lpThreadParameter)
{
while ( 1 )
__debugbreak();
}
```
Bài này thì nhảy một phát tới luôn cái hàm cái hàm thực hiện gán seed flag và nhảy tới hàm in ra flag và bỏ qua hàm thực hiện debug break thì sẽ có được flag
```
Part 3: FLAG-cjpG8FaodZgx2x3Prf6igbv7Zh
```
## Part 4
Bài này có một cái khá là lạ ở chỗ là chả hiểu vì lý do gì mà code ở trên mã giả và code ở trên mã assembly có sự khác nhau rất lớn đầu tiên là mã giả của phần 4 này là như sau
```python
__int64 fn_AntiDebugLevelFour()
{
char v1; // [rsp+20h] [rbp-28h]
fn_PrintShit(&qword_7FF6E4D01F00, "[*] Level 4... ");
v1 = 0;
WaitForSingleObject(hHandle, 0xFFFFFFFF);
while ( !v1 )
{
qword_7FF6E4D01E88();
v1 = 1;
}
return fn_PrintFlag(4);
}
```
Phân tích qua thì ta thấy được rằng chương trình sẽ thực hiện việc lệnh `WaitForSingleObject` cho một cái thread có thể là như vậy nhưng trong vòng lặp thì lại có call tới `qword_7FF6E4D01E88` cái này chưa rõ lắm nhưng mà tôi cần phải phân tích qua cái phần assembly

Ở phần này nếu như nhảy trực tiếp vào trong cái phần `PrintFlag` thì không ổn cho lắm do tôi thử thì thấy là không ra được flag chuẩn
Đi theo flow chuẩn thì đoạn code bị khựng lại ở ngay cái đoạn `call cs:qword_7FF6E4D01E88` không lạ lắm tôi sẽ thử với việc là nhảy cóc qua cái đoạn đấy xem như nào tuy nhiên nhảy qua cái đoạn đó và đi theo flow thường thì tôi lại không vào được các cái đoạn mã khác chương trình đi luôn tới cái đoạn in flag nhưng lại không có flag tiếp tục đi theo hướng khác xem như nào
Tôi không tìm được cái hướng gì cho nó ổn nên là tôi đã thử là cho cái địa chỉ khác với số khác vào xem như nào

Tôi thử với là `5875E2D506757DA` thì thấy là có sự thay đổi nhất định trong dữ liệu đầu ra nhưng dù gì thì cũng tốt hơn là không có thông tin gì
Nhưng tôi phân tích kỹ hơn thì mới thấy là có vẻ là tôi nhìn chưa đủ kỹ chẳng là nếu như tôi bấm `xref` vào trong cái `qword_7FF7BD441E88` thì thấy được rằng chương trình có được gọi tới ở trong một cái đoạn code khác

Và ở trong hàm `sub_7FF7BD406170` thì thấy được cái seed tiếp theo

Patch lại thử ở cái hàm anti debug thành như sau mong là được

Cuối cùng thì ta chạy tiếp chương trình thì sẽ có được cái seed flag chuẩn và ra được cái flag tiếp theo
```python
Part 4: FLAG-JzeQdOb0VNJsbDRGc2pwSNkffk
```
## Part 5
Tôi cứ nghĩ phần này ngon ăn khi mà chỉ cần chạy là xong nhưng mà đời đâu có mơ phải có lý do để mà nó là phần cuối chứ phân tích qua cái phần này thì chương trình chỉ đơn giản là chạy hàm print flag nhưng cái sai là do ta không có được cái seed chuẩn khiến cho không thể giải mã ra được flag đúng phân tích thêm thì thấy được rằng seed cuối được thiết lập ngay khi chương trình thực hiện tls callback
```python
__int64 sub_7FF7A5EE61C0()
{
DWORD Buffer; // [rsp+50h] [rbp-1C8h] BYREF
DWORD LastError; // [rsp+54h] [rbp-1C4h]
DWORD NumberOfBytesRead; // [rsp+58h] [rbp-1C0h] BYREF
DWORD CurrentProcessId; // [rsp+5Ch] [rbp-1BCh] BYREF
DWORD NumberOfBytesWritten; // [rsp+60h] [rbp-1B8h] BYREF
__int64 v6; // [rsp+68h] [rbp-1B0h] BYREF
__int64 v7; // [rsp+70h] [rbp-1A8h] BYREF
struct _PROCESS_INFORMATION ProcessInformation; // [rsp+78h] [rbp-1A0h] BYREF
struct _STARTUPINFOA StartupInfo; // [rsp+90h] [rbp-188h] BYREF
CHAR Filename[280]; // [rsp+100h] [rbp-118h] BYREF
hObject = CreateNamedPipeA("\\\\.\\pipe\\wawawa", 0x80003u, 6u, 0xFFu, 0x100u, 0x100u, 0, 0i64);
LastError = GetLastError();
if ( hObject == (HANDLE)-1i64 || LastError == 5 )
{
hObject = CreateFileA("\\\\.\\pipe\\wawawa", 0xC0000000, 0, 0i64, 3u, 0x80u, 0i64);
v6 = 0x3AFB2372819375F1i64;
ReadFile(hObject, &Buffer, 4u, &NumberOfBytesRead, 0i64);
if ( DebugActiveProcess(Buffer) )
{
DebugSetProcessKillOnExit(0);
DebugActiveProcessStop(Buffer);
v6 = 0xD38B557A224FFEDCui64;
}
WriteFile(hObject, &v6, 8u, &NumberOfBytesRead, 0i64);
CloseHandle(hObject);
return Buffer;
}
else if ( hObject == (HANDLE)-1i64 )
{
return 10i64;
}
else
{
GetModuleFileNameA(0i64, Filename, 0x105u);
GetStartupInfoA(&StartupInfo);
CreateProcessA(Filename, 0i64, 0i64, 0i64, 0, 0x20u, 0i64, 0i64, &StartupInfo, &ProcessInformation);
ConnectNamedPipe(hObject, 0i64);
CurrentProcessId = GetCurrentProcessId();
WriteFile(hObject, &CurrentProcessId, 4u, &NumberOfBytesWritten, 0i64);
ReadFile(hObject, &v7, 8u, &NumberOfBytesWritten, 0i64);
CloseHandle(hObject);
seedOfFlag[4] = v7;
return 0i64;
}
}
```
Mình dùng chatgpt bảo nó giải thích thì nó bảo luôn là đây là dạng anti debug với hai process cha và con khá là phức tạp nếu như ta bỏ qua và cứ chạy thì ta sẽ được cái seed cuối là `3AFB2372819375F1` nghĩa là sai nên đặt sao cho để mà khi chạy nó phải là `0xD38B557A224FFEDC` patch lại cái phần `DebugActiveProcess` để nó luôn nhảy vào trong phần thay giá trị mới cho seed và ta có được flag cuối(cái này hơi giống bài ASCIS 2023 sanryu dùng nanomites)
```
Part 5: FLAG-Ukow9CQfAZWBixEOIlZlrdtjZs
```