windows环境下的自保护探究

本文探讨了64位Windows系统中,由于系统安全性的提升,如何实现进程保护。通过深入研究驱动保护,特别是利用微软提供的对象回调函数接口,详细解析了如何阻止进程读写,实现自保护。文章还介绍了强制完整性检查,句柄回调机制,并展示了针对常见杀软的测试案例,展示如何绕过其自保护机制。
摘要由CSDN通过智能技术生成

0x00 前言

我们要想在32位下实现进程保护很简单,通过SSDT hook重写函数即可实现,但是在64位系统下因为引入了PGDSE的原因,导致SSDT hook实现起来处处受限。但微软同样为了系统安全,增加了一个对象回调函数的接口,利用该回调可以实现对对象请求的过滤保护自身的进程,目前大部分64位下的安全软件保护机制都是基于该方法,我们深入进行探究

0x01 驱动保护

其实在最开始研究的时候我的思路是通过研究游戏这一块的保护来进行延申,说到游戏保护这块做得比较好的就是鹅厂的tp了

在经过搜索引擎的洗礼之后,我发现tp是通过hypervisor进行驱动保护,但是这里细节十分复杂,对我这种小白十分不友好,简略来说就是接管内核里面常见的读写API来阻止读写

在研究的过程中,我又发现了另外一种驱动保护的方法:剥离句柄回调

我们在前面提到过微软为了安全性的考虑在64位下面不允许我们去动内核里面的代码了,而是通过回调函数的机制来进行操作,比如说要实现进程的监控就注册PsSetCreateProcessNotifyRoutineEx的回调,如果想要实现模块的监控就注册PsSetLoadImageNotifyRoutine的回调

那么如果想要进行调试,必须用到的一个API就是OpenProcess,最终在内核调用的函数就是NtOpenProcess,而NtOpenProcess会触发ObRegisterCallbacks这个回调函数。那么只要能够捕获ObRegisterCallbacks发送的这些回调信息,将一些敏感的剥离,就能够达到防止进程读写的效果

那么我们去msdn里面找一下ObRegisterCallbacks这个函数

NTSTATUS ObRegisterCallbacks (
  _In_  POB_CALLBACK_REGISTRATION CallBackRegistration,
  _Out_ PVOID                     *RegistrationHandle
);

image-20220430161205580.png

第一个参数 CallBackRegistration是个指向 OB_CALLBACK_REGISTRATION类型的结构体的指针。当 ObRegisterCallbacks例程注册 ObjectPreCallback或 ObjectPostCallback回调例程时这个结构体指定回调例程和其他注册信息的的列表,结构如下

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

第五个成员 OperationRegistration比较关键,这是个指向 OB_OPERATION_REGISTRATION类型结构体数组的指针。每个 OB_OPERATION_REGISTRATION结构体指定 ObjectPreCallback和 ObjectPostCallback回调例程以及那些例程被调用的操作类型,结构如下

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;

在这里需要注意的是第三个成员 PreOperation。这是个指向 ObjectPreCallback例程的指针,系统会在请求的操作发生之前调用这个例程,通过这个 ObjectPreCallback例程来达到我们的目的

OB_PREOP_CALLBACK_STATUS ObjectPreCallback (
  _In_ PVOID                         RegistrationContext,
  _In_ POB_PRE_OPERATION_INFORMATION OperationInformation
);

这里延伸一下,如果想要使用ObRegisterCallbacks,windows会首先通过MmVerifyCallbackFunction这个函数去实现强制完整性检查

强制完整性检查是一种确保正在加载的二进制文件在加载前需要使用签名的策略,IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY标志在链接时通过使用/integritycheck链接器标志在PE头中进行设置,让正在加载的二进制文件必须签名,这个标志使windows内存管理器在加载时对二进制文件进行签名检查

那么微软就是通过加载二进制文件时是否存在标志来确认驱动的发布者身份是否为已知状态,这就是强制完整性检查

我在IDA里面逆了一下MmVerifyCallbackFunction这个函数,发现其逻辑就是通过比较[rax+68h]是否包含了0x20来判断是否拥有正确的数字签名

image-20220430162029355.png

这里的rax表示DriverSection,而DriverSection指向的是_LDR_DATA_TABLE_ENTRY结构,那么[rax + 0x68]指向的就是ProcessStaticImport

image-20220430162109373.png

那么如果我们要使用ObRegisterCallbacks这个函数就需要拥有数字签名,这里我们就可以将DriverObject->DriverSection->Flags的值与0x20按位或即可

在64位系统里面一些杀软的自保护都是通过设置OBOperationRegistration这个回调函数实现,关键代码如下

VOID InstallCallBacks()
{
    NTSTATUS NtHandleCallback = STATUS_UNSUCCESSFUL;
    NTSTATUS NtThreadCallback = STATUS_UNSUCCESSFUL;
    OB_OPERATION_REGISTRATION OBOperationRegistration[2];
    OB_CALLBACK_REGISTRATION OBOCallbackRegistration;
    REG_CONTEXT regContext;
    UNICODE_STRING usAltitude;
    memset(&OBOpe
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值