Win64 驱动内核编程-11.回调监控进线程句柄操作
无HOOK监控进线程句柄操作
在 NT5 平台下,要监控进线程句柄的操作。
通常要挂钩三个API:NtOpenProcess、NtOpenThread、NtDuplicateObject。但是在 VISTA SP1 以及之后的系统中,我们可以完全抛弃 HOOK 方案了,转而使用一个标准的 API:ObRegisterCallbacks。下面做一个监视进线程句柄操作的程序,并实现保护名为 CALC.EXE 的进程不被结束。
首先介绍一下 ObRegisterCallbacks 这个函数。此函数的前缀是Ob,看得出它是属于对象管理器的函数,Register 是注册,Callbacks 是回调(复数)。
因此从字面意思上看,它是注册一个对象回调的意思。现在它只能监控进程对象和线程对象。但微软承诺会给此函数增加功能,实现对其它内核对象的监控。这个函数在不能合法进行内核挂钩的 WIN64 上特别有用,但是微软做了一个很扯淡的限制: 驱动程序必须有数字签名才能使用 此函数。不过国外的黑客对此限制很不爽,他们通过逆向 ObRegisterCallbacks,找到了破解这个限制的方法。经研究,内核通过 MmVerifyCallbackFunction 验证此回调是否合法,但此函数只是简单的验证了一下 DriverObject->DriverSection->Flags 的值是不是为 0x20:所以可以简单破解掉这个限制:
X32
typedef struct _LDR_DATA_TABLE_ENTRY32
{
LIST_ENTRY32 InLoadOrderLinks;
LIST_ENTRY32 InMemoryOrderLinks;
LIST_ENTRY32 InInitializationOrderLinks;
ULONG DllBase;
ULONG EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING32 FullDllName;
UNICODE_STRING32 BaseDllName;
ULONG Flags;
USHORT LoadCount;
USHORT TlsIndex;
union {
LIST_ENTRY32 HashLinks;
struct {
ULONG SectionPointer;
ULONG CheckSum;
};
};
union {
struct {
ULONG TimeDateStamp;
};
struct {
ULONG LoadedImports;
};
};
} LDR_DATA_TABLE_ENTRY32, *PLDR_DATA_TABLE_ENTRY32;
PLDR_DATA_TABLE_ENTRY32 ldr;
ldr = (PLDR_DATA_TABLE_ENTRY32)(pDriverObj->DriverSection);
ldr->Flags |= 0x20;
X64
typedef struct _LDR_DATA_TABLE_ENTRY64
{
LIST_ENTRY64 InLoadOrderLinks;
LIST_ENTRY64 InMemoryOrderLinks;
LIST_ENTRY64 InInitializationOrderLinks;
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
USHORT LoadCount;
USHORT TlsIndex;
PVOID SectionPointer;
ULONG CheckSum;
PVOID LoadedImports;
PVOID EntryPointActivationContext;
PVOID PatchInformation;
LIST_ENTRY64 ForwarderLinks;
LIST_ENTRY64 ServiceTagLinks;
LIST_ENTRY64 StaticLinks;
PVOID ContextInformation;
ULONG64 OriginalBase;
LARGE_INTEGER LoadTime;
} LDR_DATA_TABLE_ENTRY64, *PLDR_DATA_TABLE_ENTRY64;
PLDR_DATA_TABLE_ENTRY64 ldr;
ldr = (PLDR_DATA_TABLE_ENTRY64)(pDriverObj->DriverSection);
ldr->Flags |= 0x20;
上面代码如果是用于商业或者其他正当场合,注意要好好测试下,我是在网上找了到了那个结构体定义,然后自己在win7 32和win764位机器上测试了一下,没问题。小伙伴记得好好测试其他系统再用。然后就是来两个回调函数,一个是进程回调,一个是线程回调:
NTKERNELAPI PEPROCESS IoThreadToProcess(PETHREAD Thread);
NTKERNELAPI char* PsGetProcessImageFileName(PEPROCESS Process);
BOOLEAN IsProtectedProcessName(PEPROCESS eprocess)
{
char *Name=PsGetProcessImageFileName(eprocess);
if(!_stricmp("calc.exe",Name))
return TRUE;
else
return FALSE;
}
PVOID obHandle=NULL,obHandle2=NULL;
OB_PREOP_CALLBACK_STATUS preCall(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION pOperationInformation)
{
#define PROCESS_TERMINATE 0x1
HANDLE pid;
if(pOperationInformation->ObjectType!=*PsProcessType)
goto exit_sub;
pid = PsGetProcessId((PEPROCESS)pOperationInformation->Object);
DbgPrint("[OBCALLBACK][Process]PID=%ld\n",pid);
UNREFERENCED_PARAMETER(RegistrationContext);
if( IsProtectedProcessName((PEPROCESS)pOperationInformation->Object) )
{
if (pOperationInformation->Operation == OB_OPERATION_HANDLE_CREATE)
{
//pOperationInformation->Parameters->CreateHandleInformation.DesiredAccess=0;
if ((pOperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess & PROCESS_TERMINATE) == PROCESS_TERMINATE)
{
pOperationInformation->Parameters->CreateHandleInformation.DesiredAccess &= ~PROCESS_TERMINATE;
}
}
if(pOperationInformation->Operation == OB_OPERATION_HANDLE_DUPLICATE)
{
//pOperationInformation->Parameters->DuplicateHandleInformation.DesiredAccess=0;
if ((pOperationInformation->Parameters->DuplicateHandleInformation.OriginalDesiredAccess & PROCESS_TERMINATE) == PROCESS_TERMINATE)
{
pOperationInformation->Parameters->DuplicateHandleInformation.DesiredAccess &= ~PROCESS_TERMINATE;
}
}
}
exit_sub:
return OB_PREOP_SUCCESS;
}
OB_PREOP_CALLBACK_STATUS preCall2(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION pOperationInformation)
{
#define THREAD_TERMINATE2 0x1
PEPROCESS ep;
PETHREAD et;
HANDLE pid;
if(pOperationInformation->ObjectType!=*PsThreadType)
goto exit_sub;
et=(PETHREAD)pOperationInformation->Object;
ep=IoThreadToProcess(et);
pid = PsGetProcessId(ep);
DbgPrint("[OBCALLBACK][Thread]PID=%ld; TID=%ld\n",pid,PsGetThreadId(et));
UNREFERENCED_PARAMETER(RegistrationContext);
if( IsProtectedProcessName(ep) )
{
if (pOperationInformation->Operation == OB_OPERATION_HANDLE_CREATE)
{
//pOperationInformation->Parameters->CreateHandleInformation.DesiredAccess=0;
if ((pOperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess & THREAD_TERMINATE2) == THREAD_TERMINATE2)
{
pOperationInformation->Parameters->CreateHandleInformation.DesiredAccess &= ~THREAD_TERMINATE2;
}
}
if(pOperationInformation->Operation == OB_OPERATION_HANDLE_DUPLICATE)
{
//pOperationInformation->Parameters->DuplicateHandleInformation.DesiredAccess=0;
if ((pOperationInformation->Parameters->DuplicateHandleInformation.OriginalDesiredAccess & THREAD_TERMINATE2) == THREAD_TERMINATE2)
{
pOperationInformation->Parameters->DuplicateHandleInformation.DesiredAccess &= ~THREAD_TERMINATE2;
}
}
}
exit_sub:
return OB_PREOP_SUCCESS;
}
然后就是在驱动里注册/卸载这两个回调函数:
NTSTATUS ObProtectProcess(BOOLEAN Enable)
{
if(Enable==TRUE)
{
NTSTATUS obst1=0,obst2=0;
OB_CALLBACK_REGISTRATION obReg,obReg2;
OB_OPERATION_REGISTRATION opReg,opReg2;
//reg ob callback 1
memset(&obReg, 0, sizeof(obReg));
obReg.Version = ObGetFilterVersion();
obReg.OperationRegistrationCount = 1;
obReg.RegistrationContext = NULL;
RtlInitUnicodeString(&obReg.Altitude, L"321124");
obReg.OperationRegistration = &opReg;
memset(&opReg, 0, sizeof(opReg));
opReg.ObjectType = PsProcessType;
opReg.Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE;
opReg.PreOperation = (POB_PRE_OPERATION_CALLBACK)&preCall;
obst1=ObRegisterCallbacks(&obReg, &obHandle);
//reg ob callback 2
memset(&obReg2, 0, sizeof(obReg2));
obReg2.Version = ObGetFilterVersion();
obReg2.OperationRegistrationCount = 1;
obReg2.RegistrationContext = NULL;
RtlInitUnicodeString(&obReg2.Altitude, L"321125");
obReg2.OperationRegistration = &opReg2;
memset(&opReg2, 0, sizeof(opReg2));
opReg2.ObjectType = PsThreadType;
opReg2.Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE;
opReg2.PreOperation = (POB_PRE_OPERATION_CALLBACK)&preCall2;
obst1=ObRegisterCallbacks(&obReg2, &obHandle2);
return NT_SUCCESS(obst1) & NT_SUCCESS(obst2);
}
else
{
if(obHandle!=NULL)
ObUnRegisterCallbacks(obHandle);
if(obHandle2!=NULL)
ObUnRegisterCallbacks(obHandle2);
return TRUE;
}
}
执行结果:
Win64 驱动内核编程-11.回调监控进线程句柄操作的更多相关文章
- Win64 驱动内核编程-12.回调监控进线程创建和退出
回调监控进线程创建和退出 两个注册回调的函数:PsSetCreateProcessNotifyRoutine 进程回调PsSetCreateThreadNotifyRoutine 线程回调分 ...
- Win64 驱动内核编程-14.回调监控文件
回调监控文件 使用 ObRegisterCallbacks 实现保护进程,其实稍微 PATCH 下内核,这个函数还能实现文件操作监视.但可惜只能在 WIN7X64 上用.因为在 WIN7X64 上 P ...
- Win64 驱动内核编程-15.回调监控注册表
回调监控注册表 在 WIN32 平台上,监控注册表的手段通常是 SSDT HOOK.不过用 SSDT HOOK 的方式监控注册表实在是太麻烦了,要 HOOK 一大堆函数,还要处理一些 NT6 系统有而 ...
- Win64 驱动内核编程-30.枚举与删除线程回调
枚举与删除线程回调 进程回调可以监视进程的创建和退出,这个在前面的章节已经总结过了.某些游戏保护的驱动喜欢用这个函数来监视有没有黑名单中的程序运行,如果运行则阻止运行或者把游戏退出.而线程回调则通常用 ...
- Win64 驱动内核编程-13.回调监控模块加载
回调监控模块加载 模块加载包括用户层模块(.DLL)和内核模块(.SYS)的加载.传统方法要监控这两者加在必须 HOOK 好几个函数,比如 NtCreateSection 和 NtLoadDriver ...
- Win64 驱动内核编程-31.枚举与删除映像回调
枚举与删除映像回调 映像回调可以拦截 RING3 和 RING0 的映像加载.某些游戏保护会用此来拦截黑名单中的驱动加载,比如 XUETR.WIN64AST 的驱动.同理,在反游戏保护的过程中,也可以 ...
- Win64 驱动内核编程-8.内核里的其他常用
内核里的其他常用 1.遍历链表.内核里有很多数据结构,但它们并不是孤立的,内核使用双向链表把它们像糖 葫芦一样给串了起来.所以遍历双向链表能获得很多重要的内核数据.举个简单的例子,驱 动对象 Driv ...
- Win64 驱动内核编程-3.内核里使用内存
内核里使用内存 内存使用,无非就是申请.复制.设置.释放.在 C 语言里,它们对应的函数是:malloc.memcpy.memset.free:在内核编程里,他们分别对应 ExAllocatePool ...
- Win64 驱动内核编程-18.SSDT
SSDT 学习资料:http://blog.csdn.net/zfdyq0/article/details/26515019 学习资料:WIN64内核编程基础 胡文亮 SSDT(系统服务描述表),刚开 ...
随机推荐
- Java 面向对象 03
面向对象·三级 代码块的概述和分类 * A:代码块概述 * 在Java中,使用 { } 括起来的代码被称为代码块. * B:代码块分类 * 根据其位置和声明的不同,可以分为局部代码块, ...
- POJ_2065 SETI 【同余高斯消元】
一.题目 SETI 二.分析 给定一个模数,一串字符串,字符串长度为N,相当于是N个方程的答案,而这N个方程中有N个未知数,要求的就是这N个未知数的值,很显然的高斯消元,遇到模数和除法,用逆元就好. ...
- vue全家桶常用命名
1,版本查看 node -vnpm -v2,修改NPM的缓存目录和全局目录路径 D盘node目录下创建两个目录,分别是node_cache和node_global,这是用来放安装过程的缓存文件以及最终 ...
- python程序控制结构
一:顺序结构 顺序结构的程序是指程序中的所有语句都是按照书写顺序逐一执行的,但是顺序结构的程序功能有限. 二:选择结构 选择结构也称为分支结构,用于处理在程序中出现两条或更多执行路径可供选择的情况.选 ...
- 【.NET 与树莓派】小风扇模块
小风扇,其实就是一个电机(马达),然后轴子上套一个扇叶.扇叶有两叶的,也有三叶的.这种我们小时候没少玩,太阳能帽子上就有一个小风扇,骑着自行车上学,路上只要有太阳光照射到,小风扇就会转.当然还有装干电 ...
- JVM之调优及常见场景分析
JVM调优 GC调优是最后要做的工作,GC调优的目的可以总结为下面两点: 减少对象晋升到老年代的数量 减少FullGC的执行时间 通过监控排查问题及验证优化结果,可以分为: 命令监控:jps.jinf ...
- 剪切DOM节点中断transition执行【问题】
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- 一个C++引用库的头文件预编译陷阱
写在前面 老胡最近在工作中,有个场景需要使用一个第三方库,引用头文件,链接库,编译运行,一切都很正常,但是接下来就遇到了一个很诡异的问题,调用该库的中的一个对象方法为对象修改属性的时候,会影响到对象的 ...
- SSM 电影后台管理项目
SSM 电影后台管理项目 概述 通过对数据库中一张表的CRUD,将相应的操作结果渲染到页面上. 笔者通过这篇博客还原了项目(当然有一些隐藏的坑),然后将该项目上传到了Github.Gitee,在末尾会 ...
- Java例题_19 打印菱形图案
1 /*19 [程序 19 打印菱形图案] 2 题目:打印出如下图案(菱形) 3 * 4 *** 5 ***** 6 ******* 7 ***** 8 *** 9 * 10 */ 11 12 /*分 ...