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
================================================
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Name="Pe-Loader-Sample"
ProjectGUID="{8DED49F0-69AF-4815-B5DE-522CEEEFD56C}"
RootNamespace="PeLoaderSample"
Keyword="Win32Proj"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
FixedBaseAddress="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
EnableIntrinsicFunctions="true"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
FixedBaseAddress="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\src\Main.cpp"
>
</File>
<File
RelativePath=".\src\PeLdr.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath=".\src\Debug.h"
>
</File>
<File
RelativePath=".\src\PEB.h"
>
</File>
<File
RelativePath=".\src\PeLdr.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
================================================
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 <stdio.h>
#define __DEBUG
#ifdef __DEBUG
#include <strsafe.h>
#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 <strsafe.h>
#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 <windows.h>
#include <tchar.h>
#include <winnt.h>
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
gitextract_cjiu6xeh/
├── .gitattributes
├── .gitignore
├── Pe-Loader-Sample.vcproj
├── README.md
└── src/
├── Debug.h
├── Main.cpp
├── PEB.h
├── PeLdr.cpp
└── PeLdr.h
SYMBOL INDEX (13 symbols across 4 files)
FILE: src/Main.cpp
function INT (line 4) | static
function wmain (line 14) | int wmain(int argc, wchar_t *argv[])
FILE: src/PEB.h
type UNICODE_STR (line 6) | typedef struct _UNICODE_STR
type LDR_DATA_TABLE_ENTRY (line 15) | typedef struct _LDR_DATA_TABLE_ENTRY
type PEB_LDR_DATA (line 33) | typedef struct _PEB_LDR_DATA //, 7 elements, 0x28 bytes
type PEB_FREE_BLOCK (line 45) | typedef struct _PEB_FREE_BLOCK // 2 elements, 0x8 bytes
type _PEB (line 53) | typedef struct __PEB // 65 elements, 0x210 bytes
type IMAGE_RELOC (line 122) | typedef struct
FILE: src/PeLdr.cpp
function BOOL (line 17) | static
function BOOL (line 76) | static
function BOOL (line 174) | static
function BOOL (line 209) | static
FILE: src/PeLdr.h
type PE_LDR_PARAM (line 8) | typedef struct {
Condensed preview — 9 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (30K chars).
[
{
"path": ".gitattributes",
"chars": 483,
"preview": "# Auto detect text files and perform LF normalization\n* text=auto\n\n# Custom for Visual Studio\n*.cs diff=csharp\n*.sln"
},
{
"path": ".gitignore",
"chars": 2006,
"preview": "\n#################\n## Eclipse\n#################\n\n*.pydevproject\n.project\n.metadata\nbin/**\ntmp/**\ntmp/**/*\n*.tmp\n*.bak\n*."
},
{
"path": "Pe-Loader-Sample.vcproj",
"chars": 4053,
"preview": "<?xml version=\"1.0\" encoding=\"Windows-1252\"?>\n<VisualStudioProject\n\tProjectType=\"Visual C++\"\n\tVersion=\"9.00\"\n\tName=\"Pe-L"
},
{
"path": "README.md",
"chars": 826,
"preview": "PE Loader Sample\n=================\n\nIn memory execution of PE executables:\n\n * Self Relocation\n * Memory Mapping\n * IAT "
},
{
"path": "src/Debug.h",
"chars": 332,
"preview": "#ifndef _DEBUG_H\n#define _DEBUG_H\n\n#include <stdio.h>\n\n#define __DEBUG\n\n#ifdef __DEBUG\n#include <strsafe.h>\n#define DMSG"
},
{
"path": "src/Main.cpp",
"chars": 357,
"preview": "#include \"PeLdr.h\"\n#include \"Debug.h\"\n\nstatic\nINT ShowUsage()\n{\n\tprintf(\"-- PE Loader Sample --\\n\\n\");\n\tprintf(\"PeLdr [P"
},
{
"path": "src/PEB.h",
"chars": 3701,
"preview": "#ifndef _PEB_H\n#define _PEB_H\n\n// https://github.com/stephenfewer/ReflectiveDLLInjection\n//============================="
},
{
"path": "src/PeLdr.cpp",
"chars": 13873,
"preview": "#include \"PeLdr.h\"\n#include \"Debug.h\"\n#include \"PEB.h\"\n\n#include <strsafe.h>\n\n#ifndef NTSTATUS\n#define NTSTATUS\tLONG\n#en"
},
{
"path": "src/PeLdr.h",
"chars": 609,
"preview": "#ifndef _PE_LDR_H\n#define _PE_LDR_H\n\n#include <windows.h>\n#include <tchar.h>\n#include <winnt.h>\n\ntypedef struct {\n\tTCHAR"
}
]
About this extraction
This page contains the full source code of the abhisek/Pe-Loader-Sample GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 9 files (25.6 KB), approximately 8.4k tokens, and a symbol index with 13 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.