typedef enum _KAPC_ENVIRONMENT {
OriginalApcEnvironment, //原始的进程环境
AttachedApcEnvironment, //挂靠后的进程环境
CurrentApcEnvironment, //当前的环境
InsertApcEnvironment //被插入时的环境
} KAPC_ENVIRONMENT;
typedef
VOID
(*PKNORMAL_ROUTINE) (
IN PVOID NormalContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2
);
typedef
VOID
(*PKKERNEL_ROUTINE) (
IN struct _KAPC* Apc,
IN OUT PKNORMAL_ROUTINE* NormalRoutine,
IN OUT PVOID* NormalContext,
IN OUT PVOID* SystemArgument1,
IN OUT PVOID* SystemArgument2
);
typedef
VOID
(*PKRUNDOWN_ROUTINE) (
IN struct _KAPC* Apc
);
EXTERN_C NTKERNELAPI
VOID
KeInitializeApc(
__out PRKAPC Apc,
__in PRKTHREAD Thread,
__in KAPC_ENVIRONMENT Environment,
__in PKKERNEL_ROUTINE KernelRoutine,
__in_opt PKRUNDOWN_ROUTINE RundownRoutine,
__in_opt PKNORMAL_ROUTINE NormalRoutine,
__in_opt KPROCESSOR_MODE ProcessorMode,
__in_opt PVOID NormalContext
);
EXTERN_C NTSYSAPI
BOOLEAN
NTAPI
KeInsertQueueApc(
IN PRKAPC Apc,
IN PVOID SystemArgument1 OPTIONAL,
IN PVOID SystemArgument2 OPTIONAL,
IN KPRIORITY Increment
);
EXTERN_C PETHREAD LookupThread(HANDLE handle)
{
NTSTATUS status;
PETHREAD PThread;
status = PsLookupThreadByThreadId(handle, &PThread);
if (status == STATUS_SUCCESS)
{
return PThread;
}
else
{
return NULL;
}
}
EXTERN_C NTSTATUS GetProcessAvailableThread(PEPROCESS process, PETHREAD *res) {
*res = NULL;
for (int i = 8; i < 1000000; i = i + 4)
{
PETHREAD ethrd = LookupThread((HANDLE)i);
if (ethrd != NULL)
{
PEPROCESS eproc = IoThreadToProcess(ethrd);
ObDereferenceObject(ethrd);
if (eproc == process)
{
if (*(ULONG*)((ULONG64)ethrd + hardOffset.KTHREAD_WaitStatus) == 0)
{
if (((*(ULONG*)((ULONG64)ethrd + hardOffset.KTHREAD_Alertable) >> 4) & 1) == 1)
{
*res = ethrd;
return STATUS_SUCCESS;
}
}
}
}
}
return STATUS_UNSUCCESSFUL;
}
EXTERN_C typedef ULONG64(WINAPI* UserModeAPCRoutine)(ULONG64 userContext);
EXTERN_C typedef struct _KINJECT {
ULONG64 routine;
ULONG64 UserContext;
}KINJECT, * PKINJECT;
EXTERN_C ULONG64 AllocateVirtualMemory(SIZE_T length) {
ULONG64 ret = 0;
ZwAllocateVirtualMemory((HANDLE)-1, (PVOID*)&ret, 0, &length, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
return ret;
}
/*
EXTERN_C VOID UserModeApc32(PVOID NormalContext, PVOID SystemArgument1, PVOID SystemArgument2) {
005715D0 55 push ebp
005715D1 8B EC mov ebp,esp
PKINJECT context = (PKINJECT)(NormalContext);
UserModeAPCRoutine routine = reinterpret_cast<UserModeAPCRoutine>(context->routine);
routine(context->UserContext);
005715D3 8B 45 08 mov eax,dword ptr [NormalContext]
005715D6 FF 70 0C push dword ptr [eax+0Ch]
005715D9 FF 70 08 push dword ptr [eax+8]
005715DC 8B 00 mov eax,dword ptr [eax]
005715DE FF D0 call eax
}
005715E0 5D pop ebp
005715E1 C3 ret
55 push ebp
8B EC mov ebp, esp
8B 45 08 mov eax, [ebp+NormalContext]
FF 70 0C push dword ptr [eax+0Ch]
FF 70 08 push dword ptr [eax+8]
8B 00 mov eax, [eax]
FF D0 call eax
5D pop ebp
C3 retn
*/
//0x55 ,0x8B ,0xEC ,0x8B ,0x45 ,0x08 ,0xFF ,0x70 ,0x0C ,0xFF ,0x70 ,0x08 ,0x8B ,0x00 ,0xFF ,0xD0 ,0x5D ,0xC3
EXTERN_C char UserModeApc32[] = { 0x55 ,0x8B ,0xEC ,0x8B ,0x45 ,0x08 ,0xFF ,0x70 ,0x0C ,0xFF ,0x70 ,0x08 ,0x8B ,0x00 ,0xFF ,0xD0 ,0x5D ,0xC3 };
EXTERN_C VOID UserModeApc64(PVOID NormalContext, PVOID SystemArgument1, PVOID SystemArgument2) {
PKINJECT context = (PKINJECT)(NormalContext);
UserModeAPCRoutine routine = reinterpret_cast<UserModeAPCRoutine>(context->routine);
routine(context->UserContext);
}
ULONG64 CalcFuncSize(PVOID FuncAddr) {
ULONG64 ret = 0;
__try {
while (*(unsigned char*)((ULONG64)FuncAddr + ret) != 0xcc) {
ret++;
if (ret > 1000) return ret;
}
}
__except (1) {
return 0;
}
return ret + 1;
}
EXTERN_C void NTAPI KernelRoutine(PKAPC apc, PKNORMAL_ROUTINE* NormalRoutine, PVOID* NormalContext, PVOID* SystemArgument1, PVOID* SystemArgument2)
{
}
extern BOOL IsProcessX86(PEPROCESS Process);
EXTERN_C VOID InjectApcRoutine(PEPROCESS pProcess, PETHREAD pThread, ULONG64 routineAddr, ULONG64 userContext) {
SIZE_T size = 0;
ULONG64 ShellCodeBuffer = 0;
BOOL Wow64Process = IsProcessX86(pProcess);
ULONG64 ShellCodeSize;
if (Wow64Process) {
ShellCodeSize = sizeof(UserModeApc32);
}
else {
ShellCodeSize = CalcFuncSize(UserModeApc64);
}
KAPC_STATE apc_state = { 0 };
LARGE_INTEGER interval = { 0 };
PRKAPC apc = (PKAPC)ExAllocatePool(NonPagedPool, sizeof(KAPC));
RtlZeroMemory(apc, sizeof(KAPC));
KeStackAttachProcess(pProcess, &apc_state);
ShellCodeBuffer = AllocateVirtualMemory(0x1000);
ShellCodeBuffer = routineAddr + 0x20;
PKINJECT data = (PKINJECT)AllocateVirtualMemory(sizeof(KINJECT));
PrintLog("ShellCodeBuf: %llX; ShellcodeSize: %llX; data: %llX \r\n", ShellCodeBuffer, ShellCodeSize, data);
if (ShellCodeBuffer && ShellCodeSize) {
if (Wow64Process) {
memcpy((PVOID)ShellCodeBuffer, UserModeApc32, ShellCodeSize);
}
else {
memcpy((PVOID)ShellCodeBuffer, UserModeApc64, ShellCodeSize);
}
data->routine = routineAddr;
data->UserContext = userContext;
PrintLog("data->routine = %llX \n", data->routine);
PrintLog("data->UserContext = %llX \n", data->UserContext);
PKAPC_STATE ApcState = (PKAPC_STATE)((PUCHAR)pThread + hardOffset.KTHREAD_ApcState);
ApcState->UserApcPending = TRUE;
if (Wow64Process) {
PrintLog("Inject to 32 process! OriginShellcodeBuf = %llX ! \n", ShellCodeBuffer);
ShellCodeBuffer = ((LONG_PTR)ShellCodeBuffer * (-4));
PrintLog("Inject to 32 process! CalcShellcodeBuf = %llX ! \n", ShellCodeBuffer);
}
KeInitializeApc(apc, pThread, OriginalApcEnvironment, KernelRoutine, NULL, (PKNORMAL_ROUTINE)ShellCodeBuffer, UserMode, data);
if (!KeInsertQueueApc(apc, 0, 0, IO_NO_INCREMENT))
{
PrintLog("KeInsertQueueApc err\n");
}
}
end:
KeUnstackDetachProcess(&apc_state);
ExFreePool(apc);
}
EXTERN_C NTSTATUS QueueUserApcRoutine(struct IoQueueUserApcPack param) {
PEPROCESS Process;
NTSTATUS status = PsLookupProcessByProcessId((HANDLE)param.pid, &Process);
if (!NT_SUCCESS(status)) {
PrintLog("%s : Unable to lookup the process!\r\n", __FUNCTION__);
return status;
}
PETHREAD pThread = NULL;
status = GetProcessAvailableThread(Process, &pThread);
if (!NT_SUCCESS(status)) {
PrintLog("%s : Unable to lookup the suitable thread to inject!\r\n", __FUNCTION__);
return status;
}
PrintLog("[PID = %d] pThread = %llX \r\n", param.pid, pThread);
InjectApcRoutine(Process, pThread, param.routine, param.userContext);
PrintLog("Inject APC success! \r\n");
return STATUS_SUCCESS;
}