☰
Windows 驱动实例分析系列:injdrv 驱动分析 - src篇(一)
2026/10/9 5:18:33 网站建设 项目流程

子文档 1:驱动骨架与初始化(src/injdrv/main.c)

src/injdrv/main.c是整个内核驱动的入口点,其代码量虽然不大(约 150 行),却承担着承上启下的关键作用:解析配置、准备DLL路径、选择注入方法并启动回调监听。

1. 驱动入口 DriverEntry 的实现细节

DriverEntry接收两个参数:PDRIVER_OBJECT DriverObject和PUNICODE_STRING RegistryPath。后者指向注册表中该服务的配置键(通常为\Registry\Machine\System\CurrentControlSet\Services\injdrv)。函数首先设置DriverObject->DriverUnload = &DriverDestroy,确保卸载时能清理资源。

紧接着,函数在栈上声明INJ_SETTINGS Settings结构体,并为其内部的DllPath数组分配栈上的缓冲区(每个 128 个 WCHAR)。这里有一个重要的安全编码习惯:由于驱动栈大小有限(通常是 12KB 或 24KB),将BufferDllPathX86等大数组放在栈上需谨慎,但此处共 4 个架构,每个 128 WCHAR(256 字节),总计约 1KB,尚在安全范围内。

2. InjCreateSettings:逆向读取自身路径

这是初始化的核心难点。驱动需要知道injdllx86.dll等载荷文件位于何处。由于驱动文件通常与injldr.exe放在同一目录,它利用RegistryPath参数(即服务项路径)配合ImagePath值来定位。

函数调用ZwOpenKey打开自身服务注册表项,然后调用ZwQueryValueKey读取ImagePath(类型为REG_EXPAND_SZ)。这个路径通常为\??\C:\Path\to\injdrv.sys。代码检测到\??\前缀后将其跳过(通过比较ObpDosDevicesShortNamePrefix的 8 字节魔数),然后使用wcsrchr找到最后一个\并将其截断为NUL,从而提取出目录部分。

最后,通过InjpJoinPath将目录分别与injdllx86.dll、injdllx64.dll、injdllARM.dll、injdllARM64.dll拼接,存入Settings.DllPath对应槽位。若任一拼接失败(如缓冲区溢出),则返回STATUS_DATA_ERROR。

3. 注入方法的选择策略

在DriverEntry尾部,通过条件编译注入默认方法:

  • x86 平台选InjMethodThunk。
  • x64 平台选InjMethodThunkless(这是最有特色的技法)。
  • ARM64 平台选InjMethodWow64LogReparse。

这个默认选择体现了设计者的意图:优先注入原生(x64)DLL 以实现对所有进程(含 Wow64)的最大覆盖。用户若想改变,可在源码中修改Settings.Method后重新编译。

4. 驱动卸载与回调反注册

DriverDestroy调用PsRemoveLoadImageNotifyRoutine和PsSetCreateProcessNotifyRoutineEx(..., TRUE)移除回调,并调用InjDestroy释放全局链表中的INJ_INJECTION_INFO节点,防止内存泄漏。

5. 为什么不在 DriverEntry 中直接注入?

驱动加载时,系统尚未有任何用户态进程启动(除 System 进程外),因此此时注入无目标。必须等待进程创建回调触发后,才能捕获新进程的EPROCESS对象并开始跟踪。


需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询