在笔者前面有一篇文章《驱动开发:断链隐藏驱动程序自身》
通过摘除驱动的链表实现了断链隐藏自身的目的,但此方法恢复时会触发PG会蓝屏,偶然间在网上找到了一个作者介绍的一种方法,觉得有必要详细分析一下他是如何实现的驱动隐藏的,总体来说作者的思路是最终寻找到MiProcessLoaderEntry
的入口地址,该函数的作用是将驱动信息加入链表和移除链表,运用这个函数即可动态处理驱动的添加和移除问题。
- MiProcessLoaderEntry(pDriverObject->DriverSection, 1) 添加
- MiProcessLoaderEntry(pDriverObject->DriverSection, 0) 移除
那么如何找到MiProcessLoaderEntry
函数入口地址就是下一步的目标,寻找入口可以总结为;
- 1.寻找
MmUnloadSystemImage
函数地址,可通过MmGetSystemRoutineAddress
函数得到。 - 2.在
MmUnloadSystemImage
里面寻找MiUnloadSystemImage
函数地址。 - 3.在
MiUnloadSystemImage
里面继续寻找MiProcessLoaderEntry
即可。
搜索MmUnloadSystemImage
可定位到call nt!MiUnloadSystemImage
地址。
搜索MiUnloadSystemImage
定位到call nt!MiProcessLoaderEntry
即得到了我们想要的。
根据前面枚举篇
系列文章,定位这段特征很容易实现,如下是一段参考代码。
// PowerBy: LyShark
// Email: me@lyshark.com
#include <ntddk.h>
#include <ntstrsafe.h>
typedef NTSTATUS(__fastcall *MiProcessLoaderEntry)(PVOID pDriverSection, BOOLEAN bLoad);
// 取出指定函数地址
PVOID GetProcAddress(WCHAR *FuncName)
{
UNICODE_STRING u_FuncName = { 0 };
PVOID ref = NULL;
RtlInitUnicodeString(&u_FuncName, FuncName);
ref = MmGetSystemRoutineAddress(&u_FuncName);
if (ref != NULL)
{
return ref;
}
return ref;
}
// 特征定位 MiUnloadSystemImage
ULONG64 GetMiUnloadSystemImageAddress()
{
// 在MmUnloadSystemImage函数中搜索的Code
/*
lyshark.com: kd> uf MmUnloadSystemImage
fffff801`37943512 83caff or edx,0FFFFFFFFh
fffff801`37943515 488bcf mov rcx,rdi
fffff801`37943518 488bd8 mov rbx,rax
fffff801`3794351b e860b4ebff call nt!MiUnloadSystemImage (fffff801`377fe980)
*/
CHAR MmUnloadSystemImage_Code[] = "\x83\xCA\xFF" // or edx, 0FFFFFFFFh
"\x48\x8B\xCF" // mov rcx, rdi
"\x48\x8B\xD8" // mov rbx, rax
"\xE8"; // call nt!MiUnloadSystemImage (fffff801`377fe980)
ULONG_PTR MmUnloadSystemImageAddress = 0;
ULONG_PTR MiUnloadSystemImageAddress = 0;
ULONG_PTR StartAddress = 0;
MmUnloadSystemImageAddress = (ULONG_PTR)GetProcAddress(L"MmUnloadSystemImage");
if (MmUnloadSystemImageAddress == 0)
{
return 0;
}
// 在MmUnloadSystemImage中搜索特征码寻找MiUnloadSystemImage
StartAddress = MmUnloadSystemImageAddress;
while (StartAddress < MmUnloadSystemImageAddress + 0x500)
{
if (memcmp((VOID*)StartAddress, MmUnloadSystemImage_Code, strlen(MmUnloadSystemImage_Code)) == 0)
{
// 跳过call之前的指令
StartAddress += strlen(MmUnloadSystemImage_Code);
// 取出 MiUnloadSystemImage地址
MiUnloadSystemImageAddress = *(LONG*)StartAddress + StartAddress + 4;
break;
}
++StartAddress;
}
if (MiUnloadSystemImageAddress != 0)
{
return MiUnloadSystemImageAddress;
}
return 0;
}
// 特征定位 MiProcessLoaderEntry
MiProcessLoaderEntry GetMiProcessLoaderEntry(ULONG64 StartAddress)
{
if (StartAddress == 0)
{
return NULL;
}
while (StartAddress < StartAddress + 0x600)
{
// 操作数MiProcessLoaderEntry内存地址是动态变化的
/*
lyshark.com: kd> uf MiUnloadSystemImage
fffff801`377fed19 33d2 xor edx,edx
fffff801`377fed1b 488bcb mov rcx,rbx
fffff801`377fed1e e84162b4ff call nt!MiProcessLoaderEntry (fffff801`37344f64)
fffff801`377fed23 8b05d756f7ff mov eax,dword ptr [nt!PerfGlobalGroupMask (fffff801`37774400)]
fffff801`377fed29 a804 te