找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 2937|回复: 1

GetProcAddress解析(一)

[复制链接]

307

主题

228

回帖

7349

积分

用户组: 真·技术宅

UID
2
精华
76
威望
291 点
宅币
5599 个
贡献
253 次
宅之契约
0 份
在线时间
949 小时
注册时间
2014-1-25
发表于 2015-6-13 12:42:57 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

×
本帖最后由 元始天尊 于 2015-6-13 15:06 编辑

剔除了很多无关代码

可以借鉴的地方:
1、考虑了很多极端情况如dllmain未执行,获得函数地址不能等于基址等
2、名称查找采用二分搜索
3、考虑了forward导出函数
4、对按序号和按名称分别处理
5、对内存pe解析

  1. FARPROC WINAPI GetProcAddress(HMODULE hModule, LPCSTR lpProcName)
  2. {
  3.     if (HIWORD(lpProcName) != 0)
  4.     {//按名称查找
  5.         RtlInitAnsiString(&ProcedureName, (LPSTR)lpProcName);
  6.         ProcNamePtr = &ProcedureName;
  7.     }
  8.     else
  9.     { //按序号查找
  10.         Ordinal = (ULONG)lpProcName;
  11.     }
  12.     hMapped = BasepMapModuleHandle(hModule, FALSE);//如果没提供hModule则取得当前模块hModule
  13.     Status = LdrGetProcedureAddress(hMapped,ProcNamePtr, Ordinal,(PVOID*)&fnExp);
  14. }

  15. PVOID WINAPI BasepMapModuleHandle(HMODULE hModule, BOOLEAN AsDataFile)
  16. {
  17.         if (!hModule) return NtCurrentPeb()->ImageBaseAddress;
  18.         if (LDR_IS_DATAFILE(hModule) && !AsDataFile)//如果为资源DLL
  19.                 return NULL;
  20.         return hModule;
  21. }

  22. NTSTATUS NTAPI LdrpGetProcedureAddress(IN PVOID BaseAddress,IN PANSI_STRING Name,IN ULONG Ordinal,OUT PVOID *ProcedureAddress,IN BOOLEAN ExecuteInit)
  23. {
  24.     NTSTATUS Status = STATUS_SUCCESS;
  25.     UCHAR ImportBuffer[64];
  26.     PLDR_DATA_TABLE_ENTRY LdrEntry;
  27.     IMAGE_THUNK_DATA Thunk;
  28.     PVOID ImageBase;
  29.     PIMAGE_IMPORT_BY_NAME ImportName = NULL;
  30.     PIMAGE_EXPORT_DIRECTORY ExportDir;
  31.     ULONG ExportDirSize, Length;
  32.     PLIST_ENTRY Entry;
  33.     if (Name)//若按名称查找
  34.     {
  35.         Length = Name->Length +sizeof(CHAR) + FIELD_OFFSET(IMAGE_IMPORT_BY_NAME, Name);
  36.         ImportName->Hint = 0;
  37.         RtlCopyMemory(ImportName->Name, Name->Buffer, Name->Length);
  38.         ImportName->Name[Name->Length] = ANSI_NULL;
  39.         ImageBase = ImportName;
  40.         Thunk.u1.AddressOfData = 0;
  41.     }
  42.     else//若按序号查找
  43.     {
  44.         ImageBase = NULL;
  45.         Thunk.u1.Ordinal = Ordinal | IMAGE_ORDINAL_FLAG;
  46.     }
  47.     LdrpCheckForLoadedDllHandle(BaseAddress, &LdrEntry); //查找已加载dll
  48.     ExportDir = RtlImageDirectoryEntryToData(LdrEntry->DllBase,TRUE,IMAGE_DIRECTORY_ENTRY_EXPORT, &ExportDirSize);//查找导出表
  49.     Status = LdrpSnapThunk(LdrEntry->DllBase,ImageBase,&Thunk, &Thunk,ExportDir,ExportDirSize,FALSE,NULL);//获取导出表Thunk结构
  50.         *ProcedureAddress = (PVOID)Thunk.u1.Function;
  51. }

  52. BOOLEAN NTAPI LdrpCheckForLoadedDllHandle(IN PVOID Base,OUT PLDR_DATA_TABLE_ENTRY *LdrEntry)
  53. {
  54.         PLDR_DATA_TABLE_ENTRY Current;
  55.         PLIST_ENTRY ListHead, Next;
  56.         if ((LdrpLoadedDllHandleCache) && (LdrpLoadedDllHandleCache->DllBase == Base))//查找缓存
  57.         {
  58.                 *LdrEntry = LdrpLoadedDllHandleCache;
  59.                 return TRUE;
  60.         }
  61.         ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;//线性查找ldr
  62.         Next = ListHead->Flink;
  63.         while (Next != ListHead)
  64.         {
  65.                 Current = CONTAINING_RECORD(Next,LDR_DATA_TABLE_ENTRY,InLoadOrderLinks);
  66.                 if ((Current->InMemoryOrderModuleList.Flink) && (Base == Current->DllBase))
  67.                 {
  68.                         LdrpLoadedDllHandleCache = Current;
  69.                         *LdrEntry = Current;
  70.                         return TRUE;
  71.                 }
  72.                 Next = Next->Flink;
  73.         }
  74.         return FALSE;
  75. }

  76. PVOID NTAPI RtlImageDirectoryEntryToData(PVOID BaseAddress,BOOLEAN MappedAsImage,USHORT Directory,PULONG Size)
  77. {
  78.         PIMAGE_NT_HEADERS NtHeader;
  79.         ULONG Va;
  80.         NtHeader = RtlImageNtHeader(BaseAddress);
  81.         if (NtHeader == NULL)
  82.                 return NULL;
  83.         if(NtHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
  84.                 return RtlpImageDirectoryEntryToData32(BaseAddress,MappedAsImage,Directory,Size,NtHeader);
  85.         else if(NtHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
  86.                 return RtlpImageDirectoryEntryToData64(BaseAddress,MappedAsImage,Directory,Size,NtHeader);
  87.         return NULL;
  88. }

  89. PIMAGE_NT_HEADERS NTAPI RtlImageNtHeader(IN PVOID Base)
  90. {
  91.         PIMAGE_NT_HEADERS NtHeaders = NULL;
  92.         PIMAGE_DOS_HEADER DosHeader;
  93.         if ((Base != NULL) && (Base == (PVOID)-1) && (DosHeader->e_magic == IMAGE_DOS_SIGNATURE))
  94.         {
  95.                 if (DosHeader->e_lfanew < 0x10000000)
  96.                 {
  97.                         NtHeaders = (BYTE*)Base + DosHeader->e_lfanew;
  98.                         if(NtHeaders->Signature != IMAGE_NT_SIGNATURE)
  99.                                 NtHeaders = NULL;
  100.                 }
  101.         }
  102.         return NtHeaders;
  103. }

  104. PVOID NTAPI RtlpImageDirectoryEntryToData32(PVOID BaseAddress, BOOLEAN MappedAsImage, USHORT Directory, PULONG Size, PIMAGE_NT_HEADERS32 NtHeader)
  105. {
  106.         if(Directory >= NtHeader->OptionalHeader.NumberOfRvaAndSizes)
  107.                 return NULL;
  108.         DWORD vaaddr = NtHeader->OptionalHeader.DataDirectory[Directory].VirtualAddress;
  109.         if(vaaddr == 0)
  110.                 return NULL;
  111.         *Size = NtHeader->OptionalHeader.DataDirectory[Directory].Size;
  112.         if(MappedAsImage || vaaddr < NtHeader->OptionalHeader.SizeOfHeaders)
  113.                 return (PVOID)((BYTE*)BaseAddress + vaaddr);
  114. }

  115. PVOID NTAPI RtlpImageDirectoryEntryToData64(PVOID BaseAddress, BOOLEAN MappedAsImage, USHORT Directory, PULONG Size, PIMAGE_NT_HEADERS64 NtHeader)
  116. {
  117.         if(Directory >= NtHeader->OptionalHeader.NumberOfRvaAndSizes)
  118.                 return NULL;
  119.         DWORD vaaddr = NtHeader->OptionalHeader.DataDirectory[Directory].VirtualAddress;
  120.         if(vaaddr == 0)
  121.                 return NULL;
  122.         *Size = NtHeader->OptionalHeader.DataDirectory[Directory].Size;
  123.         if(MappedAsImage || vaaddr < NtHeader->OptionalHeader.SizeOfHeaders)
  124.                 return (PVOID)((BYTE*)BaseAddress + vaaddr);
  125. }

  126. NTSTATUS NTAPI LdrpSnapThunk(IN PVOID ExportBase,IN PVOID ImportBase,IN PIMAGE_THUNK_DATA OriginalThunk,IN OUT PIMAGE_THUNK_DATA Thunk,
  127.         IN PIMAGE_EXPORT_DIRECTORY ExportEntry,IN ULONG ExportSize,IN BOOLEAN Static,IN LPSTR DllName)
  128. {
  129.         BOOLEAN IsOrdinal;
  130.         USHORT Ordinal;
  131.         ULONG OriginalOrdinal = 0;
  132.         PIMAGE_IMPORT_BY_NAME AddressOfData;
  133.         PULONG NameTable;
  134.         PUSHORT OrdinalTable;
  135.         LPSTR ImportName = NULL;
  136.         USHORT Hint;
  137.         NTSTATUS Status;
  138.         ULONG_PTR HardErrorParameters[3];
  139.         UNICODE_STRING HardErrorDllName, HardErrorEntryPointName;
  140.         ANSI_STRING TempString;
  141.         ULONG Mask;
  142.         ULONG Response;
  143.         PULONG AddressOfFunctions;
  144.         UNICODE_STRING TempUString;
  145.         ANSI_STRING ForwarderName;
  146.         PANSI_STRING ForwardName;
  147.         PVOID ForwarderHandle;
  148.         ULONG ForwardOrdinal;

  149.         if ((IsOrdinal = IMAGE_SNAP_BY_ORDINAL(OriginalThunk->u1.Ordinal)))//按序号
  150.         {
  151.                 OriginalOrdinal = IMAGE_ORDINAL(OriginalThunk->u1.Ordinal);
  152.                 Ordinal = (USHORT)(OriginalOrdinal - ExportEntry->Base);
  153.         }
  154.         else
  155.         {
  156.                 AddressOfData = (PIMAGE_IMPORT_BY_NAME)((ULONG_PTR)ImportBase +((ULONG_PTR)OriginalThunk->u1.AddressOfData & 0xffffffff));
  157.                 ImportName = (LPSTR)AddressOfData->Name;
  158.                 NameTable = (PULONG)((ULONG_PTR)ExportBase + (ULONG_PTR)ExportEntry->AddressOfNames);
  159.                 OrdinalTable = (PUSHORT)((ULONG_PTR)ExportBase + (ULONG_PTR)ExportEntry->AddressOfNameOrdinals);
  160.                 Hint = AddressOfData->Hint;
  161.                 Ordinal = LdrpNameToOrdinal(ImportName,ExportEntry->NumberOfNames,ExportBase,NameTable,OrdinalTable);//根据名称找到序号
  162.         }

  163.         if ((ULONG)Ordinal >= ExportEntry->NumberOfFunctions)
  164.         {
  165.         }
  166.         else
  167.         {
  168.                 AddressOfFunctions = (PULONG)((ULONG_PTR)ExportBase + (ULONG_PTR)ExportEntry->AddressOfFunctions);
  169.                 Thunk->u1.Function = (ULONG_PTR)ExportBase + AddressOfFunctions[Ordinal];
  170.                 if ((Thunk->u1.Function > (ULONG_PTR)ExportEntry) && (Thunk->u1.Function < ((ULONG_PTR)ExportEntry + ExportSize)))
  171.                 {//对于前向索引的动态链  Function指向字符串  "dll.func"
  172.                         ImportName = (LPSTR)Thunk->u1.Function;
  173.                         ForwarderName.Buffer = ImportName;
  174.                         ForwarderName.Length = (USHORT)(strchr(ImportName, '.') - ImportName);//取得dll名称
  175.                         ForwarderName.MaximumLength = ForwarderName.Length;
  176.                         Status = RtlAnsiStringToUnicodeString(&TempUString,&ForwarderName,TRUE);
  177.                         if (NT_SUCCESS(Status))
  178.                         {
  179.                                 Status = LdrpLoadDll(FALSE,NULL,NULL,&TempUString,&ForwarderHandle,FALSE);
  180.                                 RtlFreeUnicodeString(&TempUString);
  181.                         }
  182.                         RtlInitAnsiString(&ForwarderName,ImportName + ForwarderName.Length + sizeof(CHAR));//取得函数名
  183.                         if ((ForwarderName.Length > 1) && (*ForwarderName.Buffer == '#'))
  184.                         {//按序号
  185.                                 ForwardName = NULL;
  186.                                 Status = RtlCharToInteger(ForwarderName.Buffer + sizeof(CHAR),0,&ForwardOrdinal);
  187.                         }
  188.                         else
  189.                         {//按名称
  190.                                 ForwardName = &ForwarderName;
  191.                         }
  192.                         Status = LdrpGetProcedureAddress(ForwarderHandle,ForwardName,ForwardOrdinal,(PVOID*)&Thunk->u1.Function,FALSE);//重新获取地址
  193.                 }
  194. }

  195. USHORT
  196. NTAPI
  197. LdrpNameToOrdinal(IN LPSTR ImportName,
  198.                   IN ULONG NumberOfNames,
  199.                   IN PVOID ExportBase,
  200.                   IN PULONG NameTable,
  201.                   IN PUSHORT OrdinalTable)
  202. {
  203.     LONG Start, End, Next, CmpResult;

  204.     /* Use classical binary search to find the ordinal */
  205.     Start = Next = 0;
  206.     End = NumberOfNames - 1;
  207.     while (End >= Start)
  208.     {
  209.         /* Next will be exactly between Start and End */
  210.         Next = (Start + End) >> 1;

  211.         /* Compare this name with the one we need to find */
  212.         CmpResult = strcmp(ImportName, (PCHAR)((ULONG_PTR)ExportBase + NameTable[Next]));

  213.         /* We found our entry if result is 0 */
  214.         if (!CmpResult) break;

  215.         /* We didn't find, update our range then */
  216.         if (CmpResult < 0)
  217.         {
  218.             End = Next - 1;
  219.         }
  220.         else if (CmpResult > 0)
  221.         {
  222.             Start = Next + 1;
  223.         }
  224.     }

  225.     /* If end is before start, then the search failed */
  226.     if (End < Start) return -1;

  227.     /* Return found name */
  228.     return OrdinalTable[Next];
  229. }
复制代码
回复

使用道具 举报

307

主题

228

回帖

7349

积分

用户组: 真·技术宅

UID
2
精华
76
威望
291 点
宅币
5599 个
贡献
253 次
宅之契约
0 份
在线时间
949 小时
注册时间
2014-1-25
 楼主| 发表于 2015-6-13 16:14:56 | 显示全部楼层
依据上述过程,我们可以写出一个简化版的GetProcAddress,且不用依赖peb的ldr,输入是pe加载地址和函数名,输出是函数位置,只做查输出表的操作,该函数可以实现我之后要研究的dll隐藏技术。
这份代码除了比原有功能少了通过index获取函数地址之外,增加了一些特殊功能,比如支持unicode,支持顺序查找和二分查找,已在win8.1 x86 x64 环境下测试,若有坑请指出。


  1. #include <windows.h>
  2. #include <winternl.h>

  3. #if defined(WIN64) || defined(_WIN64)
  4. #pragma comment(lib,"ntdll64.lib")
  5. #else
  6. #pragma comment(lib,"ntdll.lib")
  7. #endif

  8. #if defined(UNICODE) || defined(_UNICODE)
  9. #define GetProcAddressT GetProcAddressW
  10. #else
  11. #define GetProcAddresT GetProcAddressA
  12. #endif

  13. /*
  14. 改进之处:
  15. 1.只允许使用名称索引
  16. 2.采用二分查找(后期改成hash)
  17. 3.精简代码
  18. 4.支持unicode版本
  19. 5.加入对资源方式加载dll的处理
  20. */

  21. typedef struct _MTEB
  22. {
  23.         _NT_TIB NtTib;
  24.         PVOID ProcessEnvironmentBlock;
  25. }MTEB,*PMTEB;

  26. typedef struct _MPEB
  27. {
  28.         DWORD flags;
  29.         PVOID Mutant;
  30.         PVOID ImageBaseAddress;
  31. }MPEB,*PMPEB;

  32. #define SEARCH_LINEAR 1
  33. #define SEARCH_BINARY 2

  34. FARPROC WINAPI GetProcAddressTA(HMODULE hModule,LPCSTR lpProcName,INT how);
  35. FARPROC WINAPI GetProcAddressTW(HMODULE hModule,LPCWSTR lpProcName,INT how = SEARCH_BINARY)
  36. {
  37.         ANSI_STRING ProcNameA;
  38.         UNICODE_STRING ProcNameW;
  39.         FARPROC ObjAddr = NULL;
  40.         if(lpProcName == NULL)
  41.                 return NULL;
  42.         RtlInitUnicodeString(&ProcNameW,lpProcName);
  43.         if(!RtlUnicodeStringToAnsiString(&ProcNameA,&ProcNameW,TRUE))
  44.                 return NULL;
  45.         ObjAddr = GetProcAddressTA(hModule,ProcNameA.Buffer,how);
  46.         RtlFreeAnsiString(&ProcNameA);
  47.         return ObjAddr;
  48. }

  49. #define DLL_RESOURCE_FLAG 3
  50. FARPROC WINAPI GetProcAddressTA(HMODULE hModule,LPCSTR lpProcName,INT how = SEARCH_BINARY)
  51. {
  52.         if(!hModule)//获取当前模块
  53.                 hModule = (HMODULE)((PMPEB)((PMTEB)NtCurrentTeb())->ProcessEnvironmentBlock)->ImageBaseAddress;
  54.         BYTE* pFlag = (BYTE*)&hModule;
  55.         if(*pFlag & DLL_RESOURCE_FLAG)//还原到'MZ'位置
  56.                 *pFlag &= ~DLL_RESOURCE_FLAG;
  57.         if(hModule == NULL || hModule == (HMODULE)-1)
  58.                 return NULL;
  59.         //找到导出表
  60.         PIMAGE_DOS_HEADER DosHeader = (PIMAGE_DOS_HEADER)hModule;
  61.         PIMAGE_NT_HEADERS NtHeaders = NULL;
  62.         if(DosHeader->e_magic == IMAGE_DOS_SIGNATURE && DosHeader->e_lfanew)
  63.         {//简单检查hModule对应内存PE的合法性
  64.                 NtHeaders = (PIMAGE_NT_HEADERS)((BYTE*)hModule + DosHeader->e_lfanew);
  65.                 if(NtHeaders->Signature != IMAGE_NT_SIGNATURE)
  66.                         NtHeaders = NULL;
  67.         }
  68.         if(!NtHeaders)
  69.                 return NULL;

  70.         PVOID BaseAddress = hModule;
  71.         USHORT Directory = IMAGE_DIRECTORY_ENTRY_EXPORT;
  72.         PIMAGE_EXPORT_DIRECTORY ExportDir = NULL;
  73.         ULONG ExportDirSize = 0;
  74.         if(NtHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
  75.         {
  76.                 PIMAGE_NT_HEADERS32 tpnh = (PIMAGE_NT_HEADERS32)NtHeaders;
  77.                 if(Directory >= tpnh->OptionalHeader.NumberOfRvaAndSizes)
  78.                         return NULL;
  79.                 DWORD VA = tpnh->OptionalHeader.DataDirectory[Directory].VirtualAddress;
  80.                 if(VA == NULL)
  81.                         return NULL;
  82.                 ExportDirSize = tpnh->OptionalHeader.DataDirectory[Directory].Size;
  83.                 ExportDir = (PIMAGE_EXPORT_DIRECTORY)((BYTE*)BaseAddress + VA);
  84.         }
  85.         else
  86.         {
  87.                 PIMAGE_NT_HEADERS64 tpnh = (PIMAGE_NT_HEADERS64)NtHeaders;
  88.                 if(Directory >= tpnh->OptionalHeader.NumberOfRvaAndSizes)
  89.                         return NULL;
  90.                 DWORD VA = tpnh->OptionalHeader.DataDirectory[Directory].VirtualAddress;
  91.                 if(VA == NULL)
  92.                         return NULL;
  93.                 ExportDirSize = tpnh->OptionalHeader.DataDirectory[Directory].Size;
  94.                 ExportDir = (PIMAGE_EXPORT_DIRECTORY)((BYTE*)BaseAddress + VA);
  95.         }
  96.         //匹配导出名,假设按字母排序
  97.         PULONG NameTable = (PULONG)((ULONG_PTR)BaseAddress + (ULONG_PTR)ExportDir->AddressOfNames);
  98.         PUSHORT OrdinalTable = (PUSHORT)((ULONG_PTR)BaseAddress + (ULONG_PTR)ExportDir->AddressOfNameOrdinals);
  99.        
  100.         USHORT Ordinal = -1;
  101.         if(how == SEARCH_LINEAR)
  102.         {
  103.                 for(LONG i = 0;i < ExportDir->NumberOfNames;i++)
  104.                 {
  105.                         if(!strcmp(lpProcName,(PCHAR)((ULONG_PTR)BaseAddress + NameTable[i])))
  106.                         {
  107.                                 Ordinal = OrdinalTable[i];
  108.                                 break;
  109.                         }
  110.                 }
  111.         }
  112.         else if(how == SEARCH_BINARY)
  113.         {
  114.                 LONG Start = 0,Next = 0,End = ExportDir->NumberOfNames -1,CmpResult;
  115.                 while(End >= Start)
  116.                 {
  117.                         Next = (Start + End) >> 1;
  118.                         CmpResult = strcmp(lpProcName,(PCHAR)((ULONG_PTR)BaseAddress + NameTable[Next]));
  119.                         if(!CmpResult)
  120.                                 break;
  121.                         if(CmpResult < 0)
  122.                                 End = Next - 1;
  123.                         else
  124.                                 Start = Next + 1;
  125.                 }
  126.                 if(End >= Start)
  127.                         Ordinal = OrdinalTable[Next];
  128.         }

  129.         //处理forward export情况
  130.         if(Ordinal >= ExportDir->NumberOfFunctions)
  131.                 return NULL;
  132.         PULONG AddressOfFunctions = (PULONG)((ULONG_PTR)BaseAddress + (ULONG_PTR)ExportDir->AddressOfFunctions);
  133.         ULONG_PTR Function = (ULONG_PTR)BaseAddress + AddressOfFunctions[Ordinal];
  134.         if(Function > (ULONG_PTR)ExportDir && Function < (ULONG_PTR)ExportDir + ExportDirSize)
  135.                 return NULL;
  136.         return (FARPROC)Function;
  137. }

  138. void main()
  139. {
  140.         typedef int (WINAPI* MSGBOX)(DWORD,CHAR*,CHAR*,DWORD);
  141.         HMODULE hmod = LoadLibraryA("user32.dll");
  142.         if(hmod == NULL)
  143.                 return;
  144.         MSGBOX box ;
  145. //         box = (MSGBOX)GetProcAddress(hmod,"MessageBoxA");
  146. //         if(box == NULL)
  147. //                 return;
  148. //         box(NULL,"ok","ok",0);
  149.         box = (MSGBOX)GetProcAddressTA(hmod,"MessageBoxA");
  150.         if(box == NULL)
  151.                 return;
  152.         box(NULL,"ok","ok",0);

  153.         FreeLibrary(hmod);
  154. }
复制代码
回复 赞! 靠!

使用道具 举报

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2024-5-6 13:05 , Processed in 0.032950 second(s), 28 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表