内存中载入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); } } }
不错,慢慢测试代码,PE Loader真TM挑战大