此系列是本人一个字一个字码出来的,包括示例和实验截图。由于系统内核的复杂性,故可能有错误或者不全面的地方,如有错误,欢迎批评指正,本教程将会长期更新。 如有好的建议,欢迎反馈。码字不易,如果本篇文章有帮助你的,如有闲钱,可以打赏支持我的创作。如想转载,请把我的转载信息附在文章后面,并声明我的个人信息和本人博客地址即可,但必须事先通知我。
你如果是从中间插过来看的,请仔细阅读 羽夏看Win系统内核——简述 ,方便学习本教程。
看此教程之前,问几个问题,基础知识储备好了吗?保护模式篇学会了吗?练习做完了吗?没有的话就不要继续了。
华丽的分割线
上一篇我们简单介绍了APC
的概念。有些人可能对为什么线程不能被“杀掉”、“挂起”和“恢复”还是有些疑问,我们举个极端的例子:如果不调用API,屏蔽中断,并保证代码不出现异常,线程将永久占用CPU,何谈控制呢?所以说线程如果想“死”,一定是自己执行代码把自己杀死,不存在“他杀”这种情况。我们可以画个简单的示意图:
下面我们来看看存储APC
的结构体:
kd> dt _KAPC
ntdll!_KAPC
+0x000 Type : Int2B
+0x002 Size : Int2B
+0x004 Spare0 : Uint4B
+0x008 Thread : Ptr32 _KTHREAD
+0x00c ApcListEntry : _LIST_ENTRY
+0x014 KernelRoutine : Ptr32 void
+0x018 RundownRoutine : Ptr32 void
+0x01c NormalRoutine : Ptr32 void
+0x020 NormalContext : Ptr32 Void
+0x024 SystemArgument1 : Ptr32 Void
+0x028 SystemArgument2 : Ptr32 Void
+0x02c ApcStateIndex : Char
+0x02d ApcMode : Char
+0x02e Inserted : UChar
存在于KTHREAD
结构体的0x34
偏移的位置有一个ApcState
,如下所示:
kd> dt _KTHREAD
nt!_KTHREAD
...
+0x034 ApcState : _KAPC_STATE
...
我们看到这个存着一个结构体,如下所示:
kd> dt _KAPC_STATE
ntdll!_KAPC_STATE
+0x000 ApcListHead : [2] _LIST_ENTRY
+0x010 Process : Ptr32 _KPROCESS
+0x014 KernelApcInProgress : UChar
+0x015 KernelApcPending : UChar
+0x016 UserApcPending : UChar
第一个成员ApcListHead
是个双向链表的数组,一共有两个成员,所谓的APC
就是插入到里面的,给个示意图如下:
ApcListHead
一个成员存储着用户APC
,用户APC
的函数地址位于用户空间,在用户空间执行;另一个成员存储着内核APC
,内核APC
函数地址位于内核空间,在内核空间执行。
线程线程所属或者所挂靠的进程,这个在逆向线程切换的时候我们就用过。具体细节都在进程线程篇的总结与提升讲过,就不再赘述了。
指示内核APC
是否正在执行。
指示是否有正在等待执行的内核APC
。
指示是否有正在等待执行的用户APC
。
上面的介绍仅仅是对APC
的初步讲解,里面所有的详细细节将在后面的教程讲解。后面会详细介绍KAPC
这个结构体,并研究APC
是谁插入的、插入到哪里、谁执行APC
和什么时候执行APC
。本篇是对后面学习的铺垫。
本节的答案将会在下一节进行讲解,务必把本节练习做完后看下一个讲解内容。不要偷懒,实验是学习本教程的捷径。
俗话说得好,光说不练假把式,如下是本节相关的练习。如果练习没做好,就不要看下一节教程了,越到后面,不做练习的话容易夹生了,开始还明白,后来就真的一点都不明白了。本节练习不多,请保质保量的完成。
1️⃣ 使用现成提供的API
,自己编写代码向某个线程插入一个用户APC
。
2️⃣ 分析TerminateThread
和SuspendThread
是如何实现的(从3环开始分析)。(要求:只需逆向分析到别的进程是如何控制目标进程行为,其他细节暂时不需分析,本题参考将会在正文给出。)
手机扫一扫
移动阅读更方便
你可能感兴趣的文章