MmGetSystemRoutineAddress和MiFindExportedRoutineByName函数的实现代码

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

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

你可能感兴趣的:(MmGetSystemRoutineAddress和MiFindExportedRoutineByName函数的实现代码)