一、回顾
第71篇博客我们分析了 PspTerminateThreadByPointer 函数,其中调用了 KeInitializeApc 函数初始化 KAPC 结果。这次课我们来分析 KeInitializeApc 函数,了解 APC 如何初始化。
PspTerminateThreadByPointer(psdelete.c) 调用 KeInitializeApc
KeInitializeApc (ExitApc,
PsGetKernelThread (Thread),
OriginalApcEnvironment, // 父进程
PsExitSpecialApc, // 释放APC内存,退出当前线程
PspExitApcRundown, // 释放APC内存
PspExitNormalApc,
KernelMode, // 内核模式
ULongToPtr (ExitStatus)); // 线程退出码
NtQueueApcThread(psctx.c) 调用 KeInitializeApc
KeInitializeApc (Apc,
&Thread->Tcb,
OriginalApcEnvironment, // 插入到所属进程(创建线程的那个进程)
PspQueueApcSpecialApc, // KernelRoutine , 作用是释放 APC 内存(ExFreePool)
NULL, // RundownRoutine 未指定
(PKNORMAL_ROUTINE)ApcRoutine, // 用户APC总入口 BaseDispatchAPC(3环函数)
UserMode, // 用户模式APC
ApcArgument1); // 3环APC函数
二、KeInitializeApc (apcobj.c)
这个函数比较简单,就是初始化,最难理解的是 ApcStateIndex ,我已经在注释里写清楚了,还是不懂的话,可以结合 KiInsertQueueApc 函数来分析 ApcStateIndex 的用途。
VOID
KeInitializeApc (
IN PRKAPC Apc, // APC结构体指针
IN PRKTHREAD Thread, // 要插入APC的目标线程
IN KAPC_ENVIRONMENT Environment, // 四种环境状态,包括父进程,挂靠进程,当前进程(提供CR3的进程),插入时的当前进程
IN PKKERNEL_ROUTINE KernelRoutine, // 不管是用户APC还是内核APC,这个函数的共同作用是释放APC;内核APC可能会有额外的功能,如退出、挂起、恢复线程
IN PKRUNDOWN_ROUTINE RundownRoutine OPTIONAL, // 如果是用户APC,这里是NULL;如果是要求退出线程的内核APC,这里是 PspExitApcRundown
IN PKNORMAL_ROUTINE NormalRoutine OPTIONAL, // 如果是用户APC,这里是 BaseDispatchAPC(3环函数);
// 如果是内核APC,这里就是内核APC函数
IN KPROCESSOR_MODE ApcMode OPTIONAL, // 用户模式 / 内核模式
IN PVOID NormalContext OPTIONAL // 如果是用户APC,这里就是3环提供的APC函数的参数
)
/*++
Routine Description:
This function initializes a kernel APC object. The thread, kernel
routine, and optionally a normal routine, processor mode, and normal
context parameter are stored in the APC object.
分配空间,初始化KAPC结构体
Arguments:
Apc - Supplies a pointer to a control object of type APC.
Thread - Supplies a pointer to a dispatcher object of type thread.
Environment - Supplies the environment in which the APC will execute.
Valid values for this parameter are: OriginalApcEnvironment,
AttachedApcEnvironment, CurrentApcEnvironment, or InsertApcEnvironment
KernelRoutine - Supplies a pointer to a function that is to be
executed at IRQL APC_LEVEL in kernel mode.
RundownRoutine - Supplies an optional pointer to a function that is to be
called if the APC is in a thread's APC queue when the thread terminates.
NormalRoutine - Supplies an optional pointer to a function that is
to be executed at IRQL 0 in the specified processor mode. If this
parameter is not specified, then the ProcessorMode and NormalContext
parameters are ignored.
ApcMode - Supplies the processor mode in which the function specified
by the NormalRoutine parameter is to be executed.
NormalContext - Supplies a pointer to an arbitrary data structure which is
to be passed to the function specified by the NormalRoutine parameter.
Return Value:
None.
--*/
{
ASSERT(Environment <= InsertApcEnvironment);
//
// Initialize standard control object header.
//
Apc->Type = ApcObject; // 0x12 内核对象类型
Apc->Size = sizeof(KAPC);
//
// Initialize the APC environment, thread address, kernel routine address,
// rundown routine address, normal routine address, processor mode, and
// normal context parameter. If the normal routine address is null, then
// the processor mode is defaulted to KernelMode and the APC is a special
// APC. Otherwise, the processor mode is taken from the argument list.
//
//typedef enum _KAPC_ENVIRONMENT {
// OriginalApcEnvironment, // 所属进程(创建线程的进程)
// AttachedApcEnvironment, // 挂靠进程
// CurrentApcEnvironment, // 当前环境,提供CR3的进程(正常状态是所属进程,挂靠状态是挂靠进程)
// InsertApcEnvironment // 插入APC时的环境
//} KAPC_ENVIRONMENT;
// ApcStateIndex 决定了挂到哪个进程的APC队列
if (Environment == CurrentApcEnvironment) {
// 如果要求的是当前状态,那么就从 Thread->ApcStateIndex 里取值,如果当前没有挂靠,则是0,;如果挂靠了,就是1.
Apc->ApcStateIndex = Thread->ApcStateIndex;
} else {
ASSERT((Environment <= Thread->ApcStateIndex) || (Environment == InsertApcEnvironment));
// 否则就默认插入到所属进程(创建线程的进程)的APC队列里
Apc->ApcStateIndex = (CCHAR)Environment;
}
Apc->Thread = Thread; // 目标线程
Apc->KernelRoutine = KernelRoutine; // 主要功能是释放APC
Apc->RundownRoutine = RundownRoutine; // 可选,退出线程时会用到
Apc->NormalRoutine = NormalRoutine; // 如果是用户APC,这里是 BaseDispatchAPC(3环函数);
// 如果是内核APC,这里就是内核APC函数
if (ARGUMENT_PRESENT(NormalRoutine)) {
Apc->ApcMode = ApcMode; // 0内核,1用户
Apc->NormalContext = NormalContext; // 内核APC:NULL;用户APC:真正的APC函数
} else {
Apc->ApcMode = KernelMode;
Apc->NormalContext = NIL; // NULL
}
Apc->Inserted = FALSE;
return;
}
---------------------
作者:hambaga
来源:CSDN
原文:https://blog.csdn.net/Kwansy/article/details/110234089
版权声明:本文为作者原创文章,转载请附上博文链接!
内容解析By:CSDN,CNBLOG博客文章一键转载插件