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(系统服务描述表),刚开 ...
随机推荐
- python基础学习之类
面向对象和面向过程 面向过程:以吃饭为例,即为 煮饭.洗菜.洗碗.切菜.炒菜.出锅.吃饭面向对象:目标对象做完,直接吃疑问点:1.面向对象就是把过程用函数封装起来,随时调用?:2.面向过程就是每次都把 ...
- Matplotlib图例中文乱码
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签 plt.rcParams['axes.unicode_minus']=False #用来正 ...
- 如何学习python爬虫
分享网易云课堂上一个不错的视频教学:http://study.163.com/course/courseMain.htm?courseId=1003285002
- python ORM之sqlalchemy
前沿对象关系映射ORM是在实际应用编程中常用到的技术,它在对象和关系之间建立了一条桥梁,前台的对象型数据和数据库中的关系型的数据通过这个桥梁来相互转化.简单来说就是开发人员在使用ORM模型编程时,不需 ...
- 关于Handler同步屏障你可能不知道的问题
前言 很高兴遇见你 ~ 关于handler的内容,基本每个android开发者都掌握了,网络中的优秀博客也非常多,我之前也写过一篇文章,读者感兴趣可以去看看:传送门. 这篇文章主要讲Handler中的 ...
- 2、MyBatis教程之第一个MyBatis程序
3.MyBatis第一个程序 1.搭建实验数据库 CREATE DATABASE `mybatis`; USE `mybatis`; DROP TABLE IF EXISTS `user`; CREA ...
- Rust 内置 trait :PartialEq 和 Eq
GitHub: https://github.com/storagezhang Emai: debugzhang@163.com 华为云社区: https://bbs.huaweicloud.com/ ...
- Hibernate&MyBatis
ORM程序技术 概念:ORM是对象(Object).关系(Relational).映射(Mapping)的缩写. 作用:用于替代JDBC 用法:数据库类名与表名对应:字段名和属性名对应: 优势: 更方 ...
- 用 Go + WebSocket 快速实现一个 chat 服务
前言 在 go-zero 开源之后,非常多的用户询问是否可以支持以及什么时候支持 websocket,终于在 v1.1.6 里面我们从框架层面让 websocket 的支持落地了,下面我们就以 cha ...
- java例题_40 字母字符串转数组后排序
1 /*40 [程序 40 字符串排序] 输入一个字符串数组,按照字母表的降序对这些字符串进行排序. 2 题目:字符串排序. 3 */ 4 5 /*分析 6 * 1.从键盘得到一个纯字母的字符串 7 ...