现在的位置: 首页 > 综合 > 正文

MmGetSystemRoutineAddress和MiFindExportedRoutineByName函数的实现代码

2013年08月26日 ⁄ 综合 ⁄ 共 3062字 ⁄ 字号 评论关闭

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

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

在模块中定位指定函数名的地址,这个算法挺不错的

抱歉!评论已关闭.