异常的登记(一)
一、windows的异常分类异常Exception可以按“产生源”分为两大类1.CPU 硬件产生的异常2.软件主动触发/模拟产生的异常二、CPU 硬件产生的异常以除0异常#DE为例我们从一个最简单、最典型的 CPU 异常 #DEDivide Error 入手当逆向 Windows 7 x86 内核对异常的处理路径并以此为入口分析 nt!KiTrap00。2.1 _EXCEPTION_RECORD结构体nt!_EXCEPTION_RECORD0x000ExceptionCode:Int4B0x004ExceptionFlags:Uint4B0x008ExceptionRecord:Ptr32 _EXCEPTION_RECORD0x00cExceptionAddress:Ptr32 Void0x010NumberParameters:Uint4B0x014ExceptionInformation:[15]Uint4B1️⃣ExceptionCode异常类型编号。例如0xC0000005 → 内存访问错误Access Violation0xC0000094 → 整数除0Divide by zero0x80000003 → 断点异常INT32️⃣ExceptionFlags异常的状态标志。// 表示这是一个“不可继续执行”的异常。 // 如果某个异常带有这个标志那么异常处理函数不能返回 // ExceptionContinueExecution继续执行否则系统会再次抛出 // STATUS_NONCONTINUABLE_EXCEPTION。#define EXCEPTION_NONCONTINUABLE 0x1// 表示当前正在进行异常展开unwind。 // 也就是说系统已经不再是“找谁来处理异常” // 而是开始沿着栈逐层回退执行清理逻辑比如 __finally。#define EXCEPTION_UNWINDING 0x2// 表示当前是“退出式展开exit unwind”。 // 一般表示线程/流程正在退出系统正在做整条异常链的展开清理。#define EXCEPTION_EXIT_UNWIND 0x4// 表示当前异常对应的栈状态无效。 // 常见场景包括SEH 链节点超出线程栈范围、未按要求对齐等。 // 一旦置位说明异常链/栈结构已经不可信。#define EXCEPTION_STACK_INVALID 0x8// 表示发生了“嵌套异常调用nested exception handler call”。 // 即某个异常处理函数在执行过程中又触发了新的异常 // 导致系统进入更深一层的异常分发流程。#define EXCEPTION_NESTED_CALL 0x10// 表示正在向目标帧target frame展开。 // 常见于系统为了到达某个指定的异常处理目标 // 正在逐层展开中间的栈帧。#define EXCEPTION_TARGET_UNWIND 0x20// 表示发生了“冲突展开collided unwind”。 // 即在栈展开过程中又遇到了新的展开请求 // 导致原本的展开流程和新的展开流程发生冲突。 // 这是异常处理里比较复杂的一种情况。#define EXCEPTION_COLLIDED_UNWIND 0x403️⃣ExceptionRecord指针指向“前一个异常记录”。用于异常嵌套异常在异常处理过程中再次发生形成一个链表。4️⃣ExceptionAddress发生异常的指令地址EIP。例如除0时这里就是 idiv 那条指令地址。这是非常重要的字段。5️⃣NumberParameters6️⃣ExceptionInformationNumberParameters表示 ExceptionInformation[] 数组中 有效参数的个数0~15。处理器/内核在构造异常记录时会填它。ExceptionInformation[15]存放异常的 附加参数具体每个参数的含义取决于 ExceptionCode。只有前 NumberParameters 个元素有效后面不看。2.2 KiTrap00.text:0043EFC0 _KiTrap00 proc near;DATA XREF:INIT:_IDT↓o.text:0043EFC0.text:0043EFC0 var_2word ptr-2.text:0043EFC0 arg_4dword ptr8.text:0043EFC0.text:0043EFC0;FUNCTION CHUNK AT.text:0043ED6B SIZE00000021BYTES.text:0043EFC0.text:0043EFC0 push0.text:0043EFC2 mov[esp4var_2],0.text:0043EFC9 push ebp.text:0043EFCA push ebx.text:0043EFCB push esi.text:0043EFCC push edi.text:0043EFCD push fs.text:0043EFCF mov ebx,30h;0.text:0043EFD4 mov fs,bx;换成内核fs.text:0043EFD7 assume fs:nothing.text:0043EFD7 mov ebx,large fs:_KPCR;ExceptionList.text:0043EFDE push ebx.text:0043EFDF sub esp,4;跳过4字节.text:0043EFE2 push eax.text:0043EFE3 push ecx.text:0043EFE4 push edx.text:0043EFE5 push ds.text:0043EFE6 push es.text:0043EFE7 push gs.text:0043EFE9 mov ax,23h;#.text:0043EFED sub esp,30h;跳过48字节.text:0043EFED;esp直接指向_KTRAP_FRAME开始部分.text:0043EFF0 mov ds,ax.text:0043EFF3 assume ds:nothing.text:0043EFF3 mov es,ax;替换内核es.text:0043EFF6 assume es:nothing.text:0043EFF6 mov ebp,esp.text:0043EFF8 test[esp_KTRAP_FRAME.EFlags],20000h;判断vm位.text:0043F000 jnzshortV86_kit0_a;如果是虚拟8086模式跳转.text:0043F002.text:0043F002 loc_43F002:;CODE XREF:V86_kit0_a25↑j.text:0043F002 mov ecx,large fs:_KPCR.PrcbData.CurrentThread.text:0043F009 cld.text:0043F00Aand[ebp_KTRAP_FRAME.Dr7],0.text:0043F00E test[ecx_KTHREAD.Header.___u0.__s3.DebugActive],0DFh;该线程当前是否正在“被调试”状态中.text:0043F012 jnz Dr_kit0_a;如果在调试状态则跳转.text:0043F018.text:0043F018 loc_43F018:;CODE XREF:Dr_kit0_aD↑j.text:0043F018;Dr_kit0_a79↑j.text:0043F018 mov ebx,[ebp_KTRAP_FRAME._Ebp].text:0043F01B mov edi,[ebp_KTRAP_FRAME._Eip].text:0043F01E mov[ebp_KTRAP_FRAME.DbgArgPointer],edx.text:0043F021 mov[ebp_KTRAP_FRAME.DbgArgMark],0BADB0D00h.text:0043F028 mov[ebp_KTRAP_FRAME.DbgEbp],ebx.text:0043F02B mov[ebp_KTRAP_FRAME.DbgEip],edi.text:0043F02E test byte ptr[ebp(_KTRAP_FRAME.EFlags2)],2;判断是不是虚拟8086.text:0043F032 jnzshortloc_43F082.text:0043F034 test byte ptr[ebp_KTRAP_FRAME.SegCs],1;判断是不是内核模式.text:0043F038 jnzshortloc_43F04B;如果是内核模式直接蓝屏.text:0043F038;否则是来自用户态CPL3则继续按用户态异常处理.text:0043F03A sti.text:0043F03B push ebp.text:0043F03C push0.text:0043F03E push0.text:0043F040 push0.text:0043F042 push0.text:0043F044 push7Fh.text:0043F046 call _KeBugCheck224;KeBugCheck2(x,x,x,x,x,x).text:0043F04B;---------------------------------------------------------------------------.text:0043F04B.text:0043F04B loc_43F04B:;CODE XREF:_KiTrap0078↑j.text:0043F04B cmp word ptr[ebp_KTRAP_FRAME.SegCs],1Bh;判断是不是r3的段选择子.text:0043F050 jnzshortloc_43F06F;如果不是r3的段选择子跳转.text:0043F052 sti.text:0043F053 push ebp;_KTRAP_FRAME.text:0043F054 call _Ki386CheckDivideByZeroTrap4;这函数通常会检查触发原因除数为0vs 商溢出.text:0043F054;返回值eax错误号.text:0043F059 mov ebx,[ebp_KTRAP_FRAME._Eip];ebx异常地址.text:0043F05C jmp loc_43ED6B.text:0043F061;---------------------------------------------------------------------------.text:0043F061.text:0043F061 loc_43F061:;CODE XREF:_KiTrap00C0↓j.text:0043F061;_KiTrap00CB↓j.text:0043F061 sti.text:0043F062 mov ebx,[ebp68h].text:0043F065 mov eax,0C0000094h.text:0043F06A jmp loc_43ED6B.text:0043F06F;---------------------------------------------------------------------------.text:0043F06F.text:0043F06F loc_43F06F:;CODE XREF:_KiTrap0090↑j.text:0043F06F mov ebx,large fs:124h.text:0043F076 mov ebx,[ebx50h].text:0043F079 cmp dword ptr[ebx148h],0.text:0043F080 jzshortloc_43F061.text:0043F082.text:0043F082 loc_43F082:;CODE XREF:_KiTrap0072↑j.text:0043F082 push0.text:0043F084 call _Ki386VdmReflectException_A4;Ki386VdmReflectException_A(x).text:0043F089oral,al.text:0043F08B jzshortloc_43F061.text:0043F08D jmp Kei386EoiHelper0;Kei386EoiHelper().text:0043F08D _KiTrap00 endp.text:0043ED6B loc_43ED6B:;CODE XREF:_KiRaiseAssertion81↑j.text:0043ED6B;sub_43EEAF64↓j....text:0043ED6Bxorecx,ecx;参数个数清零.text:0043ED6D call CommonDispatchException2.3 CommonDispatchException.text:0043ED8C CommonDispatchException proc near;CODE XREF:_KiRaiseAssertion471↑p.text:0043ED8C;_KiRaiseAssertion47D↑p....text:0043ED8C.text:0043ED8C var_50dword ptr-50h.text:0043ED8C var_4Cdword ptr-4Ch.text:0043ED8C var_48dword ptr-48h.text:0043ED8C var_44dword ptr-44h.text:0043ED8C var_40dword ptr-40h.text:0043ED8C var_3Cbyte ptr-3Ch.text:0043ED8C.text:0043ED8C sub esp,50h.text:0043ED8F mov[esp_EXCEPTION_RECORD.ExceptionCode],eax.text:0043ED92xoreax,eax.text:0043ED94 mov[esp_EXCEPTION_RECORD.ExceptionFlags],eax.text:0043ED98 mov[esp_EXCEPTION_RECORD.ExceptionRecord],eax.text:0043ED9C mov[esp_EXCEPTION_RECORD.ExceptionAddress],ebx.text:0043EDA0 mov[esp_EXCEPTION_RECORD.NumberParameters],ecx.text:0043EDA4 cmp ecx,0;判断有没有参数.text:0043EDA7 jzshortloc_43EDB5.text:0043EDA9 lea ebx,[esp_EXCEPTION_RECORD.ExceptionInformation].text:0043EDAD mov[ebx],edx;参数1.text:0043EDAF mov[ebx4],esi;参数2.text:0043EDB2 mov[ebx8],edi;参数3.text:0043EDB5.text:0043EDB5 loc_43EDB5:;CODE XREF:CommonDispatchException1B↑j.text:0043EDB5 mov ecx,esp;ecx_EXCEPTION_RECORD.text:0043EDB7 test byte ptr[ebp(_KTRAP_FRAME.EFlags2)],2;判断是否8086模式.text:0043EDBB jzshortloc_43EDC4.text:0043EDBD mov eax,0FFFFh.text:0043EDC2 jmpshortloc_43EDC7.text:0043EDC4;---------------------------------------------------------------------------.text:0043EDC4.text:0043EDC4 loc_43EDC4:;CODE XREF:CommonDispatchException2F↑j.text:0043EDC4 mov eax,[ebp_KTRAP_FRAME.SegCs].text:0043EDC7.text:0043EDC7 loc_43EDC7:;CODE XREF:CommonDispatchException36↑j.text:0043EDC7andeax,1;内核CS低位为0用户CS0x1B低位为1.text:0043EDC7;因此1就足够区分KernelMode(0)/UserMode(1)。.text:0043EDCA push1;FirstChance.text:0043EDCC push eax;PreviousMode.text:0043EDCD push ebp;TrapFrame.text:0043EDCE push0;ExceptionFrame.text:0043EDD0 push ecx;ExceptionRecord.text:0043EDD1 call _KiDispatchException20;KiDispatchException(x,x,x,x,x).text:0043EDD6 mov esp,ebp.text:0043EDD8 jmp Kei386EoiHelper0;Kei386EoiHelper().text:0043EDD8 CommonDispatchException endp2.4 从 KiTrap00 到 CommonDispatchException做了什么用户态执行 除0||CPU 触发 #DE(vector0)v IDT[0]gate-nt!KiTrap00||--保存现场/切 fs0x30/建 KTRAP_FRAME||--判断 V86/VDM?||--是:Ki386VdmReflectException_A...|--否:继续||--判断来源 SegCs:||--KernelMode:KeBugCheck2(0x7F,...)|--UserMode(CS0x1B):||||--Ki386CheckDivideByZeroTrap(得到异常错误码)||--eaxExceptionCode(如0xC0000094)||--ebxExceptionAddress(EIP)|--ecxNumberParameters(这里为0)v CommonDispatchException||--在栈上构造 _EXCEPTION_RECORD|--计算 PreviousMode(SegCs1)--调用KiDispatchException(...,FirstChance1)
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2434489.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!