本篇原文为 Depths of Windows APC ,如果有良好的英文基础,可以点击该链接进行阅读。本文为我个人:寂静的羽夏(wingsummer) 中文翻译,非机翻,著作权归原作者 Rbmm 和 Dennis A. Babkin 所有。
由于原文十分冗长,也十分干货,采用机翻辅助,人工阅读比对修改的方式进行,如有翻译不得当的地方,欢迎批评指正。翻译不易,如有闲钱,欢迎支持。注意在转载文章时注意保留原文的作者链接,我(译者)的相关信息。
本篇文章包含一些没有被原厂家(指微软)进行文档化的功能和特色。在阅读本篇文章的相关内容和建议之后,你应该为自己的所作所为负责。展示在本文的方法依赖于内部实现并且可能以后不再有效。
介绍
在我们的第一篇关于错综复杂的用户APC的博文发布之后,我们决定从细节的深度拓展该主题,将会介绍有关异步过程调用(APC)在Windows操作系统的内部实现。
那我们就开始吧,这里介绍没有什么特别的先后顺序。
目录
以下所有主题之间的联系并不是特别紧密,所以你或许想要一个可以更容易查阅的目录表:
- 介绍
- 目录
- APC 内部实现概要
- 来自内核的用户 APC
- Windows XP 中漏洞百出的用户模式 APC 实现
- 错综复杂的用户模式 APC 实现 DLL 注入
- ZwQueueApcThread 与 QueueUserAPC 孰优孰劣
- 用户 APC 演示代码
- 32 位进程中的 64 位用户 APC
- 后记
APC 内部实现概要
为了在后面的文章——《伸入 NT 内核的异步过程调用内幕》,能够更好让大家更深入的理解内核 APC 的内部实现,我们不会重复原来已经讲过的了,而是多多陈述一些其他且鲜为人知的 APC 相关的细节。
为了更简洁的描述,在技术上说 APC 就是一堆在内存里存储的二进制字节,也就是所谓的 KAPC 结构体:
typedef struct _KAPC {
UCHAR Type;
UCHAR SpareByte0;
UCHAR Size;
UCHAR SpareByte1;
ULONG SpareLong0;
_KTHREAD * Thread;
_LIST_ENTRY ApcListEntry;
void (* KernelRoutine)( _KAPC * , void (* * )( void * , void * , void * ), void * * , void * * , void * * );
void (* RundownRoutine)( _KAPC * );
void (* NormalRoutine)( void * , void * , void * );
void * Reserved[0x3];
void * NormalContext;
void * SystemArgument1;
void * SystemArgument2;
CHAR ApcStateIndex;
CHAR ApcMode;
UCHAR Inserted;
}KAPC, *PKAPC;
上述结构体是在KAPC_STATE结构体里面的双向链表一部分:
typedef struct _KAPC_STATE {
_LIST_ENTRY ApcListHead[0x2];
_KPROCESS * Process;
UCHAR InProgressFlags;
UCHAR KernelApcInProgress : 01; // 0x01;
UCHAR SpecialApcInProgress : 01; // 0x02;
UCHAR KernelApcPending;
UCHAR UserApcPendingAll;
UCHAR SpecialUserApcPending : 01; // 0x01;
UCHAR UserApcPending : 01; // 0x02;
}KAPC_STATE, *PKAPC_STATE;
并且KAPC_STATE自身也是线程对象的一部分,存储在内核里的KTHREAD结构体中: