内核漏洞挖掘技术系列(5)——KernelFuzzer
字数 1954 2025-08-05 08:19:22

内核漏洞挖掘技术:KernelFuzzer 工具详解

1. KernelFuzzer 概述

KernelFuzzer 是 MWRLabs 在 Defcon24 开源的一款内核模糊测试工具,宣称支持 Windows 7/10、OS X 和 QNX 系统,但实际上主要支持 Windows 系统。

项目地址:https://github.com/mwrlabs/KernelFuzzer

2. 工具架构

2.1 目录结构

crash_processing/        # 处理崩溃
crashes/                 # 存放发现的崩溃
library_calls/           # 要模糊测试的库调用
reproducer/              # 崩溃复现(功能有限)
worker_setup/            # 环境设置和启动
bughunt.c                # 主程序,启动模糊测试线程
bughunt.h                # 提供随机字符/数组生成函数
bughunt_build_*_*.bat    # 编译脚本
bughunt_loop.py          # 处理发现的崩溃
bughunt_syscall_x64/     # 64位系统调用实现
bughunt_syscall.asm      # 32位系统调用实现
bughunt_syscalls.h       # 要模糊测试的系统调用定义
bughunt_thread.h         # 模糊测试线程实现
handles_database.h       # 生成各种句柄
helpers.h                # 辅助函数
hooking.h                # 设置和取消hook
library_calls.h          # 库调用定义
logger.h                 # 日志功能

2.2 工作流程

  1. 在主机上使用 VS 环境编译可执行文件
  2. 将所有文件拷贝到目标虚拟机系统
  3. 在虚拟机安装 Python 环境
  4. 运行 worker_setup.py 设置环境
  5. 启动模糊测试

3. 核心组件分析

3.1 worker_setup.py

该脚本负责环境准备:

  • 安装 WinDbg
  • 执行注册表脚本(禁用 UAC、自动更新、锁屏、错误报告)
  • 安装 Python couchdb 模块
  • 配置 dump 文件路径
  • 设置登录时运行 bughunt_loop.py 的计划任务
  • 为 win32k.sys 启用 special pool
  • 开启内核调试
  • 重启系统

3.2 bughunt_loop.py

崩溃处理流程:

  1. 监控 C:/Dumps/ 目录下的 .dmp 文件
  2. 发现崩溃后将文件拷贝到新文件夹
  3. 使用 kd.exe 分析 dump 文件,输出到 windbg.log
  4. 将日志文件与 dump 文件放在同一目录
  5. 调用 couchdb_submit.py 提交崩溃信息到远程数据库
  6. 运行 bughunt.exe(线程数=1,系统调用=350000,seed=1,超时=10分钟)
  7. 超时后执行清理并重启

3.3 bughunt_thread.h

模糊测试线程主要逻辑:

  1. 随机调用要测试的库调用(library_calls.h 中定义)
  2. 随机进行系统调用(根据 bughunt_syscalls.h 提供的参数类型信息生成随机参数)
  3. 调用 bughunt_syscall 函数执行系统调用

3.4 系统调用实现

32位实现 (bughunt_syscall.asm):

  • 参数通过栈传递
  • 提取系统调用号和参数压栈
  • mov edx, 7FFE0300h
  • call dword ptr [edx]

64位实现 (bughunt_syscall_x64.asm):

  • 前四个参数通过 RCX,RDX,R8,R9 传递
  • 系统调用号 RCX 放入 RAX
  • 参数依次前移:RCX←RDX, RDX←R8, R8←R9, R9←[rbp + 30h]
  • 执行 syscall 指令

4. 功能扩展

4.1 增加系统调用

工具默认提供的系统调用有限,可以通过以下方法扩展:

  1. 获取系统调用表:

    • 下载 j00ru 提供的系统调用表:https://github.com/j00ru/windows-syscalls
    • 下载 ReactOS 代码:https://github.com/reactos/reactos
  2. 使用脚本分析 ReactOS 头文件,提取系统调用信息:

import os
import csv
import shutil

# 查找包含系统调用的头文件
def findstring(pathfile, syscallname):
    file = open(pathfile, "r")
    string = file.read()
    if string.find(syscallname) != -1:
        global allfiles
        if pathfile not in allfiles:
            allfiles.append(pathfile)

# 遍历目录查找.h文件
def readFilename(file_dir, syscallname):
    for root, dirs, files in os.walk(file_dir):
        for file in files:
            if file.endswith(".h"):
                full_path = os.path.join(root, file)
                findstring(full_path, syscallname)

# 主程序
file_path = "F:\\windows-fuzzing\\ReactOS-0.4.11"
fscv = csv.reader(open("F:\\windows-fuzzing\\KernelFuzzer\\nt.csv", 'r'))
for row in fscv:
    syscallname = row[0]
    readFilename(file_path, syscallname)

fscv = csv.reader(open("F:\\windows-fuzzing\\KernelFuzzer\\win32k.csv", 'r'))
for row in fscv:
    syscallname = row[0]
    readFilename(file_path, syscallname)

print(allfiles)
  1. 将提取的信息转换为 KernelFuzzer 需要的格式:
import re
import csv

# 从CSV中查找系统调用信息
def search_csv(str, fscv, f):
    for row in fscv:
        if str in row:
            if row[26]:  # win10 1903:27, win10 1809:26, win7 SP1:15, XP SP2:2
                syscallname = row[0]
                syscallnumber = row[15]
                arguments = "{"
                while True:
                    str = f.readline()
                    flag = 0
                    # 匹配各种参数类型
                    matchobj = re.search(r'(\s)+DWORD|int\s', str)
                    if matchobj: 
                        flag = 1
                        arguments += " _INT32,"
                    # 其他类型匹配...
                    matchobj = re.search(r'\);', str)
                    if matchobj:
                        arguments += " NIL }, NIL },"
                        break
                finalstr = " { ((DWORD)" + syscallnumber + "), " + arguments + " //" + syscallname
                print(finalstr)
                return True
    return False

# 定位要搜索的函数
def locate_function_to_search(f):
    while True:
        str = f.readline()
        if not str:
            break
        matchobj = re.search(r'Nt(.*)\(', str)
        if matchobj:
            index = str.find("(")
            str = str[:index]
            # 搜索NT系统调用
            ntfile = open("F:\\windows-fuzzing\\KernelFuzzer\\nt.csv", 'r')
            fntscv = csv.reader(ntfile)
            if search_csv(str, fntscv, f) == True:
                continue
            # 搜索win32k系统调用
            win32kfile = open("F:\\windows-fuzzing\\KernelFuzzer\\win32k.csv", 'r')
            fwin32kscv = csv.reader(win32kfile)
            if search_csv(str, fwin32kscv, f) == True:
                continue

# 主程序
if __name__ == '__main__':
    files = ('F:\\windows-fuzzing\\ReactOS-0.4.11\\sdk\\include\\ndk\\lpcfuncs.h',
             # 其他头文件列表...
            )
    for file in files:
        f = open(file)
        locate_function_to_search(f)
  1. 将转换后的结果添加到 bughunt_syscalls.h 中

4.2 相关工具:NtCall64

另一个 Windows 系统调用模糊测试工具:https://github.com/hfiref0x/NtCall64

主要特点:

  • 支持 fuzz W32pServiceTable (win32k.sys) 或 KiServiceTable (ntoskrnl.exe)
  • 通过特征码定位未导出的系统调用表
  • 随机生成系统调用参数

工作流程:

  1. 解析命令行参数
  2. FuzzInitPhase1 进行准备工作
  3. FuzzInitPhase2 根据参数选择 fuzz 目标
  4. FuzzRunThreadWithWait -> FuzzThreadProc -> DoSystemCall -> ntSyscallGate
  5. 在 syscall.asm 中完成实际系统调用

5. 总结

KernelFuzzer 是一个基础的 Windows 内核模糊测试框架,虽然功能相对简单,但通过扩展可以支持更多系统调用。关键点包括:

  1. 理解工具的整体架构和工作流程
  2. 掌握系统调用的实现机制(32位和64位不同)
  3. 学会扩展系统调用列表的方法
  4. 了解相关工具如 NtCall64 的不同实现方式

工具局限性:

  • 缺乏反馈驱动机制,发现漏洞效率有限
  • 默认提供的系统调用和库调用较少
  • 需要手动扩展功能

通过结合 ReactOS 代码和系统调用表,可以显著增强工具的测试范围,提高发现内核漏洞的可能性。

内核漏洞挖掘技术:KernelFuzzer 工具详解 1. KernelFuzzer 概述 KernelFuzzer 是 MWRLabs 在 Defcon24 开源的一款内核模糊测试工具,宣称支持 Windows 7/10、OS X 和 QNX 系统,但实际上主要支持 Windows 系统。 项目地址:https://github.com/mwrlabs/KernelFuzzer 2. 工具架构 2.1 目录结构 2.2 工作流程 在主机上使用 VS 环境编译可执行文件 将所有文件拷贝到目标虚拟机系统 在虚拟机安装 Python 环境 运行 worker_ setup.py 设置环境 启动模糊测试 3. 核心组件分析 3.1 worker_ setup.py 该脚本负责环境准备: 安装 WinDbg 执行注册表脚本(禁用 UAC、自动更新、锁屏、错误报告) 安装 Python couchdb 模块 配置 dump 文件路径 设置登录时运行 bughunt_ loop.py 的计划任务 为 win32k.sys 启用 special pool 开启内核调试 重启系统 3.2 bughunt_ loop.py 崩溃处理流程: 监控 C:/Dumps/ 目录下的 .dmp 文件 发现崩溃后将文件拷贝到新文件夹 使用 kd.exe 分析 dump 文件,输出到 windbg.log 将日志文件与 dump 文件放在同一目录 调用 couchdb_ submit.py 提交崩溃信息到远程数据库 运行 bughunt.exe(线程数=1,系统调用=350000,seed=1,超时=10分钟) 超时后执行清理并重启 3.3 bughunt_ thread.h 模糊测试线程主要逻辑: 随机调用要测试的库调用(library_ calls.h 中定义) 随机进行系统调用(根据 bughunt_ syscalls.h 提供的参数类型信息生成随机参数) 调用 bughunt_ syscall 函数执行系统调用 3.4 系统调用实现 32位实现 (bughunt_ syscall.asm): 参数通过栈传递 提取系统调用号和参数压栈 mov edx, 7FFE0300h call dword ptr [edx] 64位实现 (bughunt_ syscall_ x64.asm): 前四个参数通过 RCX,RDX,R8,R9 传递 系统调用号 RCX 放入 RAX 参数依次前移:RCX←RDX, RDX←R8, R8←R9, R9←[ rbp + 30h ] 执行 syscall 指令 4. 功能扩展 4.1 增加系统调用 工具默认提供的系统调用有限,可以通过以下方法扩展: 获取系统调用表: 下载 j00ru 提供的系统调用表:https://github.com/j00ru/windows-syscalls 下载 ReactOS 代码:https://github.com/reactos/reactos 使用脚本分析 ReactOS 头文件,提取系统调用信息: 将提取的信息转换为 KernelFuzzer 需要的格式: 将转换后的结果添加到 bughunt_ syscalls.h 中 4.2 相关工具:NtCall64 另一个 Windows 系统调用模糊测试工具:https://github.com/hfiref0x/NtCall64 主要特点: 支持 fuzz W32pServiceTable (win32k.sys) 或 KiServiceTable (ntoskrnl.exe) 通过特征码定位未导出的系统调用表 随机生成系统调用参数 工作流程: 解析命令行参数 FuzzInitPhase1 进行准备工作 FuzzInitPhase2 根据参数选择 fuzz 目标 FuzzRunThreadWithWait -> FuzzThreadProc -> DoSystemCall -> ntSyscallGate 在 syscall.asm 中完成实际系统调用 5. 总结 KernelFuzzer 是一个基础的 Windows 内核模糊测试框架,虽然功能相对简单,但通过扩展可以支持更多系统调用。关键点包括: 理解工具的整体架构和工作流程 掌握系统调用的实现机制(32位和64位不同) 学会扩展系统调用列表的方法 了解相关工具如 NtCall64 的不同实现方式 工具局限性: 缺乏反馈驱动机制,发现漏洞效率有限 默认提供的系统调用和库调用较少 需要手动扩展功能 通过结合 ReactOS 代码和系统调用表,可以显著增强工具的测试范围,提高发现内核漏洞的可能性。