# Các kĩ thuật Anti-Debug cơ bản ## *1. IsDebuggerPresent()* Hàm kernel32! `IsDebuggerPresent()` xác định rằng khi nào mà chương trình hiện tại đang được debug bằng 1 công cụ debug được sử dụng bởi con người ví dụ như là `OllyDbg` hay `x64dbg`. Nói tóm lại, hàm này chỉ check `BeingDebugged flag` trong môi trường ngăn chặn thực thi chương trình. Dưới đây là code 2 code ví dụ về cách thức mà hàm này hoạt động #### Code C ``` #include <stdio.h> #include <stdlib.h> #include <string.h> #include <windows.h> int main() { int check; int mot = 1; int sau = 3; int hai; scanf("%d", &check); if(check != 1) { printf("Em chao` anh Ajomix\n"); } hai = mot + sau; if (IsDebuggerPresent()) { printf("Adu ko debug duoc roi huhu\n"); ExitProcess(-1); } } ``` --- ## *2. CheckRemoteDebuggerPresent()* Hàm kernel32! `CheckRemoteDebuggerPresent()` kiểm tra rằng nếu 1 trình debug đang chạy(trong 1 chương trình khác trên cùng 1 thiết bị) gắn với trình thực thi hiện tại #### Code C++ ``` #include <iostream> #include "windows.h" using namespace std; int main() { BOOL HasDebugPort = FALSE; cout << "Em chao` anh Ajomix" << endl ; if(CheckRemoteDebuggerPresent(GetCurrentProcess(), &HasDebugPort)) { cout << "Buon vay khong debug duoc roi :<<<<" << endl; ExitProcess(0); } return 0; } ``` ## 3. *NtQueryInformationProcess()* Hàm ntdll!`NtQueryInformationProcess()` có thể lấy ra một loại thông tin khác của chương trình. Nó chấp thuận 1 thông số `ProcessInformationClass` thứ mà chỉ định thông tin mà bạn muốn lấy ra và định dạng nó kiểu thông tin đầu ra của tham số `ProcessInformationClass`. ### *3.1 ProcessDebugPort* Ta hoàn toàn có thể lấy được `port number` của trình debug cho quá trình sử dụng hàm ntdll! `NtQueryInformationProcess()`. Ở đây có 1 `documented class ProcessDebugPort`, thứ mà lấy giá trị có bộ nhớ 4 bytes(DWORD) có giá trị bằng 0xFFFFFFFF(decimal -1) khi chương trình được debug #### Code C++ ``` #include <iostream> #include "windows.h" #include "winternl.h" using namespace std; typedef NTSTATUS(NTAPI* pfnNtQueryInformationProcess)( IN HANDLE ProcessHandle, IN PROCESSINFOCLASS ProcessInformationClass, OUT PVOID ProcessInformation, IN ULONG ProcessInformationLength, OUT PULONG ReturnLength ); int main(int argc, char* argv[]) { pfnNtQueryInformationProcess NtQueryInformationProcess = NULL; NTSTATUS status; DWORD isDebuggerPresent = 0; HMODULE hNtDll = LoadLibrary(TEXT("ntdll.dll")); PROCESSINFOCLASS *ProcessDebugPort = (PROCESSINFOCLASS*)malloc(sizeof(PROCESSINFOCLASS)); cout << "EM chao` anh Ajomix" << endl; if (NULL != hNtDll) { NtQueryInformationProcess = (pfnNtQueryInformationProcess)GetProcAddress(hNtDll, "NtQueryInformation"); if (NULL != NtQueryInformationProcess) { status = NtQueryInformationProcess( GetCurrentProcess(), *ProcessDebugPort, &isDebuggerPresent, sizeof(DWORD), NULL); if (status == 0 && isDebuggerPresent != 0) { cout << "Dcm van ko the debug noi :<<" << endl; ExitProcess(-1); } } } return 0; } ``` --- ### *3.2NtQuerySystemInformation()* Hàm ntdll! NtQuerySystemInformation() chấp thuận 1 thông số nằm trong lớp thông tin được truy vấn. Hầu hết các lớp ko được dẫn chứng. Nó bao gồm lớp `SystemKernelDebuggerInformation (0x23)`. Lớp `SystemKernelDebuggerInformation` trả về giá trị của 2 cờ: `KdDebuggerEnabled` trong thanh ghi 8-bit al và `KdDebuggerNotPresent` trong thanh ghi 8-bit ah. Vì thế, giá trị trả về trên thanh ghi 8-bit ah là 0 nếu như trình debug kernel đang hoạt động #### Code C++ ``` #include <iostream> #include "windows.h" #include "winternl.h" using namespace std; enum { SystemKernelDebuggerInformation = 0x23}; typedef NTSTATUS(NTAPI* TNtQueryInformationProcess)( IN HANDLE ProcessHandle, IN DWORD ProcessInformationClass, OUT PVOID ProcessInformation, IN ULONG ProcessInformationLength, OUT PULONG ReturnLength ); typedef struct _SYSTEM_KERNEL_DEBUGGER_INFORMATION { BOOLEAN DebuggerEnabled; BOOLEAN DebuggerNotPresent; } SYSTEM_KERNEL_DEBUGGER_INFORMATION, * PSYSTEM_KERNEL_DEBUGGER_INFORMATION; bool Check() { NTSTATUS status; SYSTEM_KERNEL_DEBUGGER_INFORMATION SystemInfo; status = NtQuerySystemInformation( (SYSTEM_INFORMATION_CLASS)SystemKernelDebuggerInformation, &SystemInfo, sizeof(SystemInfo), NULL); return SUCCEEDED(status) ? (SystemInfo.DebuggerEnabled && !SystemInfo.DebuggerNotPresent) : false; } ``` #### Cách khắc phục Đối với `IsDebuggerPresent()`: Đặt cờ BeingDebugged của Process Environment Block (PEB) thành 0 Đối với `CheckRemoteDebuggerPresent()` và `NtQueryInformationProcess():` Khi `CheckRemoteDebuggerPresent()` gọi `NtQueryInformationProcess()`, cách duy nhất là nối `NtQueryInformationProcess()` và đặt các giá trị sau trong bộ đệm trả về: 0 (hoặc bất kỳ giá trị nào ngoại trừ -1) trong trường hợp truy vấn ProcessDebugPort. Giá trị khác 0 trong trường hợp truy vấn `ProcessDebugFlags`. 0 trong trường hợp truy vấn ProcessDebugObjectHandle. Cách duy nhất để giảm thiểu những kiểm tra này với các hàm `RtlQueryProcessHeapInformation()`, `RtlQueryProcessDebugInformation()` và `NtQuerySystemInformation()` là nối chúng và sửa đổi các giá trị trả về: `RTL_PROCESS_HEAPS :: HeapInformation :: Heaps [0] `:: Gắn cờ cho `HEAP_GROWABLE` cho `RtlQueryProcessHeapInformation()` và `RtlQueryProcessDebugInformation()`. SYSTEM_KERNEL_DEBUGGER_INFORMATION :: DebuggerEnabled thành 0 và SYSTEM_KERNEL_DEBUGGER_INFORMATION :: DebuggerNotPresent thành 1 cho hàm NtQuerySystemInformation () trong trường hợp truy vấn SystemKernelDebuggerInformation. --- ### *3.3ProcessDebugFlags()* Khi việc kiểm tra cờ đang diễn ra, nó trả về giá trị nghịch đảo của `NoDebugInherit` bit thuộc cấu trúc kernel `EPROCESS`. Nếu giá trị trả về của hàm `NtQueryInformationProcess` bằng với 0, thì khí đó, chương trình tiếp tục được debug #### Code C++ ``` status = NtQueryInformationProcess( GetCurrentProcess(), ProcessDebugObjectHandle, &debugFlags, sizeof(ULONG), NULL); if (0x00000000 == status && NULL != debugFlags) { std::cout << "Stop debugging program!" << std::endl; exit(-1); } ```