MmGetSystemRoutineAddress 函数实现代码

来源:互联网 发布:如何自己出书 知乎 编辑:程序博客网 时间:2024/06/05 18:32

MmGetSystemRoutineAddress这个函数也是比较有用的,是得到系统导出函数的地址,不过网上都是写了一堆汇编代码在哪里,根本没有可读性,还不如用IDA看呢。

下面的函数是摘自ReactOS项目的代码:

PVOIDNTAPIMmGetSystemRoutineAddress(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;    /* 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实现

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

在函数MiFindExportedRoutineByName中,利用RtlImageDirectoryEntryToData 函数得到模块的导出表地址,然后二分遍历导出表,查看是否有指定的字符串导出,还用了Ordinal值判断(PE解析的内容~)

原创粉丝点击