对付DNF硬件断点的NtGetContextThread的写法

本文介绍了一种绕过游戏反作弊系统TP的技术实现,通过重写NtGetContextThread函数来隐藏特定线程的硬件断点信息,并在游戏进程中进行应用。文章详细展示了如何查找目标函数地址、实现函数钩子、维护断点信息链表等关键步骤。
摘要由CSDN通过智能技术生成
初始化部分 
//NtGetContextThread(对付硬件断点) 
// HookAddr_NtGetContextThread = FindHookNtGetContextThread(); 
// dprintf("[ByPassTp] HookAddr_NtGetContextThread = %08X\r\n",HookAddr_NtGetContextThread); 
// JmpHookInitialFun(NtGetContextThread); 


挂钩部分 
//NtGetContextThreadStart(); 

恢复部分 
//NtGetContextThreadStop(); 

//*****************H部分****************************************************************************************** 

#pragma once 

#include "struct.h" 
#include "Common.h" 

typedef struct _THREADCONTEXTLINK 
{ 
LIST_ENTRY ListEntry; //主要是为了把数据连接到一起 
DWORD ThreadHandle; 
DWORD Dr0Seg; 
DWORD Dr1Seg; 
DWORD Dr2Seg; 
DWORD Dr3Seg; 
DWORD Dr6Seg; 
DWORD Dr7Seg; 
}THREADCONTEXTLINK,*PTHREADCONTEXTLINK; 

VOID ShowDrRegInfo(PCONTEXT pThreadContext); 
VOID ClearDrReg(PCONTEXT pThreadContext); 
VOID AddLinkTable(DWORD ThreadHandle, PCONTEXT pThreadContext); 
VOID RecoveryDrReg(DWORD ThreadHandle,PCONTEXT pThreadContext); 
DWORD ExsitsLinkTable(DWORD ThreadHandle); 

extern DWORD HookAddr_NtGetContextThread; 
DWORD FindHookNtGetContextThread(); 
VOID __stdcall HookFunc_NtGetContextThread();

//******************CPP部分*************************************************************************************** 

#ifdef __cplusplus 
extern "C" { 
#endif 
#include <ntddk.h> 
#include <string.h> 
#ifdef __cplusplus 
}; // extern "C" 
#endif 

#include "_NtGetContextThread.h" 

DWORD ThreadHandle=0; 
PCONTEXT pThreadContext =0; 
LIST_ENTRY linkListHead; // 链表 
KSPIN_LOCK spin_lock; // 自旋锁 


//----------------- 
// 后继 
//----------------- 
// 前驱 
//----------------- 
// 数据域 
// ThreadHandle 
// Dr0 
// Dr1 
// ..... 
// Dr7 
//----------------- 
DWORD HookAddr_NtGetContextThread = 0; 
//NtGetContextThread(Thread+0x8,ThreadContext+0xC) 
//获得调用者的EPROCESS 
PEPROCESS ProcessEPROCESSForGetContextThread = NULL; //保存访问者的EPROCESS 
ANSI_STRING CurrentProcessNameForGetContextThread,GameProcessNameForGetContextThread; //保存进程名称 
__declspec(naked) VOID __stdcall HookFunc_NtGetContextThread() 
{ 
__asm 
{ 
pushad 
mov edx,DWORD ptr[ebp+0x8] //线程句柄 
mov ThreadHandle,edx 
mov ebx,DWORD ptr[ebp+0xC] //CONTEXT指针 
mov pThreadContext,ebx 
popad 
} 

ProcessEPROCESSForGetContextThread = IoGetCurrentProcess(); //-->EPROCESS 
//将调用者的进程名保存到CurrentProcessName中 
//dprintf("[ByPassTp] 调用进程:%s\r\n",(char *)((DWORD)ProcessEPROCESSForOpenProcess+0x174)); 
RtlInitAnsiString(&CurrentProcessNameForGetContextThread,(char *)((DWORD)ProcessEPROCESSForGetContextThread+0x174)); 
//将我们要比对的进程名放入GameProcessName 
RtlInitAnsiString(&GameProcessNameForGetContextThread,"DNF.exe"); 
if (RtlCompareString(&CurrentProcessNameForGetContextThread, &GameProcessNameForGetContextThread,TRUE) == 0) 
{ 

dprintf("[ByPassTp] DnfThreadHandle = %08X\n",ThreadHandle); 
dprintf("[ByPassTp] DnfpThreadContext = %08X\n",pThreadContext); 
ShowDrRegInfo(pThreadContext); 
AddLinkTable(ThreadHandle,pThreadContext); 
ClearDrReg(pThreadContext); 
dprintf("\n==============================================\n"); 
}else 
{ 
dprintf("[ByPassTp] %s 访问NtGetContextThread \n",(char *)((DWORD)ProcessEPROCESSForGetContextThread+0x174)); 
//RecoveryDrReg(ThreadHandle,pThreadContext); 
} 
//执行被覆盖的代码 
__asm 
{ 
mov eax, esi 
pop esi 
leave 
retn 8 
} 

} 

//恢复被隐藏的Dr寄存器 
VOID RecoveryDrReg(DWORD ThreadHandle,PCONTEXT pThreadContext) 
{ 
if (IsListEmpty(&linkListHead)) 
{ 
//链表为空 
dprintf("[ByPassTp] 链表为空!\n"); 
return; 
} 
PTHREADCONTEXTLINK pTarget = NULL; // 节点数据 
PLIST_ENTRY pListWalker = &linkListHead; //pListWalker 的节点的头部地址 
pTarget = CONTAINING_RECORD(&linkListHead, //用这个宏,可以得到节点的头部地址 
THREADCONTEXTLINK, 
ListEntry); 
dprintf("链表头 = %08X\n",pTarget); 
dprintf("线程句柄 = %08X\n",ThreadHandle); 
while(pTarget !=NULL) 
{ 
pListWalker = pListWalker->Blink; 
pTarget = CONTAINING_RECORD(pListWalker,THREADCONTEXTLINK,ListEntry); //用这个宏,可以得到包含着 
if (pTarget->ThreadHandle == ThreadHandle) 
{ 
pTarget->Dr0Seg = pThreadContext->Dr0; 
pTarget->Dr1Seg = pThreadContext->Dr1; 
pTarget->Dr2Seg = pThreadContext->Dr2; 
pTarget->Dr3Seg = pThreadContext->Dr3; 
pTarget->Dr6Seg = pThreadContext->Dr6; 
pTarget->Dr7Seg = pThreadContext->Dr7; 
break; 
} 
} 
return; 
} 

VOID AddLinkTable(DWORD ThreadHandle, PCONTEXT pThreadContext) 
{ 
PTHREADCONTEXTLINK pData = NULL; // 节点数据 
KIRQL irql; // 中断级别 

if (IsListEmpty(&linkListHead)) 
{ 
//如果链表为空 
KeInitializeSpinLock(&spin_lock); 
// 锁定,注意这里的irql是个指针 
KeAcquireSpinLock(&spin_lock, &irql); 
pData = (PTHREADCONTEXTLINK)ExAllocatePool(PagedPool,sizeof(THREADCONTEXTLINK)); 
if (NULL == pData) return; 
//拷贝第一个元素 
pData->ThreadHandle = ThreadHandle; 
//拷贝Dr寄存器的值 
pData->Dr0Seg = pThreadContext->Dr0; 
pData->Dr1Seg = pThreadContext->Dr1; 
pData->Dr2Seg = pThreadContext->Dr2; 
pData->Dr3Seg = pThreadContext->Dr3; 
pData->Dr6Seg = pThreadContext->Dr6; 
pData->Dr7Seg = pThreadContext->Dr7; 
//如果为空就插到头 
InsertHeadList(&linkListHead,&pData->ListEntry); 
// 解锁,注意这里的irql不是指针 
KeReleaseSpinLock(&spin_lock, irql); 
return; 
}else 
{ 
//如果不为空,先判断是不是存在了 
DWORD Value = ExsitsLinkTable(ThreadHandle); 
if (Value > 1) 
{ 
dprintf("存在了,不用插入了!"); 
KeInitializeSpinLock(&spin_lock); 
// 锁定,注意这里的irql是个指针 
KeAcquireSpinLock(&spin_lock, &irql); 
//拷贝Dr寄存器的值到链表元素里(更新Dr数据) 
((PTHREADCONTEXTLINK)Value)->Dr0Seg = pThreadContext->Dr0; 
((PTHREADCONTEXTLINK)Value)->Dr1Seg = pThreadContext->Dr1; 
((PTHREADCONTEXTLINK)Value)->Dr2Seg = pThreadContext->Dr2; 
((PTHREADCONTEXTLINK)Value)->Dr3Seg = pThreadContext->Dr3; 
((PTHREADCONTEXTLINK)Value)->Dr6Seg = pThreadContext->Dr6; 
((PTHREADCONTEXTLINK)Value)->Dr7Seg = pThreadContext->Dr7; 
KeReleaseSpinLock(&spin_lock, irql); 
return; 
}else 
{ 
KeInitializeSpinLock(&spin_lock); 
// 锁定,注意这里的irql是个指针 
KeAcquireSpinLock(&spin_lock, &irql); 
pData = (PTHREADCONTEXTLINK)ExAllocatePool(PagedPool,sizeof(THREADCONTEXTLINK)); 
if (NULL == pData) return; 
//拷贝第一个元素 
pData->ThreadHandle = ThreadHandle; 
//拷贝Dr寄存器的值 
pData->Dr0Seg = pThreadContext->Dr0; 
pData->Dr1Seg = pThreadContext->Dr1; 
pData->Dr2Seg = pThreadContext->Dr2; 
pData->Dr3Seg = pThreadContext->Dr3; 
pData->Dr6Seg = pThreadContext->Dr6; 
pData->Dr7Seg = pThreadContext->Dr7; 
//如果不为空就插到尾 
InsertTailList(&linkListHead,&pData->ListEntry); 
// 解锁,注意这里的irql不是指针 
KeReleaseSpinLock(&spin_lock, irql); 
return; 
} 
} 
} 


DWORD ExsitsLinkTable(DWORD ThreadHandle) 
{ 
if (IsListEmpty(&linkListHead)) 
{ 
//链表为空 
dprintf("[ByPassTp] 链表为空!\n"); 
return 1; 
} 

PTHREADCONTEXTLINK pTarget = NULL; // 节点数据 
PLIST_ENTRY pListWalker = &linkListHead; //pListWalker 的节点的头部地址 
pTarget = CONTAINING_RECORD(&linkListHead, //用这个宏,可以得到节点的头部地址 
THREADCONTEXTLINK, 
ListEntry); 
dprintf("链表头 = %08X\n",pTarget); 
while(pTarget !=NULL) 
{ 
pListWalker = pListWalker->Blink; 
pTarget = CONTAINING_RECORD(pListWalker,THREADCONTEXTLINK,ListEntry); //用这个宏,可以得到包含着 
if (pTarget->ThreadHandle == ThreadHandle) 
{ 
//存在了 
dprintf("元素地址 = %08X\n",pTarget); 
return (DWORD)pTarget; 
} 
} 
return 0; 
} 

VOID ShowDrRegInfo(PCONTEXT pThreadContext) 
{ 
dprintf("[ByPassTp] Dr0 = %08X\n",pThreadContext->Dr0); 
dprintf("[ByPassTp] Dr1 = %08X\n",pThreadContext->Dr1); 
dprintf("[ByPassTp] Dr2 = %08X\n",pThreadContext->Dr2); 
dprintf("[ByPassTp] Dr3 = %08X\n",pThreadContext->Dr3); 
dprintf("[ByPassTp] Dr6 = %08X\n",pThreadContext->Dr6); 
dprintf("[ByPassTp] Dr7 = %08X\n",pThreadContext->Dr7); 
} 

DWORD FindHookNtGetContextThread() 
{ 
// 初始化 
InitializeListHead(&linkListHead); 
dprintf("[ByPassTp] 链表头 = %08X\r\n",linkListHead); 
dprintf("[ByPassTp] 链表初始化完成!\r\n"); 
//----------------------------------- 
BYTE Characteristic0 = 0x8B, 
Characteristic1 = 0xC6, //+1 
Characteristic2 = 0x5E, //+2 
Characteristic3 = 0xC9, //+3 
Characteristic4 = 0xC2, //+4 
Characteristic5 = 0x08, //+5 
Characteristic6 = 0x00, //+6 
Characteristic7 = 0xCC; //+7 
//----------------------------------- 
BYTE *FindPointer = NULL; 
DWORD HookNtGetContextThreadAddress=0; 
__try 
{ 
//将FindPointer指向NtOpenProcess函数开始处 
FindPointer = (PBYTE)FindInKeServiceDescriptorTable(0x55); 
dprintf("[ByPassTp] NtGetContextThread = %08X\n",FindPointer); 
//遍历找特征码 
for (DWORD i=0;i<0x100;i++) 
{ 
if((*(FindPointer)==Characteristic0)&& 
(*(FindPointer+1)==Characteristic1)&& 
(*(FindPointer+2)==Characteristic2)&& 
(*(FindPointer+3)==Characteristic3)&& 
(*(FindPointer+4)==Characteristic4)&& 
(*(FindPointer+5)==Characteristic5)&& 
(*(FindPointer+6)==Characteristic6)&& 
(*(FindPointer+7)==Characteristic7)) 
{ 
HookNtGetContextThreadAddress = (DWORD)FindPointer; 
dprintf("[ByPassTp] HookNtGetContextThreadAddress = %08X\r\n",HookNtGetContextThreadAddress); 
break; 
} 
FindPointer++;//推进指针 
} 
} 
__except(EXCEPTION_EXECUTE_HANDLER) 
{ 
dprintf("[ByPassTp] FindHookNtGetContextThread中发生异常!\r\n"); 
dprintf("[ByPassTp] 程序将继续运行\r\n"); 
} 
return HookNtGetContextThreadAddress; 
} 

VOID ClearDrReg(PCONTEXT pThreadContext) 
{ 
dprintf("\n-------------ClearDrRegBegin-------------\n"); 
pThreadContext->Dr0 = 0; 
pThreadContext->Dr1 = 0; 
pThreadContext->Dr2 = 0; 
pThreadContext->Dr3 = 0; 
pThreadContext->Dr6 = 0; 
pThreadContext->Dr7 = 0; 
ShowDrRegInfo(pThreadContext); 
dprintf("\n-------------ClearDrRegEnd-------------\n"); 
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值