MmGetSystemRoutineAddress和MiFindExportedRoutineByName函数的实现代码

来源:互联网 发布:脊柱侧弯 知乎 编辑:程序博客网 时间:2024/06/16 08:09

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

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

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

原创粉丝点击