MmGetSystemRoutineAddress实际调用的MiFindExportedRoutineByName
PVOID
MiFindExportedRoutineByName (
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;
}
在模块中定位指定函数名的地址,这个算法挺不错的