Ps回调函数.拦截驱动模块原理+实现.
- 2019 年 10 月 8 日
- 筆記
目录
一丶简介
主要是讲解.内核中如何拦截模块加载的. 需要熟悉.内核回调的设置 PE知识. ShellCode
二丶原理
1.原理
原理是通过回调函数. 回调函数中有 ImageBase. 使用PE解析ImageBase 得到OEP. OEP位置写入 ret等ShellCode
如何判断 是加载DLL 还是加载Sys. 可以看回调的第二个参数.(ProcessId) 如果ProcessId == 0. 则是加载Sys
PS: 在内核中解析PE需要用到 ntImage.h头文件来进行解析.
2.代码实现
#include <ntimage.h> #include <ntddk.h> #include <wdm.h> ULONG_PTR g_LoadPtr = 0; void WPONx64(KIRQL irql) { UINT64 cr0 = __readcr0(); cr0 |= 0x10000; _enable(); __writecr0(cr0); KeLowerIrql(irql); } KIRQL WPOFFx64() { KIRQL irql = KeRaiseIrqlToDpcLevel(); UINT64 cr0 = __readcr0(); cr0 &= 0xfffffffffffeffff; __writecr0(cr0); _disable(); return irql; } BOOLEAN Fuck(PVOID pOep) { KIRQL kirql; if (NULL == pOep) return FALSE; //写入字节. UCHAR FuckCode[] = { "xB8x22x00x00xC0xC3" }; kirql = WPOFFx64(); KdBreakPoint(); memcpy(pOep, FuckCode, sizeof(FuckCode) / sizeof(FuckCode[0])); //开头写入拒绝访问错误码让其无法加载即可. WPONx64(kirql); return TRUE; } //根据ImageBase来获取加载模块的入口点 PVOID GetImageOep(PVOID ImageBase) { PVOID pAddressOfEntryPoint = NULL; PIMAGE_DOS_HEADER pDosHead = NULL; PIMAGE_NT_HEADERS pNtHead = NULL; PIMAGE_FILE_HEADER pFileHead = NULL; PIMAGE_OPTIONAL_HEADER pOptHead = NULL; //开始解析 if (ImageBase == NULL) return NULL; pDosHead = (PIMAGE_DOS_HEADER)ImageBase; pNtHead = (PIMAGE_NT_HEADERS)(pDosHead->e_lfanew + (char *)ImageBase); pFileHead = (PIMAGE_FILE_HEADER)&pNtHead->FileHeader; pOptHead = (PIMAGE_OPTIONAL_HEADER)&pNtHead->OptionalHeader; //判断是否是PE头 if (pDosHead->e_magic != 0x5A4D && pNtHead->Signature != 0x5045) return NULL; pAddressOfEntryPoint = pOptHead->AddressOfEntryPoint + (char *)ImageBase; return pAddressOfEntryPoint; } char * MyWideUnicodeStringToMutilString(PUNICODE_STRING uString) { ANSI_STRING asStr; char *Buffer = NULL; ; RtlUnicodeStringToAnsiString(&asStr, uString, TRUE); Buffer = ExAllocatePoolWithTag(NonPagedPool, uString->MaximumLength * sizeof(wchar_t), 0); if (Buffer == NULL) return NULL; RtlCopyMemory(Buffer, asStr.Buffer, asStr.Length); return Buffer; } VOID pSfFilterModule( _In_opt_ PUNICODE_STRING FullImageName, _In_ HANDLE ProcessId, // pid into which image is being mapped _In_ PIMAGE_INFO ImageInfo ) { /* 模块拦截思路: 1.通过 PIMAGE_INFO->ImageBase 得到模块的ImageBase 2.解析PE头. 3.可选头的OEP + ImageBase = 程序运行位置 4.在程序开头写入 ret. 5.通过参数一,判断是不是我们想要拦截的模块.然后进行1 2 3 4步 6.如何判断加载驱动模块还是DLL 根据参数2.ProcessId高低位判断即可. == 0加载驱动模块.否则加载DLL */ PVOID pDriverOep = NULL; char *ComPareString = NULL; if (MmIsAddressValid(FullImageName)) { if (ProcessId == 0) { //代表拦截驱动模块 //判断名字是否是你想要拦截的. KdBreakPoint(); ComPareString = MyWideUnicodeStringToMutilString(FullImageName); if (ComPareString == NULL) return; if (strstr(ComPareString,"1.sys")) { KdBreakPoint(); KdPrint(("你要拦截的驱动模块名字为: %wZ rn", FullImageName)); pDriverOep = GetImageOep(ImageInfo->ImageBase); //判断拦截的名字是否是你想要拦截的 if (pDriverOep != NULL) { Fuck(pDriverOep); } } } //输出调试 } } NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pRegPath) { ULONG iCount = 0; NTSTATUS ntStatus; pDriverObj->DriverUnload = DriverUnLoad; ntStatus = InitDeviceAnSybolicLinkName(pDriverObj); if (!NT_SUCCESS(ntStatus)) { return ntStatus; } ntStatus = InitDisPatchFunction(pDriverObj); if (!NT_SUCCESS(ntStatus)) { return ntStatus; } PsSetLoadImageNotifyRoutine(pSfFilterModule); return STATUS_SUCCESS; }
3.效果
win7 64 sp1 下测试.
