闲话少说,直奔主题,首先OD载入一个程序,然后执行一下单步(调试器会将TF置1)

  此时,CPU会在基于当前线程上下文的环境中,进入int 1的中断门,也就是KiTrap01

kd> !idt -a

Dumping IDT:

00:	805431a0 nt!KiTrap00
01: 8054331c nt!KiTrap01 // int 1会转到这个函数执行
02: Task Selector = 0x0058 // NMI 从这里可以看到NMI是通过任务门执行的
03: 80543730 nt!KiTrap03
04: 805438b0 nt!KiTrap04
05: 80543a10 nt!KiTrap05
06: 80543b84 nt!KiTrap06
07: 805441fc nt!KiTrap07
08: Task Selector = 0x0050 // DF 因为发生DF时,寄存器可能已经出错了,所以需要任务门,加载新的环境
09: 80544600 nt!KiTrap09

  然后我们看下windbg,首先在KiTrap01下断,其次通过OD的单步后,确实已经中断到windbg的KiTrap01处了,其环境也是被调试线程的环境

    看下TSS中ESP0的值

kd> r tr
tr=00000028
kd> dg 28
P Si Gr Pr Lo
Sel Base Limit Type l ze an es ng Flags
---- -------- -------- ---------- - -- -- -- -- --------
0028 80042000 000020ab TSS32 Busy 0 Nb By P Nl 0000008b
kd> dd 80042000
80042000 0c458b24 b23b9de0 8b080010 758b0855  //b23b9de0就是ESP0的值

        intel手册中说到,在转移到中断例程入口前,会先将SS  ESP  EFLAGS  CS  EIP  ErrorCode压入内核栈,所以我们看看ESP0中的值

kd> dd esp
b23b9dcc 00421480 0000001b 00000346 0012ffc0
b23b9ddc 00000023                  //从这里可以得知 SS:23 ESP:12FFC0 EFLAGS:346 CS:1b EIP:421480

    好了,可以进入正题了,先看下KiTrap01的执行过程

nt!KiTrap01:
8054331c 6a00 push 0                 // ErrorCode
8054331e 66c74424020000 mov word ptr [esp+2],0
80543325 55 push ebp
80543326 53 push ebx
80543327 56 push esi
80543328 57 push edi
80543329 0fa0 push fs
8054332b bb30000000 mov ebx,30h
80543330 668ee3 mov fs,bx
80543333 648b1d00000000 mov ebx,dword ptr fs:[0]
8054333a 53 push ebx                // ExceptionList
8054333b 83ec04 sub esp,4               // PreviousPreviousMode
8054333e 50 push eax
8054333f 51 push ecx
80543340 52 push edx
80543341 1e push ds
80543342 06 push es
80543343 0fa8 push gs
80543345 66b82300 mov ax,23h
80543349 83ec30 sub esp,30h             // 到这里_KTRAP_FRAME已经填充一半了,还差30h
8054334c 668ed8 mov ds,ax
8054334f 668ec0 mov es,ax
80543352 8bec mov ebp,esp
80543354 f744247000000200 test dword ptr [esp+70h],20000h  // 检测是否是虚拟8086模式
8054335c 7596 jne nt!V86_kit1_a (805432f4)      // 是虚拟8086模式的话,就发生跳转,这里我们应该继续执行
8054335e fc cld
8054335f 8b5d60 mov ebx,dword ptr [ebp+60h]      // 被压入栈的EBP寄存器的值,这里是12FFF0
80543362 8b7d68 mov edi,dword ptr [ebp+68h]      // 被压入栈中EIP寄存器的值,这里是421480
80543365 89550c mov dword ptr [ebp+0Ch],edx    // KiFastSystemCall
80543368 c74508000ddbba mov dword ptr [ebp+8],0BADB0D00h // DbgArgMark
8054336f 895d00 mov dword ptr [ebp],ebx      // DbgEbp
80543372 897d04 mov dword ptr [ebp+4],edi     // DbgEip /**************************************************************************************************************************************
/*****                  执行完这几个栈操作后,我们看下栈中的值                                   *****
/**************************************************************************************************************************************
  kd> dd ebp  其实这里都是KTRAP_FTAME的值
  b23b9d64 0012fff0  00421480 badb0d00 7c92e4f4
  b23b9d74 7c930208 ffffffff ffffffff 0012fff0
  b23b9d84 00000000 80543349 00000008 00000196
  b23b9d94 00000000 00000023 00000023 7c92e4f4
  b23b9da4 0012ffb0 00000000 00000146 ffffffff
  b23b9db4 00000030 7c930208 ffffffff 7ffd8000
  b23b9dc4 0012fff0 00000000 00421480 0000001b
  b23b9dd4 00000346 0012ffc0 00000023 805470de 80543375 64f60550000000ff test byte ptr fs:[50h],0FFh    // 测试DebugActive
8054337d 0f85edfeffff jne nt!Dr_kit1_a (80543270)
80543383 64833d5400000000 cmp dword ptr fs:[54h],0
8054338b 7561 jne nt!KiTrap01+0xd2 (805433ee)
8054338d 8b4d68 mov ecx,dword ptr [ebp+68h]
80543390 81f920255480 cmp ecx,offset nt!KiFastCallEntry (80542520)  
80543396 0f84c4feffff je nt!KiTrap00+0xc0 (80543260) // 测试是不是sysenter指令,如果是的话,不能步过
8054339c f7457000000200 test dword ptr [ebp+70h],20000h
805433a3 7524       jne    nt!KiTrap01+0xad (805433c9) // 检测虚拟8086模式
805433a5 66f7456c0100 test   word ptr [ebp+6Ch],1    
805433ab 7408      je    nt!KiTrap01+0x99 (805433b5)   // 检测当前CPL,如果是R3的话,就不发生跳转
805433ad 66837d6c1b   cmp    word ptr [ebp+6Ch],1Bh
805433b2 7515       jne    nt!KiTrap01+0xad (805433c9)     // 如果是R3的话,CS应该是1B,如果不是的话,发生跳转
805433b4 fb         sti
805433b5 816570fffeffff and    dword ptr [ebp+70h],0FFFFFEFFh   //EFLAGS的TF位清零
805433bc 8b5d68 mov    ebx,dword ptr [ebp+68h]     // (ebx)-> faulting instruction
805433bf b804000080 mov   eax,80000004h         // TF异常的错误码
805433c4 e94efcffff jmp   nt!KiExceptionExit+0x16b (80543017)

 

80543017 33c9            xor     ecx,ecx
80543019 e81a000000 call nt!CommonDispatchException (80543038)  // Never return

接下来看看CommonDispatchException内部都做了些什么

/**********************************************************************************************
/*****          Set up exception record for raising exception            *****
/**********************************************************************************************
首先来看看EXCEPTION_RECORD
  kd> dt _exception_record
  nt!_EXCEPTION_RECORD
  +0x000 ExceptionCode : Int4B
  +0x004 ExceptionFlags : Uint4B
  +0x008 ExceptionRecord : Ptr32 _EXCEPTION_RECORD
  +0x00c ExceptionAddress : Ptr32 Void
  +0x010 NumberParameters : Uint4B
  +0x014 ExceptionInformation : [15] Uint4B nt!CommonDispatchException:
80543038 83ec50 sub esp,50h            // ExceptionRecordLength, allocate exception record
8054303b 890424 mov dword ptr [esp],eax     // set ExceptionCode        其实也就是上文的80000004h
8054303e 33c0 xor eax,eax
80543040 89442404 mov dword ptr [esp+4],eax    // set ExceptionFlags         这里为0
80543044 89442408 mov dword ptr [esp+8],eax   // set associated ExceptionRecord 这里为0
80543048 895c240c mov dword ptr [esp+0Ch],ebx  // set ExceptionAddress       其实也就是上文的421480
8054304c 894c2410 mov dword ptr [esp+10h],ecx  // set NumberParameters       这里为0
80543050 83f900 cmp ecx,0
80543053 740c je nt!CommonDispatchException+0x29 (80543061)   //跳到了这里 set up arguments and call _KiDispatchException
80543061 8bcc       mov ecx,esp              // (ecx)->exception record
80543063 f7457000000200 test dword ptr [ebp+70h],20000h
8054306a 7407       je nt!CommonDispatchException+0x3b (80543073)  // 因为不是虚拟8086模式,所以会发生跳转 //跳转到这里后,就该调用KiDispatchException了
stdCall _KiDispatchException,<ecx, 0, ebp, eax, 1>      // 汇编中的原型
KiDispatchException (                       // API中的原型
IN PEXCEPTION_RECORD ExceptionRecord,
IN PKEXCEPTION_FRAME ExceptionFrame,
IN PKTRAP_FRAME TrapFrame,
IN KPROCESSOR_MODE PreviousMode,
IN BOOLEAN FirstChance
) 80543073 8b456c      mov   eax,dword ptr [ebp+6Ch]   
80543076 83e001      and   eax,1           // 通过CS段选择子,得到被调试程序的CPL, 通过与运算后,得到后面的PreviousMode
80543079 6a01       push  1              // 1 - first chance TRUE
8054307b 50        push  eax            // eax - PreviousMode
8054307c 55         push  ebp            // TrapFrame
8054307d 6a00       push  0             // ExceptionFrame
8054307f 51        push  ecx            // ExceptionRecord
80543080 e8e1c3fbff   call   nt!KiDispatchException (804ff466)

  

这里再看看我们的KTRAP_FRAME的具体值,这些值能很详细的说明故障信息

kd> dt _ktrap_frame b2bf3d64
nt!_KTRAP_FRAME
+0x000 DbgEbp : 0x12fff0
+0x004 DbgEip : 0x421480
+0x008 DbgArgMark : 0xbadb0d00
+0x00c DbgArgPointer : 0x7c92e4f4
+0x010 TempSegCs : 0x7c930208
+0x014 TempEsp : 0xffffffff
+0x018 Dr0 : 0xffffffff
+0x01c Dr1 : 0x12fff0
+0x020 Dr2 : 0
+0x024 Dr3 : 0x80543349
+0x028 Dr6 : 8
+0x02c Dr7 : 0x196
+0x030 SegGs : 0
+0x034 SegEs : 0x23
+0x038 SegDs : 0x23
+0x03c Edx : 0x7c92e4f4
+0x040 Ecx : 0x12ffb0
+0x044 Eax : 0
+0x048 PreviousPreviousMode : 0x146
+0x04c ExceptionList : 0xffffffff _EXCEPTION_REGISTRATION_RECORD
+0x050 SegFs : 0x30
+0x054 Edi : 0x7c930208
+0x058 Esi : 0xffffffff
+0x05c Ebx : 0x7ffd8000
+0x060 Ebp : 0x12fff0
+0x064 ErrCode : 0
+0x068 Eip : 0x421480
+0x06c SegCs : 0x1b
+0x070 EFlags : 0x246
+0x074 HardwareEsp : 0x12ffc0
+0x078 HardwareSegSs : 0x23
+0x07c V86Es : 0
+0x080 V86Ds : 0
+0x084 V86Fs : 0
+0x088 V86Gs : 0

  

  好了,先分析到这吧,明天分析KiDispatchException这个函数......困了!

                                                              01:08:21

  

  

 

Int 1的实现过程 (一)的更多相关文章

  1. 【系统篇】从int 3探索Windows应用程序调试原理

    探索调试器下断点的原理 在Windows上做开发的程序猿们都知道,x86架构处理器有一条特殊的指令——int 3,也就是机器码0xCC,用于调试所用,当程序执行到int 3的时候会中断到调试器,如果程 ...

  2. 关于int指令

    1.关于int指令 格式:int n     n为中断类型码: 作用:     调用n号中断程序:   指令“int n”的执行过程:     1]获取中断类型码n     2]标志寄存器入栈,IF. ...

  3. 七种机器内部排序的原理与C语言实现,并计算它们的比较次数与移动次数。

    内部排序是指待排序列完全存放在内存中所进行的排序过程,适合不太大的元素序列. 排序是计算机程序设计中的一种重要操作,其功能是对一个数据元素集合或序列重新排列成一个按数据元素某个相知有序的序列.排序分为 ...

  4. php的mysql\mysqli\PDO(二)mysqli

    原文链接:http://www.orlion.ga/1147/ mysqli有面向对象风格和面向过程风格,个人感觉还是用面向对象风格比较好(毕竟是面向对象) 1.mysqli::_construct( ...

  5. 基本概念----Beginning Visual C#

    更多相关文章,见本人的个人主页:zhongxiewei.com 变量 注释方式:// 注释在这里和/* 注释在这里 */ 整形变量的类型: Type Alias for Allowed Values ...

  6. .NET基础面试题整理

    1.什么是.NET?什么是CLI?什么是CLR?IL是什么?   (1).net用于代码编译和执行的集成托管环境,换句话,它管理应用程序运行的方方面面,包括首次运行的编译,为程序分配内存存储数据和指令 ...

  7. JAVA学习笔记(1-32)

    1:数据的输入中,也需要提前声明变量.java区分大小写,注意保留字的问题,注意分号. 2:用import调用一个类.用new新建一个对象,相当于c中的malloc. 3:用final定义一个宏,相当 ...

  8. Java语法糖2:自动装箱和自动拆箱

    前言 一开始想学学自动拆箱和自动装箱是被这个名字吸引到,听上去好像很高端的样子,其实自动拆箱.自动装箱是很简单的内容. 自动拆箱和自动装箱 Java为每种基本数据类型都提供了对应的包装器类型.举个例子 ...

  9. Java总结篇系列:类型转换/造型

    Java中,经常可以遇到类型转换的场景,从变量的定义到复制.数值变量的计算到方法的参数传递.基类与派生类间的造型等,随处可见类型转换的身影.Java中的类型转换在Java编码中具有重要的作用.首先,来 ...

随机推荐

  1. python set dict tuple and list

    1 set 1.1 不变集合,frozenset 也就是说,集合中的元素不能删除,也不能增加. 1.2 两个集合之间的关系 isdisjoint()函数. 2 各个数据结构的不同显示 2.1 set ...

  2. java语法基础(一)

    这个是自己前两年做java视频教程时候的课件.感兴趣的同学可以参考下. 这里是纯粹的语法行总结. editplus的使用 选择项目目录 打开editplus 左侧目录导航栏 可以打开盘符,文件夹 可以 ...

  3. mac下Android Studio干净卸载

    1.卸载Android Studio,在终端(terminal)执行以下命令: rm -Rf /Applications/Android\ Studio.app rm -Rf ~/Library/Pr ...

  4. BZOJ_4459_[Jsoi2013]丢番图_数学+分解质因数

    BZOJ_4459_[Jsoi2013]丢番图_数学+分解质因数 Description 丢番图是亚历山大时期埃及著名的数学家.他是最早研究整数系数不定方程的数学家之一. 为了纪念他,这些方程一般被称 ...

  5. java如何遍历map的所有的元素(各种方法)

    JDK1.4中 Map map = new HashMap(); Iterator it = map.entrySet().iterator(); while (it.hasNext()) { Map ...

  6. 【140】◀▶ ArcGIS技巧

    目录: Add XY Data 图例修改 中文字符左斜体设置 专题图只显示“度” 制作渐变图例 待定 待定 待定 1. 在ArcGIS中插入含有经纬度的*.txt或者*.xls文件等 File> ...

  7. 10_传智播客iOS视频教程_NSString

    从今天开始不会再去用C语言当中的字符串.因为OC当中设计了一种更为好用的存储字符串的变量. C的字符串和OC的字符串是有区别的. NSString类型的指针变量,只能存储OC字符串的地址.第一步是声明 ...

  8. EF7学习资料整理

    EntityFramework 7 开发纪录 http://www.cnblogs.com/xishuai/archive/2014/11/28/ef7-develop-note.html Entit ...

  9. LUR和缺页次数

    缺页:缺页中断就是要访问的页不在主存,需要操作系统将其调入主存后再进行访问. LRU(Least recently used)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问 ...

  10. bzoj 4184: shallot【线性基+时间线段树】

    学到了线段树新姿势! 先离线读入,根据时间建一棵线段树,每个节点上开一个vector存这个区间内存在的数(使用map来记录每个数出现的一段时间),然后在线段树上dfs,到叶子节点就计算答案. 注意!! ...