# Chapter 10: Anti-Debugging

Anti-debugging (chống gỡ lỗi) là một kỹ loạt kỹ thuật chống đảo ngược được sử dụng bởi malware (và thậm chí một số chương trình hợp pháp) để cản trở hoặc ngăn chặn việc gỡ lỗi. Ví dụ, malware có thể cố gắng can thiệp vào quá trình gỡ lỗi nếu phát hiện rằng có một trình gỡ lỗi đang gắn vào nó, hoặc nó có thể cố gắng ngăn chặn việc gỡ lỗi hoàn toàn bằng cách sử dụng các cơ chế (anti-attach) hoặc làm cho chương trình gỡ lỗi bị sập. Trong chương này chúng ta sẽ khám phá một số kỹ thuật này một cách chi tiết.

## 10.1 Using Windows API Functions to Access the PEB

Như đã được đọc Chapter 1, PEB (Process Enviroment Block) là một cấu trúc chứa các con trỏ đến thông tin trong bộ nhớ về quy trình đang chạy. PEB bao gồm một số con trỏ liên quan đến anti-debugging, như được liệt kê trong bảng sau:

<table><thead><tr><th width="116">Địa chỉ PEB</th><th width="171">Thành viên PEB</th><th>Mô tả</th></tr></thead><tbody><tr><td>0x002</td><td>BeingDebugged</td><td>Chỉ ra liệu chương trình hiện đang được gỡ lỗi hay không</td></tr><tr><td>0x018</td><td>ProcessHeap</td><td>Chứa các con trỏ đến các thành viên Flags và ForceFlags của heap</td></tr><tr><td>0x068</td><td>NtGlobalFlag</td><td>Chứa thông tin liên quan đến việc tạo ra các heap bộ nhớ</td></tr></tbody></table>

Windows cung cấp một lượng lớn dữ liệu về hoạt động nội bộ của nó cho các chương trình thông qua các API của mình. Một số hàm API của Windows có mục đich duy nhất là cho chương trình gọi biết liệu một trình gỡ lỗi có đang được gắn hay không, và malware có thể dễ dàng khai thác thực tế này bằng cách yêu cầu chúng truy vấn PEB để xác định liệu nó có đang bị gỡ lỗi hay không. Không chỉ vậy, malware cũng có thể lạm dụng một số hàm API để đánh lừa Windows tiết lộ một trình gỡ lỗi đang được gắn. Trong phần này chúng ta sẽ xem xét một số cách phổ biến mà phần mềm độc hại có thể tận dụng API Windows và NT API để cố gắng xác định một nhà phân tích phần mềm độc hại đang gỡ lỗi mã của nó. Sau đó trong chương, bạn sẽ thấy cách malware cũng có thể truy vấn trực tiếp PEB, đó là lý do tại sao điều quan trọng phải có ít nhất một hiểu biết cơ bản về các thành viên liên quan của PEB.

### 10.1.1 IsDebuggerPresent and CheckRemoteDebuggerPresent

Một trong những hàm Windows đơn giản và nổi tiếng nhất để phát hiện trình gỡ lỗi là `IsDebuggerPresent`. Hàm này trả về một giá trị khác 0 nếu quy trình hiện tại đang bị gỡ lỗi; nếu không, nó trả về 0. Hàm `CheckRemoteDebuggerPresent` trả về thông tin tương tự, nhưng với giá trị là True hoặc False. Ví dụ sau đây cho thấy cách malware có thể sử dụng nó.

```nasm
--snip--
push [ebp+hProcess]
push [ebp+DebuggerPresent]
call CheckRemoteDebuggerPresent
--snip--
```

Hai tham số đang được đẩy vào stack ở đây: một handle đến quy trình mục tiêu (trong trường hợp này, là quy trình của phần mềm độc hại, `hProcess`) và sau đó là một con trỏ đến một biến sẽ nhận thông tin được trả về (`DebuggerPresent`). Khi phần mềm độc hại gọi hàm `CheckRemoteDebuggerPresent`, giá trị trả về (True hoặc False) sẽ được lưu trong biến `DebuggerPresent`. Như bạn sẽ thấy sau trong chương này, đây là một số kỹ thuật phát hiện trình gỡ lỗi dễ dàng nhất để vượt qua.

### 10.1.2 NtQueryInformationProcess

Để phát hiện một trình gỡ lỗi, hàm `CheckRemoteDebuggerPresent` gọi đến hàm `NtQueryInformationProcess`, một hàm cấp thấp hơn của Windows NT cso thể trả về nhiều thông tin khác nhau về hệ thống. `NtQueryInformationProcess` cũng có thể được gọi trực tiếp. Nó nhận nhiều tham số, bao gồm `ProcessHandle` (một handle đến quy trình mục tiêu) và giá trị `ProcessInformationClass` (loại thông tin cần được trả về). Trong trường hợp phát hiện trình gỡ lỗi, giá trị `ProcessInformationClass` sẽ là 7, hoặc `ProcessDebugPort`. Một gía trị khác 0 cho thấy quy trình hiện đang chạy dưới một trình gỡ lỗi.

Ngoài ra, tác giả malware có thể chỉ định `ProcessInformationClass` là `ProcessDebugFlags` (1F). Nếu quy trình đang bị gỡ lỗi, các cờ gỡ lỗi sẽ được thiết lập, báo hiệu cho malware. Cuối cùng, lớp thông tin `ProcessDebugObjectHandle` (1E) cũng có thể tiết lộ sự hiện diện của một trình gỡ lỗi.

### 10.1.3 NtQuerySystemInformation

`NtQuerySystemInformation` là một hàm Windows NT có thể được sử dụng để truy vấn thông tin hệ thống. Hàm này có thể trả về nhiều loại thông tin khác nhau, và một cấu trúc đặc biệt quan trọng cho mục đích của chúng ta là SYSTEM\_KERNEL\_DEBUGGER\_INFORMATION. Cấu trúc này chứa 2 giá trị quan trọng cho việc phát hiện trình gỡ lỗi: `KdDebuggerEnabled` và `KdDebuggerNotPresent`, cả 2 đều có thể được sử dụng để phát hiện một trình gỡ lỗi kernel gắn vào quy trình gọi. Các trình gỡ lỗi kernel là các công cụ chuyên biệt để gỡ lỗi phần mêm ở mức thấp và đôi khi cho phân tích phần mềm độc hại. Nếu KdDebuggerEnabled trả về giá trị khác 0 hoặc KdDebuggerNotPresent trả về 0, điều này có thể chỉ ra cho malware rằng một trình gỡ lỗi kernel đang có mặt.

### 10.1.4 OutputDebugString

Hàm `OutputDebugString` đơn giản là hiển thị một chuỗi trong trình gỡ lỗi. Nếu một quy trình được gắn vào một trình gỡ lỗi, chuỗi sẽ được hiển thị; nếu không, `OutputDebugString` sẽ trả về với một lỗi. Malware có thể lạm dụng hàm này bằng cách thiết lập mã lỗi một cách thủ công bằng cách sử dụng `SetLastError` (lỗi này có thể là bất kỳ giá trị tùy ý nào), gọi `OutputDebugString` với mọt giá trị chuỗi ngẫu nhiên, và sau đó gọi `GetLastError` để kiểm tra xem trạng thái lỗi đã thay đổi hay chưa, như được minh họa trong đoạn mã sau đây:

```c
SetLastError("5");
OutputDebugString("testing123");
error = GetLastError();
if (error == "5"):
    // Đã phát hiện trình gỡ lỗi.
    // Thực thi mã né tránh, chẳng hạn như TerminateProcess.
else:
    // Không phát hiện trình gỡ lỗi; tiếp tục thực thi.
```

Mẫu malware này thiết lập mã lỗi là "5" bằng cách sử dụng `SetLastError`, sau đó gọi hàm OutputDebugString với giá trị chuỗi ngẫu nhiên "testing123". Tiếp theo, phần mềm độc hại gọi `GetLastError` để lấy mã lỗi cuối cùng và so sánh giá trị đso với mã lỗi từ cuộc gọi `SetLastError` trước đó. Nếu cuộc gọi đến `OutputDebugString` thành công mà không có lỗi, mã `GetLastError` nên vẫn là "5", có nghĩa là một trình gỡ lỗi đang có mặt. Đây là một kỹ thuật cũ, nhưng phần mềm độc hại thỉnh thoảng vẫn cố gắng sử dụng nó.

### 10.1.5 CloseHandle and NtClose

Nếu một mẫu malware đang bị gỡ lỗi và malware cố gắng gọi hàm CloseHandle hoặc NtClose với một handle không hợp lệ, nó sẽ kích hoạt một ngoại lệ `EXCEPTION_INVALID_HANDLE`. Khi ngoại lệ này được kích hoạt, nó sẽ được chuyển đến trình xử lý ngoại lệ của trình gỡ lỗi, báo hiệu cho malware biết rằng nó đang bị gỡ lỗi. Đoạn mã đơn giản sau đây minh họa điều này:

```nasm
mov ebx, [invalid_handle]
call NtClose
```

Đoạn mã trước gọi hàm NtClose với một handle không hợp lệ làm tham số. Khi được thực thi, điều này sẽ kích hoạt một ngoại lệ và báo hiệu cho phần mềm độc hại rằng nó đang bị gỡ lỗi.

### 10.1.6 NtQueryObject

Để một trình gỡ lỗi hoạt động đúng, nó phải tạo ra một đối tượng kernel đặc biệt gọi là đối tượng gỡ lỗi (debug object). Phần mềm độc hại có thể gọi hàm NtQueryObject để nhận danh sách tất cả các đối tượng gỡ lỗi, sự hiện diện của chúng sẽ cho thấy rằng phần mềm độc hại hiện đang bị gỡ lỗi hoặc rằng host đã sử dụng một trình gỡ lỗi trong quá khứ.

Tham số đầu tiên cho hàm này, Handle, là handle đến đối tượng đang được truy vấn thông tin. Tham số thứ hai, `NtQueryObject`, chấp nhận một giá trị `ObjectInformationClass` sẽ cho hàm biết loại dữ liệu nào cần được trả về. Tham số thứ ba, `ObjectInformation`, chấp nhận môt con trỏ đến nơi mà dữ liệu trả về sẽ được lưu trữ.

Nếu bạn phát hiện malware gọi hàm NtQueryObject, cung cấp giá trị `ObjectInformationClass` là 3 (`ObjectAllTypesInformation`), và sau đó kiểm tra bộ đệm `ObjectInformation` để tìm các chuỗi như DebugObject, bạn có thể tương đối chắc chắn rằng phần mềm độc hại đang cố gắng xác định một trình gỡ lỗi.

### 10.1.7 Heap Flags

PEB chứa các con trỏ đến cấu trúc heap bộ nhớ của quy trình, được gọi là process heap, tại địa chỉ 0x18 (0x30 cho các quy trình x64). Process heap chứa nhiều thành viên khác nhau là các con trỏ đến dữ liệu bổ sung; 2 trong số các thành viên này là `Flags` và `ForceFlags`, mà trỏ đến một khối dữ liệu cung cáp thông tin cho kernel Windows về bộ nhớ heap của quy trình. Trong Windows 7 và các phiên bản mới hơn, nếu một quy trình đang bị gỡ lỗi, giá trị của thành viên Flags sẽ là `0x40000062`, và giá trị của thành viên `ForceFlags` sẽ là `0x40000060`. Để phát hiện một trình gỡ lỗi, phần mềm độc hại có thể cố gắng độc các giá trị này trong cấu trúc heap của nó bằng cách gọi hàm `RtlQueryProcessHeapInformation` hoặc `RtlQueryProcessDebugInformation`, hoặc nó có thể độc thủ công PEB như chúng ta thảo luận trong phần sau.

## 10.2 Directly Accessing the PEB

Thay vì dựa vào các hàm Windows được mô tả trong phần trước, malware có thể trực tiếp truy cập và đọc `PEB`, như được hiển thị trong đoạn code sau:

```nasm
--snip--
mov eax, [fs:0x30]
cmp [eax+0x2], 1
jnz DebuggerDetected
--snip--
```

Ở đây, để lấy địa chỉ của `PEB` để đọc nó, malware di chuyển địa chỉ tại `fs:0x30` vào `eax`. (như ta còn nhớ thì ở chương 1 đã đề cập, `fs:0x30` là địa chỉ cho phần đầu của `PEB`). Tiếp theo, malware so sánh giá trị 1 với gái trị `eax+0x2`, đầy là trường `BeingDebugged` trong cấu trúc `PEB`. Nếu giá trị này là 1, có khả năng 1 trình gỡ lỗi đang được gắn vào quy trình, và phần mềm độc hại có thể phản ứng tương ứng.

Một ví dụ khác về việc đọc `PEB` thủ công liên quan đến `NtGlobalFlag`, nằm ở byte `0x68` trong `PEB` và chứa thông tin liên quan đến việc tạo ra các heap bộ nhớ. Khi một quy trình được bắt đầu dưới một một trình gỡ lỗi, giá trị của `NtGlobalFlag` sẽ là `0x70`, vì vậy malware có thể đọc giá trị đó trong `PEB` của nó để kiểm tra trình gỡ lỗi một cách nhanh chóng.

Hãy nhớ rằng malware có thể truy vấn bất kỳ thành viên nào của cấu trúc PEB theo cách này. Việc truy cập PEB trực tiếp, thay vì gọi các hàm Windows phổ biến để làm như vậy, có thể là một cách hiệu quả để malware phát hiện trình gỡ lỗi không làm kích hoạt cảnh báo.

## 10.3 Timing Checks

Ba phương pháp phổ biến dựa trên thời gian để phát hiện trình gỡ lỗi là `GetTickCount`, lệnh `rdtsc`, và kiểm tra thời gian hệ thống (system time).

`GetTickCount` trả về số mili giây đã trôi qua kể từ khi hệ thống khởi động. Malware có thể gọi `GetTickCount` tại nhiều điểm trong mã của nó để xem bao nhiêu thời gian đã trôi qua để từ lần gọi cuối cùng của nó đến hàm này. Khi malware đang bị gỡ lỗi, chương trình sẽ tự nhiên thực thi chậm hơn, đặc biệt là nếu nhà phần tích phần mềm độc hại đang đặt các breakpoint trong suốt quá trình gỡ lỗi. Nếu nhà phân tích tình cờ đặt một điểm dừng trên một hàm hoặc đang thực hiện từng bước qua code, sự khác biệt giữa lần gọi đầu tiên của `GetTickCount` và lần gọi cuối cùng sẽ lơn hơn nhiều so với trường hợp khác. Malware có thể khai thác thực tế này để phát hiện trình gỡ lỗi.&#x20;

Phần mềm độc hại có thể sử dụng lệnh rdtsc theo cách tương tự. Bằng cách đặt các lệnh `rdtsc` trong suốt mã của nó, malware có thể xác định liệu nó có đang bị gỡ lỗi dựa trên thời gian CPU hay không.

<figure><img src="/files/ARqMjnYwbeWDKI1XBqmI" alt=""><figcaption></figcaption></figure>

Cuối cùng, malware có thể đơn gian truy vấn thời gian hệ thống bằng cách gọi các hàm như `GetLocalTime`, `GetSystemTime`, và `NtQuerySystemTime` tại nhiều điểm trong mã của nó để phát hiện một trình gỡ lỗi đang được sử dụng.

Có nhiều phương pháp khác để sử dụng kiểm tra thười gian để bắt một trình gỡ lỗi đang hoạt động; đây chỉ là một số phương pháp phổ biến nhất. Điều cần hiểu ở đây là nếu bạn phát hiện malware thỉnh thoảng gọi hàm thời gian hoặc sử dụng các lệnh như rdtsc trong suốt mã của nó, nó có thể đang sử dụng các kỹ thuật chống gỡ lỗi. Bạn có thể phải xác định nơi các hàm và lệnh này đang được thực thi trong malware và vá chúng (patch), hoặc có thể sửa đổi các giá trị trả về của chúng để lừa malware tin rằng nó không bị gỡ lỗi.

## 10.4 System Artifacts (các dấu vết hệ thống)

Malware có thể phát hiện một trình gỡ lỗi thông qua các dấu vết hệ thống như cửa số máy tính, khóa registry, và các module đã tải.&#x20;

### 10.4.1 Hunting for Debugger Windows

Chương 5 đã thảo luận về cách phần mềm độc hại có thể phát hiện các công cụ của nhà phân tích bằng cách sử dụng các hàm như `FindWindow`, hàm này định vị một cửa sổ máy tính, và `EnumWindows`, hàm này truy xuất các cửa sổ máy tính đang mở. Malware cũng có thể sử dụng các hàm này để tìm kiếm cụ thể các cửa sổ trình gỡ lỗi. Ví dụ, nó có thể gọi `FindWindow` để truy xuất các cửa sổ với tên trình gỡ lỗi như x64dbg, OllyDbg hoặc Immunity debugger. Ví dụ như đoạn code sau:

<figure><img src="/files/06WW2OCnuVEBd7eBONfL" alt=""><figcaption></figcaption></figure>

### 10.4.2 Enumerating Loaded Modules

Khi bạn gắn malware vào một trình gỡ lỗi, trình gỡ lỗi có thể tải các module vào không gian địa chỉ của malware; Ví dụ, trình gỡ lỗi WinDbg có thể tải thư hiện `dbghelp.dll`. Malware có thể định vị một module đáng ngờ bằng cách gọi hàm `GetModuleHandle` và truyền tên của module (chẳng hạn như `dbghelp.dll`) làm tham số. Ngoài ra, nó có thể truy xuất tất cả các module đã tải bằng cách sử dụng `Module32First` và `Module32Next` và sau đó tìm kiêm một tên module cụ thể.

### 10.4.3 Searching for Debugger Processes

Malware cũng có thể liệ tkee các quy trình đang chạy trên máy chủ để tìm kiếm các quy trình trình gỡ lỗi. Để làm điều này, nó có thể gọi CreateToolhelp32Snapshot, Process32First, và Process32Next, sau đó tìm kiếm cụ thể tên các quy trình gỡ lỗi phổ biến, chẳng hạn như x64dbg.exe hoặc ida64.exe.

### 10.4.4 Checking Parent Processes

Để phát hiện một trình gỡ lỗi, phần mềm độc hại có thể kiểm tra xem quy trình cha của nó là gì. Nếu phần mềm độc hại đang chạy bên trong một trình gỡ lỗi, quy trình cha của nó sẽ là quy trình gỡ lỗi. Nếu malware phát hiện ra rằng nó đang chạy như một quy trình con của một quy trình gỡ lỗi (chẳng hạn như x64dbg.exe), malware sẽ xác định rằng nó đang bị gỡ lỗi.

Phần mềm độc hại có thể phát hiện quy trình cha của nó theo một vài cách. Một cách tiếp cận là lấy ID quy trình của chính nó (`GetCurrentProcessId`), chụp ảnh nhanh tất cả các quy trình đang chạy (`CreateToolhelp32Snapshot`) và sử dụng `Process32First` và `Process32Next` để tìm kiếm tên quy trình của chính nó. Khi nó tìm thấy quy trình của mình, cấu trúc ảnh chụp quy trình chứa một mục (`th32ParentProcessID`) đại diện cho ID quy trình cha của nó.

Tương tự, malware có thể tạo ra một quy trình con bằng cách sử dụng CreateProcess, làm cho quy trình gốc của malware trở thành quy trình cha của quy trình mới này. Quy trình con sau đó có thể hàm DebugActiveProcess với quy trình cha của nó làm tham số. Nếu quy trình cha (malware gốc) đã đang bị gỡ lỗi, hàm này sẽ ném ra một ngoại lệ STATUS\_PORT\_ALREADY\_SET, cho malware biết rằng có một trình gỡ lỗi đang gắn vào nó.

## 10.5 Breakpoint Detection and Traps

Khi điều tra malware trong một trình gỡ lỗi, một nhà phân tích phần mềm độc hại thường tạo các điểm dừng trên các lệnh cụ thể, cuộc gọi hàm, hoặc các phân đoạn bộ nhớ cụ thể. Như đã đề cập từ chương 3, hành động tạo ra các điểm dừng malware sẽ sửa đổi mẫu phần mềm độc hại đang chạy. Điều này có nghĩa là malware có thể phát hiện các điểm dừng này theo một số cách thú vị. Phần này sẽ thảo luận về một số phương pháp phát hiện, vượt qua và khai thác điểm dừng mà phần mềm độc hại có thể sử dụng.

### 10.5.1 Detecting Debuggers with Breakpoints

Khi một trình gỡ lỗi gặp một lệnh dừng như `int 3` (một trong những lệnh phổ biến nhất) trong một chương trình. Điều này xảy ra vì lệnh điểm dừng gây ra một ngoại lệ ngắt trong chương trình, cuối cùng chuyển đến trình gỡ lỗi. Tuy nhiên, khi một chương trình không bị gỡ lỗi, các lệnh điểm dừng gây ra một `EXCEPTION_BREAKPOINT` và luồng điều khiển được chuyển đến trình xử lý ngoại lệ mặc định của chương trình.

Đây là một cách tuyệt vời để phần mềm độc hại kiểm tra xem nó có đang bị gỡ lỗi hay không. Nếu malware thực thi lệnh `int 3` và nó không bị gỡ lỗi, một `EXCEPTION_BREAKPOINT` sẽ được kích hoạt và trình xử lý ngoại lệ sẽ được gọi. Tất nhiên, điều ngược lại cũng đúng. Nếu `EXCEPTION_BREAKPOINT` này không gọi trình xử lý ngoại lệ, malware có thể suy ra rằng đang bị gỡ lỗi. Hãy xem đoạn mã đơn giản hóa sau đây:

<figure><img src="/files/ZerbVNFqw2eXigeNanwU" alt=""><figcaption></figcaption></figure>

Đoạn mã có một câu lệnh try...catch đơn giản. Malware cố gắng thực thi lệnh int 3 (1), và nếu câu lệnh này trả về thành công mà không gọi trình xử lý ngoại lệ, malware giả định rằng nó đang chạy trong một trình gỡ lỗi. Tuy nhiên, nếu lệnh này kích hoạt một ngoại lệ (2), phần mềm độc hại có thể an toàn giả định rằng nó không được gắn vào một trình gỡ lỗi.

### 10.5.2 Detecting and Circumventing Software Breakpoints (phát hiện và vượt qua)

Malware có thể cũng có thể trực tiếp phát hiện việc sử dụng các điểm dừng bằng cách triển khai các kỹ thuật quét điểm dừng. trong ví dụ mã sau đây, malware quết mã của nó để tìm lệnh dừng `int 3` (`0xCC` ở dạng thập lục phân):

```nasm
--snip--
mov ebx, <kernel32.WriteProcessMemory>
cmp byte ptr ds:[ebx], 0xCC
--snip
```

Mẫu malware này đang cố gắng xác định liệu một nhà phân tích phần mềm độc hại đã đặt một điểm dừng phần mềm trên hàm `WriteProcessMemory` hay chưa. Đầu tiên, malware di chuyển địa chỉ của `WriteProcessMemory` vào thanh ghi ebx. Sau đó so sánh giá trị `0xCC` (lệnh điểm dừng int 3 của trình gỡ lỗi) với byte đầu tiên trong ebx, đây là phần bắt đầu của hàm `WriteProcessMemory` và nơi điểm dừng sẽ cư trú. Khi phần mềm độc hại xác định được một điểm dừng phần mềm, nó có thể cố gắng ghi đè hoặc xóa điểm dừng.

Bạn có thể vượt qua một số kỹ thuật phát hiện điểm dừng bằng cách sử dụng các lệnh điểm dừng không phổ biến. Nhiều trình gỡ lỗi có tùy chỉnh này. Trong x64dbg, chỉ cần điều hướng đến `Options -> Preferences-> Engine` và đặt lệnh điểm dừng ưa thích của bạn dưới mục Default Breakpoint Type, được hiển thị như hình:

<figure><img src="/files/KDGcc6j2USerB6DdOu5U" alt=""><figcaption></figcaption></figure>

Một số biến thể của malware cũng tìm kiếm các lệnh dừng thay thế này, vì vậy một lựa chọn tốt hơn là sử dụng các điểm dừng phần cứng để vượt qua các kỹ thuật phất hiện điểm dừng phần mềm. Tuy nhiên, điểm dừng phần cứng cũng có thể bị malware vượt qua, như phần tiếp theo sẽ thảo luận.

### 10.5.3 Detecting and Circumventing Hardware and Memory Breakpoints

Giống như các điểm dừng phần mềm, các điểm dừng phần cứng có thể được sử dụng bởi các nhà phân tích để chặn các cuộc gọi hàm, dừng lại khi có hành bi thú bị, và nhìn chung kiểm soát việc thực thi của malware. Vì các điểm dừng phần cứng được triển khai trong các thanh ghi CPU (DR0-DR3) thay vì như các lệnh, malware có thể quét các thanh ghi này để tìm chúng. Nếu bất kỳ thanh ghi nào trong số này chứa dữ liệu (cụ thể là một địa chỉ bộ nhớ), phần mềm độc hại có thể giả định rằng có một điểm dừng phần cứng và thực hiện các hành động né tránh, chẳng hạn như xóa các thanh ghi này, hiệu quả loại bỏ các điểm dừng. Một cách để tìm các điểm dừng phần cứng là bằng cách sử dụng hàm `GetThreadContext` (hoặc `Wow64GetThreadContext` cho các chương trình 64bit) như sau:

```c
CONTEXT context;
context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
HANDLE hThread = GetCurrentThread();
GetThreadContext(hThread, &context);
if ((context.Dr0) || (context.Dr1) || (context.Dr2) || (context.Dr3)) {
    return true;
}
```

Trong mẫu này, malware định nghĩa một cấu trúc CONTEXT mới (`context`), đây là mọt cấu trúc Windows được sử dụng đẻ lưu trữ trạng thái CPU và dữ liệu liên quan cho quy trình. Cấu trúc này phải được thiết lập để lưu trữ dữ liệu thanh ghi gỡ lỗi (DR0-DR3) mà malware sẽ kiểm tra ngay sau đó. Tiếp theo phần mềm độc hại chỉ định rằng `CONTEXT_DEBUG_REGISTERS` nên là dữ liệu mà `GetThreadContext` trả về. Malware sau đó lấy một handle đến luồng hiện tại của nó (HANDLE) và gọi `GetThreadContext`, hàm này sẽ lưu trữ `CONTEXT_DEBUG_REGISTERS` của luồng hiện tại trong cấu context. Cuối cùng, mẫu malware kiểm tra các thanh ghi gỡ lỗi để tìm dữ liệu. Nếu các thanh ghi này khác 0, kiểm tra trả về true, thông báo cho malware rằng một điểm dừng phần cứng đã được đặt bởi trình gỡ lỗi.

Phần mềm độc hại sau đó có thể hoàn toàn loại bỏ bất kỳ điểm dừng phần cứng nào nó phát hiện bằng cách sử dụng `SetThreadContext` (hoặc `Wow64SetThreadContext` cho phần mềm độc hại 64 bit). Thêm dòng này vào ví dụ mã trước đố sẽ hiệu quả xóa các thanh ghi gỡ lỗi, sau đó loại bỏ các điểm dừng phần cứng của nahf phân tích phần mềm độc hại:

```c
context.Dr0 = null;
context.Dr1 = null;
context.Dr2 = null;
context.Dr3 = null;
SetThreadContext(hThread, &context);
```

Cuối cùng, malware có thể phát hiện các điểm dừng bộ nhớ với hàm `ReadProcessMemory`. Việc đặt một điểm dừng bộ nhớ làm thay đổi trang bộ nhớ, vì vậy nếu malware gọi `ReadProcessMemory` trên một trang bộ nhớ đáng ngờ, và nếu nó trả về một giá trị không mong đợi như `PAGE_NOACCESS` hoặc `PAGE_GUARD`, nó có thể suy ra rằng một điểm dừng phần cứng đã được đặt trên trang bộ nhớ này. Một tùy chọn khác để đạt được cùng hiệu quả là phần mềm độc hại thực thi `VirtualQuery`, `VirtualQueryEx`, hoặc `NtQueryVirtualMemory`. Chúng ta sẽ thảo luận thêm về các điểm dừng bộ nhớ trong phần tiếp theo.

Nếu bạn nghi ngờ rằng một mẫu malware đang sử dụng bất kỳ kỹ thuật nào được mô tả trong phần này, sẽ hữu ích khi hook (đặt điểm dừng trên) các hàm này. Khi một điểm dừng được kích hoạt, bạn có thể đơn giản sửa sổi giá trị trả về hoặc nop hoàn toàn cuộc gọi đến hàm. Plug-in trình gỡ lỗi ScyllaHide cũng sẽ hữu ích ở đây.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://viettaliii.gitbook.io/home/mal/evasive-malware/chapter-10-anti-debugging.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
