MmGetSystemRoutineAddress和MiFindExportedRoutineByName函数的实现代码
2013-07-2913:4517人阅读评论(0)收藏举报MmGetSystemRoutineAddress这个函数也是比较有用的,是得到系统导出函数的地址,不过网上都是写了一堆汇编代码在哪里,根本没有可读性,还不如用IDA看呢。
下面的函数是摘自ReactOS项目的代码:
[cpp]viewplaincopy- PVOID
- NTAPI
- MmGetSystemRoutineAddress(INPUNICODE_STRINGSystemRoutineName)
- {
- PVOIDProcAddress=NULL;
- ANSI_STRINGAnsiRoutineName;
- NTSTATUSStatus;
- PLIST_ENTRYNextEntry;
- PLDR_DATA_TABLE_ENTRYLdrEntry;
- BOOLEANFound=FALSE;
- UNICODE_STRINGKernelName=RTL_CONSTANT_STRING(L"ntoskrnl.exe");
- UNICODE_STRINGHalName=RTL_CONSTANT_STRING(L"hal.dll");
- ULONGModules=0;
- ERESOURCEPsLoadedModuleResource;
- Status=RtlUnicodeStringToAnsiString(&AnsiRoutineName,
- SystemRoutineName,
- TRUE);
- if(!NT_SUCCESS(Status))returnNULL;
- KeEnterCriticalRegion();
- ExAcquireResourceSharedLite(&PsLoadedModuleResource,TRUE);
- NextEntry=PsLoadedModuleList.Flink;
- while(NextEntry!=&PsLoadedModuleList)
- {
- LdrEntry=CONTAINING_RECORD(NextEntry,
- LDR_DATA_TABLE_ENTRY,
- InLoadOrderLinks);
- if(RtlEqualUnicodeString(&KernelName,&LdrEntry->BaseDllName,TRUE))
- {
- Found=TRUE;
- Modules++;
- }
- elseif(RtlEqualUnicodeString(&HalName,&LdrEntry->BaseDllName,TRUE))
- {
- Found=TRUE;
- Modules++;
- }
- if(Found)
- {
- ProcAddress=MiFindExportedRoutineByName(LdrEntry->DllBase,
- &AnsiRoutineName);
- if(ProcAddress)break;
- if(Modules==2)break;
- }
- NextEntry=NextEntry->Flink;
- }
- ExReleaseResourceLite(&PsLoadedModuleResource);
- KeLeaveCriticalRegion();
- RtlFreeAnsiString(&AnsiRoutineName);
- returnProcAddress;
- }
MiFindExportedRoutineByName——EAT中定位到指定函数
MmGetSystemRoutineAddress实际调用的MiFindExportedRoutineByName
[cpp]viewplaincopy- PVOID
- MiFindExportedRoutineByName(
- INPVOIDDllBase,
- INPANSI_STRINGAnsiImageRoutineName
- )
- {
- USHORTOrdinalNumber;
- PULONGNameTableBase;
- PUSHORTNameOrdinalTableBase;
- PULONGAddr;
- LONGHigh;
- LONGLow;
- LONGMiddle;
- LONGResult;
- ULONGE--xportSize;//保存表项的大小
- PVOIDFunctionAddress;
- PIMAGE_EXPORT_DIRECTORYExportDirectory;
- PAGED_CODE();
- ExportDirectory=(PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData(
- DllBase,
- TRUE,
- IMAGE_DIRECTORY_ENTRY_EXPORT,
- &ExportSize);
- if(ExportDirectory==NULL){
- returnNULL;
- }
- 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;
- }
- elseif(Result>0){
- Low=Middle+1;
- }
- else{
- break;
- }
- }
- //如果High<Low,表明没有在EAT中找到这个函数;否则,返回此函数的索引
- if(High<Low){
- returnNULL;
- }
- OrdinalNumber=NameOrdinalTableBase[Middle];
- //如果索引值大于EAT中已有的函数数量,则查找失败
- if((ULONG)OrdinalNumber>=ExportDirectory->NumberOfFunctions){
- returnNULL;
- }
- Addr=(PULONG)((PCHAR)DllBase+(ULONG)ExportDirectory->AddressOfFunctions);
- FunctionAddress=(PVOID)((PCHAR)DllBase+Addr[OrdinalNumber]);
- ASSERT((FunctionAddress<=(PVOID)ExportDirectory)||
- (FunctionAddress>=(PVOID)((PCHAR)ExportDirectory+ExportSize)));
- returnFunctionAddress;
- }
在模块中定位指定函数名的地址,这个算法挺不错的