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 下測試.
