APC挂入
			 2023-08-02
			  160
			 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);
        }
    }
}
`
 APC异步过程调用
			APC异步过程调用
			




