zoukankan      html  css  js  c++  java
  • 对XP上的KiFastSystemCall进行浅析

    Windows API的系统调用过程通过KiFastSystemCall或int 2e进入内核,本文仅对XP上的KiFastSystemCall进行浅析。
      以ntdll!ZwCreateProcessEx为例:
    名称:  1.png查看次数: 1文件大小:  5.0 KB
      Eax中保存系统调用号,此处ZwCreateProcessEx的为30h;Edx是SharedUserData!SystemCallStub的地址,里面保存着KiFastSystemCall的地址。SharedUserData总是存放在0x7ffe0000处,其偏移0x300处正是SystemCall。
    名称:  2.png查看次数: 0文件大小:  6.9 KB
    名称:  3.png查看次数: 0文件大小:  2.3 KB
      证实下0x7ffe0300处是否真保存着KiFastSystemCall的地址:
    名称:  4.png查看次数: 0文件大小:  4.3 KB
      Sysenter时eax中保存着系统调用号,edx中保存着用户空间线程栈栈顶地址即保存着ZwCreateProcessEx中call KiFastSystemCall的返回地址,那么edx+4保存着call ZwCreateProcessEx的返回地址,edx+8为ZwCreateProcessEx的第一个参数,以此类推。
      Sysenter将会从MSR寄存器组中加载cs:eip和ss:esp令cs=IA32_SYSENTER_CS、eip=IA32_SYSENTER_EIP、ss=IA32_SYSENTER_CS+8、esp=IA32_SYSENTER_ESP,这些值均在系统初始化时固定下来。
    代码:
    0: kd> u 7c92e514
    ntdll!KiFastSystemCallRet:
    7c92e514 c3              ret    ; 与call dword ptr [edx]相对应
    
    lkd> rdmsr 174
    msr[174] = 00000000`00000008  ; cs=0x0008 ss=0x0010
    lkd> rdmsr 175
    msr[175] = 00000000`f78b3000  ; esp=0xf78b3000 DPC Stack
    lkd> rdmsr 176
    msr[176] = 00000000`804de89f  ; eip=0x804de89f KiFastCallEntry
    sysenter切换堆栈时是从用户栈切换到DPC栈,这是因为MSR寄存器中的值是操作系统安排好的固定的值,它与具体的线程上下文无关,所以需要在DPC栈中再切换到线程的内核栈。
    
    nt!KiFastCallEntry:
    804de89f b923000000      mov     ecx,23h  ; KGDT_R3_DATA 0x23 = 0x20 + 011b(CPL Ring3)
    804de8a4 6a30            push    30h    ; KGDT_R0_PCR  0x30 = 0x30 + 000b(CPL Ring0), DPC Stack
    804de8a6 0fa1            pop     fs      ; DPC Stack
    804de8a8 8ed9            mov     ds,cx
    804de8aa 8ec1            mov     es,cx
    804de8ac 648b0d40000000  mov     ecx,dword ptr fs:[40h]    ; fs Base:ffdff000 Limit:1fff Data RW, KPCR 0x40处为TSS Ptr32 _KTSS
    804de8b3 8b6104          mov     esp,dword ptr [ecx+4]    ; KTSS 0x4处为Esp0 Uint4B, Ring0下的esp
    804de8b6 6a23            push    23h      ; 此时已在内核堆栈, Ring3下的ss, KTRAP_FRAME.HardwareSegSs
    804de8b8 52              push    edx      ; Ring3下的esp, KTRAP_FRAME.HardwareEsp
    804de8b9 9c              pushfd    ; eflags  ; KTRAP_FRAME.EFlags
    804de8ba 6a02            push    2
    804de8bc 83c208          add     edx,8          ; Ring3堆栈的参数
    804de8bf 9d              popfd              ; 初始eflags为2, 即各位清零
    804de8c0 804c240102      or      byte ptr [esp+1],2    ; 4字节eflags第二个字节的IF中断允许位置1
    804de8c5 6a1b            push    1Bh          ; KGDT_R3_CODE 0x1B = 0x18 + 011b(CPL Ring3), KTRAP_FRAME.SegCs
    804de8c7 ff350403dfff    push    dword ptr ds:[0FFDF0304h]    ; KTRAP_FRAME.EIP, 0x7ffe0000与0xffdf000映射到同一块物理内存, 0xffdf0304处存放的是KiFastSystemCallRet
    804de8cd 6a00            push    0    ; KTRAP_FRAME.ErrCode
    ; 以下四个寄存器从Ring3到Ring0没修改过, 直接保存
    804de8cf 55              push    ebp  ; KTRAP_FRAME.Ebp
    804de8d0 53              push    ebx  ; KTRAP_FRAME.Ebx
    804de8d1 56              push    esi  ; KTRAP_FRAME.Esi
    804de8d2 57              push    edi  ; KTRAP_FRAME.Edi
    804de8d3 648b1d1c000000  mov     ebx,dword ptr fs:[1Ch]    ; 指向自己的指针, 头部即是TIB
    804de8da 6a3b            push    3Bh  ; KTRAP_FRAME.SegFs, fs Base:00000000 Limit:fff Data RW, Ring3
    804de8dc 8bb324010000    mov     esi,dword ptr [ebx+124h]  ; KPCR.SelfPcr->PrcbData.CurrentThead Ptr32 _KTHREAD
    804de8e2 ff33            push    dword ptr [ebx]      ; KTRAP_FRAME.ExceptionList, TIB的头部即是ExceptionList
    804de8e4 c703ffffffff    mov     dword ptr [ebx],0FFFFFFFFh
    804de8ea 8b6e18          mov     ebp,dword ptr [esi+18h]  ; KTHREAD.InitialStack Ptr32 Void
    804de8ed 6a01            push    1    ; KTRAP_FRAME.PreviousPreviousMode
    804de8ef 83ec48          sub     esp,48h    ; 预留KTRAP_FRAME中Eax到DbgEbp的空间
    804de8f2 81ed9c020000    sub     ebp,29Ch    ; ...
    804de8f8 c6864001000001  mov     byte ptr [esi+140h],1    ; KTHREAD.PreviousMode
    804de8ff 3bec            cmp     ebp,esp
    804de901 0f8565ffffff    jne     nt!KiFastCallEntry2+0x25 (804de86c)
    804de907 83652c00        and     dword ptr [ebp+2Ch],0    ; KTRAP_FRAME第12个(0x2C/4+1)参数Dr7
    804de90b f6462cff        test    byte ptr [esi+2Ch],0FFh  ; KTHREAD.DebugActive
    804de90f 89ae34010000    mov     dword ptr [esi+134h],ebp  ; KTHREAD.TrapFrame Ptr32 _KTRAP_FRAME
    804de915 0f8535feffff    jne     nt!Dr_FastCallDrSave (804de750)  ; if(KTHREAD.DebugActive != 0) ...
    804de91b 8b5d60          mov     ebx,dword ptr [ebp+60h]
    804de91e 8b7d68          mov     edi,dword ptr [ebp+68h]
    804de921 89550c          mov     dword ptr [ebp+0Ch],edx    ; 将Ring3参数地址赋给KTRAP_FRAME.DbgArgPointer
    804de924 c74508000ddbba  mov     dword ptr [ebp+8],0BADB0D00h  ; KTRAP_FRAME.DbgArgMark = 0xBADB0D00
    804de92b 895d00          mov     dword ptr [ebp],ebx      ; KTRAP_FRAME.DbgEbp = KTRAP_FRAME.Ebp
    804de92e 897d04          mov     dword ptr [ebp+4],edi      ; KTRAP_FRAME.DbgEip = KTRAP_FRAME.Eip
    804de931 fb              sti
    ; 当调用KeServiceDescriptorTableShadow中的系统服务时, eax是系统调用号再加0x1000
    804de932 8bf8            mov     edi,eax
    804de934 c1ef08          shr     edi,8
    804de937 83e730          and     edi,30h
    804de93a 8bcf            mov     ecx,edi
    ; 经过以上4条指令后, 若ecx为0则为调用KeServiceDescriptorTable中的系统服务, 否则ecx为0x10调用KeServiceDescriptorTableShadow中的系统服务
    804de93c 03bee0000000    add     edi,dword ptr [esi+0E0h]    ; edi = KTHREAD.ServiceTable + 0x00或0x10
    804de942 8bd8            mov     ebx,eax
    804de944 25ff0f0000      and     eax,0FFFh    ; 系统调用号
    804de949 3b4708          cmp     eax,dword ptr [edi+8]    ; 系统调用号必须小于系统服务数
    804de94c 0f8330fdffff    jae     nt!KiBBTUnexpectedRange (804de682)  ; ...
    804de952 83f910          cmp     ecx,10h
    804de955 751b            jne     nt!KiFastCallEntry+0xcf (804de972)    ; KeServiceDescriptorTable
    804de957 648b0d18000000  mov     ecx,dword ptr fs:[18h]    ; _NT_TIB地址, 这里也是_TEB的地址了?
    804de95e 33db            xor     ebx,ebx
    804de960 0b99700f0000    or      ebx,dword ptr [ecx+0F70h]  ; TEB.GdiBatchCount
    804de966 740a            je      nt!KiFastCallEntry+0xcf (804de972)    ; KeServiceDescriptorTable
    804de968 52              push    edx  ; Ring3参数地址
    804de969 50              push    eax  ; 系统调用号
    804de96a ff1568355680    call    dword ptr [nt!KeGdiFlushUserBatch (80563568)]
    804de970 58              pop     eax
    804de971 5a              pop     edx
    804de972 64ff0538060000  inc     dword ptr fs:[638h]    ; KeServiceDescriptorTable直接跳转到这来, ++KPCR.KPRCB.KeSystemCalls
    804de979 8bf2            mov     esi,edx
    804de97b 8b5f0c          mov     ebx,dword ptr [edi+0Ch]  ; SSDT参数表的地址
    804de97e 33c9            xor     ecx,ecx
    804de980 8a0c18          mov     cl,byte ptr [eax+ebx]    ; 该系统调用的参数个数
    804de983 8b3f            mov     edi,dword ptr [edi]    ; 系统服务表地址
    804de985 8b1c87          mov     ebx,dword ptr [edi+eax*4]  ; 该系统服务地址
    804de988 2be1            sub     esp,ecx  ; 在内核栈中分配参数空间
    804de98a c1e902          shr     ecx,2    ; 参数以DWORD大小拷贝
    804de98d 8bfc            mov     edi,esp
    804de98f 3b35d48e5680    cmp     esi,dword ptr [nt!MmUserProbeAddress (80568ed4)]
    804de995 0f83a8010000    jae     nt!KiSystemCallExit2+0x9f (804deb43)    ; 若参数地址超过用户空间地址(0x7fff0000)
    804de99b f3a5            rep movs dword ptr es:[edi],dword ptr [esi]
    804de99d ffd3            call    ebx    ; 调用!
    804de99f 8be5            mov     esp,ebp  ; 恢复堆栈到只有KTRAP_FRAME时
    804de9a1 648b0d24010000  mov     ecx,dword ptr fs:[124h]
    804de9a8 8b553c          mov     edx,dword ptr [ebp+3Ch]
    804de9ab 899134010000    mov     dword ptr [ecx+134h],edx    ; KPCR.KPRCB.CurrentThread->TrapFrame = KTRAP_FRAME.Edx
    
    nt!KiServiceExit:
    804de9b1 fa              cli
    804de9b2 f7457000000200  test    dword ptr [ebp+70h],20000h        ; eflags是否是Virtual-8086 Mode
    804de9b9 7506            jne     nt!KiServiceExit+0x10 (804de9c1)    ; 非Virtual-8086 Mode则跳
    804de9bb f6456c01        test    byte ptr [ebp+6Ch],1
    804de9bf 7456            je      nt!KiServiceExit+0x66 (804dea17)    ; KTRAP_FRAME.SegCs, CPL为Ring0则跳
    804de9c1 648b1d24010000  mov     ebx,dword ptr fs:[124h]        ; 非Virtual-8086 Mode, 以及下面的交付APC, 跳到这来
    804de9c8 c6432e00        mov     byte ptr [ebx+2Eh],0          ; KPCR.KPRCB.CurrentThread->Alerted = 0
    804de9cc 807b4a00        cmp     byte ptr [ebx+4Ah],0
    804de9d0 7445            je      nt!KiServiceExit+0x66 (804dea17)    ; if(KPCR.KPRCB.CurrentThread->ApcState.UserApcPending == 0)跳
    804de9d2 8bdd            mov     ebx,ebp
    804de9d4 894344          mov     dword ptr [ebx+44h],eax    ; KTRAP_FRAME.Eax, 系统调用号
    804de9d7 c743503b000000  mov     dword ptr [ebx+50h],3Bh    ; KTRAP_FRAME.SegFs = 0x3B
    804de9de c7433823000000  mov     dword ptr [ebx+38h],23h    ; KTRAP_FRAME.SegDs = KGDT_R3_DATA
    804de9e5 c7433423000000  mov     dword ptr [ebx+34h],23h    ; KTRAP_FRAME.SegEs = KGDT_R3_DATA
    804de9ec c7433000000000  mov     dword ptr [ebx+30h],0      ; KTRAP_FRAME.SegGs = 0
    804de9f3 b901000000      mov     ecx,1
    804de9f8 ff152c904d80    call    dword ptr [nt!_imp_KfRaiseIrql (804d902c)]    ; 提升IRQL
    804de9fe 50              push    eax
    804de9ff fb              sti
    804dea00 53              push    ebx  ; PKTRAP_FRAME
    804dea01 6a00            push    0    ; Reserved
    804dea03 6a01            push    1    ; UserMode
    804dea05 e8f7f3ffff      call    nt!KiDeliverApc (804dde01)    ; 交付APC
    804dea0a 59              pop     ecx  ; 原来的IRQL
    804dea0b ff1530904d80    call    dword ptr [nt!_imp_KfLowerIrql (804d9030)]    ; 降回原来的IRQL
    804dea11 8b4344          mov     eax,dword ptr [ebx+44h]    ; 赋回系统调用号
    804dea14 fa              cli
    804dea15 ebaa            jmp     nt!KiServiceExit+0x10 (804de9c1)
    ;;;;;;;;;;;;;;;;;;;;;;;;;分割线;;;;;;;;;;;;;;;;;;;;;;;;;
    804dea17 8b54244c        mov     edx,dword ptr [esp+4Ch]    ; KTRAP_FRAME.SegCs CPL为Ring0, 以及无用户APC等待处理, 跳到这来
    804dea1b 648b1d50000000  mov     ebx,dword ptr fs:[50h]
    804dea22 64891500000000  mov     dword ptr fs:[0],edx      ; KPCR.NtTib.Exception = KTRAP_FRAME.ExceptionList
    804dea29 8b4c2448        mov     ecx,dword ptr [esp+48h]
    804dea2d 648b3524010000  mov     esi,dword ptr fs:[124h]
    804dea34 888e40010000    mov     byte ptr [esi+140h],cl      ; KPCR.KPRCB.CurrentThread->PreviousMode = KTRAP_FRAME.PreviousPreviousMode
    804dea3a f7c3ff000000    test    ebx,0FFh
    804dea40 7579            jne     nt!KiSystemCallExit2+0x17 (804deabb)    ; if(KPCR.DebugActive != 0) ...
    804dea42 f744247000000200 test    dword ptr [esp+70h],20000h
    804dea4a 0f8506090000    jne     nt!Kei386EoiHelper+0x12c (804df356)    ; 非Virtual-8086 Mode则跳
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;nt!Kei386EoiHelper+0x12c;;;;;;;;;;;;;;;;;;;;;;;;;
    nt!Kei386EoiHelper+0x12c
    804df356 83c43c          add     esp,3Ch    ; 指向KTRAP_FRAME.Edx
    804df359 5a              pop     edx
    804df35a 59              pop     ecx
    804df35b 58              pop     eax
    804df35c 8d6554          lea     esp,[ebp+54h]  ; 指向KTRAP_FRAME.Edi
    804df35f 5f              pop     edi
    804df360 5e              pop     esi
    804df361 5b              pop     ebx
    804df362 5d              pop     ebp
    804df363 66817c24088000  cmp     word ptr [esp+8],80h
    804df36a 7706            ja      nt!Kei386EoiHelper+0x148 (804df372)    ; if(KTRAP_FRAME.SegCs > 0x80), 则跳. 0x80后的GDT不能用于cs
    804df36c 83c404          add     esp,4      ; 指向KTRAP_FRAME.Eip
    804df36f cf              iretd    ; pop KTRAP_FRAME.Eip, KTRAP_FRAME.SegCs, KTRAP_FRAME.EFlags
  • 相关阅读:
    matplotlib数据可视化之柱形图
    xpath排坑记
    Leetcode 100. 相同的树
    Leetcode 173. 二叉搜索树迭代器
    Leetcode 199. 二叉树的右视图
    Leetcode 102. 二叉树的层次遍历
    Leetcode 96. 不同的二叉搜索树
    Leetcode 700. 二叉搜索树中的搜索
    Leetcode 2. Add Two Numbers
    Leetcode 235. Lowest Common Ancestor of a Binary Search Tree
  • 原文地址:https://www.cnblogs.com/vcerror/p/4289170.html
Copyright © 2011-2022 走看看