PsExitSpecialApc线程的退出示例
2023-08-02
37
0
在上一节KiInsertQueueApc中,可以看到有一个特殊的APC,其为PsExitSpecialApc,表示线程退出的APC.
if (Apc->NormalRoutine)
{
/* Normal APC; is it the Thread Termination APC? */
if ((ApcMode != KernelMode) &&
(Apc->KernelRoutine == PsExitSpecialApc))
{
/* Set User APC pending to true */
Thread->ApcState.UserApcPending = TRUE;
/* Insert it at the top of the list */
InsertHeadList(&ApcState->ApcListHead[ApcMode],
&Apc->ApcListEntry);
}
else
{
/* Regular user or kernel Normal APC */
InsertTailList(&ApcState->ApcListHead[ApcMode],
&Apc->ApcListEntry);
}
}
我们找一个线程退出的时的调用:
PspTerminateThreadByPointer函数中:
/* Initialize a Kernel Mode APC to Kill the Thread */
KeInitializeApc(Apc,
&Thread->Tcb,
OriginalApcEnvironment,
PsExitSpecialApc,
PspExitApcRundown,
PspExitNormalApc,
KernelMode,
UlongToPtr(ExitStatus));//NormalContext=status
/* Insert it into the APC Queue */
if (!KeInsertQueueApc(Apc, Apc, NULL, 2))
{
/* The APC was already in the queue, fail */
Status = STATUS_UNSUCCESSFUL;
}
else
{
/* Forcefully resume the thread and return */
KeForceResumeThread(&Thread->Tcb);
return Status;
}
执行的是PsExitSpecialApc:
VOID NTAPI PsExitSpecialApc ( PKAPC Apc,
PKNORMAL_ROUTINE * NormalRoutine,
PVOID * NormalContext,
PVOID * SystemArgument1,
PVOID * SystemArgument2
)
{
NTSTATUS Status;
PAGED_CODE();
PSTRACE(PS_KILL_DEBUG,
"Apc: %p SystemArgument2: %p\n", Apc, SystemArgument2);
/* Don't do anything unless we are in User-Mode */
if (Apc->SystemArgument2)
{
/* Free the APC */
Status = PtrToUlong(Apc->NormalContext);
PspExitApcRundown(Apc);
/* Terminate the Thread */
PspExitThread(Status);
}
}
其中PspExitApcRundown仅为释放APC.
VOID NTAPI PspExitApcRundown ( IN PKAPC Apc )
{
PAGED_CODE();
/* Free the APC */
ExFreePool(Apc);
}
而最终执行的是:
VOID PspExitThread (IN NTSTATUS ExitStatus) ;
而我们在内核中熟知的PsTerminateSystemThread的代码如下:
NTSTATUS NTAPI PsTerminateSystemThread ( IN NTSTATUS ExitStatus )
{
PETHREAD Thread = PsGetCurrentThread();
/* Make sure this is a system thread */
if (!Thread->SystemThread) return STATUS_INVALID_PARAMETER;
/* Terminate it for real */
return PspTerminateThreadByPointer(Thread, ExitStatus, TRUE);
}
所以,在内核中不调用PsTerminateSystemThread,可以看到无法真正的卸载线程。