天天看點

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;  
}      

繼續閱讀