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
  • 相关阅读:
    阿里妈妈MaxCompute架构演进_-_AON(MPI)集群
    阿里云ECS部署Grafana接入zabbix
    ECS实例RAM角色实践
    上海云栖—人工智能-视觉计算专场预热
    阿里云论坛版主制作最新教程汇总贴
    移动相关的css
    GULP入门(一)
    mongodb+nodejs 增删查的demo
    nodejs+express 初学(三)
    nodejs+express 初学(二)
  • 原文地址:https://www.cnblogs.com/vcerror/p/4289169.html
Copyright © 2011-2022 走看看