一、内核对象,句柄
这次课讨论的内核对象是指创建时需要指定 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.通过句柄表项找到内核对象
下面我们编写一个程序,打开计算器的进程句柄,然后在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"
...
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 50
HBGCOMMUNICATION 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;
// 遍历 ActiveProcessLinks
do
{
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;
// 遍历 ActiveProcessLinks
do
{
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位置0
mov cr0, eax;
}
}
// 开启页保护
VOID PageProtectOn()
{
__asm
{
mov eax, cr0;
or eax, 0x10000; // WP位置1
mov 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;
}
}
---------------------
作者:hambaga
来源:优快云
原文:https://blog.youkuaiyun.com/Kwansy/article/details/109801722
版权声明:本文为作者原创文章,转载请附上博文链接!
内容解析By:优快云,CNBLOG博客文章一键转载插件