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