异常篇——异常处理
写在前面
??此系列是本人一个字一个字码出来的,包括示例和实验截图。由于系统内核的复杂性,故可能有错误或者不全面的地方,如有错误,欢迎批评指正,本教程将会长期更新。 如有好的建议,欢迎反馈。码字不易,如果本篇文章有帮助你的,如有闲钱,可以打赏支持我的创作。如想转载,请把我的转载信息附在文章后面,并声明我的个人信息和本人博客地址即可,但必须事先通知我。
你如果是从中间插过来看的,请仔细阅读 羽夏看Win系统内核——简述 ,方便学习本教程。??看此教程之前,问几个问题,基础知识储备好了吗?保护模式篇学会了吗?练习做完了吗?没有的话就不要继续了。
?
华丽的分割线
?
概述 ??之前我们介绍了异常的记录。既然记录好的异常,我肯定需要分发来处理它。对于异常有来自用户模式的异常和内核态的异常。在我们之前学习中,它们的区别还是挺大的。无论是内核的异常,还是用户的异常,异常处理的重心我们得放到
KiDispatchException
这个函数的分析上,先介绍相对简单的内核异常处理流程。内核异常处理 【异常篇——异常处理】??对于内核异常处理,我们先看看
KiDispatchException
的处理流程:KeContextFromKframes
将TrapFrame
备份到Context
,为返回3环做准备。- 判断先前模式,0是内核调用反之是用户层调用。
- 是否是第一次机会。
- 是否有内核调试器。
- 如果没有或者内核调试器不处理。
- 调用
RtlDispatchException
,查找并调用异常处理函数。 - 如果返回
FALSE
,再次判断是否有内核调试器,有调用,没有直接蓝屏。
push390h
pushoffset stru_401FA0
call__SEH_prolog
moveax, ___security_cookie
mov[ebp+security_cookie], eax
movesi, [ebp+ExceptionRecord]
mov[ebp+var_ExceptionRecord], esi
movecx, [ebp+ExceptionFrame]
mov[ebp+var_ExceptionFrame], ecx
movebx, [ebp+TrapFrame]
mov[ebp+var_TrapFrame], ebx
db3Eh
moveax, ds:0FFDFF020h
inc[eax+_KPRCB.KeExceptionDispatchCount] ;
异常派发数加1
mov[ebp+Context.ContextFlags], 10017h
cmp[ebp+PreviousMode], 1
jzshort IsUserMode
cmp_KdDebuggerEnabled, 0
jzshort KernelModeAndNoDBG
??函数开始开始赋值一波,然后判断否是为3环,但我们是内核的,故不会跳转,然后
cmp _KdDebuggerEnabled, 0
判断调试器是否开启,具体将会在调试篇进行讲解,这里就不多说了。??这里我们没有调试器,就会跳转到下面的汇编代码:
KernelModeAndNoDBG:;
CODE XREF: KiDispatchException(x,x,x,x,x)+55↑j
;
KiDispatchException(x,x,x,x,x)+68↑j
leaeax, [ebp+Context]
pusheax;
ContextRecord
pushecx;
ExceptionFrame
pushebx;
TrapFrame
call_KeContextFromKframes@12 ;
KeContextFromKframes(x,x,x)
moveax, [esi]
cmpeax, STATUS_BREAKPOINT
jzshort IsBreakPoint
cmpeax, KI_EXCEPTION_ACCESS_VIOLATION
jnzshort OtherExceptionProc
movdword ptr [esi], STATUS_ACCESS_VIOLATION
cmp[ebp+PreviousMode], 1
jnzshort OtherExceptionProc
leaeax, [ebp+Context]
pusheax;
Context
pushesi;
ExceptionRecord
call_KiCheckForAtlThunk@8 ;
KiCheckForAtlThunk(x,x)
testal, al
jnzloc_425AFD
cmpbyte ptr ds:0FFDF0280h, 1
jnzshort OtherExceptionProc
cmpdword ptr [esi+14h], 8
jnzshort OtherExceptionProc
test_KeNumberProcessors+0Fh, 40h
jnzshort loc_425A30
moveax, large fs:_KPCR.PrcbData.CurrentThread
moveax, [eax+_KTHREAD.ApcState.Process]
test[eax+_EPROCESS.Pcb.___u27.Flags._bf_0], 2
jnzshort loc_425A30
test_KeNumberProcessors+0Fh, 80h
jnzshort OtherExceptionProc
moveax, large fs:_KPCR.PrcbData.CurrentThread
moveax, [eax+_KTHREAD.ApcState.Process]
test[eax+_EPROCESS.Pcb.___u27.Flags._bf_0], 1
jnzshort OtherExceptionProc
??这里就开始将
TrapFrame
备份到Context
,首先判断是否是int3
断点,如果是的话就会跳转到如下代码:IsBreakPoint:;
CODE XREF: KiDispatchException(x,x,x,x,x)+89↑j
dec[ebp+Context._Eip]OtherExceptionProc:;
CODE XREF: KiDispatchException(x,x,x,x,x)+90↑j
;
KiDispatchException(x,x,x,x,x)+9C↑j ...
xoredi, ediDebugRoutine:;
CODE XREF: KiDispatchException(x,x,x,x,x)+F7↑j
??该代码就会修正
EIP
,继续下面的流程。如果不是断点,就判断一系列的异常,并进行相应的处理,如果都不是就跳转到所谓的OtherExceptionProc
进行处理:DebugRoutine:;
CODE XREF: KiDispatchException(x,x,x,x,x)+F7↑j
cmp[ebp+PreviousMode], 0
jnzshort UserMode
cmp[ebp+FirstChance], 1
jnzshort SecondChance
moveax, _KiDebugRoutine
cmpeax, edi;
edi = 0
jzshort NoDebugRoutine
pushedi;
SecondChance
pushedi;
PreviousMode
leaecx, [ebp+Context]
pushecx;
ContextRecord
pushesi;
ExceptionRecord
push[ebp+var_ExceptionFrame] ;
ExceptionFrame
pushebx;
TrapFrame
calleax ;
_KiDebugRoutine
testal, al
jnzloc_425AFDNoDebugRoutine:;
CODE XREF: KiDispatchException(x,x,x,x,x)+114↑j
leaeax, [ebp+Context]
pusheax;
Context
pushesi;
ExceptionRecord
call_RtlDispatchException@8 ;
RtlDispatchException(x,x)
cmpal, 1
jzshort loc_425AFD
??这里同理,我们没有调试器,就会调用
RtlDispatchException
这个函数。如果失败,就会继续执行下面的代码:jzshort loc_425AFD SecondChance:;
CODE XREF: KiDispatchException(x,x,x,x,x)+10B↑j
moveax, _KiDebugRoutine
cmpeax, edi
jzNoDebugRoutine_0
push1;
SecondChance
pushedi;
PreviousMode
leaecx, [ebp+Context]
pushecx;
ContextRecord
pushesi;
ExceptionRecord
push[ebp+var_ExceptionFrame] ;
ExceptionFrame
pushebx;
TrapFrame
calleax ;
_KiDebugRoutine
testal, al
jnzshort loc_425AFD
jmpNoDebugRoutine_0
??就继续判断有没有调试器,但我这里没有,就会跳到下面的汇编代码:
NoDebugRoutine_0:;
CODE XREF: KiDispatchException(x,x,x,x,x)+149↑j
;
KiDispatchException(x,x,x,x,x)+167↑j
pushedi;
BugCheckParameter4
pushebx;
BugCheckParameter3
push[esi+_EXCEPTION_RECORD32.ExceptionAddress] ;
BugCheckParameter2
push[esi+_EXCEPTION_RECORD32.ExceptionCode] ;
BugCheckParameter1
pushKERNEL_MODE_EXCEPTION_NOT_HANDLED ;
BugCheckCode
call_KeBugCheckEx@20 ;
KeBugCheckEx(x,x,x,x,x)
??上面的代码,就是所谓的蓝屏。有关内核异常处理就介绍到这里,具体的细节将会到总结与提升篇进行介绍。
用户异常处理 ??对于用户异常处理,我们先看看
KiDispatchException
的处理流程:KeContextFromKframes
将TrapFrame
备份到Context
,为返回3环做准备。- 判断先前模式,0是内核调用反之是用户层调用。
- 是否是第一次机会。
- 是否有内核调试器。
- 发送给3环调试。
inc[eax+_KPRCB.KeExceptionDispatchCount] ;
异常派发数加1
mov[ebp+Context.ContextFlags], 10017h
cmp[ebp+PreviousMode], 1
jzshort IsUserMode
cmp_KdDebuggerEnabled, 0
jzshort KernelModeAndNoDBG
??这里我们是用户的异常,所以会跳转:
IsUserMode:;
CODE XREF: KiDispatchException(x,x,x,x,x)+4C↑j
mov[ebp+Context.ContextFlags], 1001Fh
cmp_KeI386XMMIPresent, 0
jzshort KernelModeAndNoDBG
mov[ebp+Context.ContextFlags], 1003FhKernelModeAndNoDBG:;
CODE XREF: KiDispatchException(x,x,x,x,x)+55↑j
;
KiDispatchException(x,x,x,x,x)+68↑j
leaeax, [ebp+Context]
??这里就是赋值,不是我们关注的重点,我们继续:
KernelModeAndNoDBG:;
CODE XREF: KiDispatchException(x,x,x,x,x)+55↑j
;
KiDispatchException(x,x,x,x,x)+68↑j
leaeax, [ebp+Context]
pusheax;
ContextRecord
pushecx;
ExceptionFrame
pushebx;
TrapFrame
call_KeContextFromKframes@12 ;
KeContextFromKframes(x,x,x)
moveax, [esi]
cmpeax, STATUS_BREAKPOINT
jzshort IsBreakPoint
cmpeax, KI_EXCEPTION_ACCESS_VIOLATION
jnzshort OtherExceptionProc
movdword ptr [esi], STATUS_ACCESS_VIOLATION
cmp[ebp+PreviousMode], 1
jnzshort OtherExceptionProc
leaeax, [ebp+Context]
pusheax;
Context
pushesi;
ExceptionRecord
call_KiCheckForAtlThunk@8 ;
KiCheckForAtlThunk(x,x)
testal, al
jnzloc_425AFD
cmpbyte ptr ds:0FFDF0280h, 1
jnzshort OtherExceptionProc
cmpdword ptr [esi+14h], 8
jnzshort OtherExceptionProc
test_KeNumberProcessors+0Fh, 40h
jnzshort loc_425A30
moveax, large fs:_KPCR.PrcbData.CurrentThread
moveax, [eax+_KTHREAD.ApcState.Process]
test[eax+_EPROCESS.Pcb.___u27.Flags._bf_0], 2
jnzshort loc_425A30
test_KeNumberProcessors+0Fh, 80h
jnzshort OtherExceptionProc
moveax, large fs:_KPCR.PrcbData.CurrentThread
moveax, [eax+_KTHREAD.ApcState.Process]
test[eax+_EPROCESS.Pcb.___u27.Flags._bf_0], 1
jnzshort OtherExceptionProc
??由于我们是3环的,就会调用到
KiCheckForAtlThunk
这个函数作用如下:This marks the beginning of an x86 ATL thunk. Control will branch here if the ATL thunk was built in memory marked no execute. If that is the case, then the thunk code will be emulated and control returned to the thread.??看描述并不是我们关注的重点,继续走到了我所标注的
DebugRoutine
:DebugRoutine:;
CODE XREF: KiDispatchException(x,x,x,x,x)+F7↑j
cmp[ebp+PreviousMode], 0
jnzshort UserMode_0
cmp[ebp+FirstChance], 1
jnzshort SecondChance
moveax, _KiDebugRoutine
cmpeax, edi;
edi = 0
jzshort NoDebugRoutine
pushedi;
SecondChance
pushedi;
PreviousMode
leaecx, [ebp+Context]
pushecx;
ContextRecord
pushesi;
ExceptionRecord
push[ebp+var_ExceptionFrame] ;
ExceptionFrame
pushebx;
TrapFrame
calleax ;
_KiDebugRoutine
testal, al
jnzloc_425AFD
??由于我们是用户态,就直接跳转到
UserMode_0
:UserMode_0:;
CODE XREF: KiDispatchException(x,x,x,x,x)+105↑j
cmp[ebp+FirstChance], 1
jnzSecondChance_0
cmp_KiDebugRoutine, edi
jzshort NoDebugRoutine_1
moveax, large fs:_KPCR.PrcbData.CurrentThread
moveax, [eax+_KTHREAD.ApcState.Process]
cmp[eax+_EPROCESS.DebugPort], edi
jzshort NoDebugPort
push1
leaeax, [ebp+Context]
pusheax
pushesi
call_KdIsThisAKdTrap@12 ;
KdIsThisAKdTrap(x,x,x)
testal, al
jzshort NoDebugRoutine_1NoDebugPort:;
CODE XREF: KiDispatchException(x,x,x,x,x)+18D↑j
pushedi;
SecondChance
pushdword ptr [ebp+PreviousMode] ;
PreviousMode
leaeax, [ebp+Context]
pusheax;
ContextRecord
pushesi;
ExceptionRecord
push[ebp+var_ExceptionFrame] ;
ExceptionFrame
pushebx;
TrapFrame
call_KiDebugRoutine
testal, al
jzshort NoDebugRoutine_1
??由于我们不是调试模式,会跳到
NoDebugRoutine_1
:NoDebugRoutine_1:;
CODE XREF: KiDispatchException(x,x,x,x,x)+17C↑j
;
KiDispatchException(x,x,x,x,x)+1A0↑j ...
pushedi;
SecondChance
push1;
DebugException
pushesi;
ExceptionRecord
call_DbgkForwardException@12 ;
DbgkForwardException(x,x,x)
testal, al
jnzshort EndProc
mov[ebp+var_SecondChance], edi
??
DbgkForwardException
就是向3环派发处理异常了,剩余的具体细节的讲解同样将会在总结与提升进行。下一篇 ??异常篇—— VEH 与 SEH
推荐阅读
- flask框架安装使用
- 『德不孤』Pytest框架|『德不孤』Pytest框架 — 7、Pytest预期失败
- Python|爬虫学习日记第六篇(异步爬虫之多进程、线程池和实战项目爬取新发地价格行情)
- xss|xss-labs通关(未完成)
- Python|爬虫学习日记第四篇(xpath解析)
- 面试题|数据仓库——数据仓库基础
- Anchor-free目标检测综述|Anchor-free目标检测综述 -- Keypoint-based篇
- c语言编写显示一行字程序,C语言文件操作——读一行和写一行
- 入门教程|C语言总结项目和入门——文件操作
- 密码学|密码学的发展(第二篇(恩尼格码机))