首页 > Computer > 内存中载入DLL并执行(C代码,兼容vc,bcb)

内存中载入DLL并执行(C代码,兼容vc,bcb)

系统载入dll的整体过程可以分为以下几个步骤:

1、将dll文件内容载入内存,并按照对齐粒度进行对齐并设置对应的各个内存区间的权限属性;

2、如果dll有重定位表,则进行重定位操作;

3、填充dll的导入表;

4、用ATTACH参数调用dll的入口函数进行初始化,之后返回imagebase即可。

因此了解了系统载入dll的整体流程,也就可以自己实现将dll载入内存并执行,这种方法对于加密等有一定意义。

但由于自己载入内存后,系统api GetProcAddress函数失效,因此在自己实现loadlibrary函数的同时必须自己实现此函数。

下面附上参考网上现有代码原理后写的代码。

进过少量测试,暂未发现bug,如发现bug,欢迎提出。

DLLLoader.h文件内容如下

//---------------------------------------------------------------------------
 
#ifndef DLLLoaderH
#define DLLLoaderH
 
#ifdef __cplusplus
extern "C" {
#endif
 
#include <stdio.h>
#include <windows.h>
//---------------------------------------------------------------------------
 
//public functions
 
DWORD LoadDllFromMemory(LPVOID lpBuffer,__int64 BufferSize);
DWORD FreeDllFromMemory(LPVOID lpBaseAddress);
FARPROC GetDllProcAddress(LPVOID imagebase,char * FuncName);
 
// private functions
 
DWORD AlignDllToMemory(LPVOID lpBuffer,PIMAGE_DOS_HEADER &dosHeader,PIMAGE_NT_HEADERS &ntHeader,__int64 BufferSize);   //从内存载入到对齐内存
DWORD GetAlignedSize(DWORD Origin,DWORD Alignment);                                                                    //计算对齐后的位置
DWORD GetImageSize(PIMAGE_NT_HEADERS ntHeader,PIMAGE_SECTION_HEADER sectionHeaders);                                   //计算总imagesize
DWORD Relocation(PIMAGE_NT_HEADERS ntHeader,LPVOID NewBase);                                                           //修正重定位
DWORD FillImportTable(LPVOID imagebase,PIMAGE_NT_HEADERS ntHeader);                                                    //填充IAT
 
 
//entrypoint function type
typedef UINT (CALLBACK * LPENTRYPOINT) (HANDLE hInstance, DWORD Reason, LPVOID Reserved);
 
 
#ifdef __cplusplus
}
#endif
 
#endif

DLLLoader.c内容如下

//---------------------------------------------------------------------------
 
 
 
#include "DLLLoader.h"
 
//---------------------------------------------------------------------------
 
 
 
DWORD GetAlignedSize(DWORD Origin,DWORD Alignment)
{
	return ((int((Origin+Alignment-1)/Alignment)) * Alignment);
}
 
 
DWORD GetImageSize(PIMAGE_NT_HEADERS ntHeader,PIMAGE_SECTION_HEADER sectionHeaders)
{
	DWORD imagesize = 0;
	imagesize = GetAlignedSize(ntHeader->OptionalHeader.SizeOfHeaders,ntHeader->OptionalHeader.SectionAlignment);
	for (int i = 0; i < ntHeader->FileHeader.NumberOfSections; i++) {
		if (0 != sectionHeaders[i].VirtualAddress) {
			if (0 != sectionHeaders[i].Misc.VirtualSize) {
				imagesize = GetAlignedSize(sectionHeaders[i].VirtualAddress+sectionHeaders[i].Misc.VirtualSize,ntHeader->OptionalHeader.SectionAlignment);
			}else{
				imagesize = GetAlignedSize(sectionHeaders[i].VirtualAddress+sectionHeaders[i].SizeOfRawData,ntHeader->OptionalHeader.SectionAlignment);
			}
		}else{
			imagesize += GetAlignedSize(((sectionHeaders[i].Misc.VirtualSize > sectionHeaders[i].SizeOfRawData) ? sectionHeaders[i].Misc.VirtualSize : sectionHeaders[i].SizeOfRawData),ntHeader->OptionalHeader.SectionAlignment);
		}
	}
	return imagesize;
}
 
DWORD AlignDllToMemory(LPVOID lpBuffer,PIMAGE_DOS_HEADER &dosHeader,PIMAGE_NT_HEADERS &ntHeader,__int64 BufferSize)
{
	DWORD result=0;
	LPVOID DLLBuffer;
	PIMAGE_SECTION_HEADER psectionHeader;
	PIMAGE_IMPORT_DESCRIPTOR pImportDesc;
	PIMAGE_IMPORT_BY_NAME pOridinalName;
	PIMAGE_BASE_RELOCATION baseReloc;
	if (NULL==lpBuffer) {
		dosHeader = NULL;
		ntHeader = NULL;
		return 0;
	}
	dosHeader=(PIMAGE_DOS_HEADER)lpBuffer;
	if ((IMAGE_DOS_SIGNATURE!=dosHeader->e_magic)||IsBadReadPtr(dosHeader,sizeof (IMAGE_DOS_HEADER))) {
		dosHeader = NULL;
		ntHeader = NULL;
		return 0;
	}
	ntHeader=(PIMAGE_NT_HEADERS)((DWORD)dosHeader+dosHeader->e_lfanew);
	if (IsBadReadPtr(ntHeader,sizeof(IMAGE_NT_HEADERS))||(IMAGE_NT_SIGNATURE!=ntHeader->Signature)) {
		dosHeader = NULL;
		ntHeader = NULL;
		return 0;
	}
	if ((ntHeader->FileHeader.SizeOfOptionalHeader!=sizeof(ntHeader->OptionalHeader))||(IMAGE_NT_OPTIONAL_HDR32_MAGIC!=ntHeader->OptionalHeader.Magic)) {
		dosHeader = NULL;
		ntHeader = NULL;
		return 0;
	}
	if (ntHeader->FileHeader.NumberOfSections < 1) {
		dosHeader = NULL;
		ntHeader = NULL;
		return 0;
	}
	psectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)ntHeader + sizeof(IMAGE_NT_HEADERS));
	DWORD imagesize = GetImageSize(ntHeader,psectionHeader);
	if (0 == imagesize) {
		dosHeader = NULL;
		ntHeader = NULL;
		return 0;
	}
	if (NULL == DLLBuffer) {
		dosHeader = NULL;
		ntHeader = NULL;
		return 0;
	}
	DWORD movesize = ntHeader->OptionalHeader.SizeOfHeaders;
	DWORD totalrawsize =movesize;
	for (int i = 0; i < ntHeader->FileHeader.NumberOfSections; i++) {
		totalrawsize += psectionHeader[i].SizeOfRawData;
	}
	if (totalrawsize > BufferSize) {
		return 0;
	}
	DLLBuffer = VirtualAlloc(NULL,imagesize,MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE);    //为了方便,所有内存权限都设成了可执行。
	MoveMemory(DLLBuffer,lpBuffer,movesize);
	for (int i = 0; i < ntHeader->FileHeader.NumberOfSections; i++) {
		MoveMemory((LPVOID)((DWORD)DLLBuffer+psectionHeader[i].VirtualAddress),(LPVOID)((DWORD)lpBuffer+psectionHeader[i].PointerToRawData),psectionHeader[i].SizeOfRawData);
	}
	dosHeader = (PIMAGE_DOS_HEADER)DLLBuffer;
	ntHeader = (PIMAGE_NT_HEADERS)((DWORD)dosHeader+dosHeader->e_lfanew);
	return 1;
}
 
 
DWORD Relocation(PIMAGE_NT_HEADERS ntHeader,LPVOID NewBase)
{
	if ((ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress > 0) && (ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size > 0)) {
		DWORD delta=(DWORD)NewBase - ntHeader->OptionalHeader.ImageBase;
		PIMAGE_BASE_RELOCATION reloc = (PIMAGE_BASE_RELOCATION)((unsigned long)NewBase + ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
		while (0 != (reloc->VirtualAddress + reloc->SizeOfBlock)){
			WORD *relocdata=(WORD *)((DWORD)reloc + sizeof(IMAGE_BASE_RELOCATION));
			int relocNumber = (reloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION))/sizeof(WORD);
			for (int i = 0; i < relocNumber; i++) {
				if ((DWORD)(relocdata[i] & 0xF000) == 0x00003000) {
					DWORD *address = (DWORD *)((unsigned long)NewBase + reloc->VirtualAddress + (relocdata[i] & 0x0fff));
					*address += delta;
				}
			}
			reloc = (PIMAGE_BASE_RELOCATION)((DWORD)reloc + reloc->SizeOfBlock);
		}
 
	}
}
 
 
DWORD FillImportTable(LPVOID imagebase,PIMAGE_NT_HEADERS ntHeader)
{
	DWORD IATOffset = ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
	if (0 == IATOffset) {
		return 1;
	}
	PIMAGE_IMPORT_DESCRIPTOR iat =(PIMAGE_IMPORT_DESCRIPTOR)((DWORD)imagebase + IATOffset);
	while (0 != iat->Characteristics){
		PIMAGE_THUNK_DATA realIAT = (PIMAGE_THUNK_DATA)((DWORD)imagebase + iat->FirstThunk);
		PIMAGE_THUNK_DATA originalIAT = (PIMAGE_THUNK_DATA)((DWORD)imagebase + iat->OriginalFirstThunk);
		char buf[256];
		memset(buf,0,256);
		BYTE *name=(BYTE *)((DWORD)imagebase + iat->Name);
		int i;
		for (i = 0; i < 256; i++) {
			if (0 == name[i]) {
				break;
			}
			buf[i] = name[i];
		}
		if (i >= 256) {
			return 0;
		}
		HMODULE hDll = GetModuleHandle(buf);
		if (NULL == hDll) {
			hDll = LoadLibrary(buf);
			if (NULL == hDll) {
				return 0;
			}
		}
		for (i = 0; ; i++) {
			if (originalIAT[i].u1.Function == 0) {
				break;
			}
			FARPROC lpFunction = NULL;
			if (originalIAT[i].u1.Ordinal & IMAGE_ORDINAL_FLAG) {
				lpFunction = GetProcAddress(hDll,(LPCSTR)(originalIAT[i].u1.Ordinal & 0x0000FFFF));
			}else{
				PIMAGE_IMPORT_BY_NAME byname = (PIMAGE_IMPORT_BY_NAME)((DWORD)imagebase + (DWORD)(originalIAT[i].u1.AddressOfData));
				lpFunction = GetProcAddress(hDll,(char *)byname->Name);
			}
			if (NULL != lpFunction) {
				realIAT[i].u1.Function =(DWORD)lpFunction;
			}else{
				return 0;
			}
		}
		iat = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)iat + sizeof(IMAGE_IMPORT_DESCRIPTOR));
	}
	return 1;
}
 
DWORD LoadDllFromMemory(LPVOID lpBuffer,__int64 BufferSize)
{
	LPVOID imagebase = NULL;
	PIMAGE_DOS_HEADER dosHeader;
	PIMAGE_NT_HEADERS ntHeader;
	if (AlignDllToMemory(lpBuffer,dosHeader,ntHeader,BufferSize)) {
		imagebase = (LPVOID)dosHeader;
		Relocation(ntHeader,imagebase);
		if (FillImportTable(imagebase,ntHeader)) {
			LPENTRYPOINT EntryPointFunc = (LPENTRYPOINT)(ntHeader->OptionalHeader.AddressOfEntryPoint + (DWORD)imagebase);
			if (!EntryPointFunc((HINSTANCE)imagebase,DLL_PROCESS_ATTACH,0)) {
				EntryPointFunc((HINSTANCE)imagebase,DLL_PROCESS_DETACH,0);
				VirtualFree(imagebase,0,MEM_RELEASE);
				EntryPointFunc = NULL;
				return NULL;
			}else{
				return (DWORD)imagebase;
            }
		}else{
			VirtualFree(imagebase,0,MEM_RELEASE);
			return NULL;
        }
	}else{
		return NULL;
	}
}
 
 
DWORD FreeDllFromMemory(LPVOID lpBaseAddress)
{
	PIMAGE_DOS_HEADER dosHeader;
	PIMAGE_NT_HEADERS ntHeader;
	dosHeader = (PIMAGE_DOS_HEADER)lpBaseAddress;
	if (NULL == dosHeader) {
		return 0;
	}
	ntHeader = (PIMAGE_NT_HEADERS)((DWORD)dosHeader + dosHeader->e_lfanew);
	if (IMAGE_NT_SIGNATURE != ntHeader->Signature) {
		return 0;
	}
	if ((ntHeader->FileHeader.SizeOfOptionalHeader != sizeof(ntHeader->OptionalHeader)) || (ntHeader->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)) {
		return 0;
	}
	LPENTRYPOINT EntryPointFunc = (LPENTRYPOINT)(ntHeader->OptionalHeader.AddressOfEntryPoint + (DWORD)lpBaseAddress);
	EntryPointFunc((HINSTANCE)lpBaseAddress,DLL_PROCESS_DETACH,0);
	int i=VirtualFree(lpBaseAddress,0,MEM_RELEASE);
	return i;
}
 
 
 
FARPROC GetDllProcAddress(LPVOID imagebase,char * FuncName)
{
	PIMAGE_DOS_HEADER dosHeader;
	PIMAGE_NT_HEADERS ntHeader;
	dosHeader = (PIMAGE_DOS_HEADER)imagebase;
	if (NULL == dosHeader) {
		return NULL;
	}
	ntHeader = (PIMAGE_NT_HEADERS)((DWORD)dosHeader + dosHeader->e_lfanew);
	if (IMAGE_NT_SIGNATURE != ntHeader->Signature) {
		return NULL;
	}
	if ((ntHeader->FileHeader.SizeOfOptionalHeader != sizeof(ntHeader->OptionalHeader)) || (ntHeader->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)) {
		return NULL;
	}
	DWORD exportsStartRVA,size;
	exportsStartRVA = ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
	size = ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
	PIMAGE_EXPORT_DIRECTORY pexports = (PIMAGE_EXPORT_DIRECTORY)((DWORD)imagebase + ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
	int iBase = pexports->Base;
	int iNumOfFuncs = pexports->NumberOfFunctions;
	int iNumOfNames = pexports->NumberOfNames;
	LPDWORD pAddressOfFuncs =(LPDWORD)(pexports->AddressOfFunctions + (DWORD)imagebase);
	LPWORD pAddressOfOrdinals = (LPWORD)(pexports->AddressOfNameOrdinals + (DWORD)imagebase);
	LPDWORD pAddressOfNames = (LPDWORD)(pexports->AddressOfNames + (DWORD)imagebase);
	int iOrdinal = -1;
	if (((DWORD)FuncName & 0xFFFF0000) == 0) {
		iOrdinal = (DWORD)FuncName & 0x0000FFFF - iBase;
	}else{
		int iFound = -1;
		for (int i = 0; i < iNumOfNames; i++) {
			if (0 == strcmp((char *)(pAddressOfNames[i]+(DWORD)imagebase),FuncName)) {
				iFound = i;
				break;
			}
		}
		if (iFound >=0) {
			iOrdinal = (int)(pAddressOfOrdinals[iFound]);
		}
	}
	if ((iOrdinal < 0) || (iOrdinal >= iNumOfFuncs)) {
		return NULL;
	}else{
		DWORD FuncOffset = pAddressOfFuncs[iOrdinal];
		if ((FuncOffset > exportsStartRVA) && (FuncOffset < exportsStartRVA + size)) {
			return NULL;
		}else{
			return (FARPROC)((DWORD)imagebase + FuncOffset);
        }
    }
}
分类: Computer 标签: ,
  1. 2011年7月26日13:14 | #1

    不错,慢慢测试代码,PE Loader真TM挑战大 :-|

  1. 本文目前尚无任何 trackbacks 和 pingbacks.

:wink: :-| :-x :twisted: :) 8-O :( :roll: :-P :oops: :-o :mrgreen: :lol: :idea: :-D :evil: :cry: 8) :arrow: :-? :?: :!: