一、内核对象,句柄

这次课讨论的内核对象是指创建时需要指定 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       : 0y0

2.通过句柄表项找到内核对象(句柄数量少于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       : 0y0

0xe11a4000 低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)句柄表,遍历所有进程的句柄表实现反调试相关推荐

  1. python99乘法表四种_Python 99乘法表实现的两种方式

    #方法1 print("<<九九乘法表>>") for i in range(1,10): for j in range(1,i+1): print('%d ...

  2. 顺序表类的声明java_顺序表实现解约瑟夫环_Java

    今天我们来使用顺序表类求解约瑟夫(Josephus)环问题. 首先我闲来描述下约瑟夫环问题:古代某法官要裁决n个犯人的死刑,他有一条荒唐的法律,将犯人站成一个圆圈,从第s个人开始数起,每数到第d个犯人 ...

  3. 浅谈windows句柄表

    windows定义了很多内核对象:进程对象.线程对象.互斥量对象.信号量对象.事件对象.文件对象等等.在调用相应的函数创建这些对象后,我们都可以通过HANDLE类型的句柄来引用它们.或许你在一些书上看 ...

  4. Windows句柄表学习笔记 —— 句柄表全局句柄表

    Windows句柄表学习笔记 -- 句柄表&全局句柄表 句柄表 实验一:在WinDbg中查看句柄表 第一步:打开一个Win32窗口程序 第二步:编译并运行以下代码 第三步:查看运行结果 第四步 ...

  5. R3下,遍历所有进程的伪句柄表,关闭指定句柄

    之所以产生这个想法,是在删除文件的时候有时会提示文件被占用了,然后让我们先关闭之后在来删除,但是我怎么知道哪个进程打开了我的文件? 于是就去网上了找了一份代码然后改了改,接着来说说是怎么实现功能的.首 ...

  6. (65)如何根据句柄从二级、三级结构句柄表中找到内核对象

    一.回顾 上一篇博客介绍了如何遍历一级句柄表.一级句柄表非常简单,就是一个4KB页,最多存储512个句柄表项.如果句柄数量在 512 - 1024*512 之间,句柄表就是二级结构:如果句柄数量大于 ...

  7. UNICODE_STRING、全局句柄表、文件、注册表、LIST_ENTRY、HASH、TREE、LookAside

    本公众号分享的所有技术仅用于学习交流,请勿用于其他非法活动,如有错漏,欢迎留言交流指正 内核基本操作,数据结构 内核的基本操作 UNICODE_STRING 为什么字符串很重要 大型工程中10%~20 ...

  8. 私有句柄表(内核对象,并非用户对象),全局句柄表

    文章目录 私有句柄表 1.什么是句柄(内核对象) 2.为什么要有句柄? Windows设计理念: 3.句柄表在哪? 全局句柄表 注意 私有句柄表 1.什么是句柄(内核对象) 当一个进程创建或者打开一个 ...

  9. DuplicateHandle进程间句柄复制

    1. BOOL DuplicateHandle(HANDLE hSourceProcessHandle,HANDLE hSourceHandle,HANDLE hTargetProcessHandle ...

最新文章

  1. Stack Overflow上188万浏览量的提问:Java 到底是值传递还是引用传递?
  2. 云计算之路-阿里云上:RDS用户的烦恼
  3. html语言div什么意思,css中div是什么意思?
  4. myeclipse安装、导入一个项目、解决2个程序错误、解决运行错误、运行项目
  5. 随笔(二)-- PyCharm如何更改背景图片
  6. 入门Web前端要注意什么?要学哪些软件?
  7. 剑指offer之31-35题解
  8. Linux-- 查看文件 more与其它
  9. c语言存储学生信息并显示,C语言实现学生信息管理程序
  10. JAVA基础整理-6.Java数据类型
  11. ZendFramework多模块配置
  12. 读书笔记--对象、实例、原型、继承 1
  13. 手把手教你使用XUI的正确姿势
  14. 毕业论文页码及目录设置方法
  15. vue将图片保存到相册_vue 图片下载到本地,图片保存到本地
  16. rstudio 连接mysql_Rstudio ODBC 连接MySQL
  17. 大于23的男生女生都该看.看完你会变一个人【转】
  18. 深度神经网络之Keras(三)——正则化、超参数调优和学习方向
  19. <span>的宽高到底是多少?
  20. L3-001 凑零钱 (30 分)

热门文章

  1. html5拍照上传 java_如何使用HTML5实现拍照上传应用
  2. 数据传输完整性_生产系统数据完整性事件常见指标(下)
  3. string替换_GEE数据类型—String,Number
  4. Excel:Excel使用技巧经验总结之(利用Excel自带功能统计各个字段不同类别及其个数并进行图表可视化+非编程实现)图文教程之详细攻略
  5. AI:人工智能实践六大场景(金融信用违约、反欺诈模型、客户偏好洞察、智能推荐、精准营销、客户流失管理)及其对应常用机器学习算法经验总结(不断更新)
  6. AI:2020年6月16日晚20点陆奇博士演讲《正视挑战把握创业创新机会》
  7. 成功解决Error:invalid character in identifier
  8. EL之Boosting之GB(DTR):利用梯度提升法解决回归(对多变量的数据集+实数值评分预测)问题
  9. android 图片压缩
  10. BZOJ2490 Zombie’s Treasure Chest