Pe研究之: 从内存中加载Pe文件 作者:Sunline lisunlin0@yahoo.com.cn 日期:2007年7月 关键字:代码重定位,代码注入,远程代码, 加载exe文件, 加载dll文件 Remotthread, injectcode, relocation code, load dll from memory, load pe from memory load pe from memory, execute from meory 代码下载: http://download.csdn.net/source/297095 第二版:(代码几乎完全重写了一遍,修正了很多bug) http://download.csdn.net/source/359338 概述: 在某些特殊场合下需要将Pe文件(.exe, .dll等)直接从内存中启动,比如一段验证软件注册的核心代码, 防Dump的代码, 一些补丁,外挂,当然病毒也常常用这种技术。网上流传了几种解决方案,不过都或多或少存在一些不足,最主要是对MFC程序和带有资源的Pe支持不稳定,或者需要按某些特殊的约定编程,总之不太适合初学者,我这里给出了一个PeBlock的解决方法,可以加载绝大多数的执行文件。 我的这个解决方案克服了前面提到的一些不足,但也没有做到完美。那就是推荐编译时给Pe文件带上重定位信息(一般的Dll是带的,编译自己的exe时需要使用/fixed:no 的编译选项产生重定位表)。更具体的信息请参看示例代码。 这里以库的方式给出LoadPe(…)在自身空间内加载Pe,和LoadPeEx(…)在其它进程空间加载Pe,欢迎大家测试使用。 另外,如果代码不要求加载.exe,仅要求支持Dll,适当修改源代码就可以做到近乎完美了。 具体实现: Pe文件的加载大体过程是:申请Pe文件建议的内存地址,沿此地址将磁盘中的Pe文件按内存对齐拷贝到内存中,按节属性初始化节,初始化导入函数表,跳入Pe入口执行之。因为网上很早就有这方面知识的相关文章了,这里不再详细叙述,请自己从网上搜索。或参看Bo2000的源代码。 在测试Bo2000的源代码时发现可以使多数的简单.dll文件正确加载,却无法正确加载用MFC生成的.dll文件以及压缩过的可执行文件,仔细调试发现GetModuleFileName是罪魁祸首(另外BO2k里面dll_load存在好几个BUG,这也是其不稳定的直接原因.),调用这个函数将返回NULL,而一般的Dll编写者都默认这个返回结果不会是NULL,并且依赖这个返回结果。 既然找到了原因,那么就可以使用相应的对策来克服之。在这里,我是通过在Pe的映象尾部附加了一个PeBlock的块来解决这个问题(如果仅要求在进程本身加载.dll,这个PeBlock是没有必要的,但是为了能够在其它进程中加载和兼顾加载.exe,使用这个PeBlock是必要的),通过这个PeBlock,不但可以加载.dll,还可以加载.exe(包括压缩的DLL和EXE.)。 注意:这些代码仅作测试,如果要用作非法用途,本人不承担任何法律责任。 其它细节请看打包的源工程文件。 源代码: // LoadPe.h// // wirite by Sunline 13.July 2007// #pragma once // 在内存中加载PE文件(主要支持EXE,DLL以及由之衍生的OCX,AX等) // 最原始的代码参见Bo2000中dll_load.cpp。 // 要求: // 推荐带重定位信息,否则对于多数Pe文件是无法成功加载的。 // 注意: // 仅在本人机器上测试,环境:CPU: Celeron 1.7G Memory: 256M OS:WinXp sp2 Complier: VC++6.0 Editor: VS2005 // 支持Win2000,WinXp,Win2003,WinVista; // 不支持WinMe,Win98,Win95以及更早的Windows产品 // 限制: // Commandline 应该是"ModuleFileName Param1 param2 ...", 如果ModuleFileName为空,GetModuleFileName将返回空,这对于多数程序是无法接受的。 // 不支持通过间接途径或通过函数序号调用GetModuleHandle,GetModuleFileName,GetCommandLine且依赖这些函数其返回值的Pe文件。 // 对于MFC程序,ModuleFileName必须带有"."(参看MFC源代码AppInit.cpp中CWinApp::SetCurrentHandles()函数,要求文件名中必须有"."的存在,比如"my.dll", "my.", ".my"都合法)。 // 不支持动态链接的MFC程序(原因是在动态链接MFC库的程序中GetModuleHandle,GetModuleFileName,GetCommandLine是在MFC*.dll中调用,违反上述限制)。 // 如何正确地使用: // fSuicid是一个必须仔细考虑的一个标志: // 设定了fSuicid,且Pe文件是多线程的,则应该保证ExeEntry或DllEntry是最后一个返回的线程,否则会卸载仍有活动线程的内存区域,导致线程访问已卸载的内存空间而出错。 // 带apiHook目的的Pe不应该指定fSuicid=TRUE; // 本人的英语能力有限,大约着用英语作了些注释,呵呵,促进国际化嘛 // // Load pe file from memory(support exe, dll or other pe file derived from exe/dll, for instances .ocx, .ax eg.) // the source file reference dll_load.cpp in Bo2000, you can get more details from it. // desire: // desire the pe file with relocation information, or it will failed for most pe files. // notice: // It's only test on my machion, Environment: CPU: Celeron 1.7G Memory: 256M OS:WinXp sp2 compile: VC++6.0 Editor: VS2005 // surpport Win2000,WinXp,Win2003,WinVista; // not surpport WinMe,Win98,Win95 or other early Windows os // Commandline contain the modulename, so please assure the Commandline is not NULL // Limit: // not surpport the pe file which depend on the GetModuleHandle,GetModuleFileName,GetCommandLine functions but call them indirect. // not suport the pe file which use the MFC in a share dll // CommandLine form as "ModuleFileName Param1 param2 ...", if ModuleFileName is NULL, GetModuleFileName() will return NULL, // for most pe file, the LoadPeXX() will failed, and 哪位英语好一点的仁兄有时间的话帮忙给把这补全啊, 哈哈, 上面这段英语估计中国人看不懂,外国人也看不懂 // #ifdef __cplusplusextern "C" {#endif typedef int (__stdcall *PROCUNLOAD)(int uExitCode); HINSTANCE __stdcall _LoadLibraryA( LPVOID lpRawRelocPe, LPCSTR lpLibFileName); HINSTANCE __stdcall _LoadLibraryW( LPVOID lpRawRelocPe, LPCWSTR lpLibFileName); HINSTANCE __stdcall _LoadLibraryExA(LPVOID lpRawRelocPe, LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags); HINSTANCE __stdcall _LoadLibraryExW(LPVOID lpRawRelocPe, LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags); BOOL __stdcall _FreeLibrary( HMODULE hLibModule); HANDLE __stdcall LoadPeA(LPVOID lpRawRelocPe, LPCSTR lpCommandLine, HINSTANCE *phInst = NULL, BOOL fSuicid = FALSE, PROCUNLOAD *pfUnload = NULL); // if fSuicid is FASLE, the pfUnload should NOT be NULL; HANDLE __stdcall LoadPeW(LPVOID lpRawRelocPe, LPCWSTR lpwCommandLine, HINSTANCE *phInst = NULL, BOOL fSuicid = FALSE, PROCUNLOAD *pfUnload = NULL); HANDLE __stdcall LoadPeExA(DWORD dwProcessID, LPVOID lpRawRelocPe, LPCSTR lpCommandLine, HINSTANCE *phRemotInst = NULL, BOOL fSuicid = FALSE, PROCUNLOAD *pfUnload = NULL); HANDLE __stdcall LoadPeExW(DWORD dwProcessID, LPVOID lpRawRelocPe, LPCWSTR lpwCommandLine, HINSTANCE *phRemotInst = NULL, BOOL fSuicid = FALSE, PROCUNLOAD *pfUnload = NULL); int __stdcall UnloadPe(PROCUNLOAD pFouncUnload); int __stdcall UnloadPeEx(DWORD dwProcessID, PROCUNLOAD pFouncUnload); FARPROC __stdcall _GetProcAddress(HMODULE hModule, LPCSTR FuncName);#ifdef __cplusplus}#endif #ifdef UNICODE #define LoadPe LoadPeW #define LoadPeEx LoadPeExW#else #define LoadPe LoadPeA #define LoadPeEx LoadPeExA#endif // LoadPe.cpp #include <windows.h> #include "libc.h" #include "RawPeApi.h" #include "LoadPe.h" extern unsigned char pRawPeBlock[]; char *pzUnLoad = "UnLoad"; // the export function UnLoad name string; // if function succed return the new thread handle, lphInstance point to the memPe instance, pfUnload point to the address to unload the instance // otherwise return NULL; HANDLE __stdcall LoadPeA(LPVOID lpRawRelocPe, LPCSTR lpCommandLine, HINSTANCE *phInst, BOOL fSuicid, PROCUNLOAD *pfUnload) { HANDLE hRet = NULL; int nCmdLineLen = lstrlenA(lpCommandLine) + 1; PWCHAR pwCmdLine = (PWCHAR)_malloc(nCmdLineLen * sizeof(WCHAR)); if(MultiByteToWideChar(CP_THREAD_ACP, MB_COMPOSITE, lpCommandLine, -1, pwCmdLine, nCmdLineLen)) hRet = LoadPeW(lpRawRelocPe, pwCmdLine, phInst, fSuicid, pfUnload); _free(pwCmdLine); return hRet; } HANDLE __stdcall LoadPeW(LPVOID lpRawRelocPe, LPCWSTR lpwCommandLine, HINSTANCE *phInst, BOOL fSuicid, PROCUNLOAD *pfUnload) { int nRet = ERROR_UNKNOWN; int nPeBlockImageSize = 0; int nRawRelocPeImageSize = 0; int nCmdLineLenA = 0; // the string length for commandlinea include the end flag. int nCmdLineLenW = 0; int nMemNead = 0; HANDLE hRet = 0; LPVOID lpPeBlock = NULL; LPVOID lpRelocPe = NULL; LPWSTR lpwCmdLine = NULL; // point to the WideByte commandline in lpPeblock LPSTR lpCommandLine = NULL; // multibyte commandline; LPSTR lpCmdLine = NULL; // point to the multibyte commandline in lpPeblock LPPEPARAM pPeParam = NULL; MEMORY_BASIC_INFORMATION mbi = {0}; PIMAGE_DOS_HEADER pDosHeader = NULL; PIMAGE_NT_HEADERS pNTHeader = NULL; __try { if(lpwCommandLine == NULL) __leave; nCmdLineLenA = lstrlenW(lpwCommandLine); nCmdLineLenA += sizeof(CHAR); nCmdLineLenW = lstrlenW(lpwCommandLine) * sizeof(WCHAR); nCmdLineLenW += sizeof(WCHAR); lpCommandLine = (LPSTR)_malloc(nCmdLineLenA); if(0 == WideCharToMultiByte(CP_THREAD_ACP, 0, lpwCommandLine, -1, lpCommandLine, nCmdLineLenA, NULL, NULL)) __leave; nRet = VerifyPE(pRawPeBlock); if(nRet) __leave; nRet = VerifyPE(lpRawRelocPe); if(nRet) __leave; pDosHeader = (PIMAGE_DOS_HEADER)pRawPeBlock; pNTHeader = PIMAGE_NT_HEADERS((LPBYTE)pDosHeader + pDosHeader->e_lfanew); nPeBlockImageSize = pNTHeader->OptionalHeader.SizeOfImage; if(pNTHeader->FileHeader.Characteristics & IMAGE_FILE_DLL) // the pRawPeBlock should not be a Dll { nRet = ERROR_INVALID_MEMPEBLOCK; __leave; } pDosHeader = (PIMAGE_DOS_HEADER)lpRawRelocPe; pNTHeader = PIMAGE_NT_HEADERS((LPBYTE)pDosHeader + pDosHeader->e_lfanew); LPVOID pImageBase = (LPVOID)(ULONG_PTR)pNTHeader->OptionalHeader.ImageBase; nRawRelocPeImageSize = pNTHeader->OptionalHeader.SizeOfImage; nMemNead = nRawRelocPeImageSize + nPeBlockImageSize + nCmdLineLenA + nCmdLineLenW + sizeof(PEPARAM); if(0 == VirtualQuery(pImageBase, &mbi, sizeof(MEMORY_BASIC_INFORMATION))) __leave; //HANDLE hmapping=CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0, nMemNead,NULL); //if(hmapping==NULL) return NULL; //LPVOID pImgBase=MapViewOfFileEx(hmapping,FILE_MAP_WRITE,0,0,0,pImageBase); //if(pImgBase==NULL) { // pImgBase=MapViewOfFileEx(hmapping,FILE_MAP_WRITE,0,0,0,NULL); //} //CloseHandle(hmapping); //if(pImageBase == NULL) // return 0; //lpRelocPe = pImgBase; if((MEM_FREE == mbi.State) && ((SIZE_T)nMemNead < mbi.RegionSize)) { lpRelocPe = (HINSTANCE)VirtualAlloc(pImageBase, nMemNead, MEM_COMMIT, PAGE_EXECUTE_READWRITE); } if(lpRelocPe == NULL) { lpRelocPe = (HINSTANCE)VirtualAlloc(NULL, nMemNead, MEM_COMMIT, PAGE_EXECUTE_READWRITE); if(NULL == lpRelocPe) { nRet = ERROR_MEMLESS; __leave; } } lpPeBlock = (LPBYTE)lpRelocPe + nRawRelocPeImageSize; lpwCmdLine = LPWSTR((LPBYTE)lpPeBlock + nPeBlockImageSize); lpCmdLine = (LPSTR)((LPBYTE)lpwCmdLine + nCmdLineLenW); pPeParam = (LPPEPARAM)((LPBYTE)lpCmdLine + nCmdLineLenA); nRet = AlignPEToMem(lpRawRelocPe, lpRelocPe); if(nRet) __leave; nRet = AlignPEToMem(pRawPeBlock, lpPeBlock); if(nRet) __leave; if(lpRelocPe != pImageBase) { nRet = RelocatePe(lpRelocPe, 0, lpRelocPe); if(nRet) __leave; } nRet = FillImportTable(lpPeBlock); if(nRet) __leave; nRet = RelocatePe(lpPeBlock, 0, lpPeBlock); if(nRet) __leave; lstrcpyA(lpCmdLine, lpCommandLine); lstrcpyW(lpwCmdLine, lpwCommandLine); pPeParam->fSuicid = fSuicid; pDosHeader = (PIMAGE_DOS_HEADER)pRawPeBlock; pNTHeader = PIMAGE_NT_HEADERS((LPBYTE)pDosHeader + pDosHeader->e_lfanew); FARPROC pEntryPoint = (FARPROC) ((LPBYTE)lpPeBlock + (unsigned int)pNTHeader->OptionalHeader.AddressOfEntryPoint); DWORD dwThreadId; hRet = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)pEntryPoint, lpRelocPe, 0, &dwThreadId); } __except(EXCEPTION_EXECUTE_HANDLER) { nRet = ERROR_UNKNOWN; } if(nRet) { if(lpRelocPe) { VirtualFree(lpRelocPe, 0, MEM_FREE); lpRelocPe = NULL; hRet = NULL; } } if(lpCommandLine) _free(lpCommandLine); if(phInst) *phInst = (HINSTANCE)lpRelocPe; if(fSuicid == FALSE) *pfUnload = (PROCUNLOAD)_GetProcAddress((HMODULE)lpPeBlock, pzUnLoad); return hRet; } HANDLE __stdcall LoadPeExA(DWORD dwProcessID, LPVOID lpRawRelocPe, LPCSTR lpCommandLine, HINSTANCE *phRemotInst, BOOL fSuicid, PROCUNLOAD *pfUnload) { HANDLE hRet = NULL; int nCmdLineLen = lstrlenA(lpCommandLine) + 1; PWCHAR pwCmdLine = (PWCHAR)_malloc(nCmdLineLen * sizeof(WCHAR)); if(MultiByteToWideChar(CP_THREAD_ACP, MB_COMPOSITE, lpCommandLine, -1, pwCmdLine, nCmdLineLen)) hRet = LoadPeExW(dwProcessID, lpRawRelocPe, pwCmdLine, phRemotInst, fSuicid, pfUnload); _free(pwCmdLine); return hRet; } HANDLE __stdcall LoadPeExW(DWORD dwProcessID, LPVOID lpRawRelocPe, LPCWSTR lpwCommandLine, HINSTANCE *phRemotInst, BOOL fSuicid, PROCUNLOAD *pfUnload) { HANDLE hRet = 0; int nRet = ERROR_UNKNOWN; int nPeBlockImageSize = 0; int nRawRelocPeImageSize = 0; int nCmdLineLenA = 0; int nCmdLineLenW = 0; UINT nMemNead = 0; PIMAGE_DOS_HEADER pDosHeader = NULL; PIMAGE_NT_HEADERS pNTHeader = NULL; MEMORY_BASIC_INFORMATION mbi = {0}; HANDLE hProcess = INVALID_HANDLE_VALUE; LPVOID pRelocPe = NULL; LPVOID pRemotRelocPe = NULL; LPVOID pPeBlock = NULL; LPVOID lpRemotePeBlock = NULL; LPSTR lpCommandLine = NULL; LPSTR lpCmdLine = NULL; LPWSTR lpwCmdLine = NULL; LPPEPARAM pPeParam = NULL; // LPWSTR lpwRemotCmdLine = NULL; LPVOID pRelocPeImageBase = NULL; __try { if(lpwCommandLine == NULL) __leave; nCmdLineLenA = lstrlenW(lpwCommandLine); nCmdLineLenA += sizeof(CHAR); nCmdLineLenW = lstrlenW(lpwCommandLine) * sizeof(WCHAR); nCmdLineLenW += sizeof(WCHAR); lpCommandLine = (LPSTR)_malloc(nCmdLineLenA); if(0 == WideCharToMultiByte(CP_THREAD_ACP, 0, lpwCommandLine, -1, lpCommandLine, nCmdLineLenA, NULL, NULL)) __leave; nRet = VerifyPE(pRawPeBlock); if(nRet) __leave; nRet = VerifyPE(lpRawRelocPe); if(nRet) __leave; hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_QUERY_INFORMATION, FALSE, dwProcessID); if(hProcess == NULL) { nRet = ERROR_INVALID_OPENPROCESS; __leave; } pDosHeader = (PIMAGE_DOS_HEADER)pRawPeBlock; pNTHeader = PIMAGE_NT_HEADERS((LPBYTE)pDosHeader + pDosHeader->e_lfanew); if(pNTHeader->FileHeader.Characteristics & IMAGE_FILE_DLL) // the pRawPeBlock should not be a Dll { nRet = ERROR_INVALID_MEMPEBLOCK; __leave; } nPeBlockImageSize = pNTHeader->OptionalHeader.SizeOfImage; pDosHeader = (PIMAGE_DOS_HEADER)lpRawRelocPe; pNTHeader = PIMAGE_NT_HEADERS((LPBYTE)pDosHeader + pDosHeader->e_lfanew); pRelocPeImageBase = (LPVOID)(ULONG_PTR)pNTHeader->OptionalHeader.ImageBase; nRawRelocPeImageSize = pNTHeader->OptionalHeader.SizeOfImage; nMemNead = nRawRelocPeImageSize + nPeBlockImageSize + nCmdLineLenA + nCmdLineLenW + sizeof(PEPARAM); if(0 == VirtualQueryEx(hProcess, pRelocPeImageBase, &mbi, sizeof(MEMORY_BASIC_INFORMATION))) __leave; if((MEM_FREE == mbi.State) && ((SIZE_T)nMemNead < mbi.RegionSize)) pRemotRelocPe = VirtualAllocEx(hProcess, pRelocPeImageBase, nMemNead, MEM_COMMIT, PAGE_EXECUTE_READWRITE); if(pRemotRelocPe == NULL) { pRemotRelocPe = VirtualAllocEx(hProcess, NULL, nMemNead, MEM_COMMIT, PAGE_EXECUTE_READWRITE); VirtualQuery(pRemotRelocPe, &mbi, sizeof(MEMORY_BASIC_INFORMATION)); if(NULL == pRemotRelocPe) __leave; } pRelocPe = VirtualAlloc(NULL, nMemNead, MEM_COMMIT, PAGE_READWRITE); pPeBlock = (LPBYTE)pRelocPe + nRawRelocPeImageSize; lpRemotePeBlock = (LPBYTE)pRemotRelocPe + nRawRelocPeImageSize; lpwCmdLine = LPWSTR((LPBYTE)pPeBlock + nPeBlockImageSize); lpCmdLine = LPSTR((LPBYTE)lpwCmdLine + nCmdLineLenW); pPeParam = LPPEPARAM((LPBYTE)lpCmdLine + nCmdLineLenA); // lpwRemotCmdLine = LPWSTR((LPBYTE)lpRemotePeBlock + nPeBlockImageSize); nRet = AlignPEToMem(lpRawRelocPe, pRelocPe); if(nRet) __leave; nRet = AlignPEToMem(pRawPeBlock, pPeBlock); if(nRet) __leave; nRet = FillImportTable(pPeBlock); if(nRet) __leave; if(pRelocPeImageBase != pRemotRelocPe) { nRet = RelocatePe(pRelocPe, 0, pRemotRelocPe); if(nRet) __leave; } nRet = RelocatePe(pPeBlock, 0, lpRemotePeBlock); if(nRet) __leave; lstrcpyA(lpCmdLine, lpCommandLine); lstrcpyW(lpwCmdLine, lpwCommandLine); pPeParam->fSuicid = fSuicid; pDosHeader = (PIMAGE_DOS_HEADER)pRawPeBlock; pNTHeader = PIMAGE_NT_HEADERS((LPBYTE)pDosHeader + pDosHeader->e_lfanew); FARPROC pEntryPoint = (FARPROC) ((LPBYTE)lpRemotePeBlock + pNTHeader->OptionalHeader.AddressOfEntryPoint); DWORD dwNumByteWrite = 0; if((FALSE == WriteProcessMemory(hProcess, pRemotRelocPe, pRelocPe, nMemNead, &dwNumByteWrite)) || / (dwNumByteWrite != nMemNead)) { nRet = ERROR_FAILED_WRITEMEMORY; __leave; } else { DWORD dwThreadId; hRet = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pEntryPoint, pRemotRelocPe, 0, &dwThreadId); } } __except(EXCEPTION_EXECUTE_HANDLER) { nRet = ERROR_UNKNOWN; } if(nRet) { if(pRemotRelocPe) { VirtualFreeEx(hProcess, pRemotRelocPe, 0, MEM_FREE); pRemotRelocPe = NULL; } } if(pRelocPe) VirtualFree(pRelocPe, 0, MEM_FREE); if(hProcess) CloseHandle(hProcess); if(lpCommandLine) _free(lpCommandLine); if(phRemotInst) *phRemotInst = (HINSTANCE)pRemotRelocPe; if(fSuicid == FALSE) { FARPROC pfProc = _GetProcAddress((HMODULE)pPeBlock, pzUnLoad); *pfUnload = (PROCUNLOAD)((LPBYTE)lpRemotePeBlock + ((LPBYTE)pPeBlock - (LPBYTE)pfProc)); } return hRet; } int __stdcall UnloadPe(PROCUNLOAD pFouncUnload) { DWORD dwRet = 0; DWORD uThreadId; HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)pFouncUnload, 0, 0, &uThreadId); WaitForSingleObject(hThread, -1); if(0 == GetExitCodeThread(hThread, &dwRet)) { dwRet = GetLastError(); } return (int)dwRet; } int __stdcall UnloadPeEx(DWORD dwProcessID, PROCUNLOAD pProcUnload) { int nRet = 0; DWORD uThreadId; HANDLE hProcess; HANDLE hThread; if(hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_QUERY_INFORMATION, FALSE, dwProcessID)) { if(hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pProcUnload, 0, 0, &uThreadId)) { CloseHandle(hThread); nRet = GetLastError(); } CloseHandle(hProcess); } else { nRet = GetLastError(); } return nRet; } // Like GetProcAddress(), returns null if the procedure/ordinal is not there, otherwise returns function addr. FARPROC __stdcall _GetProcAddress(HMODULE hModule, LPCSTR lpProcName) { if((hModule == NULL) || (lpProcName == NULL)) return NULL; // Get header PIMAGE_OPTIONAL_HEADER poh; poh = (PIMAGE_OPTIONAL_HEADER)OPTHDROFFSET (hModule); // Get number of image directories in list int nDirCount; nDirCount = poh->NumberOfRvaAndSizes; if(nDirCount < 16) return NULL; // - Sift through export table ----------------------------------------------- if(poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size == 0) return NULL; // Good, we have an export table. Lets get it. PIMAGE_EXPORT_DIRECTORY ped; ped = (IMAGE_EXPORT_DIRECTORY *)RVATOVA(hModule, poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); // Get ordinal of desired function int nOrdinal; if(HIWORD((DWORD)(ULONG_PTR)lpProcName)==0) { nOrdinal = (LOWORD((DWORD)(ULONG_PTR)lpProcName)) - ped->Base; } else { // Go through name table and find appropriate ordinal int i,count; DWORD *pdwNamePtr; WORD *pwOrdinalPtr; count=ped->NumberOfNames; pdwNamePtr=(DWORD *)RVATOVA(hModule,ped->AddressOfNames); pwOrdinalPtr=(WORD *)RVATOVA(hModule,ped->AddressOfNameOrdinals); for(i=0;i < count;i++) { // XXX should be a binary search, but, again, fuck it. char *svName; svName = (char *)RVATOVA(hModule, *pdwNamePtr); if(s_strcmpiA(svName,lpProcName) == 0) { nOrdinal = *pwOrdinalPtr; break; } pdwNamePtr++; pwOrdinalPtr++; } if(i == count) return NULL; } // Look up RVA of this ordinal DWORD *pAddrTable; DWORD dwRVA; pAddrTable = (DWORD *)RVATOVA(hModule, ped->AddressOfFunctions); dwRVA = pAddrTable[nOrdinal]; // Check if it's a forwarder, or a local addr // XXX Should probably do this someday. Just don't define forwarders. You're // XXX not loading kernel32.dll with this shit anyway. FARPROC dwAddr; dwAddr = (FARPROC)RVATOVA(hModule,dwRVA); return dwAddr; } HINSTANCE __stdcall _LoadLibraryA( LPVOID lpRawRelocPe, LPCSTR lpLibFileName) { return _LoadLibraryExA(lpRawRelocPe, lpLibFileName, NULL, 0); } HINSTANCE __stdcall _LoadLibraryW( LPVOID lpRawRelocPe, LPCWSTR lpLibFileName) { return _LoadLibraryExW(lpRawRelocPe, lpLibFileName, NULL, 0); } HINSTANCE __stdcall _LoadLibraryExA(LPVOID lpRawRelocPe, LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags) { HINSTANCE hRet = NULL; int nLibNameLen = lstrlenA(lpLibFileName) + 1; PWCHAR pwLibName = (PWCHAR)_malloc(nLibNameLen * sizeof(WCHAR)); if(MultiByteToWideChar(CP_THREAD_ACP, MB_COMPOSITE, lpLibFileName, -1, pwLibName, nLibNameLen)) hRet = _LoadLibraryExW(lpRawRelocPe, pwLibName, NULL, 0); _free(pwLibName); return hRet; } HINSTANCE __stdcall _LoadLibraryExW(LPVOID lpRawRelocPe, LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags) { HINSTANCE phInst; HANDLE hLib = LoadPeW(lpRawRelocPe, lpLibFileName, &phInst, FALSE, NULL); WaitForSingleObject(hLib, -1); return phInst; } BOOL __stdcall _FreeLibrary( HMODULE hLibModule) { PROCUNLOAD pProcUnload; pProcUnload = (PROCUNLOAD)_GetProcAddress(hLibModule, pzUnLoad); DWORD dwRet = 0; DWORD uThreadId; HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)pProcUnload, 0, 0, &uThreadId); WaitForSingleObject(hThread, -1); if(0 == GetExitCodeThread(hThread, &dwRet)) { dwRet = GetLastError(); } return !dwRet; } |
|
来自: firefox_zyw > 《待分类1》