拦截指定驱动加载

其实 32 位和 64 位的驱动拦截的区别在于调用约定的问题, 64位默认 stdcall 由调用者自身平衡堆栈,32位默认是 cdcall 由被调用者平衡堆栈,所以我们的ShellCode需要改下

入口函数为 DriverEntry 所以返回 8 字节

0环驱动代码

#include <Ntifs.h>
#include <stdio.h>
#include <ntimage.h> // 包含NT头定义
// 拦截驱动加载
// 未声明函数
PCHAR PsGetProcessImageFileName(PEPROCESS Process);
KIRQL irQl;
// 修改Cr0寄存器, 去除写保护(内存保护机制)
KIRQL RemovWP()
{
       DbgPrint("RemovWP\n");
       // (PASSIVE_LEVEL)提升 IRQL 等级为DISPATCH_LEVEL,并返回旧的 IRQL
       // 需要一个高的IRQL才能修改
       irQl = KeRaiseIrqlToDpcLevel();
       ULONG_PTR cr0 = __readcr0(); // 内联函数:读取Cr0寄存器的值, 相当于: mov eax,     cr0;
       // 将第16位(WP位)清0,消除写保护
       cr0 &= ~0x10000; // ~ 按位取反
       _disable(); // 清除中断标记, 相当于 cli 指令,修改 IF标志位
       __writecr0(cr0); // 将cr0变量数据重新写入Cr0寄存器中,相当于: mov cr0, eax
       DbgPrint("退出RemovWP\n");
       return irQl;
}
// 复原Cr0寄存器
KIRQL UndoWP()
{
       DbgPrint("UndoWP\n");
       ULONG_PTR cr0 = __readcr0();
       cr0 |= 0x10000; // WP复原为1
       _disable(); // 清除中断标记, 相当于 cli 指令,清空 IF标志位
       __writecr0(cr0); // 将cr0变量数据重新写入Cr0寄存器中,相当于: mov cr0, eax
       // 恢复IRQL等级
       KeLowerIrql(irQl);
       DbgPrint("退出UndoWP\n");
       return irQl;
}
VOID HookDriver(PCHAR ImageBase)
{
       DbgPrint("进入HookDriver\n");
       /*
                 mov rax, 0xC0000022(STATUS_ACCESS_DENIED);
                 ret;
       */
#ifdef _WIN64 // 如果为64位
       char ShellCode[6] = "\xB8\x22\x00\x00\xC0\xC3";
#else // 如果为32位
       char ShellCode[8] = "\xB8\x22\x00\x00\xC3\xC2\x08\x00";
#endif
       PCHAR AddressEntry;
       PIMAGE_DOS_HEADER DosHeader = (PIMAGE_DOS_HEADER)ImageBase;
       PIMAGE_NT_HEADERS NtHeader = (PIMAGE_NT_HEADERS)(ImageBase +  DosHeader->e_lfanew);
       AddressEntry = ImageBase + NtHeader->OptionalHeader.AddressOfEntryPoint; //   获取EP(程序入口点)
       // 关闭写保护
       RemovWP();
       RtlCopyMemory(AddressEntry, ShellCode, sizeof(ShellCode)); // 填入我们自己的ShellCode
       // 恢复写保护
       UndoWP();
}
// 通知回调函数
void PloadImageNotifyRoutine(
       PUNICODE_STRING FullImageName,
       HANDLE ProcessId,
       PIMAGE_INFO ImageInfo
)
{
       PEPROCESS Process;
       CHAR ModuleName[256] = { 0 };
       if (ProcessId == 0) // 则是驱动加载
       {
              sprintf(ModuleName, "%wZ", FullImageName); // 将 PUNICODE_STRING 转为   CHAR
              DbgPrint("发现驱动: %s\n", ModuleName);
              if (strstr(_strlwr(ModuleName), "test.sys") != NULL)
              {
                     DbgPrint("准备HookDriver\n");
                     HookDriver(ImageInfo->ImageBase); // 传入驱动模块ImageBase
              }
       }
       else
       {
              /*PsLookupProcessByProcessId(ProcessId, &Process);
              DbgPrint("模块进程ID: %d, 模块进程名称: %s, 模块路径: %wZ", ProcessId,   PsGetProcessImageFileName(Process), FullImageName);*/
       }
}
VOID Unload(IN PDRIVER_OBJECT DriverObject)
{
       // 取消加载模块,卸载模块通知函数
       PsRemoveLoadImageNotifyRoutine(PloadImageNotifyRoutine);
       DbgPrint("卸载驱动\n");
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING     RegeditPath)
{
       DbgPrint("加载驱动\n");
       NTSTATUS status = STATUS_SUCCESS;
       DriverObject->DriverUnload = Unload;
       // 注册加载模块,卸载模块通知函数
       PsSetLoadImageNotifyRoutine(PloadImageNotifyRoutine);
       return status;
}


原创文章,转载请注明: 转载自Windows内核安全驱动编程

本文链接地址: 拦截指定驱动加载

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注