MmGetSystemRoutineAddress這個函數也是比較有用的,是得到系統匯出函數的地址,不過網上都是寫了一堆彙編代碼在哪裡,根本沒有可讀性,還不如用IDA看呢。
下面的函數是摘自ReactOS項目的代碼:
PVOID NTAPI MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName) { PVOID ProcAddress = NULL; ANSI_STRING AnsiRoutineName; NTSTATUS Status; PLIST_ENTRY NextEntry; PLDR_DATA_TABLE_ENTRY LdrEntry; BOOLEAN Found = FALSE; UNICODE_STRING KernelName = RTL_CONSTANT_STRING(L"ntoskrnl.exe"); UNICODE_STRING HalName = RTL_CONSTANT_STRING(L"hal.dll"); ULONG Modules = 0; ERESOURCE PsLoadedModuleResource; /* Convert routine to ansi name */ Status = RtlUnicodeStringToAnsiString(&AnsiRoutineName, SystemRoutineName, TRUE); if (!NT_SUCCESS(Status)) return NULL; /* Lock the list */ KeEnterCriticalRegion(); ExAcquireResourceSharedLite(&PsLoadedModuleResource, TRUE); /* Loop the loaded module list */ NextEntry = PsLoadedModuleList.Flink; while (NextEntry != &PsLoadedModuleList) { /* Get the entry */ LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); /* Check if it's the kernel or HAL */ if (RtlEqualUnicodeString(&KernelName, &LdrEntry->BaseDllName, TRUE)) { /* Found it */ Found = TRUE; Modules++; } else if (RtlEqualUnicodeString(&HalName, &LdrEntry->BaseDllName, TRUE)) { /* Found it */ Found = TRUE; Modules++; } /* Check if we found a valid binary */ if (Found) { /* Find the procedure name */ ProcAddress = MiFindExportedRoutineByName(LdrEntry->DllBase, &AnsiRoutineName); /* Break out if we found it or if we already tried both modules */ if (ProcAddress) break; if (Modules == 2) break; } /* Keep looping */ NextEntry = NextEntry->Flink; } /* Release the lock */ ExReleaseResourceLite(&PsLoadedModuleResource); KeLeaveCriticalRegion(); /* Free the string and return */ RtlFreeAnsiString(&AnsiRoutineName); return ProcAddress; }
MiFindExportedRoutineByName——EAT中定位到指定函數
MmGetSystemRoutineAddress實際調用的MiFindExportedRoutineByName
PVOIDMiFindExportedRoutineByName ( IN PVOID DllBase, IN PANSI_STRING AnsiImageRoutineName ){ USHORT OrdinalNumber; PULONG NameTableBase; PUSHORT NameOrdinalTableBase; PULONG Addr; LONG High; LONG Low; LONG Middle; LONG Result; ULONG ExportSize; // 儲存表項的大小 PVOID FunctionAddress; PIMAGE_EXPORT_DIRECTORY ExportDirectory; PAGED_CODE(); ExportDirectory = (PIMAGE_EXPORT_DIRECTORY) RtlImageDirectoryEntryToData ( DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &ExportSize); if (ExportDirectory == NULL) { return NULL; } NameTableBase = (PULONG)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfNames); NameOrdinalTableBase = (PUSHORT)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfNameOrdinals); //二分尋找法 Low = 0; Middle = 0; High = ExportDirectory->NumberOfNames - 1; while (High >= Low) { Middle = (Low + High) >> 1; Result = strcmp (AnsiImageRoutineName->Buffer, (PCHAR)DllBase + NameTableBase[Middle]); if (Result < 0) { High = Middle - 1; } else if (Result > 0) { Low = Middle + 1; } else { break; } } // 如果High < Low,表明沒有在EAT中找到這個函數;否則,返回此函數的索引 if (High < Low) { return NULL; } OrdinalNumber = NameOrdinalTableBase[Middle]; // 如果索引值大於EAT中已有的函數數量,則尋找失敗 if ((ULONG)OrdinalNumber >= ExportDirectory->NumberOfFunctions) { return NULL; } Addr = (PULONG)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfFunctions); FunctionAddress = (PVOID)((PCHAR)DllBase + Addr[OrdinalNumber]); ASSERT ((FunctionAddress <= (PVOID)ExportDirectory) || (FunctionAddress >= (PVOID)((PCHAR)ExportDirectory + ExportSize))); return FunctionAddress;}
在模組中定位指定函數名的地址,這個演算法挺不錯的