www.pudn.com > remote_thread.zip > dll_load.cpp


/*  Back Orifice 2000 - Remote Administration Suite 
    Copyright (C) 1999, Cult Of The Dead Cow 
 
    This program is free software; you can redistribute it and/or modify 
    it under the terms of the GNU General Public License as published by 
    the Free Software Foundation; either version 2 of the License, or 
    (at your option) any later version. 
 
    This program is distributed in the hope that it will be useful, 
    but WITHOUT ANY WARRANTY; without even the implied warranty of 
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
    GNU General Public License for more details. 
 
    You should have received a copy of the GNU General Public License 
    along with this program; if not, write to the Free Software 
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 
	The author of this program may be contacted at dildog@l0pht.com. */ 
 
// DLL_LOAD by dildog@l0pht.com 
// This is pretty far from a fully-implemented PE Executable 
// Loader, but it does the trick for loading DLLs from an image. 
// That way, we don't have to hit the disk too much, and it 
// allows one to package DLLs as resources (kinda like static linking a DLL... :) 
 
// Differences from Win32 DLL Loader: 
// GOOD Differences 
//  1. GetDLLProcAddress returns the -REAL- entry point of exported functions 
//     instead of some bullshit stub set up by the loader. 
//  2. New flags for loading 'REBIND_IMAGE_IMPORTS' allows you to load an 
//     image that has already been loaded and rebind its import table. 
//  3. New flag 'RWX_PERMISSIONS' allows you to load a DLL with read/write/execute 
//     permissions on all sections. 
//  4. New flag 'FORCE_LOAD_NEW_IMAGE' allows you to load a single DLL more than 
//     once at different base addresses. 
 
// BAD Differences 
//  1. Never sets GetLastError code. Just don't fuck up. 
//  2. Shared segments don't work in Windows 9x. They also don't work in either 9x or NT if the DLL is forced to be rebased. 
//  3. LOAD_WITH_ALTERED_SEARCH_PATH doesn't work. 
//  4. Only loads PE executables (well duh) 
//  5. 'Thread Attaching' doesn't work (so neither does TLS in most cases) 
//     This is because I don't have access to the kernel necessarily (can't touch 
//     the thread information tables. Hell, if I could, I wouldn't need this stuff) 
//  6. Loading DLLs in different processes with different "dwFlags" via LoadDLLEx 
//     may have undesirable effects under Windows NT. Use with caution. 
//  7. 'Forwarder' support is kinda bunky. Kinda works tho. 
//  8. Resources can not be loaded from DLLs. Sigh. The problem is known 
//     and being worked on. May not have a solution. 
 
#include "stdafx.h" 
#include 
#include 
#include"dll_load.h" 
 
 
#pragma pack(push,1) 
 
typedef struct { 
	DWORD	dwPageRVA; 
	DWORD	dwBlockSize; 
} IMAGE_FIXUP_BLOCK, *PIMAGE_FIXUP_BLOCK; 
 
typedef struct { 
	WORD	offset:12; 
	WORD	type:4; 
} IMAGE_FIXUP_ENTRY, *PIMAGE_FIXUP_ENTRY; 
 
#pragma pack(pop) 
 
 
//----------------------------------------------------- 
// 根据各个section的指定,对他们实施保护 
//----------------------------------------------------- 
BOOL ProtectDLLImage(void *pMemoryImage, BOOL bRWX) 
{ 
	//----------------------------- 
	// Get Number of Sections 
	//----------------------------- 
	PIMAGE_FILE_HEADER pfh; 
	int nSectionCount; 
	 
	pfh=(PIMAGE_FILE_HEADER) PEFHDROFFSET(pMemoryImage); 
	nSectionCount=pfh->NumberOfSections; 
 
	//------------------------------------------------- 
	// Get PE Header Length + Section Header Length 
	//------------------------------------------------- 
	PIMAGE_OPTIONAL_HEADER poh; 
	DWORD hdrlen; 
 
	poh=(PIMAGE_OPTIONAL_HEADER) OPTHDROFFSET(pMemoryImage); 
	hdrlen=poh->SizeOfHeaders; 
 
 
	//------------------------------------------------- 
	// Protect sections one by one 
	//------------------------------------------------- 
	int i; 
	PIMAGE_SECTION_HEADER psh; 
 
	psh=(PIMAGE_SECTION_HEADER) SECHDROFFSET(pMemoryImage); 
	for(i=0;iVirtualAddress); 
		secLen = psh->SizeOfRawData; 
		 
	 
		//------------------------------------------------- 
		// Parse Characteristics and protect memory appropriately 
		//------------------------------------------------- 
		DWORD newProtect=0,oldProtect; 
		BOOL bWrite, bRead, bExec, bShared; 
		 
		bWrite  = (psh->Characteristics & IMAGE_SCN_MEM_WRITE)?TRUE:FALSE; 
		bRead   = (psh->Characteristics & IMAGE_SCN_MEM_READ)?TRUE:FALSE; 
		bExec   = (psh->Characteristics & IMAGE_SCN_MEM_EXECUTE)?TRUE:FALSE; 
		bShared = (psh->Characteristics & IMAGE_SCN_MEM_SHARED)?TRUE:FALSE; 
		 
		if(bWrite && bRead && bExec && bShared) newProtect=PAGE_EXECUTE_READWRITE; 
		else if(bWrite && bRead && bExec) newProtect=PAGE_EXECUTE_WRITECOPY; 
		else if(bRead && bExec) newProtect=PAGE_EXECUTE_READ; 
		else if(bExec) newProtect=PAGE_EXECUTE; 
		else if(bWrite && bRead && bShared) newProtect=PAGE_READWRITE;  
		else if(bWrite && bRead) newProtect=PAGE_WRITECOPY; 
		else if(bRead) newProtect=PAGE_READONLY; 
 
		if(bRWX) newProtect=PAGE_WRITECOPY; 
 
		if(psh->Characteristics & IMAGE_SCN_MEM_NOT_CACHED) newProtect |= PAGE_NOCACHE; 
 
		if(newProtect==0) return FALSE; 
 
		VirtualProtect(secMemAddr,secLen,newProtect,&oldProtect); 
		 
		psh++; 
	} 
 
	return TRUE; 
} 
 
//------------------------------------------------- 
// 解决IAT(Import Address Table)和重定位表 
//------------------------------------------------- 
BOOL PrepareDLLImage(void *pMemoryImage, DWORD dwImageSize, BOOL bResolve, BOOL bRebind) 
{ 
	//----------------------------------------------- 
	// Get headers 
	//----------------------------------------------- 
	PIMAGE_OPTIONAL_HEADER   poh; 
    PIMAGE_SECTION_HEADER    psh; 
    poh = (PIMAGE_OPTIONAL_HEADER)OPTHDROFFSET (pMemoryImage); 
    psh = (PIMAGE_SECTION_HEADER)SECHDROFFSET (pMemoryImage); 
 
 
	//----------------------------------------------- 
	// Get number of image directories in list 
	//----------------------------------------------- 
	int nDirCount; 
	nDirCount=poh->NumberOfRvaAndSizes; 
	if(nDirCount<16) return FALSE; 
	 
 
	//----------------------------------------------- 
	// Process import table 
	//----------------------------------------------- 
	if(poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size!=0) { 
		PIMAGE_IMPORT_DESCRIPTOR pid; 
		pid=(IMAGE_IMPORT_DESCRIPTOR *)RVATOVA(pMemoryImage,poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); 
 
 
		//--------------------------------------------------- 
		// For all imported DLLs 
		// 原来的处理有bug:对于由borland的linker编译的image 
		// OriginalFirstThunk永远都是0 
		//--------------------------------------------------- 
//		while(pid->OriginalFirstThunk!=0) { 
		while( 1 ) { 
			//--------------------------------------------------- 
			// 新的方法用他们判断是否结束 
			//--------------------------------------------------- 
			if ( (pid->TimeDateStamp==0 ) && (pid->Name==0) ) 
				break; 
 
			char *svDllName; 
			svDllName=(char *) RVATOVA(pMemoryImage,pid->Name); 
			 
			//------------------------------------------------------------- 
			// Map library into address space (could also use LoadDLL()) 
			//------------------------------------------------------------- 
			HMODULE hDll; 
			hDll=GetModuleHandleA(svDllName); 
			if(hDll==NULL) hDll=LoadLibraryA(svDllName); 
	 
			if(hDll==NULL) 
				return FALSE; 
 
			//------------------------------------------------------------- 
			// Bind if not bound already 
			//------------------------------------------------------------- 
			if(pid->TimeDateStamp==0 || bRebind) { 
				//------------------------------------------------------------- 
				// Store DLL infoz 
				//------------------------------------------------------------- 
				pid->ForwarderChain=(DWORD)hDll; 
 
				//------------------------------------------------------------- 
				// This is bullshit cuz I don't want to call libc. 
				//------------------------------------------------------------- 
				pid->TimeDateStamp=0xCDC31337; 
				 
				//------------------------------------------------------------- 
				// Fill in Import Address Table 
				//------------------------------------------------------------- 
				PIMAGE_THUNK_DATA ptd_in,ptd_out; 
				ptd_in=(PIMAGE_THUNK_DATA) RVATOVA(pMemoryImage, pid->OriginalFirstThunk); 
				ptd_out=(PIMAGE_THUNK_DATA) RVATOVA(pMemoryImage, pid->FirstThunk); 
				if( pid->OriginalFirstThunk == 0 ) // No OriginalFirstThunk field? 
				{ 
					if( pid->FirstThunk == 0 ) // No FirstThunk field?  Ooops!!! 
						break; 
		 
					//------------------------------------------------------------- 
					// Yes! Gotta have a non-zero FirstThunk field then. 
					//------------------------------------------------------------- 
					ptd_in = ptd_out; 
				} 
				 
				while(ptd_in->u1.Function!=NULL) { 
					FARPROC func; 
					 
					//------------------------------------------------------------- 
					// Determine if ordinal or name pointer 
					//------------------------------------------------------------- 
					if(ptd_in->u1.Ordinal & 0x80000000) { 
						// Ordinal 
						func=GetProcAddress(hDll,MAKEINTRESOURCEA(ptd_in->u1.Ordinal)); 
					} else { 
						// Function name 
						PIMAGE_IMPORT_BY_NAME pibn; 
						pibn=(PIMAGE_IMPORT_BY_NAME) RVATOVA(pMemoryImage,ptd_in->u1.AddressOfData); 
						func=GetProcAddress(hDll,(char *)pibn->Name); 
					} 
					 
					if(func==NULL) 
						return FALSE; 
					 
					//------------------------------------------------------------- 
					// Write address to appropriate location 
					//------------------------------------------------------------- 
					ptd_out->u1.Function = (DWORD) func; 
					 
					ptd_in++; 
					ptd_out++; 
				} 
			} 
 
			pid++; 
		} 
	} 
 
 
	//------------------------------------------------------------- 
	// Process relocation tables if necessary 
	//------------------------------------------------------------- 
 
	 
	//------------------------------------------------------------- 
	// Calculate fixup delta 
	//------------------------------------------------------------- 
	DWORD delta; 
	delta=(DWORD)pMemoryImage - (DWORD)poh->ImageBase; 
 
	if((delta!=0) && (poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size!=0)) { 
		PIMAGE_FIXUP_BLOCK pfb; 
		pfb=(PIMAGE_FIXUP_BLOCK)RVATOVA(pMemoryImage,poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress); 
		 
		 
		//------------------------------------------------------------- 
		// For each fixup block 
		//------------------------------------------------------------- 
		while(pfb->dwPageRVA!=0) { 
			PIMAGE_FIXUP_ENTRY pfe; 
			int i,count; 
 
			count=(pfb->dwBlockSize-sizeof(IMAGE_FIXUP_BLOCK))/sizeof(IMAGE_FIXUP_ENTRY); 
			pfe=(PIMAGE_FIXUP_ENTRY)((char *)pfb + sizeof(IMAGE_FIXUP_BLOCK)); 
 
			//------------------------------------------------------------- 
			// For each fixup entry 
			//------------------------------------------------------------- 
			for(i=0;idwPageRVA + pfe->offset); 
				switch(pfe->type) { 
				case IMAGE_REL_BASED_ABSOLUTE: 
					break; 
				case IMAGE_REL_BASED_HIGH: 
					*((WORD *)fixaddr) += HIWORD(delta); 
					break; 
				case IMAGE_REL_BASED_LOW: 
					*((WORD *)fixaddr) += LOWORD(delta); 
					break; 
				case IMAGE_REL_BASED_HIGHLOW: 
					*((DWORD *)fixaddr) += delta; 
					break; 
				case IMAGE_REL_BASED_HIGHADJ: // This one's really fucked up. 
					adjust=((*((WORD *)fixaddr)) << 16) | (*(WORD *)(pfe+1)); 
					adjust += delta; 
					adjust += 0x00008000; 
					*((WORD *)fixaddr) = HIWORD(adjust); 
					pfe++; 
					break; 
				default: 
					return FALSE; 
				} 
				 
				pfe++; 
			} 
 
			pfb=(PIMAGE_FIXUP_BLOCK)((char *)pfb + pfb->dwBlockSize); 
		} 
	} 
	else { 
		//------------------------------------------------------------------------------ 
		// if image base has changed but we cann't find the relocation table, 
		// we failed to fixup this image, 
		// which usually happens when this image is a release-version executable file. 
		//------------------------------------------------------------------------------ 
		if( delta !=0 && poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size == 0 ) 
			return FALSE; 
	} 
 
	return TRUE; 
} 
 
 
BOOL MapDLLFromImage(void *pDLLFileImage, void *pMemoryImage) 
{ 
	//------------------------------------------------------------------------------ 
	// Get Number of Sections 
	//------------------------------------------------------------------------------ 
	PIMAGE_FILE_HEADER pfh; 
	int nSectionCount; 
	 
	pfh=(PIMAGE_FILE_HEADER) PEFHDROFFSET(pDLLFileImage); 
	nSectionCount=pfh->NumberOfSections; 
 
	//------------------------------------------------------------------------------ 
	// Get PE Header Length + Section Header Length 
	//------------------------------------------------------------------------------ 
	PIMAGE_OPTIONAL_HEADER poh; 
	DWORD hdrlen; 
 
	poh=(PIMAGE_OPTIONAL_HEADER) OPTHDROFFSET(pDLLFileImage); 
	hdrlen=poh->SizeOfHeaders; 
 
	//------------------------------------------------------------------------------ 
	// Copy PE Header + Section Headers 
	//------------------------------------------------------------------------------ 
	memcpy(pMemoryImage,pDLLFileImage,hdrlen); 
	 
	//------------------------------------------------------------------------------ 
	// Copy Sections one by one 
	//------------------------------------------------------------------------------ 
	int i; 
	PIMAGE_SECTION_HEADER psh; 
 
	psh=(PIMAGE_SECTION_HEADER) SECHDROFFSET(pDLLFileImage); 
	for(i=0;iVirtualAddress; 
		secFileAddr = (char *)pDLLFileImage + psh->PointerToRawData; 
		secLen = psh->SizeOfRawData; 
		 
		memcpy(secMemAddr,secFileAddr,secLen); 
		 
		psh++; 
	} 
	 
 
 
	return TRUE; 
} 
 
 
//------------------------------------------------------------------------------ 
// LoadDLLFromImage()                                                                                      // 
//------------------------------------------------------------------------------ 
HMODULE LoadDLLFromImage(void *pDLLFileImage, LPTSTR svMappingName, DWORD dwFlags) 
{ 
	//---------------------------------------------------- 
	// Examine DOS Header 
	//---------------------------------------------------- 
	PIMAGE_DOS_HEADER doshead; 
	doshead=(PIMAGE_DOS_HEADER) pDLLFileImage; 
	if(doshead->e_magic!=IMAGE_DOS_SIGNATURE) return NULL; 
	 
	//---------------------------------------------------- 
	// Ensure our input is of good length 
	//---------------------------------------------------- 
	if(svMappingName!=NULL) { 
		if(lstrlen(svMappingName) >= MAX_PATH) return NULL; 
	} 
	 
	//---------------------------------------------------- 
	// Determine File Format 
	//---------------------------------------------------- 
	if(*(DWORD *)NTSIGNATURE(pDLLFileImage) != IMAGE_NT_SIGNATURE) return NULL; 
	 
	 
	//---------------------------------------------------- 
	// Get PE Header 
	//---------------------------------------------------- 
	PIMAGE_FILE_HEADER pfh; 
	pfh=(PIMAGE_FILE_HEADER) PEFHDROFFSET(pDLLFileImage); 
	 
	 
	//---------------------------------------------------- 
	// Ensure proper machine type 
	//if(pfh->Machine!=IMAGE_FILE_MACHINE_I386) return NULL; 
	// XXX Verify Characteristics 
	// XXX I don't bother to do this yet. 
	//---------------------------------------------------- 
 
	 
	//---------------------------------------------------- 
	// Get Section Count 
	//---------------------------------------------------- 
	int nSectionCount; 
	nSectionCount=pfh->NumberOfSections; 
 
	 
	//---------------------------------------------------- 
	// Get PE Optional Header 
	//---------------------------------------------------- 
	PIMAGE_OPTIONAL_HEADER poh; 
	poh=(PIMAGE_OPTIONAL_HEADER) OPTHDROFFSET(pDLLFileImage); 
 
 
	//---------------------------------------------------- 
	// Ensure we are an executable image, not a rom image 
	//---------------------------------------------------- 
	if(poh->Magic!=0x010B) return NULL; 
 
	 
	//---------------------------------------------------- 
	// Get preferred image base and image length 
	//---------------------------------------------------- 
	void *pPreferredImageBase; 
	DWORD dwImageSize; 
	 
	pPreferredImageBase=(void *)poh->ImageBase; 
	dwImageSize=poh->SizeOfImage; 
 
	//---------------------------------------------------- 
	// Get base address of virtual image 
	//---------------------------------------------------- 
	void *pImageBase; 
	HANDLE hmapping=NULL; 
	 
	BOOL bCreated=FALSE; 
	BOOL bRebased=FALSE; 
	 
	//------------------------------------------------------------- 
	// === Windows NT DLL Loading (supports shared sections) === 
	//------------------------------------------------------------- 
	if(svMappingName!=NULL) { 
		hmapping=OpenFileMapping(FILE_MAP_WRITE,TRUE,svMappingName); 
		bCreated=FALSE; 
	} 
	if(hmapping==NULL) { 
		hmapping=CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,dwImageSize+SIZE_OF_PARAMETER_BLOCK,svMappingName); 
		if(hmapping==NULL) return NULL; 
		bCreated=TRUE; 
 
 
		//----------------------------------------------------------------------------------------- 
		// Try to load file mapping view at preferred image base (not gonna happen in Win9x..sigh) 
		//----------------------------------------------------------------------------------------- 
	 
		pImageBase=MapViewOfFileEx(hmapping,FILE_MAP_WRITE,0,0,0,pPreferredImageBase); 
		if(pImageBase==NULL) { 
			pImageBase=MapViewOfFileEx(hmapping,FILE_MAP_WRITE,0,0,0,NULL); 
		} 
		CloseHandle(hmapping);					 
		if(pImageBase==NULL) return NULL; 
	} 
	 
	//----------------------------------------------------------------------------------------- 
	// Now map DLL from file image into appropriate memory image (if just created) 
	// Also remap if DLL is being rebased as well (gotta fix relocations) 
	//----------------------------------------------------------------------------------------- 
 
	if(bCreated || (pImageBase!=pPreferredImageBase)) { 
		if(!MapDLLFromImage(pDLLFileImage,pImageBase)) { 
			UnmapViewOfFile(pImageBase); 
			return NULL; 
		} 
	} 
	 
	//----------------------------------------------------------------------------------------- 
	// Prepare DLL image (handle relocations/import/export/etc) 
	//----------------------------------------------------------------------------------------- 
	 
	if(!(dwFlags & LOAD_LIBRARY_AS_DATAFILE)) { 
		if(!PrepareDLLImage(pImageBase, dwImageSize, (dwFlags & DONT_RESOLVE_DLL_REFERENCES)?FALSE:TRUE,(dwFlags & REBIND_IMAGE_IMPORTS)?TRUE:FALSE)) { 
			UnmapViewOfFile(pImageBase); 
			return NULL; 
		} 
	} 
	return (HMODULE) pImageBase;	 
} 
 
 
//------------------------------------------------------------------ 
// LoadDLLEx() 
//------------------------------------------------------------------ 
HMODULE WINAPI LoadDLLExW(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags) 
{ 
	WCHAR svPath[MAX_PATH+1]; 
	WCHAR *svFilePart; 
	int nPathLen; 
 
	//------------------------------------------------- 
	// Find DLL File	 
	//------------------------------------------------- 
	if(dwFlags & LOAD_WITH_ALTERED_SEARCH_PATH) { 
		return NULL; 
	} else { 
		nPathLen=SearchPathW(NULL,lpLibFileName,L".exe",MAX_PATH,svPath,&svFilePart); 
		if(nPathLen==0) return NULL; 
	} 
 
	//------------------------------------------------- 
	// Open File 
	//------------------------------------------------- 
	HANDLE hfile=CreateFile(svPath,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL); 
	if(hfile==INVALID_HANDLE_VALUE) return NULL; 
	 
	//------------------------------------------------- 
	// Create a file mapping 
	//------------------------------------------------- 
	HANDLE hmapping; 
	hmapping=CreateFileMapping(hfile, NULL, PAGE_READONLY, 0, 0, NULL); 
 
	//------------------------------------------------- 
	// Close file handle since we don't need it anymore 
	//------------------------------------------------- 
	CloseHandle(hfile); 
 
 
	//------------------------------------------------- 
	// Map file mapping object to memory image 
	//------------------------------------------------- 
	void *baseaddr; 
	baseaddr=MapViewOfFile(hmapping,FILE_MAP_READ,0,0,0); 
	if(baseaddr==NULL) { 
		CloseHandle(hmapping); 
		return NULL; 
	} 
 
 
	//------------------------------------------------- 
	// Now pass off to LoadDLLFromImage 
	//------------------------------------------------- 
	HMODULE ret; 
	if(dwFlags & FORCE_LOAD_NEW_IMAGE) { 
		ret=LoadDLLFromImage(baseaddr, NULL, dwFlags & ~LOAD_WITH_ALTERED_SEARCH_PATH); 
	} else { 
		ret=LoadDLLFromImage(baseaddr, svFilePart, dwFlags & ~LOAD_WITH_ALTERED_SEARCH_PATH); 
	} 
 
		 
	//------------------------------------------------- 
	// Close file mapping 
	//------------------------------------------------- 
	UnmapViewOfFile(baseaddr); 
	CloseHandle(hmapping); 
 
	//------------------------------------------------- 
	// Return base address as an instance handle 
	//------------------------------------------------- 
	return (HMODULE) ret; 
} 
 
HMODULE WINAPI LoadDLLExA(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags) 
{ 
	WCHAR szPath[MAX_PATH]; 
 
	::MultiByteToWideChar( CP_ACP, 0, 
		lpLibFileName, -1, 
		szPath, sizeof(szPath) ); 
	return LoadDLLExW(szPath,hFile,dwFlags); 
} 
 
 
 
//------------------------------------------------- 
// LoadDLLW() 
//------------------------------------------------- 
 
HMODULE WINAPI LoadDLLW(LPCWSTR lpLibFileName) 
{ 
	return LoadDLLExW(lpLibFileName,NULL,0); 
} 
 
HMODULE WINAPI LoadDLLA(LPCSTR lpLibFileName) 
{ 
	return LoadDLLExA(lpLibFileName,NULL,0); 
} 
 
 
//------------------------------------------------- 
// FreeDLL() 
//------------------------------------------------- 
BOOL WINAPI FreeDLL(HMODULE hLibModule) 
{ 
	if(hLibModule==NULL) return FALSE; 
	return UnmapViewOfFile(hLibModule); 
} 
 
 
 
BOOL WINAPI CheckTlsSectionExist( HMODULE hImage ) 
{ 
	PIMAGE_FILE_HEADER pfh; 
	int i, nSectionCount; 
	 
	pfh=(PIMAGE_FILE_HEADER) PEFHDROFFSET(hImage); 
	nSectionCount=pfh->NumberOfSections; 
 
 
	//---------------------------------------------------- 
	// Search for .tls section 
	//---------------------------------------------------- 
	PIMAGE_SECTION_HEADER psh; 
	psh=(PIMAGE_SECTION_HEADER) SECHDROFFSET(hImage); 
	for(i=0;iName, ".tls" ) == 0 ) 
			return TRUE; 
		 
		psh++; 
	} 
	 
 
	return FALSE; 
} 
 
typedef struct _UNICODE_STRING 
{ 
	WORD  Length; 
	WORD  MaximumLength; 
	PWSTR Buffer; 
} UNICODE_STRING; 
 
//-------------------------------------------------------------------- 
// LoadLibraryEx根据几个flags加载模块: 
// -- DONT_RESOLVE_DLL_REFERENCES: 加载模块,对各个section实行保护, 
//									不解决IAT和重定位表 
// -- LOAD_LIBRARY_AS_DATAFILE: 仅仅把文件映射到进程空间 
// -- LOAD_WITH_ALTERED_SEARCH_PATH: 使用不同的路径搜索策略 
// LoadLibraryEx内部用LdrLoadDll完成实际加载工作。 
// 下面实现的LoadImageExW增加了一个功能:加载模块,解决IAT和重定位表, 
// 但是不调用DllMain 
//-------------------------------------------------------------------- 
typedef DWORD (WINAPI *PNtLdrLoadDll)(LPCWSTR, DWORD*, UNICODE_STRING*, HMODULE*); 
typedef DWORD (WINAPI *PNtLdrLoadDllEx)(LPCWSTR, DWORD*, UNICODE_STRING*, HMODULE*, BOOL fCallDllMain); 
typedef DWORD (WINAPI *PNtRtlInitUnicodeString)(UNICODE_STRING*, LPCWSTR); 
 
 
 
PNtLdrLoadDll LdrLoadDll = (PNtLdrLoadDll)::GetProcAddress( ::GetModuleHandleW( L"NtDll.dll" ), "LdrLoadDll" ); 
PNtRtlInitUnicodeString RtlInitUnicodeString = (PNtRtlInitUnicodeString)::GetProcAddress( ::GetModuleHandleW( L"NtDll.dll" ), "RtlInitUnicodeString" ); 
 
 
PNtLdrLoadDllEx Find_LdrLoadDllEx() 
{ 
	DWORD fun = 0; 
	for( PBYTE p = (PBYTE)LdrLoadDll; *p != 0xC2 && *p != 0xC3; p++ ) // *p != RET 
	{ 
		//----------------------------------------------- 
		// 0xE8为intel系列的相对调用指令 
		//----------------------------------------------- 
		if( *p == 0xE8 ) 
		{ 
			//----------------------------------------------- 
			// 取得LdrLoadDllEx的相对地址 
			// (相对于call的下一条指令,即call的返回地址) 
			//----------------------------------------------- 
			DWORD rva = *((DWORD*)(p+1)); 
 
			//----------------------------------------------- 
			// 一个call指令占5个字节,因此要加上5 
			//----------------------------------------------- 
			fun = (DWORD)p+rva+5; 
			break; 
		} 
	} 
 
	return (PNtLdrLoadDllEx)fun; 
} 
 
 
//------------------------------------------------------------------------- 
// 如果最后一个参数为0,LdrLoadDllEx将解决IAT和重定位表,但不调用DllMain 
// 但是winnt没有导出这个函数。下面的地址仅仅对Winnt 4.0+sp6有效 
//------------------------------------------------------------------------- 
PNtLdrLoadDllEx LdrLoadDllEx = Find_LdrLoadDllEx(); // (PNtLdrLoadDllEx)0x77F5B333; 
 
 
//------------------------------------------------------------------- 
// 加载dll,解决IAT和重定位表,但不调用DllMain 
//------------------------------------------------------------------- 
HMODULE WINAPI LoadImageExW( LPCWSTR lpFileName, HANDLE hFile, DWORD dwFlags ) 
{ 
	if( dwFlags != -1 ) 
		//----------------------------------- 
		// 调用缺省实现 
		//----------------------------------- 
		return ::LoadLibraryExW( lpFileName, hFile, dwFlags ); 
 
 
	HMODULE hModule; 
	DWORD Flags = 0; 
	UNICODE_STRING FileName; 
 
	WCHAR svPath[MAX_PATH+1]; 
	WCHAR *svFilePart; 
 
	//------------------------------------------------ 
	// 确定image file的全路径 
	//------------------------------------------------ 
	if( SearchPathW( NULL, lpFileName, NULL, MAX_PATH, svPath, &svFilePart ) == 0 ) 
		return NULL; 
 
	//------------------------------------------------ 
	// 构造UNICODE_STRING 
	//------------------------------------------------ 
	RtlInitUnicodeString( &FileName, svPath ); 
 
 
	//-------------------------------------------------- 
	// 以最后一个参数为0,禁止LdrLoadDllEx调用DllMain 
	//-------------------------------------------------- 
	DWORD e = LdrLoadDllEx( L".", &Flags, &FileName, &hModule, 0); 
	if( e == 0 ) 
		return hModule; 
	return NULL; 
} 
 
HMODULE WINAPI LoadImageExA( LPCSTR lpFileName, HANDLE hFile, DWORD dwFlags ) 
{ 
	WCHAR szPath[MAX_PATH]; 
 
	::MultiByteToWideChar( CP_ACP, 0, 
		lpFileName, -1, 
		szPath, sizeof(szPath) ); 
	return LoadImageExW(szPath,hFile,dwFlags); 
}