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(系统服务描述表),刚开 ...
随机推荐
- 设计模式之简单工厂模式(Simple Factory Pattern)
一.简单工厂模式的由来 所有设计模式都是为解决某类问题而产生的,那么简单工厂模式是为解决什么问题呢?我们假设有以下业务场景: 在一个学生选课系统中,文科生用户选课时,我们要获得文科生的所有课程列表:理 ...
- spring事务:事务控制方式,使用AOP控制事务,七种事务传播行为,声明事务,模板对象,模板对象原理分析
知识点梳理 课堂讲义 1)事务回顾 1.1)什么是事务-视频01 事务可以看做是一次大的活动,它由不同的小活动组成,这些活动要么全部成功,要么全部失败. 1.2)事务的作用 事务特征(ACID) 原子 ...
- 001-HashMap源码分析
HashMap源码分析 哈希表(hash table)也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技术(比如 memcached)的核心其实就是在内存中维护一张大的哈希表. 一.什 ...
- CSS水平布局
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="U ...
- 《Selenium自动化测试实战:基于Python》之 Selenium IDE插件的安装与使用
第3章 Selenium IDE插件的安装与使用 京东:https://item.jd.com/13123910.html 当当:http://product.dangdang.com/292045 ...
- 20184307 实验三 Socket编程技术
实验三 Socket编程技术 学号 20184307 2019-2020-2 <Python程序设计>实验三报告 课程:<Python程序设计> 班级:1843 姓名:章森洋 ...
- 学《跟我一起写Makefile》笔记发博词
目录 笔记发博词 参考 笔记发博词 本系列笔记主要记录学了<跟我一起写Makefile>后的一些笔记 由于<跟我一起写Makefile>已经写得很详细了,所以我只是提取其中重要 ...
- 经过努力+作弊,我终于完成了leetcode通过率最低的一道题
前两天刷leetcode的时候,突发奇想,leetcode中最难的一道题是什么样子的呢? 于是,我就将所有题目(https://leetcode-cn.com/problemset/all/ )按照通 ...
- 高可用负载均衡 haproxy+keepalived
服务器 20.0.0.206 10.0.0.206 bs-hk-hk01 高可用负载均衡节点 2c2g 20.0.0.207 10.0.0.207 bs-hk-hk02 高可用负载均衡节点 ...
- [游记]2020/CSP - S总结
2020 / C S P − S 总 结 2020/CSP - S总结 2020/CSP−S总结 这年的 C S P CSP CSP考的不是很理想,本来稳进的 C S P − J CSP-J CSP− ...