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;
}