UID 2
精华
积分 7736
威望 点
宅币 个
贡献 次
宅之契约 份
最后登录 1970-1-1
在线时间 小时
本帖最后由 元始天尊 于 2015-6-13 15:06 编辑
剔除了很多无关代码
可以借鉴的地方:
1、考虑了很多极端情况如dllmain未执行,获得函数地址不能等于基址等
2、名称查找采用二分搜索
3、考虑了forward导出函数
4、对按序号和按名称分别处理
5、对内存pe解析
FARPROC WINAPI GetProcAddress(HMODULE hModule, LPCSTR lpProcName)
{
if (HIWORD(lpProcName) != 0)
{//按名称查找
RtlInitAnsiString(&ProcedureName, (LPSTR)lpProcName);
ProcNamePtr = &ProcedureName;
}
else
{ //按序号查找
Ordinal = (ULONG)lpProcName;
}
hMapped = BasepMapModuleHandle(hModule, FALSE);//如果没提供hModule则取得当前模块hModule
Status = LdrGetProcedureAddress(hMapped,ProcNamePtr, Ordinal,(PVOID*)&fnExp);
}
PVOID WINAPI BasepMapModuleHandle(HMODULE hModule, BOOLEAN AsDataFile)
{
if (!hModule) return NtCurrentPeb()->ImageBaseAddress;
if (LDR_IS_DATAFILE(hModule) && !AsDataFile)//如果为资源DLL
return NULL;
return hModule;
}
NTSTATUS NTAPI LdrpGetProcedureAddress(IN PVOID BaseAddress,IN PANSI_STRING Name,IN ULONG Ordinal,OUT PVOID *ProcedureAddress,IN BOOLEAN ExecuteInit)
{
NTSTATUS Status = STATUS_SUCCESS;
UCHAR ImportBuffer[64];
PLDR_DATA_TABLE_ENTRY LdrEntry;
IMAGE_THUNK_DATA Thunk;
PVOID ImageBase;
PIMAGE_IMPORT_BY_NAME ImportName = NULL;
PIMAGE_EXPORT_DIRECTORY ExportDir;
ULONG ExportDirSize, Length;
PLIST_ENTRY Entry;
if (Name)//若按名称查找
{
Length = Name->Length +sizeof(CHAR) + FIELD_OFFSET(IMAGE_IMPORT_BY_NAME, Name);
ImportName->Hint = 0;
RtlCopyMemory(ImportName->Name, Name->Buffer, Name->Length);
ImportName->Name[Name->Length] = ANSI_NULL;
ImageBase = ImportName;
Thunk.u1.AddressOfData = 0;
}
else//若按序号查找
{
ImageBase = NULL;
Thunk.u1.Ordinal = Ordinal | IMAGE_ORDINAL_FLAG;
}
LdrpCheckForLoadedDllHandle(BaseAddress, &LdrEntry); //查找已加载dll
ExportDir = RtlImageDirectoryEntryToData(LdrEntry->DllBase,TRUE,IMAGE_DIRECTORY_ENTRY_EXPORT, &ExportDirSize);//查找导出表
Status = LdrpSnapThunk(LdrEntry->DllBase,ImageBase,&Thunk, &Thunk,ExportDir,ExportDirSize,FALSE,NULL);//获取导出表Thunk结构
*ProcedureAddress = (PVOID)Thunk.u1.Function;
}
BOOLEAN NTAPI LdrpCheckForLoadedDllHandle(IN PVOID Base,OUT PLDR_DATA_TABLE_ENTRY *LdrEntry)
{
PLDR_DATA_TABLE_ENTRY Current;
PLIST_ENTRY ListHead, Next;
if ((LdrpLoadedDllHandleCache) && (LdrpLoadedDllHandleCache->DllBase == Base))//查找缓存
{
*LdrEntry = LdrpLoadedDllHandleCache;
return TRUE;
}
ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;//线性查找ldr
Next = ListHead->Flink;
while (Next != ListHead)
{
Current = CONTAINING_RECORD(Next,LDR_DATA_TABLE_ENTRY,InLoadOrderLinks);
if ((Current->InMemoryOrderModuleList.Flink) && (Base == Current->DllBase))
{
LdrpLoadedDllHandleCache = Current;
*LdrEntry = Current;
return TRUE;
}
Next = Next->Flink;
}
return FALSE;
}
PVOID NTAPI RtlImageDirectoryEntryToData(PVOID BaseAddress,BOOLEAN MappedAsImage,USHORT Directory,PULONG Size)
{
PIMAGE_NT_HEADERS NtHeader;
ULONG Va;
NtHeader = RtlImageNtHeader(BaseAddress);
if (NtHeader == NULL)
return NULL;
if(NtHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
return RtlpImageDirectoryEntryToData32(BaseAddress,MappedAsImage,Directory,Size,NtHeader);
else if(NtHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
return RtlpImageDirectoryEntryToData64(BaseAddress,MappedAsImage,Directory,Size,NtHeader);
return NULL;
}
PIMAGE_NT_HEADERS NTAPI RtlImageNtHeader(IN PVOID Base)
{
PIMAGE_NT_HEADERS NtHeaders = NULL;
PIMAGE_DOS_HEADER DosHeader;
if ((Base != NULL) && (Base == (PVOID)-1) && (DosHeader->e_magic == IMAGE_DOS_SIGNATURE))
{
if (DosHeader->e_lfanew < 0x10000000)
{
NtHeaders = (BYTE*)Base + DosHeader->e_lfanew;
if(NtHeaders->Signature != IMAGE_NT_SIGNATURE)
NtHeaders = NULL;
}
}
return NtHeaders;
}
PVOID NTAPI RtlpImageDirectoryEntryToData32(PVOID BaseAddress, BOOLEAN MappedAsImage, USHORT Directory, PULONG Size, PIMAGE_NT_HEADERS32 NtHeader)
{
if(Directory >= NtHeader->OptionalHeader.NumberOfRvaAndSizes)
return NULL;
DWORD vaaddr = NtHeader->OptionalHeader.DataDirectory[Directory].VirtualAddress;
if(vaaddr == 0)
return NULL;
*Size = NtHeader->OptionalHeader.DataDirectory[Directory].Size;
if(MappedAsImage || vaaddr < NtHeader->OptionalHeader.SizeOfHeaders)
return (PVOID)((BYTE*)BaseAddress + vaaddr);
}
PVOID NTAPI RtlpImageDirectoryEntryToData64(PVOID BaseAddress, BOOLEAN MappedAsImage, USHORT Directory, PULONG Size, PIMAGE_NT_HEADERS64 NtHeader)
{
if(Directory >= NtHeader->OptionalHeader.NumberOfRvaAndSizes)
return NULL;
DWORD vaaddr = NtHeader->OptionalHeader.DataDirectory[Directory].VirtualAddress;
if(vaaddr == 0)
return NULL;
*Size = NtHeader->OptionalHeader.DataDirectory[Directory].Size;
if(MappedAsImage || vaaddr < NtHeader->OptionalHeader.SizeOfHeaders)
return (PVOID)((BYTE*)BaseAddress + vaaddr);
}
NTSTATUS NTAPI LdrpSnapThunk(IN PVOID ExportBase,IN PVOID ImportBase,IN PIMAGE_THUNK_DATA OriginalThunk,IN OUT PIMAGE_THUNK_DATA Thunk,
IN PIMAGE_EXPORT_DIRECTORY ExportEntry,IN ULONG ExportSize,IN BOOLEAN Static,IN LPSTR DllName)
{
BOOLEAN IsOrdinal;
USHORT Ordinal;
ULONG OriginalOrdinal = 0;
PIMAGE_IMPORT_BY_NAME AddressOfData;
PULONG NameTable;
PUSHORT OrdinalTable;
LPSTR ImportName = NULL;
USHORT Hint;
NTSTATUS Status;
ULONG_PTR HardErrorParameters[3];
UNICODE_STRING HardErrorDllName, HardErrorEntryPointName;
ANSI_STRING TempString;
ULONG Mask;
ULONG Response;
PULONG AddressOfFunctions;
UNICODE_STRING TempUString;
ANSI_STRING ForwarderName;
PANSI_STRING ForwardName;
PVOID ForwarderHandle;
ULONG ForwardOrdinal;
if ((IsOrdinal = IMAGE_SNAP_BY_ORDINAL(OriginalThunk->u1.Ordinal)))//按序号
{
OriginalOrdinal = IMAGE_ORDINAL(OriginalThunk->u1.Ordinal);
Ordinal = (USHORT)(OriginalOrdinal - ExportEntry->Base);
}
else
{
AddressOfData = (PIMAGE_IMPORT_BY_NAME)((ULONG_PTR)ImportBase +((ULONG_PTR)OriginalThunk->u1.AddressOfData & 0xffffffff));
ImportName = (LPSTR)AddressOfData->Name;
NameTable = (PULONG)((ULONG_PTR)ExportBase + (ULONG_PTR)ExportEntry->AddressOfNames);
OrdinalTable = (PUSHORT)((ULONG_PTR)ExportBase + (ULONG_PTR)ExportEntry->AddressOfNameOrdinals);
Hint = AddressOfData->Hint;
Ordinal = LdrpNameToOrdinal(ImportName,ExportEntry->NumberOfNames,ExportBase,NameTable,OrdinalTable);//根据名称找到序号
}
if ((ULONG)Ordinal >= ExportEntry->NumberOfFunctions)
{
}
else
{
AddressOfFunctions = (PULONG)((ULONG_PTR)ExportBase + (ULONG_PTR)ExportEntry->AddressOfFunctions);
Thunk->u1.Function = (ULONG_PTR)ExportBase + AddressOfFunctions[Ordinal];
if ((Thunk->u1.Function > (ULONG_PTR)ExportEntry) && (Thunk->u1.Function < ((ULONG_PTR)ExportEntry + ExportSize)))
{//对于前向索引的动态链 Function指向字符串 "dll.func"
ImportName = (LPSTR)Thunk->u1.Function;
ForwarderName.Buffer = ImportName;
ForwarderName.Length = (USHORT)(strchr(ImportName, '.') - ImportName);//取得dll名称
ForwarderName.MaximumLength = ForwarderName.Length;
Status = RtlAnsiStringToUnicodeString(&TempUString,&ForwarderName,TRUE);
if (NT_SUCCESS(Status))
{
Status = LdrpLoadDll(FALSE,NULL,NULL,&TempUString,&ForwarderHandle,FALSE);
RtlFreeUnicodeString(&TempUString);
}
RtlInitAnsiString(&ForwarderName,ImportName + ForwarderName.Length + sizeof(CHAR));//取得函数名
if ((ForwarderName.Length > 1) && (*ForwarderName.Buffer == '#'))
{//按序号
ForwardName = NULL;
Status = RtlCharToInteger(ForwarderName.Buffer + sizeof(CHAR),0,&ForwardOrdinal);
}
else
{//按名称
ForwardName = &ForwarderName;
}
Status = LdrpGetProcedureAddress(ForwarderHandle,ForwardName,ForwardOrdinal,(PVOID*)&Thunk->u1.Function,FALSE);//重新获取地址
}
}
USHORT
NTAPI
LdrpNameToOrdinal(IN LPSTR ImportName,
IN ULONG NumberOfNames,
IN PVOID ExportBase,
IN PULONG NameTable,
IN PUSHORT OrdinalTable)
{
LONG Start, End, Next, CmpResult;
/* Use classical binary search to find the ordinal */
Start = Next = 0;
End = NumberOfNames - 1;
while (End >= Start)
{
/* Next will be exactly between Start and End */
Next = (Start + End) >> 1;
/* Compare this name with the one we need to find */
CmpResult = strcmp(ImportName, (PCHAR)((ULONG_PTR)ExportBase + NameTable[Next]));
/* We found our entry if result is 0 */
if (!CmpResult) break;
/* We didn't find, update our range then */
if (CmpResult < 0)
{
End = Next - 1;
}
else if (CmpResult > 0)
{
Start = Next + 1;
}
}
/* If end is before start, then the search failed */
if (End < Start) return -1;
/* Return found name */
return OrdinalTable[Next];
}
复制代码