天天看点

MmGetSystemRoutineAddress实现

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;  
"ntoskrnl.exe");  
"hal.dll");  
ULONG Modules = 0;  
  
/* 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;  
}  
 函数主要是遍历PsLoadedModuleList查找"ntoskrnl.exe"与"hal.dll"模块基址,然后调用MiFindExportedRoutineByName在两个模块中查找函数地址,查看下MiFindExportedRoutineByName实现 
PVOID  
MiFindExportedRoutineByName (  
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;  
    }  
  
PULONG)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfNames);  
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;  
    }  
  
PULONG)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfFunctions);  
  
PVOID)((PCHAR)DllBase + Addr[OrdinalNumber]);  
PVOID)ExportDirectory) ||  
PVOID)((PCHAR)ExportDirectory + ExportSize)));  
  
return FunctionAddress;  
}      

继续阅读