(64)句柄表,遍历所有进程的句柄表实现反调试
一、內核對象,句柄
這次課討論的內核對象是指創建時需要指定 LPSECURITY_ATTRIBUTES 參數的對象,例如 Mutex, Thread。
調用 CreateThread 等函數會返回一個 HANDLE 類型值,這種就叫句柄,它對應一個內核對象;
調用 CloseHandle 函數對某個內核對象計數減一,當內核對象計數為0,這個對象就被銷毀了。
內核對象在內核存儲,直接把地址給3環用很不安全,所以微軟設計了句柄(HANDLE)給3環使用,句柄是一個整數,它的值除以4是句柄表的下標,通過下標能找到存儲在句柄表里的句柄表項,每個占8字節。
二、句柄表,句柄表項
1.句柄表結構
句柄表存儲在 EPROCESS.ObjectTable.TableCode 里:
kd> dt _HANDLE_TABLE ntdll!_HANDLE_TABLE+0x000 TableCode : Uint4B+0x004 QuotaProcess : Ptr32 _EPROCESS+0x008 UniqueProcessId : Ptr32 Void+0x00c HandleTableLock : [4] _EX_PUSH_LOCK+0x01c HandleTableList : _LIST_ENTRY+0x024 HandleContentionEvent : _EX_PUSH_LOCK+0x028 DebugInfo : Ptr32 _HANDLE_TRACE_DEBUG_INFO+0x02c ExtraInfoPages : Int4B+0x030 FirstFree : Uint4B+0x034 LastFree : Uint4B+0x038 NextHandleNeedingPool : Uint4B+0x03c HandleCount : Int4B+0x040 Flags : Uint4B+0x040 StrictFIFO : Pos 0, 1 Bit句柄表項每個占8字節,一個頁4KB,所以一個頁能存儲512個句柄表項,當進程中的句柄數量超過512,句柄表就會以分級形式存儲,最多三級:
特別留意 TableCode 的第2位,它表明了句柄表的結構,如果第2位是01,表示現在句柄表有兩級, TableCode 指向的表存儲了 4KB / 4 = 1024 個句柄表的地址,每個地址指向一個句柄表。
我們可以編程,構造超過512個句柄,看看 TableCode 的低2位是否是01:
#include "stdafx.h" #include <windows.h>int _tmain(int argc, _TCHAR* argv[]) {DWORD PID;HANDLE hPro = NULL;HWND hwnd = FindWindowA(NULL, "計算器");GetWindowThreadProcessId(hwnd, &PID);for (int i = 0; i < 600; i++){//hPro = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, TRUE, PID);hPro = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, TRUE, PID);printf("句柄:%x\n", hPro);}SetHandleInformation(hPro, HANDLE_FLAG_PROTECT_FROM_CLOSE, HANDLE_FLAG_PROTECT_FROM_CLOSE);getchar();return 0; }確實是這樣的,觀察 +0x000 TableCode : 0xe128f001
kd> dt 0xe1be0f00 _HANDLE_TABLE ntdll!_HANDLE_TABLE+0x000 TableCode : 0xe128f001+0x004 QuotaProcess : 0x81df0da0 _EPROCESS+0x008 UniqueProcessId : 0x00000614 Void+0x00c HandleTableLock : [4] _EX_PUSH_LOCK+0x01c HandleTableList : _LIST_ENTRY [ 0x8055c448 - 0xe2307b04 ]+0x024 HandleContentionEvent : _EX_PUSH_LOCK+0x028 DebugInfo : (null) +0x02c ExtraInfoPages : 0n0+0x030 FirstFree : 0x99c+0x034 LastFree : 0+0x038 NextHandleNeedingPool : 0x1000+0x03c HandleCount : 0n613+0x040 Flags : 0+0x040 StrictFIFO : 0y02.通過句柄表項找到內核對象(句柄數量少于512)
下面我們編寫一個程序,打開計算器的進程句柄,然后在windbg里通過句柄表找到計算器的EPROCESS:
#include "stdafx.h" #include <windows.h>int _tmain(int argc, _TCHAR* argv[]) {DWORD PID;HANDLE hPro = NULL;HWND hwnd = FindWindowA(NULL, "計算器");GetWindowThreadProcessId(hwnd, &PID);for (int i = 0; i < 100; i++){//hPro = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, TRUE, PID);hPro = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, TRUE, PID);printf("句柄:%x\n", hPro);}SetHandleInformation(hPro, HANDLE_FLAG_PROTECT_FROM_CLOSE, HANDLE_FLAG_PROTECT_FROM_CLOSE);getchar();return 0; }以 1c0 為例,除以4得到 70.找到程序的句柄表:
kd> dt 0xe14be1e0 _HANDLE_TABLE ntdll!_HANDLE_TABLE+0x000 TableCode : 0xe11a4000+0x004 QuotaProcess : 0x81e6b020 _EPROCESS+0x008 UniqueProcessId : 0x00000544 Void+0x00c HandleTableLock : [4] _EX_PUSH_LOCK+0x01c HandleTableList : _LIST_ENTRY [ 0x8055c448 - 0xe2307b04 ]+0x024 HandleContentionEvent : _EX_PUSH_LOCK+0x028 DebugInfo : (null) +0x02c ExtraInfoPages : 0n0+0x030 FirstFree : 0x1c8+0x034 LastFree : 0+0x038 NextHandleNeedingPool : 0x800+0x03c HandleCount : 0n113+0x040 Flags : 0+0x040 StrictFIFO : 0y00xe11a4000 低2位是0,表示當前進程的句柄表只有一級,然后我們找一下下標為70的項:
kd> dq 0xe11a4000+70*8 e11a4380 0000003a`81dd800b 0200003a`81dd800b e11a4390 000001cc`00000000 000001d0`00000000 e11a43a0 000001d4`00000000 000001d8`00000000 e11a43b0 000001dc`00000000 000001e0`00000000 e11a43c0 000001e4`00000000 000001e8`00000000 e11a43d0 000001ec`00000000 000001f0`00000000 e11a43e0 000001f4`00000000 000001f8`00000000 e11a43f0 000001fc`00000000 00000200`00000000我們這里打印了下標70的項,同時,+8就是下標71的項,就是我們調用 SetHandleInformation 修改了句柄屬性的最后一個項,觀察它們的區別,最高字節不相同。
關于句柄表項這64位,網上是沒有文檔的,只能自己分析。這里先介紹低32位,低32位的低3位清零后就是內核對象頭(此處是EPROCESS)的虛擬地址,注意,指向內核對象頭 OBJECT_HEADER,這個結構大小是 0x18,所以要加上 0x18 才能找到 EPROCESS.
所以計算器的 EPROCESS 是在 81dd8008+18, dt 驗證一下:
kd> dt 81dd8008+18 _EPROCESS ntdll!_EPROCESS+0x000 Pcb : _KPROCESS+0x06c ProcessLock : _EX_PUSH_LOCK ...+0x174 ImageFileName : [16] "calc.exe" ...如果句柄數量超過了512,意味著句柄表的結構就是二級或者三級的,這種情況比較復雜,限于篇幅,我打算另寫一篇博客單獨介紹。
3. 句柄表項其他位
句柄表項一個8字節,它的64個位的用途是沒有文檔說明的,只能自己分析,以下內容屬于拓展,不保證內容完整且正確,需要得到更準確的情報,請逆向或閱讀源碼。
63-56 給 SetHandleInformation 函數用,如果參數是HANDLE_FLAG_PROTECT_FROM_CLOSE(0x02),那么這個字節會設置成0x0200,剛才的實驗已經驗證過了。
55-48 這個字節恒為0 存疑!140說 OpenProcess(PROCESS_ALL_ACCESS 就不是0
47-32 位存儲的是訪問掩碼,OpenProcess 的第一個參數會影響這里的值。
31-3位加上第三位清零存儲的是內核對象的地址.
低3位是屬性,2位默認是0;1位表示該句柄是否可繼承;0位默認為1.
三、實現用句柄表反調試:當調試器attach時報錯
思路:遍歷所有其他進程句柄表,看哪個進程的句柄表中保護自己的進程,如果有,說明正在被調試。
用一個驅動不停地遍歷進程鏈表,然后遍歷進程的句柄表,如果發現句柄表項和游戲EPROCESS相等,就意味著被 OpenProcess 了,就認為是被調試了。
運行結果:沒被調試
運行結果:被調試
3環代碼
// Game.cpp : 定義控制臺應用程序的入口點。 //#include "stdafx.h" #include <windows.h>//----------------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------------typedef LONG (__stdcall *HBGCOMMUNICATION) (IN ULONG OpCode, IN OUT PVOID p1, IN OUT PVOID p2, IN OUT PVOID p3);//----------------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------------BOOL LoadDriver(PCWSTR lpszDriverName, PCWSTR lpszDriverPath); void UnLoadDriver(PCWSTR lpszDriverName);//----------------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------------#define DRIVER_NAME L"HbgProtect" #define DRIVER_PATH L"HbgProtect.sys"#define OP_CHECK_DEBUG 50HBGCOMMUNICATION HbgCommunication = NULL;//----------------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------------int _tmain(int argc, _TCHAR* argv[]) {HbgCommunication = (HBGCOMMUNICATION)GetProcAddress(LoadLibraryA("ntdll.dll"),"ZwQuerySystemInformation");if (HbgCommunication == NULL) {printf("獲取函數地址失敗. %d\n",GetLastError());getchar();return 1;}// 加載游戲保護驅動LoadDriver(DRIVER_NAME,DRIVER_PATH);while (!GetAsyncKeyState('Q')){Sleep(1000);BOOL IsDebugged = FALSE;HbgCommunication(OP_CHECK_DEBUG,&IsDebugged,NULL,NULL);if (IsDebugged){printf("-----------------正在被調試!\n");}else{printf("沒有被調試.\n");}}UnLoadDriver(DRIVER_NAME);getchar();return 0; }BOOL LoadDriver(PCWSTR lpszDriverName, PCWSTR lpszDriverPath) {// 獲取驅動完整路徑WCHAR szDriverFullPath[MAX_PATH] = { 0 };GetFullPathNameW(lpszDriverPath,MAX_PATH,szDriverFullPath,NULL);//printf("%s\n", szDriverFullPath);// 打開服務控制管理器SC_HANDLE hServiceMgr = NULL; // SCM管理器句柄 hServiceMgr = OpenSCManagerW(NULL,NULL,SC_MANAGER_ALL_ACCESS);if (NULL == hServiceMgr){printf("OpenSCManagerW 失敗, %d\n", GetLastError());return FALSE;}printf("打開服務控制管理器成功.\n");// 創建驅動服務SC_HANDLE hServiceDDK = NULL; // NT驅動程序服務句柄hServiceDDK = CreateServiceW(hServiceMgr,lpszDriverName,lpszDriverName,SERVICE_ALL_ACCESS,SERVICE_KERNEL_DRIVER,SERVICE_DEMAND_START,SERVICE_ERROR_IGNORE,szDriverFullPath,NULL,NULL,NULL,NULL,NULL);if (NULL == hServiceDDK){DWORD dwErr = GetLastError();if (dwErr != ERROR_IO_PENDING && dwErr != ERROR_SERVICE_EXISTS){printf("創建驅動服務失敗, %d\n", dwErr);return FALSE;}}printf("創建驅動服務成功.\n");// 驅動服務已經創建,打開服務hServiceDDK = OpenServiceW(hServiceMgr,lpszDriverName,SERVICE_ALL_ACCESS);if (!StartService(hServiceDDK, NULL, NULL)){DWORD dwErr = GetLastError();if (dwErr != ERROR_SERVICE_ALREADY_RUNNING){printf("運行驅動服務失敗, %d\n", dwErr);return FALSE;}}printf("運行驅動服務成功.\n");if (hServiceDDK){CloseServiceHandle(hServiceDDK);}if (hServiceMgr){CloseServiceHandle(hServiceMgr);}return TRUE; }void UnLoadDriver(PCWSTR lpszDriverName) {SC_HANDLE hServiceMgr = OpenSCManagerW(0,0,SC_MANAGER_ALL_ACCESS);SC_HANDLE hServiceDDK = OpenServiceW(hServiceMgr,lpszDriverName,SERVICE_ALL_ACCESS);SERVICE_STATUS SvrStatus;ControlService(hServiceDDK,SERVICE_CONTROL_STOP,&SvrStatus);DeleteService(hServiceDDK);if (hServiceDDK){CloseServiceHandle(hServiceDDK);}if (hServiceMgr){CloseServiceHandle(hServiceMgr);} }驅動代碼
#include <ntddk.h>//----------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------typedef NTSTATUS (__stdcall *NTQUERYSYSTEMINFORMATION) (IN ULONG SystemInformationClass, OUT PVOID SystemInformation, IN ULONG SystemInformationLength, OUT PULONG ReturnLength);typedef struct _LDR_DATA_TABLE_ENTRY {LIST_ENTRY InLoadOrderLinks;LIST_ENTRY InMemoryOrderLinks;LIST_ENTRY InInitializationOrderLinks;PVOID DllBase;PVOID EntryPoint;ULONG SizeOfImage;UNICODE_STRING FullDllName;UNICODE_STRING BaseDllName;ULONG Flags;UINT16 LoadCount;UINT16 TlsIndex;LIST_ENTRY HashLinks;PVOID SectionPointer;ULONG CheckSum;ULONG TimeDateStamp;PVOID LoadedImports;PVOID EntryPointActivationContext;PVOID PatchInformation; } LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;//----------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path); VOID DriverUnload(PDRIVER_OBJECT driver); ULONG GetProcessEprocessAddr(char *processname); BOOLEAN CheckProcessDebugged(ULONG EprocessAddress); VOID PageProtectOff(); VOID PageProtectOn(); VOID GetKernelBase(PDRIVER_OBJECT driver, PVOID *pKrnlBase, PULONG uKrnlImageSize); PVOID MemorySearch(PVOID bytecode, ULONG bytecodeLen, PVOID pBeginAddress, PVOID pEndAddress); void InlineHookNtQuerySystemInformation(); void UnsetInlineHookNtQuerySystemInformation(); void HbgNtQuerySystemInformation(IN ULONG OpCode, IN OUT PVOID p1, IN OUT PVOID p2, IN OUT PVOID p3);//----------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------#define OP_CHECK_DEBUG 50#define GAMEIMAGENAME "Game.exe" ULONG g_EprocessAddress;PDRIVER_OBJECT g_Driver; NTQUERYSYSTEMINFORMATION NtQuerySystemInformation; ULONG g_HookRetAddressNtQuerySystemInformation;BOOLEAN g_IsDebug;//----------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path) {g_Driver = driver;driver->DriverUnload = DriverUnload;g_EprocessAddress = GetProcessEprocessAddr(GAMEIMAGENAME);//CheckProcessDebugged(g_EprocessAddress);// 通過 hook api 的方式實現簡易的0-3環通信// 在鉤子函數里處理3環的通信請求,3環會不停地命令驅動檢查進程是否被調試InlineHookNtQuerySystemInformation();return STATUS_SUCCESS; }VOID DriverUnload(PDRIVER_OBJECT driver) {UnsetInlineHookNtQuerySystemInformation();DbgPrint("HbgProtect Unload Successfully.\n"); }// 遍歷進程列表,獲取游戲EPROCESS地址,不考慮多開 ULONG GetProcessEprocessAddr(char *ProcessName) {PEPROCESS pEprocess, pCurProcess;PCHAR ImageFileName;ULONG GameEprocessAddr; // 游戲EPROCESS地址,用來和句柄表的值比對,如果比對相等說明正在被調試// 獲取 EPROCESS__asm{mov eax, fs:[0x124];mov eax, [eax + 0x220];mov pEprocess, eax;}pCurProcess = pEprocess;// 遍歷 ActiveProcessLinksdo{ ImageFileName = (PCHAR)pCurProcess + 0x174;if (strcmp(ImageFileName, ProcessName) == 0){GameEprocessAddr = (ULONG)pCurProcess; // 記錄游戲EPROCESS地址return (ULONG)pCurProcess;} pCurProcess = (PEPROCESS)(*(PULONG)((ULONG)pCurProcess + 0x88) - 0x88);} while (pEprocess != pCurProcess);return 0; }BOOLEAN CheckProcessDebugged(ULONG EprocessAddress) {BOOLEAN IsDebugged = FALSE;PEPROCESS pEprocess, pCurProcess;PCHAR ImageFileName;ULONG TableCode;ULONG ObjectTable; // 獲取 EPROCESS__asm{mov eax, fs:[0x124];mov eax, [eax + 0x220];mov pEprocess, eax;}pCurProcess = pEprocess;// 遍歷 ActiveProcessLinksdo{ ImageFileName = (PCHAR)pCurProcess + 0x174;ObjectTable = *(PULONG)((ULONG)pCurProcess + 0xC4);if (ObjectTable != 0){TableCode = *(PULONG)ObjectTable;//DbgPrint("%x %s\n", TableCode, ImageFileName);switch(TableCode & 0x00000003){ case 0:{// 一級句柄表int i;ULONG HandleAddr;TableCode &= 0xFFFFFFFC; // 低2位清零//DbgPrint("正在檢查 [%s] 的句柄表...\n", ImageFileName);for (i = 0; i < 512; i+=2){HandleAddr = (((PULONG)TableCode)[i] & 0xFFFFFFF8) + 0x18; // 低3位清零 + 0x18(跳過 OBJECT_HEADER ) 就是句柄的地址if (HandleAddr == EprocessAddress){DbgPrint("游戲正在被 [%s] 調試!\n", ImageFileName);IsDebugged = TRUE;}}break;}case 1:{// 二級句柄表int i,j;ULONG HandleAddr;ULONG TableCode2;TableCode &= 0xFFFFFFFC; // 低2位清零//DbgPrint("正在檢查 [%s] 的句柄表...\n", ImageFileName);for (i = 0; i < 1024; i++){TableCode2 = ((PULONG)TableCode)[i];if (!MmIsAddressValid((PVOID)TableCode2)) continue; // 跳過無效線性地址for (j = 0; j < 512; j+=2){HandleAddr = (((PULONG)TableCode2)[j] & 0xFFFFFFF8) + 0x18; // 低3位清零 + 0x18(跳過 OBJECT_HEADER ) 就是句柄的地址if (HandleAddr == EprocessAddress){DbgPrint("%s 正在調試游戲!\n", ImageFileName);IsDebugged = TRUE;}}}break;}case 2:{// 三級句柄表int i,j,k;ULONG HandleAddr;ULONG TableCode2,TableCode3;TableCode &= 0xFFFFFFFC; // 低2位清零//DbgPrint("正在檢查 [%s] 的句柄表...\n", ImageFileName);for (i = 0; i < 1024; i++){TableCode2 = ((PULONG)TableCode)[i];if (!MmIsAddressValid((PVOID)TableCode2)) continue; // 跳過無效線性地址for (j = 0; j < 1024; j++){TableCode3 = ((PULONG)TableCode2)[j];if (!MmIsAddressValid((PVOID)TableCode3)) continue; // 跳過無效線性地址for (k = 0; k < 512; k+=2){HandleAddr = (((PULONG)TableCode3)[k] & 0xFFFFFFF8) + 0x18; // 低3位清零 + 0x18(跳過 OBJECT_HEADER ) 就是句柄的地址if (HandleAddr == EprocessAddress){DbgPrint("%s 正在調試游戲!\n", ImageFileName);IsDebugged = TRUE;}}}}break;}}} pCurProcess = (PEPROCESS)(*(PULONG)((ULONG)pCurProcess + 0x88) - 0x88);} while (pEprocess != pCurProcess);if (!IsDebugged) DbgPrint("游戲沒有被調試.\n");return IsDebugged; }// 關閉頁保護 VOID PageProtectOff() {__asm{cli; // 關閉中斷mov eax, cr0;and eax, not 0x10000; // WP位置0mov cr0, eax;} }// 開啟頁保護 VOID PageProtectOn() {__asm{mov eax, cr0;or eax, 0x10000; // WP位置1mov cr0, eax;sti; // 恢復中斷} }// 獲取內核基址,大小 VOID GetKernelBase(PDRIVER_OBJECT driver, PVOID *pKrnlBase, PULONG uKrnlImageSize) {PLDR_DATA_TABLE_ENTRY pLdteHead; // 內核模塊鏈表頭PLDR_DATA_TABLE_ENTRY pLdteCur; // 遍歷指針UNICODE_STRING usKrnlBaseDllName; // 內核模塊名RtlInitUnicodeString(&usKrnlBaseDllName,L"ntoskrnl.exe");pLdteHead = (PLDR_DATA_TABLE_ENTRY)driver->DriverSection;pLdteCur = pLdteHead;do {PLDR_DATA_TABLE_ENTRY pLdte = CONTAINING_RECORD(pLdteCur, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);//DbgPrint("DllBase: %p, SizeOfImage: %08X %wZ\n", pLdteCur->DllBase, pLdteCur->SizeOfImage, &(pLdteCur->FullDllName));if (RtlCompareUnicodeString(&pLdteCur->BaseDllName, &usKrnlBaseDllName, TRUE) == 0){*pKrnlBase = pLdteCur->DllBase;*uKrnlImageSize = pLdteCur->SizeOfImage;return;}pLdteCur = (PLDR_DATA_TABLE_ENTRY)pLdteCur->InLoadOrderLinks.Flink;} while (pLdteHead != pLdteCur);return; }// 特征碼搜索 PVOID MemorySearch(PVOID bytecode, ULONG bytecodeLen, PVOID pBeginAddress, PVOID pEndAddress) {PVOID pCur = pBeginAddress;while (pCur != pEndAddress){if (RtlCompareMemory(bytecode,pCur,bytecodeLen) == bytecodeLen){return pCur;}((ULONG)pCur)++;}return 0; }// InlineHook NtQuerySystemInformation void InlineHookNtQuerySystemInformation() { // NtQuerySystemInformation 特征碼ULONG bytecode[] = {0x4589c033, 0xdc4589e4, 0x64fc4589 ,0x000124a1,0xe8858900, 0x8afffffd, 0x00014080 ,0x90458800};UCHAR ReplaceByte[5];PVOID KrnlBase;ULONG KrnlImageSize;// 通過特征碼獲取NtQuerySystemInformation函數地址GetKernelBase(g_Driver, &KrnlBase, &KrnlImageSize); NtQuerySystemInformation = (NTQUERYSYSTEMINFORMATION)((ULONG)MemorySearch( \bytecode,sizeof(bytecode),KrnlBase,(PVOID)((ULONG)KrnlBase+KrnlImageSize)) - 15); //DbgPrint("%x\n", ((PULONG)NtQuerySystemInformation)[0]);// 設置裸函數返回地址g_HookRetAddressNtQuerySystemInformation = (ULONG)NtQuerySystemInformation + 5;// 計算替換指令ReplaceByte[0] = 0xE9;*(PULONG)(ReplaceByte + 1) = (ULONG)HbgNtQuerySystemInformation - g_HookRetAddressNtQuerySystemInformation;PageProtectOff();memcpy(NtQuerySystemInformation, ReplaceByte, 5);PageProtectOn(); }// 卸載鉤子 void UnsetInlineHookNtQuerySystemInformation() {UCHAR ReplaceByte[5] = {0x68, 0x10, 0x02, 0x00, 0x00};PageProtectOff();memcpy(NtQuerySystemInformation, ReplaceByte, 5);PageProtectOn(); }// Hook NtQuerySystemInformation __declspec(naked) void HbgNtQuerySystemInformation(IN ULONG OpCode, IN OUT PVOID p1, IN OUT PVOID p2, IN OUT PVOID p3) {__asm{push ebp;mov ebp, esp;sub esp, 0x50;}switch (OpCode){case OP_CHECK_DEBUG:{g_IsDebug = CheckProcessDebugged(g_EprocessAddress);if (g_IsDebug){memset(p1,1,1);}goto ExitNtQuerySystemInformation;break;}}// 正常調用 NtQuerySystemInformation__asm{add esp, 0x50;pop ebp;push 0x210;jmp g_HookRetAddressNtQuerySystemInformation;} ExitNtQuerySystemInformation:__asm{add esp, 0x50;pop ebp;retn 0x10;} }總結
以上是生活随笔為你收集整理的(64)句柄表,遍历所有进程的句柄表实现反调试的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: (63)0环与3环通信非常规方式 ——
- 下一篇: (65)如何根据句柄从二级、三级结构句柄