1 了解PE结构
2 懂HOOK KiFastCallEntry
3 理解SSDT表 (需要修复SSDT表)
其实操作不算太复杂, 需要有一定的基础
完整测试的实例代码
#include <ntddk.h> #include "ntimage.h" #define __Max(a,b) a>b?a:b #pragma pack(1) typedef struct ServiceDescriptorEntry { unsigned int *ServiceTableBase; unsigned int *ServiceCounterTableBase; //仅适用于checked build版本 unsigned int NumberOfServices; unsigned char *ParamTableBase; } ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t; #pragma pack() __declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable; typedef struct _LDR_DATA_TABLE_ENTRY{ LIST_ENTRY InLoadOrderLinks; LIST_ENTRY InMemoryOrderLinks; LIST_ENTRY InInitializationOrderLinks; PVOID DllBase; PVOID EntryPoint; ULONG SizeOfImage; UNICODE_STRING FullDllName; UNICODE_STRING BaseDllName; ULONG Flags; USHORT LoadCount; USHORT TlsIndex; union { LIST_ENTRY HashLinks; struct { PVOID SectionPointer; ULONG CheckSum; }; }; union { ULONG TimeDateStamp; PVOID LoadedImports; }; PVOID EntryPointActivationContext; PVOID PatchInformation; } LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; typedef NTSTATUS (*NTCREATEFILE) ( __out PHANDLE FileHandle, __in ACCESS_MASK DesiredAccess, __in POBJECT_ATTRIBUTES ObjectAttributes, __out PIO_STATUS_BLOCK IoStatusBlock, __in_opt PLARGE_INTEGER AllocationSize, __in ULONG FileAttributes, __in ULONG ShareAccess, __in ULONG CreateDisposition, __in ULONG CreateOptions, __in_bcount_opt(EaLength) PVOID EaBuffer, __in ULONG EaLength ); //全局变量的定义 PVOID g_lpVirtualPointer = 0; ULONG g_ntcreatefile; ULONG g_fastcall_hookpointer; ULONG g_goto_origfunc; ULONG g_NewKernelInc; ServiceDescriptorTableEntry_t *g_pNewSeviceTable; void PageProtectOn() { __asm{//恢复内存保护 mov eax, cr0 or eax, 10000h mov cr0, eax sti } } void PageProtectOff() { __asm{//去掉内存保护 cli mov eax, cr0 and eax, not 10000h mov cr0, eax } } ULONG SearchHookPointer(ULONG StartAddress) { ULONG u_index; UCHAR *p = (UCHAR*)StartAddress; for (u_index = 0; u_index < 200; u_index++) { if (*p == 0x2B && *(p + 1) == 0xE1 && *(p + 2) == 0xC1 && *(p + 3) == 0xE9 && *(p + 4) == 0x02) { return (ULONG)p; } p--; } return 0; } ULONG FilterKiFastCallEntry(ULONG ServiceTableBase, ULONG FuncIndex, ULONG OrigFuncAddress) { if (ServiceTableBase == (ULONG)KeServiceDescriptorTable.ServiceTableBase) { if (strstr((char*)PsGetCurrentProcess() + 0x174, "Ollydbg") != 0) { //用新的NtCreateFile来处理 return g_pNewSeviceTable->ServiceTableBase[FuncIndex]; //针对inlineHook //return (OrigFuncAddress+g_NewKernelInc); } } return OrigFuncAddress; } __declspec(naked) void NewKiFastCallEntry() { __asm{ pushad pushfd push edx push eax push edi call FilterKiFastCallEntry mov [esp + 0x18], eax popfd popad sub esp, ecx shr ecx, 2 jmp g_goto_origfunc } } void UnHookKiFastCallEntry() { UCHAR str_origfuncode[5] = { 0x2B, 0xE1, 0xC1, 0xE9, 0x02 }; if (g_fastcall_hookpointer == 0) { return; } PageProtectOff(); RtlCopyMemory((PVOID)g_fastcall_hookpointer, str_origfuncode, 5); PageProtectOn(); } void HookKiFastCallEntry(ULONG HookPointer) { ULONG u_temp; UCHAR str_jmp_code[5]; str_jmp_code[0] = 0xE9; u_temp = (ULONG)NewKiFastCallEntry - HookPointer - 5; *(ULONG*)&str_jmp_code[1] = u_temp; PageProtectOff(); RtlCopyMemory((PVOID)HookPointer, str_jmp_code, 5); PageProtectOn(); } NTSTATUS NewNtCreateFile( __out PHANDLE FileHandle, __in ACCESS_MASK DesiredAccess, __in POBJECT_ATTRIBUTES ObjectAttributes, __out PIO_STATUS_BLOCK IoStatusBlock, __in_opt PLARGE_INTEGER AllocationSize, __in ULONG FileAttributes, __in ULONG ShareAccess, __in ULONG CreateDisposition, __in ULONG CreateOptions, __in_bcount_opt(EaLength) PVOID EaBuffer, __in ULONG EaLength ) { ULONG u_call_retaddr; __asm{ pushad mov eax, [ebp + 0x4] mov u_call_retaddr, eax popad } g_fastcall_hookpointer = SearchHookPointer(u_call_retaddr); if (g_fastcall_hookpointer == 0) { KdPrint(("search failed.")); } else{ KdPrint(("search success.")); } g_goto_origfunc = g_fastcall_hookpointer + 5; HookKiFastCallEntry(g_fastcall_hookpointer); PageProtectOff(); KeServiceDescriptorTable.ServiceTableBase[37] = (unsigned int)g_ntcreatefile; PageProtectOn(); return ((NTCREATEFILE)g_ntcreatefile)( FileHandle, \ DesiredAccess, \ ObjectAttributes, \ IoStatusBlock, \ AllocationSize, \ FileAttributes, \ ShareAccess, \ CreateDisposition, \ CreateOptions, \ EaBuffer, \ EaLength); } void SearchKiFastCallEntry() { HANDLE hFile; NTSTATUS Status; OBJECT_ATTRIBUTES ObjAttr; UNICODE_STRING usFileName; IO_STATUS_BLOCK IoStatusBlock; RtlInitUnicodeString(&usFileName, L"\\??\\C:\\Windows\\System32\\ntkrnlpa.exe"); InitializeObjectAttributes(\ &ObjAttr, \ &usFileName, \ OBJ_CASE_INSENSITIVE, \ NULL, \ NULL); g_ntcreatefile = KeServiceDescriptorTable.ServiceTableBase[37]; PageProtectOff(); KeServiceDescriptorTable.ServiceTableBase[37] = (unsigned int)NewNtCreateFile; PageProtectOn(); Status = ZwCreateFile(\ &hFile, \ FILE_ALL_ACCESS, \ &ObjAttr, \ &IoStatusBlock, \ NULL, \ FILE_ATTRIBUTE_NORMAL, \ FILE_SHARE_READ, \ FILE_OPEN, \ FILE_NON_DIRECTORY_FILE, \ NULL, \ 0); if (NT_SUCCESS(Status)) { ZwClose(hFile); } } VOID SetNewSSDT(\ PVOID pNewImage, \ PVOID pOrigImage, \ ServiceDescriptorTableEntry_t **pNewSeviceTable) { ULONG uIndex; ULONG uNewKernelInc, uOffset; ServiceDescriptorTableEntry_t *pNewSSDT; uNewKernelInc = (ULONG)pNewImage - (ULONG)pOrigImage; pNewSSDT = (ServiceDescriptorTableEntry_t *)((ULONG)&KeServiceDescriptorTable + uNewKernelInc); if (!MmIsAddressValid(pNewSSDT)) { KdPrint(("pNewSSDT")); return; } pNewSSDT->NumberOfServices = KeServiceDescriptorTable.NumberOfServices; uOffset = (ULONG)KeServiceDescriptorTable.ServiceTableBase - (ULONG)pOrigImage; pNewSSDT->ServiceTableBase = (unsigned int*)((ULONG)pNewImage + uOffset); if (!MmIsAddressValid(pNewSSDT->ServiceTableBase)) { KdPrint(("pNewSSDT->ServiceTableBase:%X", pNewSSDT->ServiceTableBase)); return; } for (uIndex = 0; uIndex < pNewSSDT->NumberOfServices; uIndex++) { pNewSSDT->ServiceTableBase[uIndex] += uNewKernelInc; } uOffset = (ULONG)KeServiceDescriptorTable.ParamTableBase - (ULONG)pOrigImage; pNewSSDT->ParamTableBase = (unsigned char*)((ULONG)pNewImage + uOffset); if (!MmIsAddressValid(pNewSSDT->ParamTableBase)) { KdPrint(("pNewSSDT->ParamTableBase")); return; } RtlCopyMemory(pNewSSDT->ParamTableBase, KeServiceDescriptorTable.ParamTableBase, pNewSSDT->NumberOfServices*sizeof(char)); *pNewSeviceTable = pNewSSDT; KdPrint(("set new ssdt success.")); } void RelocModule(PVOID pNewImage, PVOID pOrigImage) { ULONG uIndex; ULONG uRelocTableSize; USHORT TypeValue; USHORT *pwOffsetArrayAddress; ULONG uTypeOffsetArraySize; ULONG uRelocOffset; ULONG uRelocAddress; PIMAGE_DOS_HEADER pImageDosHeader; PIMAGE_NT_HEADERS pImageNtHeader; IMAGE_DATA_DIRECTORY ImageDataDirectory; IMAGE_BASE_RELOCATION *pImageBaseRelocation; pImageDosHeader = (PIMAGE_DOS_HEADER)pNewImage; pImageNtHeader = (PIMAGE_NT_HEADERS)((ULONG)pNewImage + pImageDosHeader->e_lfanew); uRelocOffset = (ULONG)pOrigImage - pImageNtHeader->OptionalHeader.ImageBase; //DbgPrint("pOrigImage -- %x, uRelocOffset -- %x", pOrigImage, uRelocOffset); ImageDataDirectory = pImageNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; pImageBaseRelocation = (PIMAGE_BASE_RELOCATION)(ImageDataDirectory.VirtualAddress + (ULONG)pNewImage); uRelocTableSize = ImageDataDirectory.Size; while (uRelocTableSize) { uTypeOffsetArraySize = (pImageBaseRelocation->SizeOfBlock - sizeof(ULONG)* 2) / sizeof(USHORT); pwOffsetArrayAddress = pImageBaseRelocation->TypeOffset; for (uIndex = 0; uIndex < uTypeOffsetArraySize; uIndex++) { TypeValue = pwOffsetArrayAddress[uIndex]; if (TypeValue >> 12 == IMAGE_REL_BASED_HIGHLOW) { uRelocAddress = (TypeValue & 0xfff) + pImageBaseRelocation->VirtualAddress + (ULONG)pNewImage; if (!MmIsAddressValid((PVOID)uRelocAddress)) { continue; } *(ULONG*)uRelocAddress += uRelocOffset; } } uRelocTableSize -= pImageBaseRelocation->SizeOfBlock; pImageBaseRelocation = (IMAGE_BASE_RELOCATION *)(\ (ULONG)pImageBaseRelocation + pImageBaseRelocation->SizeOfBlock); } } NTSTATUS ReadFileToMemory(wchar_t *strFileName, PVOID *lpVirtualAddress, PVOID pOrigImage) { NTSTATUS Status; LARGE_INTEGER FileOffset; HANDLE hFile; OBJECT_ATTRIBUTES ObjAttr; IO_STATUS_BLOCK IoStatusBlock; UNICODE_STRING usFileName; IMAGE_DOS_HEADER ImageDosHeader; IMAGE_NT_HEADERS ImageNtHeader; IMAGE_SECTION_HEADER *pImageSectionHeader; PVOID lpVirtualPointer; ULONG SecVirtualAddress, SizeOfSection; ULONG PointerToRawData; ULONG uIndex = 0; if (!MmIsAddressValid(strFileName)) { return STATUS_UNSUCCESSFUL; } RtlInitUnicodeString(&usFileName, strFileName); InitializeObjectAttributes(&ObjAttr, &usFileName, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = ZwCreateFile(&hFile, FILE_ALL_ACCESS, &ObjAttr, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, FILE_NON_DIRECTORY_FILE, NULL, 0); if (!NT_SUCCESS(Status)) { DbgPrint("ZwCreateFile Error --- %#X", Status); return Status; } FileOffset.QuadPart = 0; Status = ZwReadFile(hFile, NULL, NULL, NULL, &IoStatusBlock, &ImageDosHeader, sizeof(IMAGE_DOS_HEADER), &FileOffset, NULL); if (!NT_SUCCESS(Status)) { DbgPrint("ZwReadFile ImageDosHeader Error --- %#X", Status); ZwClose(hFile); return Status; } FileOffset.QuadPart = ImageDosHeader.e_lfanew; Status = ZwReadFile(hFile, NULL, NULL, NULL, &IoStatusBlock, &ImageNtHeader, sizeof(IMAGE_NT_HEADERS), &FileOffset, NULL); if (!NT_SUCCESS(Status)) { DbgPrint("ZwReadFile ImageNtHeader Error --- %#X", Status); ZwClose(hFile); return Status; } pImageSectionHeader = ExAllocatePool(NonPagedPool, sizeof(IMAGE_SECTION_HEADER)*ImageNtHeader.FileHeader.NumberOfSections); if (pImageSectionHeader == NULL) { DbgPrint("ExAllocatePool pImageSectionHeader Error --- "); return STATUS_UNSUCCESSFUL; } FileOffset.QuadPart = ImageDosHeader.e_lfanew + sizeof(IMAGE_NT_HEADERS); Status = ZwReadFile(hFile, NULL, NULL, NULL, &IoStatusBlock, pImageSectionHeader, sizeof(IMAGE_SECTION_HEADER)*ImageNtHeader.FileHeader.NumberOfSections, &FileOffset, NULL); if (!NT_SUCCESS(Status)) { DbgPrint("ZwReadFile ImageSectionHeader Error --- %#X", Status); ExFreePool(pImageSectionHeader); ZwClose(hFile); return Status; } lpVirtualPointer = ExAllocatePool(NonPagedPool, ImageNtHeader.OptionalHeader.SizeOfImage); if (lpVirtualPointer == NULL) { DbgPrint("ExAllocatePool Error "); ExFreePool(pImageSectionHeader); ZwClose(hFile); return STATUS_UNSUCCESSFUL; } memset(lpVirtualPointer, 0, ImageNtHeader.OptionalHeader.SizeOfImage); RtlCopyMemory(lpVirtualPointer, &ImageDosHeader, sizeof(IMAGE_DOS_HEADER)); RtlCopyMemory((PVOID)((ULONG)lpVirtualPointer+ImageDosHeader.e_lfanew), &ImageNtHeader, sizeof(IMAGE_NT_HEADERS)); RtlCopyMemory((PVOID)((ULONG)lpVirtualPointer + ImageDosHeader.e_lfanew + sizeof(IMAGE_NT_HEADERS)), pImageSectionHeader, sizeof(IMAGE_SECTION_HEADER)*ImageNtHeader.FileHeader.NumberOfSections); for (uIndex = 0; uIndex < ImageNtHeader.FileHeader.NumberOfSections; uIndex++) { SecVirtualAddress = pImageSectionHeader[uIndex].VirtualAddress; SizeOfSection = __Max(pImageSectionHeader[uIndex].SizeOfRawData, pImageSectionHeader[uIndex].Misc.VirtualSize); PointerToRawData = pImageSectionHeader[uIndex].PointerToRawData; FileOffset.QuadPart = PointerToRawData; Status = ZwReadFile(hFile, NULL, NULL, NULL, &IoStatusBlock, (PVOID)((ULONG)lpVirtualPointer + SecVirtualAddress), SizeOfSection, &FileOffset, NULL); if (!NT_SUCCESS(Status)) { DbgPrint("ZwReadFile ImageSectionHeader Error --- %#X", Status); ExFreePool(pImageSectionHeader); ExFreePool(lpVirtualPointer); ZwClose(hFile); return Status; } } //基址重定位 RelocModule(lpVirtualPointer, pOrigImage); SetNewSSDT(lpVirtualPointer, pOrigImage, &g_pNewSeviceTable); //DbgPrint("RelocModule ok!"); //释放内存 ExFreePool(pImageSectionHeader); *lpVirtualAddress = lpVirtualPointer; DbgPrint("文件内存复制成功"); ZwClose(hFile); return STATUS_SUCCESS; } PLDR_DATA_TABLE_ENTRY SearchDriver(PDRIVER_OBJECT pDriverObject, wchar_t *strDriverName) { ULONG Base = 0;//模块基地址 LDR_DATA_TABLE_ENTRY* SectionBase = 0; LIST_ENTRY* Entry = 0; LIST_ENTRY InLoadOrderLinks = { 0 }; UNICODE_STRING usModuleName; RtlInitUnicodeString(&usModuleName, strDriverName); Entry = ((LIST_ENTRY*)pDriverObject->DriverSection)->Flink; do{ SectionBase = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);//得到这个Entry所属的Section的地址,此方法经过验证可行 if (SectionBase->EntryPoint && SectionBase->BaseDllName.Buffer && SectionBase->FullDllName.Buffer && SectionBase->LoadCount ) { //KdPrint(("%wZ", &SectionBase->BaseDllName)); //DbgPrint("模块名称:%wZ,地址:%x\n", &(SectionBase->FullDllName), SectionBase->DllBase); if (0 == RtlCompareUnicodeString(&SectionBase->BaseDllName, &usModuleName, FALSE)) { KdPrint(("----%wZ-----", &SectionBase->BaseDllName)); return SectionBase; } //DbgPrint("方法一遍历模块名称:%wZ,地址:%x\n", &(SectionBase->FullDllName), SectionBase->DllBase); } Entry = Entry->Flink; } while (Entry != ((LIST_ENTRY*)pDriverObject->DriverSection)->Flink);//直到遍历回来 return 0; } VOID DriverUnload(IN PDRIVER_OBJECT pDriverObject) { DbgPrint("DriverUnload"); if (g_lpVirtualPointer) { ExFreePool(g_lpVirtualPointer); UnHookKiFastCallEntry(); } } NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING RegistryPath) { //C:\WINDOWS\system32\ntkrnlpa.exe //ReadFileToMemory(L"\\??\\C:\\WINDOWS\\system32\\ntkrnlpa.exe", &g_lpVitutalPointer, (PVOID)0x804D8000); //Method1(pDriverObject); PLDR_DATA_TABLE_ENTRY pLdrDataTableEntry; pLdrDataTableEntry = SearchDriver(pDriverObject, L"ntoskrnl.exe"); //g_lpVitutalPointer if (pLdrDataTableEntry) { ReadFileToMemory(L"\\??\\C:\\Windows\\System32\\ntkrnlpa.exe", &g_lpVirtualPointer, pLdrDataTableEntry->DllBase); KdPrint(("g_lpVirtualPointer:%X", g_lpVirtualPointer)); g_NewKernelInc = (ULONG)g_lpVirtualPointer - (ULONG)pLdrDataTableEntry->DllBase; SearchKiFastCallEntry(); } pDriverObject->DriverUnload = DriverUnload; DbgPrint("DriverEntry"); return STATUS_SUCCESS; }
0则评论给“[驱动开发] windows内核重载(xp3) 完整代码”