Repository: abhisek/Pe-Loader-Sample Branch: master Commit: 9aed4b3f6cd3 Files: 9 Total size: 25.6 KB Directory structure: gitextract_cjiu6xeh/ ├── .gitattributes ├── .gitignore ├── Pe-Loader-Sample.vcproj ├── README.md └── src/ ├── Debug.h ├── Main.cpp ├── PEB.h ├── PeLdr.cpp └── PeLdr.h ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitattributes ================================================ # Auto detect text files and perform LF normalization * text=auto # Custom for Visual Studio *.cs diff=csharp *.sln merge=union *.csproj merge=union *.vbproj merge=union *.fsproj merge=union *.dbproj merge=union # Standard to msysgit *.doc diff=astextplain *.DOC diff=astextplain *.docx diff=astextplain *.DOCX diff=astextplain *.dot diff=astextplain *.DOT diff=astextplain *.pdf diff=astextplain *.PDF diff=astextplain *.rtf diff=astextplain *.RTF diff=astextplain ================================================ FILE: .gitignore ================================================ ################# ## Eclipse ################# *.pydevproject .project .metadata bin/** tmp/** tmp/**/* *.tmp *.bak *.swp *~.nib local.properties .classpath .settings/ .loadpath # External tool builders .externalToolBuilders/ # Locally stored "Eclipse launch configurations" *.launch # CDT-specific .cproject # PDT-specific .buildpath ################# ## Visual Studio ################# ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. # User-specific files *.suo *.user *.sln.docstates # Build results **/[Dd]ebug/ **/[Rr]elease/ *_i.c *_p.c *.ilk *.meta *.obj *.pch *.pdb *.pgc *.pgd *.rsp *.sbr *.tlb *.tli *.tlh *.tmp *.vspscc .builds **/*.dotCover ## TODO: If you have NuGet Package Restore enabled, uncomment this #**/packages/ # Visual C++ cache files ipch/ *.aps *.ncb *.opensdf *.sdf # Visual Studio profiler *.psess *.vsp # ReSharper is a .NET coding add-in _ReSharper* # Installshield output folder [Ee]xpress # DocProject is a documentation generator add-in DocProject/buildhelp/ DocProject/Help/*.HxT DocProject/Help/*.HxC DocProject/Help/*.hhc DocProject/Help/*.hhk DocProject/Help/*.hhp DocProject/Help/Html2 DocProject/Help/html # Click-Once directory publish # Others [Bb]in [Oo]bj sql TestResults *.Cache ClientBin stylecop.* ~$* *.dbmdl Generated_Code #added for RIA/Silverlight projects # Backup & report files from converting an old project file to a newer # Visual Studio version. Backup files are not needed, because we have git ;-) _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML ############ ## Windows ############ # Windows image file caches Thumbs.db # Folder config file Desktop.ini ############# ## Python ############# *.py[co] # Packages *.egg *.egg-info dist build eggs parts bin var sdist develop-eggs .installed.cfg # Installer logs pip-log.txt # Unit test / coverage reports .coverage .tox #Translations *.mo #Mr Developer .mr.developer.cfg # Mac crap .DS_Store Debug ================================================ FILE: Pe-Loader-Sample.vcproj ================================================ ================================================ FILE: README.md ================================================ PE Loader Sample ================= In memory execution of PE executables: * Self Relocation * Memory Mapping * IAT Processing * Relocation * Control Transfer This project aims to implement a complete PE Loader capable of loading all PE and PE+ executables. The current version should be considered as a PoC only as it does not handle all practical cases. TODO: * Handle Import Forwarding * Bound Imports * Is it possible to relocate a PE if relocation table is not included? Hack++? * Most Important: Documentation of PE Loading Process Thanks ------- * Special thanks to Stephen Fewer of Harmony Security for Reflective DLL Injection paper and implementation. The IAT processing and Relocation code in this project is taken from ReflectiveDLL Loader implementation. * sincoder for ideas on Self Relocation. ================================================ FILE: src/Debug.h ================================================ #ifndef _DEBUG_H #define _DEBUG_H #include #define __DEBUG #ifdef __DEBUG #include #define DMSG(x, ...) fprintf(stderr, "[+] " x "\n", __VA_ARGS__) #define EMSG(x, ...) fprintf(stderr, "[-] " x "\n", __VA_ARGS__) #else #define DMSG(x, ...) do { } while(0) #define EMSG(x, ...) do { } while(0) #endif #endif ================================================ FILE: src/Main.cpp ================================================ #include "PeLdr.h" #include "Debug.h" static INT ShowUsage() { printf("-- PE Loader Sample --\n\n"); printf("PeLdr [PE-File]\n"); printf("\n"); return 0; } int wmain(int argc, wchar_t *argv[]) { PE_LDR_PARAM peLdr; if(argc < 2) return ShowUsage(); PeLdrInit(&peLdr); PeLdrSetExecutablePath(&peLdr, argv[1]); PeLdrStart(&peLdr); return 0; } ================================================ FILE: src/PEB.h ================================================ #ifndef _PEB_H #define _PEB_H // https://github.com/stephenfewer/ReflectiveDLLInjection //===============================================================================================// typedef struct _UNICODE_STR { USHORT Length; USHORT MaximumLength; PWSTR pBuffer; } UNICODE_STR, *PUNICODE_STR; // WinDbg> dt -v ntdll!_LDR_DATA_TABLE_ENTRY //__declspec( align(8) ) typedef struct _LDR_DATA_TABLE_ENTRY { //LIST_ENTRY InLoadOrderLinks; // As we search from PPEB_LDR_DATA->InMemoryOrderModuleList we dont use the first entry. LIST_ENTRY InMemoryOrderModuleList; LIST_ENTRY InInitializationOrderModuleList; PVOID DllBase; PVOID EntryPoint; ULONG SizeOfImage; UNICODE_STR FullDllName; UNICODE_STR BaseDllName; ULONG Flags; SHORT LoadCount; SHORT TlsIndex; LIST_ENTRY HashTableEntry; ULONG TimeDateStamp; } LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; // WinDbg> dt -v ntdll!_PEB_LDR_DATA typedef struct _PEB_LDR_DATA //, 7 elements, 0x28 bytes { DWORD dwLength; DWORD dwInitialized; LPVOID lpSsHandle; LIST_ENTRY InLoadOrderModuleList; LIST_ENTRY InMemoryOrderModuleList; LIST_ENTRY InInitializationOrderModuleList; LPVOID lpEntryInProgress; } PEB_LDR_DATA, * PPEB_LDR_DATA; // WinDbg> dt -v ntdll!_PEB_FREE_BLOCK typedef struct _PEB_FREE_BLOCK // 2 elements, 0x8 bytes { struct _PEB_FREE_BLOCK * pNext; DWORD dwSize; } PEB_FREE_BLOCK, * PPEB_FREE_BLOCK; // struct _PEB is defined in Winternl.h but it is incomplete // WinDbg> dt -v ntdll!_PEB typedef struct __PEB // 65 elements, 0x210 bytes { BYTE bInheritedAddressSpace; BYTE bReadImageFileExecOptions; BYTE bBeingDebugged; BYTE bSpareBool; LPVOID lpMutant; LPVOID lpImageBaseAddress; PPEB_LDR_DATA pLdr; LPVOID lpProcessParameters; LPVOID lpSubSystemData; LPVOID lpProcessHeap; PRTL_CRITICAL_SECTION pFastPebLock; LPVOID lpFastPebLockRoutine; LPVOID lpFastPebUnlockRoutine; DWORD dwEnvironmentUpdateCount; LPVOID lpKernelCallbackTable; DWORD dwSystemReserved; DWORD dwAtlThunkSListPtr32; PPEB_FREE_BLOCK pFreeList; DWORD dwTlsExpansionCounter; LPVOID lpTlsBitmap; DWORD dwTlsBitmapBits[2]; LPVOID lpReadOnlySharedMemoryBase; LPVOID lpReadOnlySharedMemoryHeap; LPVOID lpReadOnlyStaticServerData; LPVOID lpAnsiCodePageData; LPVOID lpOemCodePageData; LPVOID lpUnicodeCaseTableData; DWORD dwNumberOfProcessors; DWORD dwNtGlobalFlag; LARGE_INTEGER liCriticalSectionTimeout; DWORD dwHeapSegmentReserve; DWORD dwHeapSegmentCommit; DWORD dwHeapDeCommitTotalFreeThreshold; DWORD dwHeapDeCommitFreeBlockThreshold; DWORD dwNumberOfHeaps; DWORD dwMaximumNumberOfHeaps; LPVOID lpProcessHeaps; LPVOID lpGdiSharedHandleTable; LPVOID lpProcessStarterHelper; DWORD dwGdiDCAttributeList; LPVOID lpLoaderLock; DWORD dwOSMajorVersion; DWORD dwOSMinorVersion; WORD wOSBuildNumber; WORD wOSCSDVersion; DWORD dwOSPlatformId; DWORD dwImageSubsystem; DWORD dwImageSubsystemMajorVersion; DWORD dwImageSubsystemMinorVersion; DWORD dwImageProcessAffinityMask; DWORD dwGdiHandleBuffer[34]; LPVOID lpPostProcessInitRoutine; LPVOID lpTlsExpansionBitmap; DWORD dwTlsExpansionBitmapBits[32]; DWORD dwSessionId; ULARGE_INTEGER liAppCompatFlags; ULARGE_INTEGER liAppCompatFlagsUser; LPVOID lppShimData; LPVOID lpAppCompatInfo; UNICODE_STR usCSDVersion; LPVOID lpActivationContextData; LPVOID lpProcessAssemblyStorageMap; LPVOID lpSystemDefaultActivationContextData; LPVOID lpSystemAssemblyStorageMap; DWORD dwMinimumStackCommit; } _PEB, * _PPEB; typedef struct { WORD offset:12; WORD type:4; } IMAGE_RELOC, *PIMAGE_RELOC; #endif ================================================ FILE: src/PeLdr.cpp ================================================ #include "PeLdr.h" #include "Debug.h" #include "PEB.h" #include #ifndef NTSTATUS #define NTSTATUS LONG #endif #ifndef STATUS_SUCCESS #define STATUS_SUCCESS ((NTSTATUS)0x00000000L) #endif #pragma warning(disable: 4995) static BOOL PeLdrApplyImageRelocations(DWORD dwImageBase, UINT_PTR iRelocOffset) { PIMAGE_DOS_HEADER pDosHeader; PIMAGE_NT_HEADERS pNtHeaders; DWORD x; DWORD dwTmp; PIMAGE_BASE_RELOCATION pBaseReloc; PIMAGE_RELOC pReloc; DMSG("Applying Image Relocation (Base: 0x%08x RelocOffset: 0x%08x)", dwImageBase, iRelocOffset); pDosHeader = (PIMAGE_DOS_HEADER) dwImageBase; pNtHeaders = (PIMAGE_NT_HEADERS) (dwImageBase + pDosHeader->e_lfanew); pBaseReloc = (PIMAGE_BASE_RELOCATION) (dwImageBase + pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress); while(pBaseReloc->SizeOfBlock) { x = dwImageBase + pBaseReloc->VirtualAddress; dwTmp = (pBaseReloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(IMAGE_RELOC); pReloc = (PIMAGE_RELOC) (((DWORD) pBaseReloc) + sizeof(IMAGE_BASE_RELOCATION)); while(dwTmp--) { switch(pReloc->type) { case IMAGE_REL_BASED_DIR64: *((UINT_PTR*)(x + pReloc->offset)) += iRelocOffset; break; case IMAGE_REL_BASED_HIGHLOW: *((DWORD*)(x + pReloc->offset)) += (DWORD) iRelocOffset; break; case IMAGE_REL_BASED_HIGH: *((WORD*)(x + pReloc->offset)) += HIWORD(iRelocOffset); break; case IMAGE_REL_BASED_LOW: *((WORD*)(x + pReloc->offset)) += LOWORD(iRelocOffset); break; case IMAGE_REL_BASED_ABSOLUTE: break; default: DMSG("Unknown relocation type: 0x%08x", pReloc->type); break; } pReloc += 1; } pBaseReloc = (PIMAGE_BASE_RELOCATION)(((DWORD) pBaseReloc) + pBaseReloc->SizeOfBlock); } return TRUE; } static BOOL PeLdrProcessIAT(DWORD dwImageBase) { BOOL ret = FALSE; PIMAGE_DOS_HEADER pDosHeader; PIMAGE_NT_HEADERS pNtHeaders; PIMAGE_IMPORT_DESCRIPTOR pImportDesc; PIMAGE_THUNK_DATA pThunkData; PIMAGE_THUNK_DATA pThunkDataOrig; PIMAGE_IMPORT_BY_NAME pImportByName; PIMAGE_EXPORT_DIRECTORY pExportDir; DWORD flError = 0; DWORD dwTmp; BYTE *pLibName; HMODULE hMod; DMSG("Processing IAT (Image Base: 0x%08x)", dwImageBase); pDosHeader = (PIMAGE_DOS_HEADER) dwImageBase; pNtHeaders = (PIMAGE_NT_HEADERS) (dwImageBase + pDosHeader->e_lfanew); do { pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)(dwImageBase + pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); if(!pImportDesc) { DMSG("IAT not found"); break; } while((pImportDesc->Name != 0) && (!flError)) { pLibName = (BYTE*) (dwImageBase + pImportDesc->Name); DMSG("Loading Library and processing Imports: %s", (CHAR*) pLibName); if(pImportDesc->ForwarderChain != -1) { DMSG("FIXME: Cannot handle Import Forwarding"); //flError = 1; //break; } hMod = LoadLibraryA((CHAR*) pLibName); if(!hMod) { DMSG("Failed to load library: %s", pLibName); flError = 1; break; } pThunkData = (PIMAGE_THUNK_DATA)(dwImageBase + pImportDesc->FirstThunk); if(pImportDesc->Characteristics == 0) /* Borland compilers doesn't produce Hint Table */ pThunkDataOrig = pThunkData; else /* Hint Table */ pThunkDataOrig = (PIMAGE_THUNK_DATA)(dwImageBase + pImportDesc->Characteristics); while(pThunkDataOrig->u1.AddressOfData != 0) { if(pThunkDataOrig->u1.Ordinal & IMAGE_ORDINAL_FLAG) { /* Import via. Export Ordinal */ PIMAGE_DOS_HEADER _dos; PIMAGE_NT_HEADERS _nt; _dos = (PIMAGE_DOS_HEADER) hMod; _nt = (PIMAGE_NT_HEADERS) (((DWORD) hMod) + _dos->e_lfanew); pExportDir = (PIMAGE_EXPORT_DIRECTORY) (((DWORD) hMod) + _nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); dwTmp = (((DWORD) hMod) + pExportDir->AddressOfFunctions) + (((IMAGE_ORDINAL(pThunkDataOrig->u1.Ordinal) - pExportDir->Base)) * sizeof(DWORD)); dwTmp = ((DWORD) hMod) + *((DWORD*) dwTmp); pThunkData->u1.Function = dwTmp; } else { pImportByName = (PIMAGE_IMPORT_BY_NAME) (dwImageBase + pThunkDataOrig->u1.AddressOfData); pThunkData->u1.Function = (DWORD) GetProcAddress(hMod, (LPCSTR) pImportByName->Name); if(!pThunkData->u1.Function) { DMSG("Failed to resolve API: %s!%s", (CHAR*)pLibName, (CHAR*)pImportByName->Name); flError = 1; break; } } pThunkDataOrig++; pThunkData++; } pImportDesc++; } if(!flError) ret = TRUE; } while(0); return ret; } static BOOL PeLdrNeedSelfRelocation(PE_LDR_PARAM *pe) { DWORD dwMyBase; PIMAGE_DOS_HEADER pMyDosHeader; PIMAGE_NT_HEADERS pMyNtHeaders; DMSG("Checking for self relocation"); dwMyBase = (DWORD) GetModuleHandle(NULL); if(!dwMyBase) { EMSG("Failed to get our loaded address"); return FALSE; } pMyDosHeader = (PIMAGE_DOS_HEADER) dwMyBase; pMyNtHeaders = (PIMAGE_NT_HEADERS) (dwMyBase + pMyDosHeader->e_lfanew); if(pMyNtHeaders->Signature != IMAGE_NT_SIGNATURE) { EMSG("Failed to find our own headers"); return FALSE; } DMSG("MyBase: 0x%08x MySize: %d", dwMyBase, pMyNtHeaders->OptionalHeader.SizeOfImage); if((pe->pNtHeaders->OptionalHeader.ImageBase >= dwMyBase) && (pe->pNtHeaders->OptionalHeader.ImageBase < (dwMyBase + pMyNtHeaders->OptionalHeader.SizeOfImage))) { DMSG("Self relocation required"); return TRUE; } return FALSE; } static BOOL PeLdrRelocateAndContinue(PE_LDR_PARAM *pe, VOID *pContFunc, VOID *pParam) { PIMAGE_DOS_HEADER pMyDosHeader; PIMAGE_NT_HEADERS pMyNtHeaders; DWORD dwNewBase; DWORD dwMyBase; DWORD dwAddr; UINT_PTR iRelocOffset; DMSG("Relocating loader image (Continue Function: 0x%08x)", (DWORD) pContFunc); dwMyBase = (DWORD) GetModuleHandle(NULL); if(!dwMyBase) { EMSG("Failed to get our loaded address"); return FALSE; } pMyDosHeader = (PIMAGE_DOS_HEADER) dwMyBase; pMyNtHeaders = (PIMAGE_NT_HEADERS) (dwMyBase + pMyDosHeader->e_lfanew); dwNewBase = (DWORD) VirtualAlloc(NULL, pMyNtHeaders->OptionalHeader.SizeOfImage + 1, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if(!dwNewBase) { EMSG("Failed to allocate memory for self relocation"); return FALSE; } DMSG("New Loader Base: 0x%08x", dwNewBase); pe->dwLoaderRelocatedBase = dwNewBase; CopyMemory((VOID*) dwNewBase, (VOID*) dwMyBase, pMyNtHeaders->OptionalHeader.SizeOfImage); if(!PeLdrProcessIAT(dwNewBase)) { EMSG("Failed to process IAT for relocated image"); return FALSE; } iRelocOffset = dwNewBase - dwMyBase; if(!PeLdrApplyImageRelocations(dwNewBase, iRelocOffset)) { EMSG("Failed to apply relocations on relocated image"); return FALSE; } pe->dwLoaderBase = dwNewBase; dwAddr = ((DWORD) pContFunc) - dwMyBase; dwAddr += dwNewBase; DMSG("Jumping to relocated image (Relocated Continue Function: 0x%08x)", dwAddr); __asm { mov eax, pParam push eax mov eax, dwAddr call eax } return TRUE; } static BOOL PeLdrExecuteEP(PE_LDR_PARAM *pe) { DWORD dwOld; DWORD dwEP; _PPEB peb; // TODO: Fix permission as per section flags if(!VirtualProtect((LPVOID) pe->dwMapBase, pe->pNtHeaders->OptionalHeader.SizeOfImage, PAGE_EXECUTE_READWRITE, &dwOld)) { DMSG("Failed to change mapping protection"); return FALSE; } DMSG("Fixing Image Base address in PEB"); peb = (_PPEB)__readfsdword(0x30); peb->lpImageBaseAddress = (LPVOID) pe->dwMapBase; dwEP = pe->dwMapBase + pe->pNtHeaders->OptionalHeader.AddressOfEntryPoint; DMSG("Executing Entry Point: 0x%08x", dwEP); __asm { mov eax, dwEP call eax int 3 } return TRUE; } static BOOL PeLdrApplyRelocations(PE_LDR_PARAM *pe) { UINT_PTR iRelocOffset; if(pe->dwMapBase == pe->pNtHeaders->OptionalHeader.ImageBase) { DMSG("Relocation not required"); return TRUE; } if(!pe->pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size) { DMSG("PE required relocation but no relocatiom information found"); return FALSE; } iRelocOffset = pe->dwMapBase - pe->pNtHeaders->OptionalHeader.ImageBase; return PeLdrApplyImageRelocations(pe->dwMapBase, iRelocOffset); } static BOOL PeLdrMapImage(PE_LDR_PARAM *pe) { DWORD i; MEMORY_BASIC_INFORMATION mi; PIMAGE_SECTION_HEADER pSectionHeader; BOOL ret = FALSE; NTSTATUS (NTAPI *NtUnmapViewOfSection) (HANDLE, LPVOID) = NULL; if(!pe) return ret; DMSG("Mapping Target PE File"); DMSG("Loader Base Orig: 0x%08x New: 0x%08x", pe->dwLoaderBase, pe->dwLoaderRelocatedBase); NtUnmapViewOfSection = (NTSTATUS (NTAPI *)(HANDLE, LPVOID)) GetProcAddress(GetModuleHandle(TEXT("ntdll.dll")), "ZwUnmapViewOfSection"); if(!NtUnmapViewOfSection) DMSG("Failed to resolve address of NtUnmapViewOfSection"); do { DMSG("Target PE Load Base: 0x%08x Image Size: 0x%08x", pe->pNtHeaders->OptionalHeader.ImageBase, pe->pNtHeaders->OptionalHeader.SizeOfImage); // Find the size of our mapping i = pe->dwLoaderBase; while(VirtualQuery((LPVOID) i, &mi, sizeof(mi))) { if(mi.State == MEM_FREE) break; i += mi.RegionSize; } if((pe->pNtHeaders->OptionalHeader.ImageBase >= pe->dwLoaderBase) && (pe->pNtHeaders->OptionalHeader.ImageBase < i)) { if(NtUnmapViewOfSection) { DMSG("Unmapping original loader mapping"); if(NtUnmapViewOfSection(GetCurrentProcess(), (VOID*) pe->dwLoaderBase) == STATUS_SUCCESS) { pe->dwMapBase = (DWORD) VirtualAlloc((LPVOID) pe->pNtHeaders->OptionalHeader.ImageBase, pe->pNtHeaders->OptionalHeader.SizeOfImage + 1, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); } else { EMSG("Failed to unmap original loader mapping"); } } } pe->dwMapBase = (DWORD) VirtualAlloc((LPVOID) pe->pNtHeaders->OptionalHeader.ImageBase, pe->pNtHeaders->OptionalHeader.SizeOfImage + 1, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); if(!pe->dwMapBase) EMSG("Failed to allocate PE ImageBase: 0x%08x", pe->pNtHeaders->OptionalHeader.ImageBase); if(!pe->dwMapBase) { DMSG("Attempting to allocate new memory"); if(!pe->pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size) { EMSG("Failed to map required memory address, need relocation to continue"); EMSG("[WARNING] Forcing re-use of mapped memory"); pe->dwMapBase = (DWORD) pe->pNtHeaders->OptionalHeader.ImageBase; } else { pe->dwMapBase = (DWORD) VirtualAlloc(NULL, pe->pNtHeaders->OptionalHeader.SizeOfImage + 1, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); } } if(!pe->dwMapBase) { EMSG("Failed to map memory for Target PE"); break; } DMSG("Allocated memory for Target PE: 0x%08x", pe->dwMapBase); DMSG("Copying Headers"); CopyMemory((LPVOID) pe->dwMapBase, (LPVOID) pe->dwImage, pe->pNtHeaders->OptionalHeader.SizeOfHeaders); DMSG("Copying Sections"); pSectionHeader = IMAGE_FIRST_SECTION(pe->pNtHeaders); for(i = 0; i < pe->pNtHeaders->FileHeader.NumberOfSections; i++) { DMSG(" Copying Section: %s", (CHAR*) pSectionHeader[i].Name); CopyMemory( (LPVOID)(pe->dwMapBase + pSectionHeader[i].VirtualAddress), (LPVOID)(pe->dwImage + pSectionHeader[i].PointerToRawData), pSectionHeader[i].SizeOfRawData ); } ret = TRUE; } while(0); return ret; } static BOOL PeLdrLoadImage(PE_LDR_PARAM *pe) { HANDLE hFile = NULL; HANDLE hMap = NULL; BOOL ret = FALSE; _PPEB peb; if(!pe) goto out; DMSG("Mapping PE File"); if(!pe->bLoadFromBuffer) { DMSG("Creating Map View of File"); hFile = CreateFile(pe->pTargetPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if(hFile == INVALID_HANDLE_VALUE) { DMSG("Failed to open PE File"); goto out; } pe->dwImageSizeOnDisk = GetFileSize(hFile, NULL); hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); if(hMap == NULL) { DMSG("Failed to create file mapping for PE File"); goto out; } pe->dwImage = (DWORD) MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0); if(!pe->dwImage) { DMSG("Failed to obtain a map view of PE File"); goto out; } } DMSG("Map View of File created"); pe->pDosHeader = (PIMAGE_DOS_HEADER) pe->dwImage; if(pe->pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) { DMSG("DOS Signature invalid"); goto out; } pe->pNtHeaders = (PIMAGE_NT_HEADERS)(((DWORD) pe->dwImage) + pe->pDosHeader->e_lfanew); if(pe->pNtHeaders->Signature != IMAGE_NT_SIGNATURE) { DMSG("NT Signature mismatch"); goto out; } peb = (_PPEB)__readfsdword(0x30); pe->dwLoaderBase = (DWORD) peb->lpImageBaseAddress; ret = TRUE; out: if(hMap) CloseHandle(hMap); if(hFile) CloseHandle(hFile); return ret; } static BOOL PeLdrRunImage(PE_LDR_PARAM *pe) { if(!PeLdrMapImage(pe)) return FALSE; if(!PeLdrProcessIAT(pe->dwMapBase)) return FALSE; if(!PeLdrApplyRelocations(pe)) return FALSE; if(!PeLdrExecuteEP(pe)) return FALSE; return TRUE; } BOOL PeLdrStart(PE_LDR_PARAM *pe) { if(!PeLdrLoadImage(pe)) return FALSE; if(PeLdrNeedSelfRelocation(pe)) return PeLdrRelocateAndContinue(pe, (VOID*) PeLdrRunImage, (VOID*) pe); else return PeLdrRunImage(pe); } BOOL PeLdrSetExecutableBuffer(PE_LDR_PARAM *pe, PVOID pExecutable, DWORD dwLen) { if(!pe) return FALSE; pe->dwImageSizeOnDisk = dwLen; pe->dwImage = (DWORD) pExecutable; pe->bLoadFromBuffer = TRUE; return TRUE; } BOOL PeLdrSetExecutablePath(PE_LDR_PARAM *pe, TCHAR *pExecutable) { if(!pe) return FALSE; pe->pTargetPath = (TCHAR*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (lstrlen(pExecutable) + 1) * sizeof(TCHAR)); if(!pe->pTargetPath) { DMSG("Failed to allocate memory for pTargetPath"); return FALSE; } lstrcpy(pe->pTargetPath, pExecutable); return TRUE; } VOID PeLdrInit(PE_LDR_PARAM *pe) { ZeroMemory(pe, sizeof(PE_LDR_PARAM)); } ================================================ FILE: src/PeLdr.h ================================================ #ifndef _PE_LDR_H #define _PE_LDR_H #include #include #include typedef struct { TCHAR *pTargetPath; PIMAGE_DOS_HEADER pDosHeader; PIMAGE_NT_HEADERS pNtHeaders; BOOLEAN bLoadFromBuffer; DWORD dwImage; DWORD dwImageSizeOnDisk; DWORD dwLoaderBase; DWORD dwLoaderRelocatedBase; DWORD dwMapBase; } PE_LDR_PARAM; VOID PeLdrInit(PE_LDR_PARAM *pe); BOOL PeLdrSetExecutablePath(PE_LDR_PARAM *pe, TCHAR *pExecutable); BOOL PeLdrSetExecutableBuffer(PE_LDR_PARAM *pe, PVOID pExecutable, DWORD dwLen); BOOL PeLdrStart(PE_LDR_PARAM *pe); #endif