无聊之中拿起情景分析书看看....顺便做下笔记加深下印象
1.  从用户态跳转到内核态一般有三种方式:中断,异常,和自陷,除了这些还有调用门啦,快速系统调用啦什么的
2.  传统的windows是调用int 0x2e来切换到内核态的。从TSS中装入本线程的系统空间堆栈寄存器SS和堆栈指针ESP,在把用户空间的堆栈寄存器SS,堆栈指针ESP,标志位寄存器EFLAGS,代码段寄存器CS,EIP压入用户系统空间的堆栈;然后从IDT中以0x2e为索引找到相应的程序入口开始执行内核程序。返回就是上述逆过程
3.  快速系统调用sysenter指令实现。配套了3个寄存器。SYSENTER_CS_MSR,SYSENTER_EIP_MSR,SYSENTER_ESP_MSR。
SYSENTER_CS_MSR内容复制到段寄存器CS中
SYSENTER_EIP_MSR内容复制到寄存器EIP中
SYSENTER_CS_MSR内容+8写入堆栈段寄存器SS
SYSENTER_ESP_MSR的内容复制到堆栈指针ESP中
这3个寄存器的内容是在内核初始化的时候赋值的
SYSENTER_CS_MSR :Ke386Wrmsr(0x174,KGDT_R0_CODE,0);
SYSENTER_ESP_MSR:Ke386Wrmsr(0x175,(ULONG)KeGetCurrentPrcb->DpcStack,0);
SYSENTER_EIP_MSR:Ke386Wrmsr(0x176,(ULONG)KiFastCallEntry,0);
第3个参数为0,是意味着这3个寄存器为32位的。SYSENTER_CS_MSR被设置成KGDT_R0_CODE即0x8,设置堆栈段寄存器ss的就是0x10,就是KGDT_R0_DATA。
SYSENTER_ESP_MSR设置成PRCB中指针DpcStack的内容.这个是指向一个中立的不属于任何一个线程的堆栈,供内核执行DPC函数的使用的. SYSENTER_EIP_MSR设置成指向KiFastCallEntry,这是系统空间中快速调用的总入口
4.  执行sysexit退出时:
将CS设置成SYSENTER_CS_MSR的内容+16,就是KGDT_R3_CODE
把寄存器EDX的内容复制到EIP
把SS设置成SYSENTER_CS_MSR的内容+24,就是KGDT_R3_DATA
把寄存器ECX的内容复制到ESP


以ZwReadFile为例
nt!ZwReadFile:
804ffbf4 b8b7000000      mov     eax,0B7h//功能号
804ffbf9 8d542404        lea     edx,[esp+4]//参数的开始位置
804ffbfd 9c              pushfd//标志寄存器
804ffbfe 6a08            push    8//KGDT_R0_CODE
804ffc00 e88ce80300      call    nt!KiSystemService (8053e491)
804ffc05 c22400          ret     24h//9个参数,4*9


Call  8053e491进入这个函数后
Cpu自动压入以下信息:
用户空间的堆栈位置,包括堆栈段寄存器ss和堆栈指针esp的内容
Cpu中的标志寄存器EFLAGS的内容
用户空间的指令位置,包括代码段寄存器cs和指令指针eip的内容

当用户空间进入到系统空间时,cpu自动根据TR的指引从TSS中获取当前进程的SS和ESP两个寄存器的值,根据TR的指引从TSS获取当前线程的系统空间堆栈,再把好几个寄存器的内容压入这个堆栈,并且根据IDTR的指引从中断向量表中获取CS和EIP的值。


代码:
以ZwCreateFile为例
kd> t
nt!KiSystemService:
8053e491 6a00            push    0
//这个PUSH  0只是在堆栈中占一个位置,返回用户空间时其内容将被设置成寄存器eax中作为系统调用的返回值,就是出错代码。先设置成0,假设正常,还有一个方面是为了保持自陷和异常进入内核时的框架是一样的
kd> t
nt!KiSystemService+0x2:
8053e493 55              push    ebp
kd> r
eax=00000025 ebx=e108b890 ecx=0000002e edx=f66b4bbc esi=00000000 edi=f66b4c70
eip=8053e493 esp=f66b4ba8 ebp=f66b4c20 iopl=0         nv up ei pl zr na pe nc
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00000246
nt!KiSystemService+0x2:
8053e493 55              push    ebp
kd> t
nt!KiSystemService+0x3:
8053e494 53              push    ebx
kd> t
nt!KiSystemService+0x4:
8053e495 56              push    esi
kd> t
nt!KiSystemService+0x5:
8053e496 57              push    edi
kd> t
nt!KiSystemService+0x6:
8053e497 0fa0            push    fs//保存寄存器
kd> t
nt!KiSystemService+0x8:
8053e499 bb30000000      mov     ebx,30h//KGDT_R0_PCR=0x30
//windows内核有个特殊的要求,只要cpu在内核中运行,段寄存器fs就必须指向一个KPCR的结构。kd> t
nt!KiSystemService+0xd:
8053e49e 668ee3          mov     fs,bx
kd> r
eax=00000025 ebx=00000030 ecx=0000002e edx=f66b4bbc esi=00000000 edi=f66b4c70
eip=8053e49e esp=f66b4b94 ebp=f66b4c20 iopl=0         nv up ei pl zr na pe nc
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00000246
nt!KiSystemService+0xd:
8053e49e 668ee3          mov     fs,bx//是FS段的起点与KPCR数据结构对齐
kd> t
nt!KiSystemService+0x10:
8053e4a1 ff3500f0dfff    push    dword ptr ds:[0FFDFF000h]//保存当前ECCEPTIONLIST
kd> t
nt!KiSystemService+0x16:
8053e4a7 c70500f0dfffffffffff mov dword ptr ds:[0FFDFF000h],0FFFFFFFFh//新的EXCEPTIONLIST为空白
nt!KiSystemService+0x20:
8053e4b1 8b3524f1dfff    mov     esi,dword ptr ds:[0FFDFF124h]//使ESI指向当前进程的KTHREAD结构
kd> t
nt!KiSystemService+0x26:
8053e4b7 ffb640010000    push    dword ptr [esi+140h]//保存老的先前模式,可能是用户模式或者内核模式
kd> t
nt!KiSystemService+0x2c:
8053e4bd 83ec48          sub     esp,48h//跳过其他寄存器,目的是为包括寄存器其他段寄存器暂存在空间kd> t
nt!KiSystemService+0x2f:
8053e4c0 8b5c246c        mov     ebx,dword ptr [esp+6Ch]//
kd> r
eax=00000025 ebx=00000030 ecx=0000002e edx=f66b4bbc esi=823c3da8 edi=f66b4c70
eip=8053e4c0 esp=f66b4b44 ebp=f66b4c20 iopl=0         nv up ei ng nz na pe nc
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00000286
nt!KiSystemService+0x2f:
8053e4c0 8b5c246c        mov     ebx,dword ptr [esp+6Ch] ss:0010:f66b4bb0=00000008//[esp+6Ch]就是进入这个call之前的cs值
nt!KiSystemService+0x33:
8053e4c4 83e301          and     ebx,1//为1001了,0环的最低位为0,3环的为1
nt!KiSystemService+0x36:
8053e4c7 889e40010000    mov     byte ptr [esi+140h],bl//设置新的模式,此时为r3模式
nt!KiSystemService+0x3c:
8053e4cd 8bec            mov     ebp,esp
kd> t
nt!KiSystemService+0x3e:
8053e4cf 8b9e34010000    mov     ebx,dword ptr [esi+134h]//KTHREAD结构中的指针TrapFrame
kd> t
nt!KiSystemService+0x44:
8053e4d5 895d3c          mov     dword ptr [ebp+3Ch],ebx。//暂时保存下
nt!KiSystemService+0x47:
8053e4d8 89ae34010000    mov     dword ptr [esi+134h],ebp//设置新的TrapFrame,指向堆栈上的框架
kd> t
nt!KiSystemService+0x4d:
8053e4de fc              cld
kd> t
nt!KiSystemService+0x4e:
8053e4df 8b5d60          mov     ebx,dword ptr [ebp+60h]
nt!KiSystemService+0x51:
8053e4e2 8b7d68          mov     edi,dword ptr [ebp+68h]
kd> t
nt!KiSystemService+0x54:
8053e4e5 89550c          mov     dword ptr [ebp+0Ch],edx//edx中时参数的位置kd> t
nt!KiSystemService+0x57:
8053e4e8 c74508000ddbba  mov     dword ptr [ebp+8],0BADB0D00h
kd> t
nt!KiSystemService+0x5e:
8053e4ef 895d00          mov     dword ptr [ebp],ebx
kd> t
nt!KiSystemService+0x61:
8053e4f2 897d04          mov     dword ptr [ebp+4],edi
kd> t
nt!KiSystemService+0x64:
8053e4f5 f6462cff        test    byte ptr [esi+2Ch],0FFh//检查线程是否被调试kd> t
nt!KiSystemService+0x68:
8053e4f9 0f858dfeffff    jne     nt!Dr_kss_a (8053e38c)
kd> t
nt!KiSystemService+0x6e:
8053e4ff fb              sti//开中断

nt!KiSystemService+0x6f:
8053e500 e9d8000000      jmp     nt!KiFastCallEntry+0x8d (8053e5dd)

………………………..
系统调用函数的跳转kd> t
nt!KiFastCallEntry+0x8d:
8053e5dd 8bf8            mov     edi,eax//eax为系统调用号
kd> r
eax=00000025 ebx=f66b4c20 ecx=0000002e edx=f66b4bbc esi=823c3da8 edi=804ff09d
eip=8053e5dd esp=f66b4b44 ebp=f66b4b44 iopl=0         nv up ei pl zr na pe nc
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00000246
nt!KiFastCallEntry+0x8d:
8053e5dd 8bf8            mov     edi,eax
kd> p
nt!KiFastCallEntry+0x8f:
8053e5df c1ef08          shr     edi,8//SERVICE_TABLE_SHIFT,除以256
kd> p
nt!KiFastCallEntry+0x92:
8053e5e2 83e730          and     edi,30h//SERVICE_TABLE_MASK
kd> p
nt!KiFastCallEntry+0x95:
8053e5e5 8bcf            mov     ecx,edi//下面将比较ecx
kd> p
nt!KiFastCallEntry+0x97:
8053e5e7 03bee0000000    add     edi,dword ptr [esi+0E0h]//该线程的系统调用表
kd> p
nt!KiFastCallEntry+0x9d:
8053e5ed 8bd8            mov     ebx,eax//eax系统调用号
kd> p
nt!KiFastCallEntry+0x9f:
8053e5ef 25ff0f0000      and     eax,0FFFh//
kd> p
nt!KiFastCallEntry+0xa4:
8053e5f4 3b4708          cmp     eax,dword ptr [edi+8]//检查系统调用号是否越界
kd> p
nt!KiFastCallEntry+0xa7:
8053e5f7 0f8345fdffff    jae     nt!KiBBTUnexpectedRange (8053e342)//大于越界尝试去加载shadow 表
kd> p
nt!KiFastCallEntry+0xad:
8053e5fd 83f910          cmp     ecx,10h//检查是否是win32表
kd> p
nt!KiFastCallEntry+0xb0:
8053e600 751a            jne     nt!KiFastCallEntry+0xcc (8053e61c)//不是的
//这一段是使用win32k系统的调用表的
8053e602 8b0d18f0dfff    mov     ecx,dword ptr ds:[0FFDFF018h]
8053e608 33db            xor     ebx,ebx
8053e60a 0b99700f0000    or      ebx,dword ptr [ecx+0F70h]
8053e610 740a            je      nt!KiFastCallEntry+0xcc (8053e61c)
8053e612 52              push    edx
8053e613 50              push    eax
8053e614 ff1564405580    call    dword ptr [nt!KeGdiFlushUserBatch (80554064)]
8053e61a 58              pop     eax
8053e61b 5a              pop     edx
//
kd> p
nt!KiFastCallEntry+0xcc:
8053e61c ff0538f6dfff    inc     dword ptr ds:[0FFDFF638h]//增加syscall的数目(系统调用计数)
kd> p
nt!KiFastCallEntry+0xd2:
8053e622 8bf2            mov     esi,edx//esi指向用户空间堆栈上的参数块
kd> p
nt!KiFastCallEntry+0xd4:
8053e624 8b5f0c          mov     ebx,dword ptr [edi+0Ch]//参数表
kd> p
nt!KiFastCallEntry+0xd7:
8053e627 33c9            xor     ecx,ecx
kd> p
nt!KiFastCallEntry+0xd9:
8053e629 8a0c18          mov     cl,byte ptr [eax+ebx]
kd> p
nt!KiFastCallEntry+0xdc:
8053e62c 8b3f            mov     edi,dword ptr [edi]//edi指向系统调用表
kd> p
nt!KiFastCallEntry+0xde:
8053e62e 8b1c87          mov     ebx,dword ptr [edi+eax*4]//定位到具体的调用函数
kd> p
nt!KiFastCallEntry+0xe1:
8053e631 2be1            sub     esp,ecx //分配系统空间堆栈
kd> p
nt!KiFastCallEntry+0xe3:
8053e633 c1e902          shr     ecx,2//除以4,参数个数
kd> p
nt!KiFastCallEntry+0xe6:
8053e636 8bfc            mov     edi,esp
kd> p
nt!KiFastCallEntry+0xe8:
8053e638 3b35549a5580    cmp     esi,dword ptr [nt!MmUserProbeAddress (80559a54)]//是否在用户模式地址上
kd> p
nt!KiFastCallEntry+0xee:
8053e63e 0f83a8010000    jae     nt!KiSystemCallExit2+0x9f (8053e7ec)//大于的话进行访问检查
8053e644 f3a5            rep movs dword ptr es:[edi],dword ptr [esi]////拷贝参数
8053e646 ffd3            call    ebx   //call这个目标函数//下面的是开始系统调用的返回过程了
8053e648 8be5            mov     esp,ebp//回到系统调用的框架
8053e64a 8b0d24f1dfff    mov     ecx,dword ptr ds:[0FFDFF124h]//ecx指向当前线程的kthread
8053e650 8b553c          mov     edx,dword ptr [ebp+3Ch]//取出保存着的框架指针
8053e653 899134010000    mov     dword ptr [ecx+134h],edx//恢复kthread结构中的框架指针
nt!KiServiceExit:
8053e659 fa              cli//关中断呗
8053e65a f7457000000200  test    dword ptr [ebp+70h],20000h//检查是否有apc请求
8053e661 7506            jne     nt!KiServiceExit+0x10 (8053e669),有的话就去处理apc请求
8053e663 f6456c01        test    byte ptr [ebp+6Ch],1//如果先前模式是内核模式的话就不递交apc
8053e667 7457            je      nt!KiServiceExit+0x67 (8053e6c0)
//这一段式处理apc的过程
8053e669 8b1d24f1dfff    mov     ebx,dword ptr ds:[0FFDFF124h]是ebx指向当前线程的kthread结构
8053e66f c6432e00        mov     byte ptr [ebx+2Eh],0
8053e673 807b4a00        cmp     byte ptr [ebx+4Ah],0
8053e677 7447            je      nt!KiServiceExit+0x67 (8053e6c0)
8053e679 8bdd            mov     ebx,ebp
8053e67b 894344          mov     dword ptr [ebx+44h],eax
8053e67e c743503b000000  mov     dword ptr [ebx+50h],3Bh
8053e685 c7433823000000  mov     dword ptr [ebx+38h],23h
8053e68c c7433423000000  mov     dword ptr [ebx+34h],23h
8053e693 c7433000000000  mov     dword ptr [ebx+30h],0
8053e69a b901000000      mov     ecx,1
8053e69f ff15f4864d80    call    dword ptr [nt!_imp_KfRaiseIrql (804d86f4)]
8053e6a5 50              push    eax
8053e6a6 fb              sti
8053e6a7 53              push    ebx
8053e6a8 6a00            push    0
8053e6aa 6a01            push    1
8053e6ac e88d03fcff      call    nt!KiDeliverApc (804fea3e)
8053e6b1 59              pop     ecx
8053e6b2 ff151c874d80    call    dword ptr [nt!_imp_KfLowerIrql (804d871c)]
8053e6b8 8b4344          mov     eax,dword ptr [ebx+44h]
8053e6bb fa              cli
8053e6bc ebab            jmp     nt!KiServiceExit+0x10 (8053e669)
8053e6be 8bff            mov     edi,edi
::::::::::::::::::::::::::::::::::::::
8053e6c0 8b54244c        mov     edx,dword ptr [esp+4Ch]
8053e6c4 648b1d50000000  mov     ebx,dword ptr fs:[50h]
8053e6cb 64891500000000  mov     dword ptr fs:[0],edx
8053e6d2 8b4c2448        mov     ecx,dword ptr [esp+48h]
8053e6d6 648b3524010000  mov     esi,dword ptr fs:[124h]
8053e6dd 888e40010000    mov     byte ptr [esi+140h],cl
8053e6e3 f7c3ff000000    test    ebx,0FFh
8053e6e9 7579            jne     nt!KiSystemCallExit2+0x17 (8053e764)
8053e6eb f744247000000200 test    dword ptr [esp+70h],20000h
8053e6f3 0f85eb080000    jne     nt!KiExceptionExit+0x12c (8053efe4)
8053e6f9 66f744246cf8ff  test    word ptr [esp+6Ch],0FFF8h
8053e700 0f84b4000000    je      nt!KiSystemCallExit2+0x6d (8053e7ba)
8053e706 66837c246c1b    cmp     word ptr [esp+6Ch],1Bh
8053e70c 660fba64246c00  bt      word ptr [esp+6Ch],0
8053e713 f5              cmc
8053e714 0f878e000000    ja      nt!KiSystemCallExit2+0x5b (8053e7a8)
8053e71a 66837d6c08      cmp     word ptr [ebp+6Ch],8
8053e71f 7405            je      nt!KiServiceExit+0xcd (8053e726)
8053e721 8d6550          lea     esp,[ebp+50h]
8053e724 0fa1            pop     fs
8053e726 8d6554          lea     esp,[ebp+54h]
8053e729 5f              pop     edi
8053e72a 5e              pop     esi
8053e72b 5b              pop     ebx
8053e72c 5d              pop     ebp
8053e72d 66817c24088000  cmp     word ptr [esp+8],80h
8053e734 0f87c6080000    ja      nt!KiExceptionExit+0x148 (8053f000)
8053e73a 83c404          add     esp,4
8053e73d f744240401000000 test    dword ptr [esp+4],1
nt!KiSystemCallExitBranch:
8053e745 7506            jne     nt!KiSystemCallExit2 (8053e74d)//从用户空间的系统调用,使用KiSystemCallExit2

8053e747 5a              pop     edx//从内核空间发起的调用
8053e748 59              pop     ecx
8053e749 9d              popfd
8053e74a ffe2            jmp     edx//跳转到调用KsystemServices()时的返回地址
nt!KiSystemCallExit:
8053e74c cf              iretd
nt!KiSystemCallExit2:
8053e74d f644240901      test    byte ptr [esp+9],1//检查是否是通过自陷指令进入内核的
8053e752 75f8            jne     nt!KiSystemCallExit (8053e74c)
//通过自陷指令进入的,调用sysexit离开  
8053e754 5a              pop     edx//新的EIP
8053e755 83c404          add     esp,4//跳过r3 DS
8053e758 80642401fd      and     byte ptr [esp+1],0FDh恢复EFLAGS_INTERRUPT_MASK
8053e75d 9d              popfd
8053e75e 59              pop     ecx //R3下SS:ESP
8053e75f fb              sti
8053e760 0f35            sysexit
8053e762 cf              iretd
饿,世界杯快开始了,开世界杯了哦