??此系列是本人一个字一个字码出来的,包括示例和实验截图。由于系统内核的复杂性,故可能有错误或者不全面的地方,如有错误,欢迎批评指正,本教程将会长期更新。 如有好的建议,欢迎反馈。码字不易,如果本篇文章有帮助你的,如有闲钱,可以打赏支持我的创作。如想转载,请把我的转载信息附在文章后面,并声明我的个人信息和本人博客地址即可,但必须事先通知我。
你如果是从中间插过来看的,请仔细阅读 羽夏看Win系统内核——简述 ,方便学习本教程。
??看此教程之前,问几个问题,基础知识储备好了吗?保护模式篇学会了吗?练习做完了吗?没有的话就不要继续了。
?
?? 华丽的分割线 ??
?
??本篇章我们从APC是什么?是怎样初始化的,是怎样插入的,是怎样执行的这几个方面学习。总体来说APC基础知识也就这些。下面先强调一些我介绍过但没有指明出来的知识点。
??我提出几个问题,如果你能回答上来,就说明仔细学了或者自己能够挖掘我没明说的东西。
??我给出如下答案:
??我们学系统调用的时候有一个坑还没填完,那就是系统API是如何返回的,但是学完APC之后,这就没什么好讲的了,自己继续逆向就差不多了,但是还是逆向的结果还是有坑,下面我就把这个坑给你填上。现在我把如下我的反汇编结果给你:
loc_46663A: ; CODE XREF: _KiBBTUnexpectedRange+38↑j ; _KiBBTUnexpectedRange+43↑j mov ecx, ds:0FFDFF124h mov edx, [ebp+_KTRAP_FRAME._Edx] mov [ecx+_KTHREAD.TrapFrame], edx_KiFastCallEntry endp_KiServiceExit proc near ; CODE XREF: KiCallUserMode(x,x)+E7↑j ; _KiSetLowWaitHighThread+7D↓j ...; FUNCTION CHUNK AT .text:00466754 SIZE 00000088 BYTES cli test [ebp+_KTRAP_FRAME.EFlags], 20000h jnz short IsVM8086_0 test byte ptr [ebp+_KTRAP_FRAME.SegCs], 1 jz short IsRing0 ; 开始还原堆栈存储的环境IsVM8086_0: ; CODE XREF: _KiServiceExit+8↑j ; _KiServiceExit+63↓j mov ebx, ds:0FFDFF124h mov [ebx+_KTHREAD.Alerted], 0 cmp [ebx+_KTHREAD.ApcState.UserApcPending], 0 jz short IsRing0 ; 开始还原堆栈存储的环境 mov ebx, ebp mov [ebx+_KTHREAD.ApcState.Process], eax mov dword ptr [ebx+_KTHREAD.IdleSwapBlock], 3Bh ; ';' mov [ebx+_KTHREAD.ApcState.ApcListHead.Blink], 23h ; '#' mov [ebx+_KTHREAD.ApcState.ApcListHead.Flink], 23h ; '#' mov dword ptr [ebx+_KTHREAD.Iopl], 0 mov ecx, 1 ; NewIrql call ds:__imp_@KfRaiseIrql@4 ; KfRaiseIrql(x) push eax sti push ebx ; trapframe push 0 ; unknown push 1 ; CanUserAPC call _KiDeliverApc@12 ; KiDeliverApc(x,x,x) pop ecx ; NewIrql call ds:__imp_@KfLowerIrql@4 ; KfLowerIrql(x) mov eax, [ebx+_KTHREAD.ApcState.Process] cli jmp short IsVM8086_0; --------------------------------------------------------------------------- align 10hIsRing0: ; CODE XREF: _KiServiceExit+E↑j ; _KiServiceExit+1E↑j mov edx, [esp+_KTRAP_FRAME.ExceptionList] ; 开始还原堆栈存储的环境 mov ebx, large fs:_KPCR.DebugActive mov large fs:_KPCR, edx mov ecx, [esp+_KTRAP_FRAME.PreviousPreviousMode] mov esi, large fs:_KPCR.PrcbData.CurrentThread mov [esi+_KTHREAD.PreviousMode], cl test ebx, 0FFh jnz short IsDebuggingFillDebugInfoBack: ; CODE XREF: _KiServiceExit+11B↓j ; _KiServiceExit+14A↓j test [esp+_KTRAP_FRAME.EFlags], 20000h jnz IsVM8086_Exit test word ptr [esp+_KTRAP_FRAME.SegCs], 1111111111111000b jz loc_4667AA cmp word ptr [esp+_KTRAP_FRAME.SegCs], 1Bh bt word ptr [esp+_KTRAP_FRAME.SegCs], 0 ; CF = CS & 1 cmc ; CF = !CF ja IsRing3_Exit cmp word ptr [ebp+_KTRAP_FRAME.SegCs], 8 jz short IsRing0_0loc_466711: ; CODE XREF: _KiServiceExit+15C↓j lea esp, [ebp+_KTRAP_FRAME.SegFs] pop fs assume fs:nothingIsRing0_0: ; CODE XREF: _KiServiceExit+C6↑j lea esp, [ebp+_KTRAP_FRAME._Edi] pop edi pop esi pop ebx pop ebp cmp word ptr [esp+8], 80h ; '€' ; cmp tf.cs , 80 ja loc_466FF0 ; 这个地方一定不会跳转 add esp, 4 test dword ptr [esp+4], 1 ; test tf.cs,1,判断是3环还是0环_KiServiceExit endp ; sp-analysis failed??好,也就是这里开始有坑,我继续把反汇编结果列上:
_KiSystemCallExitBranch proc near ; DATA XREF: KiDisableFastSyscallReturn()+9↑w ; KiEnableFastSyscallReturn():loc_425D2C↑r ...; FUNCTION CHUNK AT .text:0046673C SIZE 00000001 BYTES jnz short _KiSystemCallExit pop edx pop ecx popf jmp edx_KiSystemCallExitBranch endp; ---------------------------------------------------------------------------; START OF FUNCTION CHUNK FOR _KiSystemCallExit2; ADDITIONAL PARENT FUNCTION _KiSystemCallExitBranch_KiSystemCallExit: ; CODE XREF: _KiSystemCallExitBranch↑j ; _KiSystemCallExit2+5↓j ; DATA XREF: ... iret; END OF FUNCTION CHUNK FOR _KiSystemCallExit2; =============== S U B R O U T I N E =======================================_KiSystemCallExit2 proc near ; DATA XREF: KiRestoreFastSyscallReturnState()+16↑oarg_5 = byte ptr 9; FUNCTION CHUNK AT .text:0046673C SIZE 00000001 BYTES test byte ptr [esp+9], 1 jnz short _KiSystemCallExit pop edx add esp, 4 and byte ptr [esp+1], 0FDh popf pop ecx sti sysexit iret_KiSystemCallExit2 endp ; sp-analysis failed??通过test判断是否是3环,如果是的话跳走用iret返回,看似没啥问题。但是如果我是快速调用进入的,这就有问题了,因为有对应的sysexit退出的。我们用WinDbg得出如下结果:

??是不是很奇怪?发现实际是通过KiSystemCallExit2退出的。这就是静态分析和动态分析的不同之处。
??sysexit的为我们做哪些事情呢?我给说明一下:
??到此系统调用怎么进0环,做了那些事情,怎么出0环,就结束了。
??羽夏看Win系统内核——句柄表篇
