Win64 驱动内核编程-30.枚举与删除线程回调

枚举与删除线程回调

    进程回调可以监视进程的创建和退出,这个在前面的章节已经总结过了。某些游戏保护的驱动喜欢用这个函数来监视有没有黑名单中的程序运行,如果运行则阻止运行或者把游戏退出。而线程回调则通常用来监控远程线程的建立,如果发现有远程线程注入到了游戏进程里,则马上把游戏退出。现在来详细讲解如何绕过这个两个监控。

    我们注册的进程回调,会存储在一个名为 PspCreateProcessNotifyRoutine 的数组里。

PspCreateProcessNotifyRoutine 可以理解成一个 PVOID 数组,它记录了系统里所有进程回调的地址。这个数组最大长度是 64*sizeof(PVOID)。所以枚举进程回调的思路如下:找到这个数组的地址,然后解密数组的数据,得到所有回调的地址(这个数组记录的数据并不是回调的 地 址 , 而 是 经 过 加 密 地 址 , 需 要 解 密 才 行 )。 枚 举 线 程 回 调 同 理 , 要 找 到PspCreateThreadNotifyRoutine 的地址(这个数组最大长度也是 64*sizeof(PVOID)),然后解密数据,并把解密后的地址打印出来。

    至于怎么处理这些回调就简单了。可以使用标准函数(PsSetCreateProcessNotifyRoutine、PsRemoveCreateThreadNotifyRoutine)将其摘掉,也可以直接在回调函数首地址写入 RET 把回调函数废掉。

    首先要获得 PspCreateProcessNotifyRoutine 的地址。PspCreateProcessNotifyRoutine 在PspSetCreateProcessNotifyRoutine 函数里出现了。而 PspSetCreateProcessNotifyRoutine 则在PsSetCreateProcessNotifyRoutine 中被调用(注意前一个是 PspXXX,后一个是 PsXXX)。找到PspSetCreateProcessNotifyRoutine 之后,再匹配特征码:

 Win64 驱动内核编程-30.枚举与删除线程回调_第1张图片

 Win64 驱动内核编程-30.枚举与删除线程回调_第2张图片

    于是我们根据特征码写出了以下代码(仅在 WIN7X64 上有效,WIN8、8.1 需要自己重新

定义特征码):

 

ULONG64 FindPspCreateProcessNotifyRoutine()
{
LONG	OffsetAddr=0;
ULONG64	i=0,pCheckArea=0;
UNICODE_STRING	unstrFunc;
//获得PsSetCreateProcessNotifyRoutine的地址
RtlInitUnicodeString(&unstrFunc, L"PsSetCreateProcessNotifyRoutine");
pCheckArea = (ULONG64)MmGetSystemRoutineAddress (&unstrFunc);
//获得PspSetCreateProcessNotifyRoutine的地址
memcpy(&OffsetAddr,(PUCHAR)pCheckArea+4,4);
pCheckArea=(pCheckArea+3)+5+OffsetAddr;
DbgPrint("PspSetCreateProcessNotifyRoutine: %llx",pCheckArea);
//获得PspCreateProcessNotifyRoutine的地址
for(i=pCheckArea;i

    找到了 PspCreateProcessNotifyRoutine,枚举操作就好办了。需要说明的是,在PspCreateProcessNotifyRoutine 里的数据竟然被加密了,需要把数组的值和 0xfffffffffffffff8进行“与”位运算才行:

 

 

 

找线程的同理:

PspCreateThreadNotifyRoutine -> 

PsSetCreateThreadNotifyRoutine ->

PspCreateThreadNotifyRoutine

 

执行结果如下(干净win7系统没有线程回调,特意注册了两个):

 

void EnumCreateProcessNotify()
{
int i=0;
BOOLEAN b;
ULONG64	NotifyAddr=0,MagicPtr=0;
ULONG64	PspCreateProcessNotifyRoutine=FindPspCreateProcessNotifyRoutine();
DbgPrint("PspCreateProcessNotifyRoutine: %llx",PspCreateProcessNotifyRoutine);
if(!PspCreateProcessNotifyRoutine)
return;
for(i=0;i<64;i++)
{
MagicPtr=PspCreateProcessNotifyRoutine+i*8;
NotifyAddr=*(PULONG64)(MagicPtr);
if(MmIsAddressValid((PVOID)NotifyAddr) && NotifyAddr!=0)
{
NotifyAddr=*(PULONG64)(NotifyAddr & 0xfffffffffffffff8);
DbgPrint("[CreateProcess]%llx",NotifyAddr);
}
}
}


代码整理: 进程

 

 

ULONG64 FindPspCreateProcessNotifyRoutine()
{
LONG	OffsetAddr=0;
ULONG64	i=0,pCheckArea=0;
UNICODE_STRING	unstrFunc;
//获得PsSetCreateProcessNotifyRoutine的地址
RtlInitUnicodeString(&unstrFunc, L"PsSetCreateProcessNotifyRoutine");
pCheckArea = (ULONG64)MmGetSystemRoutineAddress (&unstrFunc);
//获得PspSetCreateProcessNotifyRoutine的地址
memcpy(&OffsetAddr,(PUCHAR)pCheckArea+4,4);
pCheckArea=(pCheckArea+3)+5+OffsetAddr;
DbgPrint("PspSetCreateProcessNotifyRoutine: %llx",pCheckArea);
//获得PspCreateProcessNotifyRoutine的地址
for(i=pCheckArea;i


线程(包括创建线程回调测试代码):

 

 

void CreateThreadNotify1
(
    IN HANDLE  ProcessId,
    IN HANDLE  ThreadId,
    IN BOOLEAN  Create
)
{
DbgPrint("CreateThreadNotify1\n");
}
 
void CreateThreadNotify2
(
    IN HANDLE  ProcessId,
    IN HANDLE  ThreadId,
    IN BOOLEAN  Create
)
{
DbgPrint("CreateThreadNotify2\n");
}
 
void CreateThreadNotifyTest(BOOLEAN Remove)
{
if(!Remove)
{
PsSetCreateThreadNotifyRoutine(CreateThreadNotify1);
PsSetCreateThreadNotifyRoutine(CreateThreadNotify2);
}
else
{
PsRemoveCreateThreadNotifyRoutine(CreateThreadNotify1);
PsRemoveCreateThreadNotifyRoutine(CreateThreadNotify2);
}
}
 
ULONG64 FindPspCreateThreadNotifyRoutine()
{
ULONG64	i=0,pCheckArea=0;
UNICODE_STRING	unstrFunc;
RtlInitUnicodeString(&unstrFunc, L"PsSetCreateThreadNotifyRoutine");
pCheckArea = (ULONG64)MmGetSystemRoutineAddress (&unstrFunc);
DbgPrint("PsSetCreateThreadNotifyRoutine: %llx",pCheckArea);
for(i=pCheckArea;i

宋孖健,13

 

 

 

 

你可能感兴趣的:(驱动内核编程)