Windows内核开发-10-监听对象

Windows内核除了可以监听进程,线程、dll还可以监听特定的对象和注册表。这里先讲一下监听对象。

监听对象

内核提供了一种可以监听对特定的对象类型的句柄进行打开或复制的机制。正式支持的对象类型有进程和线程,Windows10还支持一个桌面对象(桌面对象这个先不考虑)。

这个和前面的监听进程线程以及模块加载是有区别的。这个是相对于对象的句柄的,比如说一个进程的句柄,线程的句柄,别的进程通过关闭这个进程的句柄来关闭这个进程这种。是这个意思。

这里也有很多和前面相似的地方。

比如说,首先得注册通知。

注册对象通知

注册对象通知的主要API:

NTSTATUS ObRegisterCallbacks(
 POB_CALLBACK_REGISTRATION CallbackRegistration,
 PVOID                     *RegistrationHandle
);

如果采用这个API,必须在链接是开启/integritycheck

void ObUnRegisterCallbacks(
 PVOID RegistrationHandle
);//关闭注册的API

整体说明下这两个API如何使用:

首先有一个公用的参数 RegistrationHandle,这个参数在注册的API里面是一个输出参数,然后在取消注册里面是一个输入参数,相当于这个参数会和注册的对象进行一个绑定,通过注册API会给它赋一个值,然后取消注册API会通过它的值,来唯一标识一个对象进行取消注册这样子。

比较重要的是注册API的第一个参数:CallbackRegistration。

typedef struct _OB_CALLBACK_REGISTRATION {
 USHORT                    Version;
 USHORT                    OperationRegistrationCount;
 UNICODE_STRING            Altitude;
 PVOID                     RegistrationContext;
 OB_OPERATION_REGISTRATION *OperationRegistration;
} OB_CALLBACK_REGISTRATION, *POB_CALLBACK_REGISTRATION;

这个结构体是必须在注册前先初始化的。

_OB_CALLBACK_REGISTRATION

这个结构体比较重要,需要展开讲讲。

字段 含义
Version 必须为设置为OB_FLT_REGISTRATION_VERSION
OperationRegistrationCount 被注册的数量,指定了OperationRegistration指向的结构体数量。
Altitude 这个高度值,用来标榜被调用的顺序,值越高在调用链中就越早。但是不能和之前的值有重复值,这个其实没啥用,最主要的是防止重复了。这个值是一个无限精度的十进制数字,所以小数或者随机数都可以,最主要的别重复了。一般会多写点,比如说 123145,111111这种,就很大程度上可以规避重复。
RegistrationContext 这个值由系统和驱动自动赋值,传个NULL就行
OperationRegistration 这个值比较重要且复杂,单独解释。

OperationRegistration

这个结构体用来具体标榜要通知的内容的信息:

typedef struct _OB_OPERATION_REGISTRATION {
 POBJECT_TYPE                *ObjectType;
 OB_OPERATION                Operations;
 POB_PRE_OPERATION_CALLBACK  PreOperation;
 POB_POST_OPERATION_CALLBACK PostOperation;
} OB_OPERATION_REGISTRATION, *POB_OPERATION_REGISTRATION;
字段 内容
ObjectType 标记要通知的对象的类型:进程、线程、桌面。PsProcessType PsThreadType ExDesktopObjectType。
Operations 标记要做的操作,打开创建还是复制。OB_OPERATION_HANDLE_CREATE OB_OPERATION_HANDLE_DUPLICATE
PreOperation 一个函数指针PobPreOperationCallback,在系统调用涉及到对象的时候之前就采用这个回调函数。
PostOperation 一个函数指针PobPreOperationCallback,在系统调用涉及到对象的时候之后就采用这个回调函数。
POB_PRE_OPERATION_CALLBACK PobPreOperationCallback;

OB_PREOP_CALLBACK_STATUS PobPreOperationCallback(
 PVOID RegistrationContext,
 POB_PRE_OPERATION_INFORMATION OperationInformation
)
{...}

POB_POST_OPERATION_CALLBACK PobPostOperationCallback;

void PobPostOperationCallback(
 PVOID RegistrationContext,
 POB_POST_OPERATION_INFORMATION OperationInformation
)
{...}

这里面的RegistrationContext是上下文寄存器环境OperationInformation是记录着一些相关的对象信息。

这个OperationInformation大同小异,比如说调用前的OperationInformation就是这个结构体:

typedef struct _OB_PRE_OPERATION_INFORMATION {
OB_OPERATION                 Operation;
union {
  ULONG Flags;
  struct {
    ULONG KernelHandle : 1;
    ULONG Reserved : 31;
  };
};
PVOID                       Object;
POBJECT_TYPE                 ObjectType;
PVOID                       CallContext;
POB_PRE_OPERATION_PARAMETERS Parameters;
} OB_PRE_OPERATION_INFORMATION, *POB_PRE_OPERATION_INFORMATION;
字段 意义
Operation 操作类型
KernelHandle 是否是内核对象
Object 进程就是EPROCESS,线程就是PETHREAD
ObjectType 对象的类型,和前面一样
CallContext 驱动自动赋值,不是很重要,这里用不到
Parameters 基于操作的附加信息

针对parameter又有扩展内容:

typedef union _OB_PRE_OPERATION_PARAMETERS {
 OB_PRE_CREATE_HANDLE_INFORMATION    CreateHandleInformation;
 OB_PRE_DUPLICATE_HANDLE_INFORMATION DuplicateHandleInformation;
} OB_PRE_OPERATION_PARAMETERS, *POB_PRE_OPERATION_PARAMETERS;

然后这里的CreateHandleInformation我们用得上:

typedef struct _OB_PRE_CREATE_HANDLE_INFORMATION {
 ACCESS_MASK DesiredAccess;
 ACCESS_MASK OriginalDesiredAccess;
} OB_PRE_CREATE_HANDLE_INFORMATION, *POB_PRE_CREATE_HANDLE_INFORMATION;

DesiredAccess表示的是访问掩码,也就是获得对进程操作的权限,我们只要在这里把关闭进程的权限给删除了就好了。

实例代码:

由于各种API啊,各种结构体啊,调用起来层次复杂,光这样讲肯定是少了很多东西,用一个实际场景来讲会更好。

这里提供一个保护进程的思想,就是通过进程的PID来进行保护,删除除掉别的进程打开保护进程的句柄时的关闭权限。就行了。

思路的话就是通过调用前,判断是不是我们保护的进程,如果是就不让关闭了,删除掉PROCESS_TERMINATE权限。,其实比较简单。

整个驱动的代码我写好打包上github了:

https://github.com/skrandy/ProtectYourProcess

最终结果:

添加了保护后,再用任务管理器就无法关闭了。

小结

监听对象,通过对其它进程对别的进程、线程以及桌面对象的处理而进行一个处理。说起来有的绕口了,就是说比如说正常的用r3的API来打开一个进程,肯定是会有权限,然后可以再内核中添加保护代码,当打开你的进程句柄时,关闭掉一些权限,比如说这里的关闭权限,那么正常的API关闭流程,比如说OpenProcess,然后CloseProcess这种就无法关闭了。

Windows内核开发-10-监听对象的更多相关文章

  1. Windows内核开发-4-内核编程基础

    Windows内核开发-4-内核编程基础 这里会构建一个简单但是完整的驱动程序和一个客户端,部署内核执行一些平时user下无法执行的操作. 将通过以下内容进行讲解: 1 介绍 2 驱动初始化 3 Cr ...

  2. Windows内核开发-6-内核机制 Kernel Mechanisms

    Windows内核开发-6-内核机制 Kernel Mechanisms 一部分Windows的内核机制对于驱动开发很有帮助,还有一部分对于内核理解和调试也很有帮助. Interrupt Reques ...

  3. Windows内核基础知识-8-监听进程、线程和模块

    Windows内核基础知识-8-监听进程.线程和模块 Windows内核有一种强大的机制,可以在重大事件发送时得到通知,比如这里的进程.线程和模块加载通知. 本次采用链表+自动快速互斥体来实现内核的主 ...

  4. AngularJS - Watch 监听对象

    <body> <div ng-app="myApp"> <div ng-controller="firstController"& ...

  5. vue 监听对象里的特定数据

    vue  监听对象里的特定数据变化 通常是这样写的,只能监听某一个特定数据 watch: { params: function(val) { console.log(val) this.$ajax.g ...

  6. Windows内核开发-3-内核编程基础

    Windows内核开发-3-内核编程基础 这里会深入讲解kernel内核的API.结构体.和一些定义.考察代码在内核驱动中运行的机制.最后把所有知识合在一起写一个有用的驱动. 本章学习要点: 1:通用 ...

  7. 在vue中使用watch监听对象或数组

    最近发现在vue中使用watch监听对象或者数组时,当数组或者对象只是单一的值改变时,并不会出发watch中的事件. 在找问题过程中,发现当数组使用push一类的方法时,会触发watch,如果只是单一 ...

  8. Object.defineProperty 监听对象属性变化

    <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8&quo ...

  9. Windows平台下Oracle监听服务启动过程中日志输出

    Windows平台下Oracle监听服务启动过程中日志输出记录. 日志目录:D:\app\Administrator\diag\tnslsnr\WIN-RU03CB21QGA\listener\tra ...

随机推荐

  1. 聊聊spring事务失效的12种场景,太坑了

    前言 对于从事java开发工作的同学来说,spring的事务肯定再熟悉不过了. 在某些业务场景下,如果一个请求中,需要同时写入多张表的数据.为了保证操作的原子性(要么同时成功,要么同时失败),避免数据 ...

  2. Linux 三剑客(1)- grep

    作用 在文件或标准输入中,通过正则表达式查找对应的内容 语法格式 grep [选项]... PATTERN [FILE]... grep的常用选项参数 参数选项 描述 -G 默认值 -F 相当于使用f ...

  3. 【HMS Core 6.0全球上线】Toolkit,您的智能辅助编程好帮手

    HMS Core 6.0已于7月15日全球上线.本次版本中,华为HMS Toolkit向广大开发者推出了智能辅助编程助手SmartCoder,帮助开发者轻松高效地集成HMS Core,开发新功能,创建 ...

  4. C# Dapper基本三层架构使用 (三、DAL)

    数据访问层(DAL),主要是存放对数据类的访问,即对数据库的添加.删除.修改.更新等基本操作 首先需要在UI层App.Config配置文件中增加连接字符串,如下所示 <connectionStr ...

  5. 部署yum仓库以及NFS共享服务

    目录: 一.YUM概述 二.准备安装源 三.访问YUM仓库 四.本地YUM仓库 五.YUM工具概述 六.软件包查询.安装.卸载 七.NFS共享 一.YUM概述 YUM(Yellow dog Updat ...

  6. SQLSERVER存储过程基础

    SQLSERVER存储过程基础 1.声明变量 DECLARE     @F001  SMALLINT,  (三元素,声明declare+变量名+类型) @F002  INTEGER, @F003  V ...

  7. 动态规划精讲(一)LC 最长递增子序列的个数

    最长递增子序列的个数 给定一个未排序的整数数组,找到最长递增子序列的个数. 示例 1: 输入: [1,3,5,4,7]输出: 2解释: 有两个最长递增子序列,分别是 [1, 3, 4, 7] 和[1, ...

  8. TP5用join进行查询出来后的循环id都是一样的

    这是因为join将两个表的所有字段都查询,id冲突了,所以需要设置名,或指定选择一个表的id 用field('a.*')

  9. update修改某个字段的值

    ---恢复内容开始--- 例:给表名 ecs_article中 content字段 的 /tianyuan 替换成 11  加where条件:UPDATE ecs_article set conten ...

  10. 一文让你彻底搞懂 vue-Router

    路由是网络工程里面的专业术语,就是通过互联把信息从源地址传输到目的地址的活动.本质上就是一种对应关系.分为前端路由和后端路由. 后端路由: URL 的请求地址与服务器上的资源对应,根据不同的请求地址返 ...