APC挂入
2023-08-02
66
0
挂入ApcListHead链表中的叫做APC,每个APC的结构如下:
2: kd> dt _KAPC
nt!_KAPC
+0x000 Type : UChar
+0x001 SpareByte0 : UChar
+0x002 Size : UChar
+0x003 SpareByte1 : UChar
+0x004 SpareLong0 : Uint4B
+0x008 Thread : Ptr64 _KTHREAD
+0x010 ApcListEntry : _LIST_ENTRY
+0x020 KernelRoutine : Ptr64 void
+0x028 RundownRoutine : Ptr64 void
+0x030 NormalRoutine : Ptr64 void
+0x020 Reserved : [3] Ptr64 Void
+0x038 NormalContext : Ptr64 Void
+0x040 SystemArgument1 : Ptr64 Void
+0x048 SystemArgument2 : Ptr64 Void
+0x050 ApcStateIndex : Char
+0x051 ApcMode : Char
+0x052 Inserted : UChar
其中:
- Type:内核对象APC类型编号
- Size:结构体大小
- SpareByte0/SpareByte1/SpareLong0:用于字节对齐的保留字段。
- Thread:APC所属线程指针,即目标线程
- ApcListEntry:链表
- KernelRoutine:指向内核APC调用完成后释放APC的函数指针。为ExFreePoolWithTag
- RundownRoutine:未知
- NormalRoutine:内核APC时,为APC函数的入口地址。应用APC时,为应用层APC的总入口地址
- NormalContext:内核APC时,为NULL,应用层APC时,为APC的入口地址。
- SystemArgument1/SystemArgument2:APC参数
- ApcStateIndex:挂入APC的队列标识,值为0~3
- ApcMode:内核模式还是应用层模式APC
- Inserted: APC是否已经挂入线程APC队列。
APC的挂入
应用层挂入的APC挂入流程如下:
- QueueUserAPC(kernel32.dll)-应用层
- NtQueueApcThread(ntoskrnl)-内核层
- KeInitializeApc(分配空间,初始化APC结构)
- KeInertQueueApc
- KiInsertQueueApc
- NtQueueApcThread(ntoskrnl)-内核层
在内核层也是通过KeInitializeApc和KeInertQueueApc实现的。
这里以ReactOS源代码说明:
VOID NTAPI KeInitializeApc (IN PKAPC Apc, //APC结构体
IN PKTHREAD Thread, //目标线程
IN KAPC_ENVIRONMENT TargetEnvironment, //目标环境0~3
IN PKKERNEL_ROUTINE KernelRoutine, //销毁APC的函数
IN PKRUNDOWN_ROUTINE RundownRoutine OPTIONAL,//可选
IN PKNORMAL_ROUTINE NormalRoutine, //内核APC函数或用户APC总入口
IN KPROCESSOR_MODE Mode, //用户层APC还是内核层APC,UserMode,KernelMode
IN PVOID Context //用户层APC或内核层NULL
)
{
/* Sanity check */
ASSERT(TargetEnvironment <= InsertApcEnvironment);
/* Set up the basic APC Structure Data */
Apc->Type = ApcObject;
Apc->Size = sizeof(KAPC);
/* Set the Environment */
if (TargetEnvironment == CurrentApcEnvironment)
{
/* Use the current one for the thread */
Apc->ApcStateIndex = Thread->ApcStateIndex;
}
else
{
/* Sanity check */
ASSERT((TargetEnvironment <= Thread->ApcStateIndex) ||
(TargetEnvironment == InsertApcEnvironment));
/* Use the one that was given */
Apc->ApcStateIndex = TargetEnvironment;
}
/* Set the Thread and Routines */
Apc->Thread = Thread;
Apc->KernelRoutine = KernelRoutine;
Apc->RundownRoutine = RundownRoutine;
Apc->NormalRoutine = NormalRoutine;
/* Check if this is a special APC */
if (NormalRoutine)//普通的APC
{
/* It's a normal one. Set the context and mode */
Apc->ApcMode = Mode;
Apc->NormalContext = Context;
}
else
{
/* It's a special APC, which can only be kernel mode */
Apc->ApcMode = KernelMode;
Apc->NormalContext = NULL;
}
/* The APC is not inserted */
Apc->Inserted = FALSE;
}
其中的:
typedef enum _KAPC_ENVIRONMENT
{
OriginalApcEnvironment, //原始环境
AttachedApcEnvironment, //挂靠环境
CurrentApcEnvironment, //当前线程环境
InsertApcEnvironment //插入APC时的环境
} KAPC_ENVIRONMENT;
插入APC:
BOOLEAN NTAPI KeInsertQueueApc ( IN PKAPC Apc,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2,
IN KPRIORITY PriorityBoost
)
{
PKTHREAD Thread = Apc->Thread;
KLOCK_QUEUE_HANDLE ApcLock;
BOOLEAN State = TRUE;
ASSERT_APC(Apc);
ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
/* Get the APC lock */
KiAcquireApcLockRaiseToSynch(Thread, &ApcLock);
/* Make sure we can Queue APCs and that this one isn't already inserted */
if (!(Thread->ApcQueueable) || (Apc->Inserted))
{
/* Fail */
State = FALSE;
}
else
{
/* Set the System Arguments and set it as inserted */
Apc->SystemArgument1 = SystemArgument1;
Apc->SystemArgument2 = SystemArgument2;
Apc->Inserted = TRUE;
/* Call the Internal Function */
KiInsertQueueApc(Apc, PriorityBoost);
}
/* Release the APC lock and return success */
KiReleaseApcLockFromSynchLevel(&ApcLock);
KiExitDispatcher(ApcLock.OldIrql);
return State;
}
KiInsertQueueApc函数如下:
VOID FASTCALL KiInsertQueueApc(IN PKAPC Apc,
IN KPRIORITY PriorityBoost
)
{
PKTHREAD Thread = Apc->Thread;
PKAPC_STATE ApcState;
KPROCESSOR_MODE ApcMode;
PLIST_ENTRY ListHead, NextEntry;
PKAPC QueuedApc;
PKGATE Gate;
NTSTATUS Status;
BOOLEAN RequestInterrupt = FALSE;
/*
* Check if the caller wanted this APC to use the thread's environment at
* insertion time.
*/
//插入时的APC环境
if (Apc->ApcStateIndex == InsertApcEnvironment)
{
/* Copy it over */
Apc->ApcStateIndex = Thread->ApcStateIndex;
}
/* Get the APC State for this Index, and the mode too */
ApcState = Thread->ApcStatePointer[(UCHAR)Apc->ApcStateIndex];
ApcMode = Apc->ApcMode;
/* The APC must be "inserted" already */
ASSERT(Apc->Inserted == TRUE);
/* Three scenarios:
* 1) Kernel APC with Normal Routine or User APC = Put it at the end of the List
* 2) User APC which is PsExitSpecialApc = Put it at the front of the List
* 3) Kernel APC without Normal Routine = Put it at the end of the No-Normal Routine Kernel APC list
*/
//含有入口的,就是普通的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);
}
}
else
{
/* Special APC, find the last one in the list */
ListHead = &ApcState->ApcListHead[ApcMode];
NextEntry = ListHead->Blink;
while (NextEntry != ListHead)
{
/* Get the APC */
QueuedApc = CONTAINING_RECORD(NextEntry, KAPC, ApcListEntry);
/* Is this a No-Normal APC? If so, break */
if (!QueuedApc->NormalRoutine) break;
/* Move to the previous APC in the Queue */
NextEntry = NextEntry->Blink;
}
/* Insert us here */
InsertHeadList(NextEntry, &Apc->ApcListEntry);
}
/* Now check if the Apc State Indexes match */
if (Thread->ApcStateIndex == Apc->ApcStateIndex)
{
/* Check that the thread matches */
if (Thread == KeGetCurrentThread())
{
/* Sanity check */
ASSERT(Thread->State == Running);
/* Check if this is kernel mode */
if (ApcMode == KernelMode)
{
/* All valid, a Kernel APC is pending now */
Thread->ApcState.KernelApcPending = TRUE;
/* Check if Special APCs are disabled */
if (!Thread->SpecialApcDisable)
{
/* They're not, so request the interrupt */
HalRequestSoftwareInterrupt(APC_LEVEL);
}
}
}
else
{
/* Acquire the dispatcher lock */
KiAcquireDispatcherLock();
/* Check if this is a kernel-mode APC */
if (ApcMode == KernelMode)
{
/* Kernel-mode APC, set us pending */
Thread->ApcState.KernelApcPending = TRUE;
/* Are we currently running? */
if (Thread->State == Running)
{
/* The thread is running, so remember to send a request */
RequestInterrupt = TRUE;
}
else if ((Thread->State == Waiting) &&
(Thread->WaitIrql == PASSIVE_LEVEL) &&
!(Thread->SpecialApcDisable) &&
(!(Apc->NormalRoutine) ||
(!(Thread->KernelApcDisable) &&
!(Thread->ApcState.KernelApcInProgress))))
{
/* We'll unwait with this status */
Status = STATUS_KERNEL_APC;
/* Wake up the thread */
KiUnwaitThread(Thread, Status, PriorityBoost);
}
else if (Thread->State == GateWait)
{
/* Lock the thread */
KiAcquireThreadLock(Thread);
/* Essentially do the same check as above */
if ((Thread->State == GateWait) &&
(Thread->WaitIrql == PASSIVE_LEVEL) &&
!(Thread->SpecialApcDisable) &&
(!(Apc->NormalRoutine) ||
(!(Thread->KernelApcDisable) &&
!(Thread->ApcState.KernelApcInProgress))))
{
/* We were in a gate wait. Handle this. */
DPRINT1("A thread was in a gate wait\n");
/* Get the gate */
Gate = Thread->GateObject;
/* Lock the gate */
KiAcquireDispatcherObject(&Gate->Header);
/* Remove it from the waiters list */
RemoveEntryList(&Thread->WaitBlock[0].WaitListEntry);
/* Unlock the gate */
KiReleaseDispatcherObject(&Gate->Header);
/* Increase the queue counter if needed */
if (Thread->Queue) Thread->Queue->CurrentCount++;
/* Put into deferred ready list with this status */
Thread->WaitStatus = STATUS_KERNEL_APC;
KiInsertDeferredReadyList(Thread);
}
/* Release the thread lock */
KiReleaseThreadLock(Thread);
}
}
else if ((Thread->State == Waiting) &&
(Thread->WaitMode == UserMode) &&
((Thread->Alertable) ||
(Thread->ApcState.UserApcPending)))
{
/* Set user-mode APC pending */
Thread->ApcState.UserApcPending = TRUE;
Status = STATUS_USER_APC;
/* Wake up the thread */
KiUnwaitThread(Thread, Status, PriorityBoost);
}
/* Release dispatcher lock */
KiReleaseDispatcherLockFromSynchLevel();
/* Check if an interrupt was requested */
KiRequestApcInterrupt(RequestInterrupt, Thread->NextProcessor);
}
}
}
`