[
  {
    "path": ".gitattributes",
    "content": "# Auto detect text files and perform LF normalization\n* text=auto\n\n# Custom for Visual Studio\n*.cs     diff=csharp\n*.sln    merge=union\n*.csproj merge=union\n*.vbproj merge=union\n*.fsproj merge=union\n*.dbproj merge=union\n\n# Standard to msysgit\n*.doc\t diff=astextplain\n*.DOC\t diff=astextplain\n*.docx diff=astextplain\n*.DOCX diff=astextplain\n*.dot  diff=astextplain\n*.DOT  diff=astextplain\n*.pdf  diff=astextplain\n*.PDF\t diff=astextplain\n*.rtf\t diff=astextplain\n*.RTF\t diff=astextplain\n"
  },
  {
    "path": ".gitignore",
    "content": "\n#################\n## Eclipse\n#################\n\n*.pydevproject\n.project\n.metadata\nbin/**\ntmp/**\ntmp/**/*\n*.tmp\n*.bak\n*.swp\n*~.nib\nlocal.properties\n.classpath\n.settings/\n.loadpath\n\n# External tool builders\n.externalToolBuilders/\n\n# Locally stored \"Eclipse launch configurations\"\n*.launch\n\n# CDT-specific\n.cproject\n\n# PDT-specific\n.buildpath\n\n\n#################\n## Visual Studio\n#################\n\n## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n\n# User-specific files\n*.suo\n*.user\n*.sln.docstates\n\n# Build results\n**/[Dd]ebug/\n**/[Rr]elease/\n*_i.c\n*_p.c\n*.ilk\n*.meta\n*.obj\n*.pch\n*.pdb\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.vspscc\n.builds\n**/*.dotCover\n\n## TODO: If you have NuGet Package Restore enabled, uncomment this\n#**/packages/ \n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opensdf\n*.sdf\n\n# Visual Studio profiler\n*.psess\n*.vsp\n\n# ReSharper is a .NET coding add-in\n_ReSharper*\n\n# Installshield output folder \n[Ee]xpress\n\n# DocProject is a documentation generator add-in\nDocProject/buildhelp/\nDocProject/Help/*.HxT\nDocProject/Help/*.HxC\nDocProject/Help/*.hhc\nDocProject/Help/*.hhk\nDocProject/Help/*.hhp\nDocProject/Help/Html2\nDocProject/Help/html\n\n# Click-Once directory\npublish\n\n# Others\n[Bb]in\n[Oo]bj\nsql\nTestResults\n*.Cache\nClientBin\nstylecop.*\n~$*\n*.dbmdl\nGenerated_Code #added for RIA/Silverlight projects\n\n# Backup & report files from converting an old project file to a newer\n# Visual Studio version. Backup files are not needed, because we have git ;-)\n_UpgradeReport_Files/\nBackup*/\nUpgradeLog*.XML\n\n\n\n############\n## Windows\n############\n\n# Windows image file caches\nThumbs.db \n\n# Folder config file\nDesktop.ini\n\n\n#############\n## Python\n#############\n\n*.py[co]\n\n# Packages\n*.egg\n*.egg-info\ndist\nbuild\neggs\nparts\nbin\nvar\nsdist\ndevelop-eggs\n.installed.cfg\n\n# Installer logs\npip-log.txt\n\n# Unit test / coverage reports\n.coverage\n.tox\n\n#Translations\n*.mo\n\n#Mr Developer\n.mr.developer.cfg\n\n# Mac crap\n.DS_Store\n\nDebug\n"
  },
  {
    "path": "Pe-Loader-Sample.vcproj",
    "content": "<?xml version=\"1.0\" encoding=\"Windows-1252\"?>\n<VisualStudioProject\n\tProjectType=\"Visual C++\"\n\tVersion=\"9.00\"\n\tName=\"Pe-Loader-Sample\"\n\tProjectGUID=\"{8DED49F0-69AF-4815-B5DE-522CEEEFD56C}\"\n\tRootNamespace=\"PeLoaderSample\"\n\tKeyword=\"Win32Proj\"\n\tTargetFrameworkVersion=\"196613\"\n\t>\n\t<Platforms>\n\t\t<Platform\n\t\t\tName=\"Win32\"\n\t\t/>\n\t</Platforms>\n\t<ToolFiles>\n\t</ToolFiles>\n\t<Configurations>\n\t\t<Configuration\n\t\t\tName=\"Debug|Win32\"\n\t\t\tOutputDirectory=\"$(SolutionDir)$(ConfigurationName)\"\n\t\t\tIntermediateDirectory=\"$(ConfigurationName)\"\n\t\t\tConfigurationType=\"1\"\n\t\t\tCharacterSet=\"1\"\n\t\t\t>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPreBuildEventTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCCustomBuildTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCXMLDataGeneratorTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCWebServiceProxyGeneratorTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCMIDLTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCCLCompilerTool\"\n\t\t\t\tOptimization=\"0\"\n\t\t\t\tPreprocessorDefinitions=\"WIN32;_DEBUG;_CONSOLE\"\n\t\t\t\tMinimalRebuild=\"true\"\n\t\t\t\tBasicRuntimeChecks=\"3\"\n\t\t\t\tRuntimeLibrary=\"3\"\n\t\t\t\tUsePrecompiledHeader=\"0\"\n\t\t\t\tWarningLevel=\"3\"\n\t\t\t\tDebugInformationFormat=\"4\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCManagedResourceCompilerTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCResourceCompilerTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPreLinkEventTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCLinkerTool\"\n\t\t\t\tLinkIncremental=\"2\"\n\t\t\t\tGenerateDebugInformation=\"true\"\n\t\t\t\tSubSystem=\"1\"\n\t\t\t\tFixedBaseAddress=\"1\"\n\t\t\t\tTargetMachine=\"1\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCALinkTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCManifestTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCXDCMakeTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCBscMakeTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCFxCopTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCAppVerifierTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPostBuildEventTool\"\n\t\t\t/>\n\t\t</Configuration>\n\t\t<Configuration\n\t\t\tName=\"Release|Win32\"\n\t\t\tOutputDirectory=\"$(SolutionDir)$(ConfigurationName)\"\n\t\t\tIntermediateDirectory=\"$(ConfigurationName)\"\n\t\t\tConfigurationType=\"1\"\n\t\t\tCharacterSet=\"1\"\n\t\t\tWholeProgramOptimization=\"1\"\n\t\t\t>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPreBuildEventTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCCustomBuildTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCXMLDataGeneratorTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCWebServiceProxyGeneratorTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCMIDLTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCCLCompilerTool\"\n\t\t\t\tOptimization=\"2\"\n\t\t\t\tEnableIntrinsicFunctions=\"true\"\n\t\t\t\tPreprocessorDefinitions=\"WIN32;NDEBUG;_CONSOLE\"\n\t\t\t\tRuntimeLibrary=\"2\"\n\t\t\t\tEnableFunctionLevelLinking=\"true\"\n\t\t\t\tUsePrecompiledHeader=\"0\"\n\t\t\t\tWarningLevel=\"3\"\n\t\t\t\tDebugInformationFormat=\"3\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCManagedResourceCompilerTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCResourceCompilerTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPreLinkEventTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCLinkerTool\"\n\t\t\t\tLinkIncremental=\"1\"\n\t\t\t\tGenerateDebugInformation=\"true\"\n\t\t\t\tSubSystem=\"1\"\n\t\t\t\tOptimizeReferences=\"2\"\n\t\t\t\tEnableCOMDATFolding=\"2\"\n\t\t\t\tFixedBaseAddress=\"1\"\n\t\t\t\tTargetMachine=\"1\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCALinkTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCManifestTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCXDCMakeTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCBscMakeTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCFxCopTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCAppVerifierTool\"\n\t\t\t/>\n\t\t\t<Tool\n\t\t\t\tName=\"VCPostBuildEventTool\"\n\t\t\t/>\n\t\t</Configuration>\n\t</Configurations>\n\t<References>\n\t</References>\n\t<Files>\n\t\t<Filter\n\t\t\tName=\"Source Files\"\n\t\t\tFilter=\"cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx\"\n\t\t\tUniqueIdentifier=\"{4FC737F1-C7A5-4376-A066-2A32D752A2FF}\"\n\t\t\t>\n\t\t\t<File\n\t\t\t\tRelativePath=\".\\src\\Main.cpp\"\n\t\t\t\t>\n\t\t\t</File>\n\t\t\t<File\n\t\t\t\tRelativePath=\".\\src\\PeLdr.cpp\"\n\t\t\t\t>\n\t\t\t</File>\n\t\t</Filter>\n\t\t<Filter\n\t\t\tName=\"Header Files\"\n\t\t\tFilter=\"h;hpp;hxx;hm;inl;inc;xsd\"\n\t\t\tUniqueIdentifier=\"{93995380-89BD-4b04-88EB-625FBE52EBFB}\"\n\t\t\t>\n\t\t\t<File\n\t\t\t\tRelativePath=\".\\src\\Debug.h\"\n\t\t\t\t>\n\t\t\t</File>\n\t\t\t<File\n\t\t\t\tRelativePath=\".\\src\\PEB.h\"\n\t\t\t\t>\n\t\t\t</File>\n\t\t\t<File\n\t\t\t\tRelativePath=\".\\src\\PeLdr.h\"\n\t\t\t\t>\n\t\t\t</File>\n\t\t</Filter>\n\t\t<Filter\n\t\t\tName=\"Resource Files\"\n\t\t\tFilter=\"rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav\"\n\t\t\tUniqueIdentifier=\"{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}\"\n\t\t\t>\n\t\t</Filter>\n\t</Files>\n\t<Globals>\n\t</Globals>\n</VisualStudioProject>\n"
  },
  {
    "path": "README.md",
    "content": "PE Loader Sample\n=================\n\nIn memory execution of PE executables:\n\n * Self Relocation\n * Memory Mapping\n * IAT Processing\n * Relocation\n * Control Transfer\n\t\nThis 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.\n\nTODO:\n\n * Handle Import Forwarding\n * Bound Imports\n * Is it possible to relocate a PE if relocation table is not included? Hack++?\n * Most Important: Documentation of PE Loading Process\n\t\nThanks\n-------\n\n* 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.\n\n* sincoder for ideas on Self Relocation."
  },
  {
    "path": "src/Debug.h",
    "content": "#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(x, ...)\tfprintf(stderr, \"[+] \" x \"\\n\", __VA_ARGS__)\n#define EMSG(x, ...)\tfprintf(stderr, \"[-] \" x \"\\n\", __VA_ARGS__)\n#else\n#define DMSG(x, ...)\tdo { } while(0)\n#define EMSG(x, ...)\tdo { } while(0)\n#endif\n\n#endif"
  },
  {
    "path": "src/Main.cpp",
    "content": "#include \"PeLdr.h\"\n#include \"Debug.h\"\n\nstatic\nINT ShowUsage()\n{\n\tprintf(\"-- PE Loader Sample --\\n\\n\");\n\tprintf(\"PeLdr [PE-File]\\n\");\n\tprintf(\"\\n\");\n\n\treturn 0;\n}\n\nint wmain(int argc, wchar_t *argv[])\n{\n\tPE_LDR_PARAM peLdr;\n\n\tif(argc < 2)\n\t\treturn ShowUsage();\n\n\tPeLdrInit(&peLdr);\n\tPeLdrSetExecutablePath(&peLdr, argv[1]);\n\tPeLdrStart(&peLdr);\n\n\treturn 0;\n}"
  },
  {
    "path": "src/PEB.h",
    "content": "#ifndef _PEB_H\n#define _PEB_H\n\n// https://github.com/stephenfewer/ReflectiveDLLInjection\n//===============================================================================================//\ntypedef struct _UNICODE_STR\n{\n  USHORT Length;\n  USHORT MaximumLength;\n  PWSTR pBuffer;\n} UNICODE_STR, *PUNICODE_STR;\n\n// WinDbg> dt -v ntdll!_LDR_DATA_TABLE_ENTRY\n//__declspec( align(8) ) \ntypedef struct _LDR_DATA_TABLE_ENTRY\n{\n\t//LIST_ENTRY InLoadOrderLinks; // As we search from PPEB_LDR_DATA->InMemoryOrderModuleList we dont use the first entry.\n\tLIST_ENTRY InMemoryOrderModuleList;\n\tLIST_ENTRY InInitializationOrderModuleList;\n\tPVOID DllBase;\n\tPVOID EntryPoint;\n\tULONG SizeOfImage;\n\tUNICODE_STR FullDllName;\n\tUNICODE_STR BaseDllName;\n\tULONG Flags;\n\tSHORT LoadCount;\n\tSHORT TlsIndex;\n\tLIST_ENTRY HashTableEntry;\n\tULONG TimeDateStamp;\n} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;\n\n// WinDbg> dt -v ntdll!_PEB_LDR_DATA\ntypedef struct _PEB_LDR_DATA //, 7 elements, 0x28 bytes\n{\n   DWORD dwLength;\n   DWORD dwInitialized;\n   LPVOID lpSsHandle;\n   LIST_ENTRY InLoadOrderModuleList;\n   LIST_ENTRY InMemoryOrderModuleList;\n   LIST_ENTRY InInitializationOrderModuleList;\n   LPVOID lpEntryInProgress;\n} PEB_LDR_DATA, * PPEB_LDR_DATA;\n\n// WinDbg> dt -v ntdll!_PEB_FREE_BLOCK\ntypedef struct _PEB_FREE_BLOCK // 2 elements, 0x8 bytes\n{\n   struct _PEB_FREE_BLOCK * pNext;\n   DWORD dwSize;\n} PEB_FREE_BLOCK, * PPEB_FREE_BLOCK;\n\n// struct _PEB is defined in Winternl.h but it is incomplete\n// WinDbg> dt -v ntdll!_PEB\ntypedef struct __PEB // 65 elements, 0x210 bytes\n{\n   BYTE bInheritedAddressSpace;\n   BYTE bReadImageFileExecOptions;\n   BYTE bBeingDebugged;\n   BYTE bSpareBool;\n   LPVOID lpMutant;\n   LPVOID lpImageBaseAddress;\n   PPEB_LDR_DATA pLdr;\n   LPVOID lpProcessParameters;\n   LPVOID lpSubSystemData;\n   LPVOID lpProcessHeap;\n   PRTL_CRITICAL_SECTION pFastPebLock;\n   LPVOID lpFastPebLockRoutine;\n   LPVOID lpFastPebUnlockRoutine;\n   DWORD dwEnvironmentUpdateCount;\n   LPVOID lpKernelCallbackTable;\n   DWORD dwSystemReserved;\n   DWORD dwAtlThunkSListPtr32;\n   PPEB_FREE_BLOCK pFreeList;\n   DWORD dwTlsExpansionCounter;\n   LPVOID lpTlsBitmap;\n   DWORD dwTlsBitmapBits[2];\n   LPVOID lpReadOnlySharedMemoryBase;\n   LPVOID lpReadOnlySharedMemoryHeap;\n   LPVOID lpReadOnlyStaticServerData;\n   LPVOID lpAnsiCodePageData;\n   LPVOID lpOemCodePageData;\n   LPVOID lpUnicodeCaseTableData;\n   DWORD dwNumberOfProcessors;\n   DWORD dwNtGlobalFlag;\n   LARGE_INTEGER liCriticalSectionTimeout;\n   DWORD dwHeapSegmentReserve;\n   DWORD dwHeapSegmentCommit;\n   DWORD dwHeapDeCommitTotalFreeThreshold;\n   DWORD dwHeapDeCommitFreeBlockThreshold;\n   DWORD dwNumberOfHeaps;\n   DWORD dwMaximumNumberOfHeaps;\n   LPVOID lpProcessHeaps;\n   LPVOID lpGdiSharedHandleTable;\n   LPVOID lpProcessStarterHelper;\n   DWORD dwGdiDCAttributeList;\n   LPVOID lpLoaderLock;\n   DWORD dwOSMajorVersion;\n   DWORD dwOSMinorVersion;\n   WORD wOSBuildNumber;\n   WORD wOSCSDVersion;\n   DWORD dwOSPlatformId;\n   DWORD dwImageSubsystem;\n   DWORD dwImageSubsystemMajorVersion;\n   DWORD dwImageSubsystemMinorVersion;\n   DWORD dwImageProcessAffinityMask;\n   DWORD dwGdiHandleBuffer[34];\n   LPVOID lpPostProcessInitRoutine;\n   LPVOID lpTlsExpansionBitmap;\n   DWORD dwTlsExpansionBitmapBits[32];\n   DWORD dwSessionId;\n   ULARGE_INTEGER liAppCompatFlags;\n   ULARGE_INTEGER liAppCompatFlagsUser;\n   LPVOID lppShimData;\n   LPVOID lpAppCompatInfo;\n   UNICODE_STR usCSDVersion;\n   LPVOID lpActivationContextData;\n   LPVOID lpProcessAssemblyStorageMap;\n   LPVOID lpSystemDefaultActivationContextData;\n   LPVOID lpSystemAssemblyStorageMap;\n   DWORD dwMinimumStackCommit;\n} _PEB, * _PPEB;\n\ntypedef struct\n{\n\tWORD\toffset:12;\n\tWORD\ttype:4;\n} IMAGE_RELOC, *PIMAGE_RELOC;\n\n#endif\n"
  },
  {
    "path": "src/PeLdr.cpp",
    "content": "#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#endif\n\n#ifndef STATUS_SUCCESS\n#define STATUS_SUCCESS  ((NTSTATUS)0x00000000L)\n#endif\n\n#pragma warning(disable: 4995)\n\nstatic\nBOOL PeLdrApplyImageRelocations(DWORD dwImageBase, UINT_PTR iRelocOffset)\n{\n\tPIMAGE_DOS_HEADER\t\t\tpDosHeader;\n\tPIMAGE_NT_HEADERS\t\t\tpNtHeaders;\n\tDWORD\t\t\t\t\t\tx;\n\tDWORD\t\t\t\t\t\tdwTmp;\n\tPIMAGE_BASE_RELOCATION\t\tpBaseReloc;\n\tPIMAGE_RELOC\t\t\t\tpReloc;\n\n\tDMSG(\"Applying Image Relocation (Base: 0x%08x RelocOffset: 0x%08x)\",\n\t\tdwImageBase, iRelocOffset);\n\n\tpDosHeader = (PIMAGE_DOS_HEADER) dwImageBase;\n\tpNtHeaders = (PIMAGE_NT_HEADERS) (dwImageBase + pDosHeader->e_lfanew);\n\n\tpBaseReloc = (PIMAGE_BASE_RELOCATION) \n\t\t(dwImageBase + \n\t\tpNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);\n\n\twhile(pBaseReloc->SizeOfBlock) {\n\t\tx = dwImageBase + pBaseReloc->VirtualAddress;\n\t\tdwTmp = (pBaseReloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(IMAGE_RELOC);\n\t\tpReloc = (PIMAGE_RELOC) (((DWORD) pBaseReloc) + sizeof(IMAGE_BASE_RELOCATION));\n\n\t\twhile(dwTmp--) {\n\t\t\tswitch(pReloc->type) {\n\t\t\t\tcase IMAGE_REL_BASED_DIR64:\n\t\t\t\t\t*((UINT_PTR*)(x + pReloc->offset)) += iRelocOffset;\n\t\t\t\t\tbreak;\t\n\t\t\t\tcase IMAGE_REL_BASED_HIGHLOW:\n\t\t\t\t\t*((DWORD*)(x + pReloc->offset)) += (DWORD) iRelocOffset;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase IMAGE_REL_BASED_HIGH:\n\t\t\t\t\t*((WORD*)(x + pReloc->offset)) += HIWORD(iRelocOffset);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase IMAGE_REL_BASED_LOW:\n\t\t\t\t\t*((WORD*)(x + pReloc->offset)) += LOWORD(iRelocOffset);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase IMAGE_REL_BASED_ABSOLUTE:\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tDMSG(\"Unknown relocation type: 0x%08x\", pReloc->type);\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tpReloc += 1;\n\t\t}\n\n\t\tpBaseReloc = (PIMAGE_BASE_RELOCATION)(((DWORD) pBaseReloc) + pBaseReloc->SizeOfBlock);\n\t}\n\n\treturn TRUE;\n}\n\nstatic\nBOOL PeLdrProcessIAT(DWORD dwImageBase)\n{\n\tBOOL\t\t\t\t\t\tret = FALSE;\n\tPIMAGE_DOS_HEADER\t\t\tpDosHeader;\n\tPIMAGE_NT_HEADERS\t\t\tpNtHeaders;\n\tPIMAGE_IMPORT_DESCRIPTOR\tpImportDesc;\n\tPIMAGE_THUNK_DATA\t\t\tpThunkData;\n\tPIMAGE_THUNK_DATA\t\t\tpThunkDataOrig;\n\tPIMAGE_IMPORT_BY_NAME\t\tpImportByName;\n\tPIMAGE_EXPORT_DIRECTORY\t\tpExportDir;\n\tDWORD\t\t\t\t\t\tflError = 0;\n\tDWORD\t\t\t\t\t\tdwTmp;\n\tBYTE\t\t\t\t\t\t*pLibName;\n\tHMODULE\t\t\t\t\t\thMod;\n\n\tDMSG(\"Processing IAT (Image Base: 0x%08x)\", dwImageBase);\n\n\tpDosHeader = (PIMAGE_DOS_HEADER) dwImageBase;\n\tpNtHeaders = (PIMAGE_NT_HEADERS) (dwImageBase + pDosHeader->e_lfanew);\n\n\tdo {\n\t\tpImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)(dwImageBase +\n\t\t\tpNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);\n\n\t\tif(!pImportDesc) {\n\t\t\tDMSG(\"IAT not found\");\n\t\t\tbreak;\n\t\t}\n\n\t\twhile((pImportDesc->Name != 0) && (!flError)) {\n\t\t\tpLibName = (BYTE*) (dwImageBase + pImportDesc->Name);\n\t\t\tDMSG(\"Loading Library and processing Imports: %s\", (CHAR*) pLibName);\n\n\t\t\tif(pImportDesc->ForwarderChain != -1) {\n\t\t\t\tDMSG(\"FIXME: Cannot handle Import Forwarding\");\n\t\t\t\t//flError = 1;\n\t\t\t\t//break;\n\t\t\t}\n\n\t\t\thMod = LoadLibraryA((CHAR*) pLibName);\n\t\t\tif(!hMod) {\n\t\t\t\tDMSG(\"Failed to load library: %s\", pLibName);\n\t\t\t\tflError = 1;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tpThunkData = (PIMAGE_THUNK_DATA)(dwImageBase + pImportDesc->FirstThunk);\n\t\t\tif(pImportDesc->Characteristics == 0)\n\t\t\t\t/* Borland compilers doesn't produce Hint Table */\n\t\t\t\tpThunkDataOrig = pThunkData;\n\t\t\telse\n\t\t\t\t/* Hint Table */\n\t\t\t\tpThunkDataOrig = (PIMAGE_THUNK_DATA)(dwImageBase + pImportDesc->Characteristics);\n\n\t\t\twhile(pThunkDataOrig->u1.AddressOfData != 0) {\n\t\t\t\tif(pThunkDataOrig->u1.Ordinal & IMAGE_ORDINAL_FLAG) {\n\t\t\t\t\t/* Import via. Export Ordinal */\n\t\t\t\t\tPIMAGE_DOS_HEADER\t\t_dos;\n\t\t\t\t\tPIMAGE_NT_HEADERS\t\t_nt;\n\n\t\t\t\t\t_dos = (PIMAGE_DOS_HEADER) hMod;\n\t\t\t\t\t_nt = (PIMAGE_NT_HEADERS) (((DWORD) hMod) + _dos->e_lfanew);\n\n\t\t\t\t\tpExportDir = (PIMAGE_EXPORT_DIRECTORY) \n\t\t\t\t\t\t(((DWORD) hMod) + _nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);\n\t\t\t\t\tdwTmp = (((DWORD) hMod) + pExportDir->AddressOfFunctions) + (((IMAGE_ORDINAL(pThunkDataOrig->u1.Ordinal) - pExportDir->Base)) * sizeof(DWORD));\n\t\t\t\t\tdwTmp = ((DWORD) hMod) + *((DWORD*) dwTmp);\n\n\t\t\t\t\tpThunkData->u1.Function = dwTmp;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tpImportByName = (PIMAGE_IMPORT_BY_NAME)\n\t\t\t\t\t\t(dwImageBase + pThunkDataOrig->u1.AddressOfData);\n\t\t\t\t\tpThunkData->u1.Function = (DWORD) GetProcAddress(hMod, (LPCSTR) pImportByName->Name);\n\n\t\t\t\t\tif(!pThunkData->u1.Function) {\n\t\t\t\t\t\tDMSG(\"Failed to resolve API: %s!%s\", \n\t\t\t\t\t\t\t(CHAR*)pLibName, (CHAR*)pImportByName->Name);\n\t\t\t\t\t\tflError = 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tpThunkDataOrig++;\n\t\t\t\tpThunkData++;\n\t\t\t}\n\n\t\t\tpImportDesc++;\n\t\t}\n\n\t\tif(!flError)\n\t\t\tret = TRUE;\n\n\t} while(0);\n\treturn ret;\n}\n\nstatic\nBOOL PeLdrNeedSelfRelocation(PE_LDR_PARAM *pe)\n{\n\tDWORD\t\t\t\tdwMyBase;\n\tPIMAGE_DOS_HEADER\tpMyDosHeader;\n\tPIMAGE_NT_HEADERS\tpMyNtHeaders;\n\n\tDMSG(\"Checking for self relocation\");\n\n\tdwMyBase = (DWORD) GetModuleHandle(NULL);\n\tif(!dwMyBase) {\n\t\tEMSG(\"Failed to get our loaded address\");\n\t\treturn FALSE;\n\t}\n\t\n\tpMyDosHeader = (PIMAGE_DOS_HEADER) dwMyBase;\n\tpMyNtHeaders = (PIMAGE_NT_HEADERS) (dwMyBase + pMyDosHeader->e_lfanew);\n\n\tif(pMyNtHeaders->Signature != IMAGE_NT_SIGNATURE) {\n\t\tEMSG(\"Failed to find our own headers\");\n\t\treturn FALSE;\n\t}\n\n\tDMSG(\"MyBase: 0x%08x MySize: %d\", dwMyBase, pMyNtHeaders->OptionalHeader.SizeOfImage);\n\n\tif((pe->pNtHeaders->OptionalHeader.ImageBase >= dwMyBase) &&\n\t\t(pe->pNtHeaders->OptionalHeader.ImageBase < (dwMyBase + pMyNtHeaders->OptionalHeader.SizeOfImage)))\n\t{\n\t\tDMSG(\"Self relocation required\");\n\t\treturn TRUE;\n\t}\n\n\treturn FALSE;\n}\n\nstatic\nBOOL PeLdrRelocateAndContinue(PE_LDR_PARAM *pe, VOID *pContFunc, VOID *pParam)\n{\n\tPIMAGE_DOS_HEADER\tpMyDosHeader;\n\tPIMAGE_NT_HEADERS\tpMyNtHeaders;\n\tDWORD\t\t\t\tdwNewBase;\n\tDWORD\t\t\t\tdwMyBase;\n\tDWORD\t\t\t\tdwAddr;\n\tUINT_PTR\t\t\tiRelocOffset;\n\n\tDMSG(\"Relocating loader image (Continue Function: 0x%08x)\", (DWORD) pContFunc);\n\n\tdwMyBase = (DWORD) GetModuleHandle(NULL);\n\tif(!dwMyBase) {\n\t\tEMSG(\"Failed to get our loaded address\");\n\t\treturn FALSE;\n\t}\n\t\n\tpMyDosHeader = (PIMAGE_DOS_HEADER) dwMyBase;\n\tpMyNtHeaders = (PIMAGE_NT_HEADERS) (dwMyBase + pMyDosHeader->e_lfanew);\n\n\tdwNewBase = (DWORD) VirtualAlloc(NULL, pMyNtHeaders->OptionalHeader.SizeOfImage + 1,\n\t\tMEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);\n\tif(!dwNewBase) {\n\t\tEMSG(\"Failed to allocate memory for self relocation\");\n\t\treturn FALSE;\n\t}\n\n\tDMSG(\"New Loader Base: 0x%08x\", dwNewBase);\n\tpe->dwLoaderRelocatedBase = dwNewBase;\n\n\tCopyMemory((VOID*) dwNewBase, (VOID*) dwMyBase,\n\t\tpMyNtHeaders->OptionalHeader.SizeOfImage);\n\n\tif(!PeLdrProcessIAT(dwNewBase)) {\n\t\tEMSG(\"Failed to process IAT for relocated image\");\n\t\treturn FALSE;\n\t}\n\n\tiRelocOffset = dwNewBase - dwMyBase;\n\tif(!PeLdrApplyImageRelocations(dwNewBase, iRelocOffset)) {\n\t\tEMSG(\"Failed to apply relocations on relocated image\");\n\t\treturn FALSE;\n\t}\n\n\tpe->dwLoaderBase = dwNewBase;\n\n\tdwAddr = ((DWORD) pContFunc) - dwMyBase;\n\tdwAddr += dwNewBase;\n\n\tDMSG(\"Jumping to relocated image (Relocated Continue Function: 0x%08x)\", dwAddr);\n\t__asm {\n\t\tmov eax, pParam\n\t\tpush eax\n\t\tmov eax, dwAddr\n\t\tcall eax\n\t}\n\n\treturn TRUE;\n}\n\nstatic\nBOOL PeLdrExecuteEP(PE_LDR_PARAM *pe)\n{\n\tDWORD\tdwOld;\n\tDWORD\tdwEP;\n\t_PPEB\tpeb;\n\n\t// TODO: Fix permission as per section flags\n\tif(!VirtualProtect((LPVOID) pe->dwMapBase, pe->pNtHeaders->OptionalHeader.SizeOfImage,\n\t\tPAGE_EXECUTE_READWRITE, &dwOld)) {\n\t\tDMSG(\"Failed to change mapping protection\");\n\t\treturn FALSE;\n\t}\n\n\t\n\tDMSG(\"Fixing Image Base address in PEB\");\n\tpeb = (_PPEB)__readfsdword(0x30);\n\tpeb->lpImageBaseAddress = (LPVOID) pe->dwMapBase;\n\n\tdwEP = pe->dwMapBase + pe->pNtHeaders->OptionalHeader.AddressOfEntryPoint;\n\tDMSG(\"Executing Entry Point: 0x%08x\", dwEP);\n\n\t__asm {\n\t\tmov eax, dwEP\n\t\tcall eax\n\t\tint 3\n\t}\n\n\treturn TRUE;\n}\n\nstatic\nBOOL PeLdrApplyRelocations(PE_LDR_PARAM *pe)\n{\n\tUINT_PTR\tiRelocOffset;\n\n\tif(pe->dwMapBase == pe->pNtHeaders->OptionalHeader.ImageBase) {\n\t\tDMSG(\"Relocation not required\");\n\t\treturn TRUE;\n\t}\n\n\tif(!pe->pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size) {\n\t\tDMSG(\"PE required relocation but no relocatiom information found\");\n\t\treturn FALSE;\n\t}\n\n\tiRelocOffset = pe->dwMapBase - pe->pNtHeaders->OptionalHeader.ImageBase;\n\treturn PeLdrApplyImageRelocations(pe->dwMapBase, iRelocOffset);\n}\n\nstatic\nBOOL PeLdrMapImage(PE_LDR_PARAM *pe)\n{\n\tDWORD\t\t\t\t\t\ti;\n\tMEMORY_BASIC_INFORMATION\tmi;\n\tPIMAGE_SECTION_HEADER\t\tpSectionHeader;\n\tBOOL\t\t\t\t\t\tret = FALSE;\n\n\tNTSTATUS\t(NTAPI *NtUnmapViewOfSection)\n\t\t\t\t\t(HANDLE, LPVOID) = NULL;\n\tif(!pe)\n\t\treturn ret;\n\n\tDMSG(\"Mapping Target PE File\");\n\tDMSG(\"Loader Base Orig: 0x%08x New: 0x%08x\", \n\t\tpe->dwLoaderBase, pe->dwLoaderRelocatedBase);\n\n\tNtUnmapViewOfSection = \n\t\t(NTSTATUS (NTAPI *)(HANDLE, LPVOID))\n\t\t\tGetProcAddress(GetModuleHandle(TEXT(\"ntdll.dll\")), \"ZwUnmapViewOfSection\");\n\tif(!NtUnmapViewOfSection)\n\t\tDMSG(\"Failed to resolve address of NtUnmapViewOfSection\");\n\n\tdo {\n\t\tDMSG(\"Target PE Load Base: 0x%08x Image Size: 0x%08x\",\n\t\t\tpe->pNtHeaders->OptionalHeader.ImageBase,\n\t\t\tpe->pNtHeaders->OptionalHeader.SizeOfImage);\n\n\t\t// Find the size of our mapping\n\t\ti = pe->dwLoaderBase;\n\t\twhile(VirtualQuery((LPVOID) i, &mi, sizeof(mi))) {\n\t\t\tif(mi.State == MEM_FREE)\n\t\t\t\tbreak;\n\n\t\t\ti += mi.RegionSize;\n\t\t}\n\n\t\tif((pe->pNtHeaders->OptionalHeader.ImageBase >= pe->dwLoaderBase) && \n\t\t\t(pe->pNtHeaders->OptionalHeader.ImageBase < i)) {\n\t\t\tif(NtUnmapViewOfSection) {\n\t\t\t\tDMSG(\"Unmapping original loader mapping\");\n\t\t\t\tif(NtUnmapViewOfSection(GetCurrentProcess(), (VOID*) pe->dwLoaderBase) == STATUS_SUCCESS) {\n\t\t\t\t\tpe->dwMapBase = (DWORD) VirtualAlloc((LPVOID) pe->pNtHeaders->OptionalHeader.ImageBase,\n\t\t\t\t\t\t\t\t\t\tpe->pNtHeaders->OptionalHeader.SizeOfImage + 1,\n\t\t\t\t\t\t\t\t\t\tMEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tEMSG(\"Failed to unmap original loader mapping\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tpe->dwMapBase = (DWORD) VirtualAlloc((LPVOID) pe->pNtHeaders->OptionalHeader.ImageBase,\n\t\t\tpe->pNtHeaders->OptionalHeader.SizeOfImage + 1,\n\t\t\tMEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);\n\n\t\tif(!pe->dwMapBase)\n\t\t\tEMSG(\"Failed to allocate PE ImageBase: 0x%08x\", \n\t\t\t\tpe->pNtHeaders->OptionalHeader.ImageBase);\n\n\t\tif(!pe->dwMapBase) {\n\t\t\tDMSG(\"Attempting to allocate new memory\");\n\n\t\t\tif(!pe->pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size) {\n\t\t\t\tEMSG(\"Failed to map required memory address, need relocation to continue\");\n\t\t\t\tEMSG(\"[WARNING] Forcing re-use of mapped memory\");\n\t\t\t\t\n\t\t\t\tpe->dwMapBase = (DWORD) pe->pNtHeaders->OptionalHeader.ImageBase;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tpe->dwMapBase = (DWORD) VirtualAlloc(NULL, \n\t\t\t\t\tpe->pNtHeaders->OptionalHeader.SizeOfImage + 1,\n\t\t\t\t\tMEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);\n\t\t\t}\n\t\t}\n\n\t\tif(!pe->dwMapBase) {\n\t\t\tEMSG(\"Failed to map memory for Target PE\");\n\t\t\tbreak;\n\t\t}\n\n\t\tDMSG(\"Allocated memory for Target PE: 0x%08x\", pe->dwMapBase);\n\t\t\n\t\tDMSG(\"Copying Headers\");\n\t\tCopyMemory((LPVOID) pe->dwMapBase, (LPVOID) pe->dwImage,\n\t\t\tpe->pNtHeaders->OptionalHeader.SizeOfHeaders);\n\n\t\tDMSG(\"Copying Sections\");\n\t\tpSectionHeader = IMAGE_FIRST_SECTION(pe->pNtHeaders);\n\t\tfor(i = 0; i < pe->pNtHeaders->FileHeader.NumberOfSections; i++) {\n\t\t\tDMSG(\"  Copying Section: %s\", (CHAR*) pSectionHeader[i].Name);\n\n\t\t\tCopyMemory(\n\t\t\t\t(LPVOID)(pe->dwMapBase + pSectionHeader[i].VirtualAddress),\n\t\t\t\t(LPVOID)(pe->dwImage + pSectionHeader[i].PointerToRawData),\n\t\t\t\tpSectionHeader[i].SizeOfRawData\n\t\t\t);\n\t\t}\n\n\t\tret = TRUE;\n\t} while(0);\n\n\treturn ret;\n}\n\nstatic \nBOOL PeLdrLoadImage(PE_LDR_PARAM *pe)\n{\n\tHANDLE\thFile\t= NULL;\n\tHANDLE\thMap\t= NULL;\n\tBOOL\tret = FALSE;\n\t_PPEB\tpeb;\n\n\tif(!pe)\n\t\tgoto out;\n\n\tDMSG(\"Mapping PE File\");\n\n\tif(!pe->bLoadFromBuffer) {\n\t\tDMSG(\"Creating Map View of File\");\n\n\t\thFile = CreateFile(pe->pTargetPath, GENERIC_READ, \n\t\t\tFILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);\n\t\tif(hFile == INVALID_HANDLE_VALUE) {\n\t\t\tDMSG(\"Failed to open PE File\");\n\t\t\tgoto out;\n\t\t}\n\n\t\tpe->dwImageSizeOnDisk = GetFileSize(hFile, NULL);\n\t\thMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);\n\t\tif(hMap == NULL) {\n\t\t\tDMSG(\"Failed to create file mapping for PE File\");\n\t\t\tgoto out;\n\t\t}\n\n\t\tpe->dwImage = (DWORD) MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);\n\t\tif(!pe->dwImage) {\n\t\t\tDMSG(\"Failed to obtain a map view of PE File\");\n\t\t\tgoto out;\n\t\t}\n\t}\n\n\tDMSG(\"Map View of File created\");\n\n\tpe->pDosHeader = (PIMAGE_DOS_HEADER) pe->dwImage;\n\tif(pe->pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {\n\t\tDMSG(\"DOS Signature invalid\");\n\t\tgoto out;\n\t}\n\n\tpe->pNtHeaders = (PIMAGE_NT_HEADERS)(((DWORD) pe->dwImage) + pe->pDosHeader->e_lfanew);\n\tif(pe->pNtHeaders->Signature != IMAGE_NT_SIGNATURE) {\n\t\tDMSG(\"NT Signature mismatch\");\n\t\tgoto out;\n\t}\n\n\tpeb = (_PPEB)__readfsdword(0x30);\n\tpe->dwLoaderBase = (DWORD) peb->lpImageBaseAddress;\n\n\tret = TRUE;\n\nout:\n\tif(hMap)\n\t\tCloseHandle(hMap);\n\tif(hFile)\n\t\tCloseHandle(hFile);\n\n\treturn ret;\n}\n\nstatic\nBOOL PeLdrRunImage(PE_LDR_PARAM *pe)\n{\n\tif(!PeLdrMapImage(pe))\n\t\treturn FALSE;\n\tif(!PeLdrProcessIAT(pe->dwMapBase))\n\t\treturn FALSE;\n\tif(!PeLdrApplyRelocations(pe))\n\t\treturn FALSE;\n\tif(!PeLdrExecuteEP(pe))\n\t\treturn FALSE;\n\n\treturn TRUE;\n}\n\nBOOL PeLdrStart(PE_LDR_PARAM *pe)\n{\n\tif(!PeLdrLoadImage(pe))\n\t\treturn FALSE;\n\n\tif(PeLdrNeedSelfRelocation(pe))\n\t\treturn PeLdrRelocateAndContinue(pe, (VOID*) PeLdrRunImage, (VOID*) pe);\n\telse\n\t\treturn PeLdrRunImage(pe);\n}\n\nBOOL PeLdrSetExecutableBuffer(PE_LDR_PARAM *pe, PVOID pExecutable, DWORD dwLen)\n{\n\tif(!pe)\n\t\treturn FALSE;\n\n\tpe->dwImageSizeOnDisk = dwLen;\n\tpe->dwImage = (DWORD) pExecutable;\n\tpe->bLoadFromBuffer = TRUE;\n\n\treturn TRUE;\n}\n\nBOOL PeLdrSetExecutablePath(PE_LDR_PARAM *pe, TCHAR *pExecutable)\n{\n\tif(!pe)\n\t\treturn FALSE;\n\n\tpe->pTargetPath = (TCHAR*) HeapAlloc(GetProcessHeap(), \n\t\tHEAP_ZERO_MEMORY, (lstrlen(pExecutable) + 1) * sizeof(TCHAR));\n\tif(!pe->pTargetPath) {\n\t\tDMSG(\"Failed to allocate memory for pTargetPath\");\n\t\treturn FALSE;\n\t}\n\n\tlstrcpy(pe->pTargetPath, pExecutable);\n\treturn TRUE;\n}\n\nVOID PeLdrInit(PE_LDR_PARAM *pe)\n{\n\tZeroMemory(pe, sizeof(PE_LDR_PARAM));\n}"
  },
  {
    "path": "src/PeLdr.h",
    "content": "#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\t\t\t\t\t*pTargetPath;\n\tPIMAGE_DOS_HEADER\t\tpDosHeader;\n\tPIMAGE_NT_HEADERS\t\tpNtHeaders;\n\n\tBOOLEAN\t\t\t\t\tbLoadFromBuffer;\n\tDWORD\t\t\t\t\tdwImage;\n\tDWORD\t\t\t\t\tdwImageSizeOnDisk;\n\n\tDWORD\t\t\t\t\tdwLoaderBase;\n\tDWORD\t\t\t\t\tdwLoaderRelocatedBase;\n\n\tDWORD\t\t\t\t\tdwMapBase;\n\n} PE_LDR_PARAM;\n\nVOID PeLdrInit(PE_LDR_PARAM *pe);\nBOOL PeLdrSetExecutablePath(PE_LDR_PARAM *pe, TCHAR *pExecutable);\nBOOL PeLdrSetExecutableBuffer(PE_LDR_PARAM *pe, PVOID pExecutable, DWORD dwLen);\nBOOL PeLdrStart(PE_LDR_PARAM *pe);\n\n#endif"
  }
]