首页
社区
课程
招聘
[分享][分享]X64系统调用_下(Ring0)
2020-6-4 18:24 6864

[分享][分享]X64系统调用_下(Ring0)

2020-6-4 18:24
6864

紧接上文, 我们知道上面 NtReadVirtualMemory() 最终调用 syscall 指令进入内核, 接下来我门查看 syscall 指令的功能

syscall 指令(参考Intel白皮书)
1. 保存 R3 的 Rflags 到 R11 寄存器中, 并 & 上 ~(msr[0xC0000084])
2. 保存 syscall 指令的下一条地址到 Rcx 中
3. 替换 CS 为 msr[0xC0000081] 的中 32 ~ 48 位的数值, SS = CS+0x8
4. 替换 Rip = msr[0xC0000082]

找到 Rip 对应的地址 KiSystemCall64() 函数

启用IDA分析(注意省略了部分代码,只保留了主线流程代码)

.text:000000014007F640 KiSystemCall64  proc near               ; DATA XREF: KiInitializeBootStructures+26Eo
.text:000000014007F640
.text:000000014007F640 var_1C0         = qword ptr -1C0h
.text:000000014007F640 var_1B8         = qword ptr -1B8h
.text:000000014007F640 var_1B0         = qword ptr -1B0h
.text:000000014007F640 var_1A8         = qword ptr -1A8h
.text:000000014007F640 var_1A0         = qword ptr -1A0h
.text:000000014007F640 var_178         = byte ptr -178h
.text:000000014007F640 var_110         = byte ptr -110h
.text:000000014007F640 arg_F8          = qword ptr  100h
.text:000000014007F640
.text:000000014007F640                 swapgs                  ; 置换 GS 由TEB64变为 KPCR
.text:000000014007F643                 mov     gs:10h, rsp     ; KPCR.NtTib.StackLimit = R3Rsp
.text:000000014007F64C                 mov     rsp, gs:1A8h    ; Rsp = KPCR.Prcb.RspBase(默认指向_KTRAP_FRAME.SegSs)
.text:000000014007F655                 push    2Bh             ; KTRAP_FRAME.SegSs = 0x2B
.text:000000014007F657                 push    qword ptr gs:10h ; KTRAP_FRAME.Rsp = R3Rsp
.text:000000014007F65F                 push    r11             ; KTRAP_FRAME.EFlags = R11 = Rflags
.text:000000014007F661                 push    33h             ; KTRAP_FRAME.SegCs = 0x33
.text:000000014007F663                 push    rcx             ; KTRAP_FRAME.Rip = Syscall指令的返回地址
.text:000000014007F664                 mov     rcx, r10        ; Rcx = 函数第一个参数
.text:000000014007F667                 sub     rsp, 8          ; 跳过 KTRAP_FRAME.ErrorCode
.text:000000014007F66B                 push    rbp             ; KTRAP_FRAME.Rbp = R3Rbp
.text:000000014007F66C                 sub     rsp, 158h       ; Rsp = &KTRAP_FRAME.P1Home
.text:000000014007F673                 lea     rbp, [rsp+80h]  ; Rbp = &KTRAP_FRAME.Xmm1
.text:000000014007F67B                 mov     [rbp+0C0h], rbx ; KTRAP_FRAME.Rbx = Rbx
.text:000000014007F682                 mov     [rbp+0C8h], rdi ; KTRAP_FRAME.Rdi = Rdi
.text:000000014007F689                 mov     [rbp+0D0h], rsi ; KTRAP_FRAME.Rsi = Rsi
.text:000000014007F690                 mov     byte ptr [rbp-55h], 2 ; KTRAP_FRAME.ExceptionActive = 0x2
.text:000000014007F694                 mov     rbx, gs:188h    ; Rbx = KPCR.Prcb.CurrentThread
.text:000000014007F69D                 prefetchw byte ptr [rbx+1D8h] ; CurrentThread.TrapFrame 保存到缓存
.text:000000014007F6A4                 stmxcsr dword ptr [rbp-54h] ; 读取 KTRAP_FRAME.MxCsr
.text:000000014007F6A8                 ldmxcsr dword ptr gs:180h ; 写入到 KPCR.Prcb.MxCsr
.text:000000014007F6B1                 cmp     byte ptr [rbx+3], 0 ; CurrentThread.Header.DebugActive 是否为 0x0
.text:000000014007F6B5                 mov     word ptr [rbp+80h], 0 ; KTRAP_FRAME.Dr7 = 0x0
.text:000000014007F6BE                 jz      loc_14007F750   ; DebugActive 为 0x0 跳转, 我们这里假设没有调试跟进看看
.text:000000014007F6C4                 mov     [rbp-50h], rax  ; KTRAP_FRAME.Rax = Rax
.text:000000014007F6C8                 mov     [rbp-48h], rcx  ; KTRAP_FRAME.Rcx = Rcx
.text:000000014007F6CC                 mov     [rbp-40h], rdx  ; KTRAP_FRAME.Rdx = Rdx
.text:000000014007F6D0                 test    byte ptr [rbx+3], 3
.text:000000014007F6D4                 mov     [rbp-38h], r8   ; KTRAP_FRAME.R8 = R8
.text:000000014007F6D8                 mov     [rbp-30h], r9   ; KTRAP_FRAME.R9 = R9
.text:000000014007F6DC                 jz      short loc_14007F6E3
.text:000000014007F6DE                 call    KiSaveDebugRegisterState ; 填充调试相关信息
.text:000000014007F750 loc_14007F750:                          ; CODE XREF: KiSystemCall64+7Ej
.text:000000014007F750                 sti                     ; 可被中断
.text:000000014007F751                 mov     [rbx+1E0h], rcx ; CurrentThread.FirstArgument = 函数第一个参数
.text:000000014007F758                 mov     [rbx+1F8h], eax ; CurretnThread.SystemCallNumber = 系统服务号
.text:000000014007F75E
.text:000000014007F75E KiSystemServiceStart:                   ; DATA XREF: KiServiceInternal+5Ao
.text:000000014007F75E                                         ; .data:00000001401EE648o
.text:000000014007F75E                 mov     [rbx+1D8h], rsp ; CurrentThread.TrapFrame = Rsp(当前_KTRAP_FRAME 结构)
.text:000000014007F765                 mov     edi, eax        ; Rdi = 系统服务号
.text:000000014007F767                 shr     edi, 7          ; Rdi = 系统服务号 >> 7
.text:000000014007F76A                 and     edi, 20h        ; Rdi = (系统服务号 >> 7) & 0x20 = 服务表的索引
.text:000000014007F76D                 and     eax, 0FFFh      ; EAX = 系统服务号
.text:000000014007F772
.text:000000014007F772 KiSystemServiceRepeat:                  ; CODE XREF: KiSystemCall64+47Bj
.text:000000014007F772                 lea     r10, KeServiceDescriptorTable
.text:000000014007F779                 lea     r11, KeServiceDescriptorTableShadow
.text:000000014007F780                 test    dword ptr [rbx+100h], 80h ; CurrentThread.GuiThread 是否为 0x0(是否是GUI线程)
.text:000000014007F78A                 cmovnz  r10, r11        ; 是GUI线程则 R10 = R11 = KeServiceDescriptorTableShadow
.text:000000014007F78E                 cmp     eax, [rdi+r10+10h] ; EAX 与 系统服务表函数个数 比较(判断是否越界)
.text:000000014007F793                 jnb     loc_14007FA82   ; 大于跳转
.text:000000014007F799                 mov     r10, [rdi+r10]  ; R10 = 系统服务表的函数地址表
.text:000000014007F79D                 movsxd  r11, dword ptr [r10+rax*4] ; R11 = 加密的SSDT表数据
.text:000000014007F7A1                 mov     rax, r11        ; Rax = 加密的SSDT表数据
.text:000000014007F7A4                 sar     r11, 4          ; R11 算术位移 4 位(高位添1或0, 由符号位决定)
.text:000000014007F7A8                 add     r10, r11        ; R10 = 系统服务表的函数地址表 + R11 = 真正系统函数地址
.text:000000014007F7AB                 cmp     edi, 20h        ; 判断服务表索引, 是否为影子表
.text:000000014007F7AE                 jnz     short loc_14007F800 ; 不是跳转, 不为影子表跟进看看
.text:000000014007F7B0                 mov     r11, [rbx+0B8h] ; R11 = CurrentThread.Teb
.text:000000014007F800 loc_14007F800:                          ; CODE XREF: KiSystemCall64+16Ej
.text:000000014007F800                                         ; KiSystemCall64+17Fj
.text:000000014007F800                 and     eax, 0Fh        ; 获取 加密的SSDT表数据 低4位(也就是内核函数参数个数)
.text:000000014007F803                 jz      KiSystemServiceCopyEnd ; 如果没有参数(低4位为0x0)跳转
.text:000000014007F809                 shl     eax, 3          ; EAX 左移 3位(Eax * 8)
.text:000000014007F80C                 lea     rsp, [rsp-70h]  ; 开辟堆栈(用于存储Ring3的参数)
.text:000000014007F811                 lea     rdi, [rsp+18h]
.text:000000014007F816                 mov     rsi, [rbp+100h] ; Rsi = R3Rsp = KTRAP_FRAME.Rsp
.text:000000014007F81D                 lea     rsi, [rsi+20h]  ; Rsi = 函数第五个参数地址-0x8
.text:000000014007F821                 test    byte ptr [rbp+0F0h], 1 ; KTRAP_FRAME.SegCs 与 0x1 比较, 判断几环过来
.text:000000014007F828                 jz      short loc_14007F840 ; KernelMode模式跳转
.text:000000014007F82A                 cmp     rsi, cs:MmUserProbeAddress ; 函数第五个参数地址-0x8 与 000007ff`ffff0000 比较
.text:000000014007F831                 cmovnb  rsi, cs:MmUserProbeAddress ; 大于则 函数第五个参数地址-0x8 = 0x00007ff`ffff0000
.text:000000014007F839                 nop     dword ptr [rax+00000000h]
.text:000000014007F840
.text:000000014007F840 loc_14007F840:                          ; CODE XREF: KiSystemCall64+1E8j
.text:000000014007F840                 lea     r11, KiSystemServiceCopyEnd
.text:000000014007F847                 sub     r11, rax        ; KiSystemServiceCopyEnd - Rax = 拷贝几个参数到 Ring0 堆栈
.text:000000014007F84A                 jmp     r11
.text:000000014007F850 KiSystemServiceCopyStart:               ; DATA XREF: KiSystemServiceHandler+1Ao
.text:000000014007F850                 mov     rax, [rsi+70h]
.text:000000014007F854                 mov     [rdi+70h], rax
.text:000000014007F858                 mov     rax, [rsi+68h]
.text:000000014007F85C                 mov     [rdi+68h], rax
.text:000000014007F860                 mov     rax, [rsi+60h]
.text:000000014007F864                 mov     [rdi+60h], rax
.text:000000014007F868                 mov     rax, [rsi+58h]
.text:000000014007F86C                 mov     [rdi+58h], rax
.text:000000014007F870                 mov     rax, [rsi+50h]
.text:000000014007F874                 mov     [rdi+50h], rax
.text:000000014007F878                 mov     rax, [rsi+48h]
.text:000000014007F87C                 mov     [rdi+48h], rax
.text:000000014007F880                 mov     rax, [rsi+40h]
.text:000000014007F884                 mov     [rdi+40h], rax
.text:000000014007F888                 mov     rax, [rsi+38h]
.text:000000014007F88C                 mov     [rdi+38h], rax
.text:000000014007F890                 mov     rax, [rsi+30h]
.text:000000014007F894                 mov     [rdi+30h], rax
.text:000000014007F898                 mov     rax, [rsi+28h]
.text:000000014007F89C                 mov     [rdi+28h], rax
.text:000000014007F8A0                 mov     rax, [rsi+20h]
.text:000000014007F8A4                 mov     [rdi+20h], rax
.text:000000014007F8A8                 mov     rax, [rsi+18h]
.text:000000014007F8AC                 mov     [rdi+18h], rax
.text:000000014007F8B0                 mov     rax, [rsi+10h]
.text:000000014007F8B4                 mov     [rdi+10h], rax
.text:000000014007F8B8                 mov     rax, [rsi+8]    ; Rax = 函数的第五个参数
.text:000000014007F8BC                 mov     [rdi+8], rax    ; 拷贝到 Ring0 的堆栈中
.text:000000014007F8C0
.text:000000014007F8C0 KiSystemServiceCopyEnd:                 ; CODE XREF: KiSystemCall64+1C3j
.text:000000014007F8C0                                         ; DATA XREF: KiSystemServiceHandler+27o ...
.text:000000014007F8C0                 test    cs:PerfGlobalGroupMask_0x8, 40h
.text:000000014007F8CA                 jnz     loc_14007FB20
.text:000000014007F8D0                 call    r10             ; 调用 内核函数地址
.text:000000014007F8D3
.text:000000014007F8D3 loc_14007F8D3:                          ; CODE XREF: KiSystemCall64+535j
.text:000000014007F8D3                 inc     dword ptr gs:2238h ; KPCR.Prcb.KeSystemCalls += 0x1
.text:000000014007F8DB
.text:000000014007F8DB KiSystemServiceExit:                    ; CODE XREF: KiSystemCall64+49Cj
.text:000000014007F8DB                                         ; KiSystemCall64+4A7j
.text:000000014007F8DB                                         ; DATA XREF: ...
.text:000000014007F8DB                 mov     rbx, [rbp+0C0h] ; Rbx = KTRAP_FRAME.Rbx
.text:000000014007F8E2                 mov     rdi, [rbp+0C8h] ; Rdi = KTRAP_FRAME.Rdi
.text:000000014007F8E9                 mov     rsi, [rbp+0D0h] ; Rsi = KTRAP_FRAME.Rsi
.text:000000014007F8F0                 mov     r11, gs:188h    ; R11 = KPCR.Prcb.CurrentThread
.text:000000014007F8F9                 test    byte ptr [rbp+0F0h], 1 ; KTRAP_FRAME.SegCs 与 0x1 比较, 判断是几环过来
.text:000000014007F900                 jz      loc_14007FA55   ; KernelMode跳转
.text:000000014007F906                 mov     rcx, cr8
.text:000000014007F90A                 or      cl, [r11+1F0h]  ; CL |= CurrentThread.ApcStateIndex
.text:000000014007F911                 or      ecx, [r11+1C4h] ; ECX |= CurrentThread.KernelApcDisable
.text:000000014007F918                 jnz     loc_14007FAEC
.text:000000014007F91E                 cli                     ; 关闭中断
.text:000000014007F91F                 mov     rcx, gs:188h    ; Rcx = KPCR.Prcb.CurrentThread
.text:000000014007F928                 cmp     byte ptr [rcx+7Ah], 0 ; CurrentThread.ApcStateFill[0x2A] 与 0x0 比较
.text:000000014007F92C                 jz      short loc_14007F985 ; 判断是否有 APC 需要执行
.text:000000014007F92E                 mov     [rbp-50h], rax  ; KTRAP_FRAME.Rax = Rax
.text:000000014007F932                 xor     eax, eax
.text:000000014007F934                 mov     [rbp-48h], rax  ; KTRAP_FRAME.Rcx = 0x0
.text:000000014007F938                 mov     [rbp-40h], rax  ; KTRAP_FRAME.Rdx = 0x0
.text:000000014007F93C                 mov     [rbp-38h], rax  ; KTRAP_FRAME.R8 = 0x0
.text:000000014007F940                 mov     [rbp-30h], rax  ; KTRAP_FRAME.R9 = 0x0
.text:000000014007F944                 mov     [rbp-28h], rax  ; KTRAP_FRAME.R10 = 0x0
.text:000000014007F948                 mov     [rbp-20h], rax  ; KTRAP_FRAME.R11 = 0x0
.text:000000014007F94C                 pxor    xmm0, xmm0
.text:000000014007F950                 movaps  xmmword ptr [rbp-10h], xmm0
.text:000000014007F954                 movaps  xmmword ptr [rbp+0], xmm0
.text:000000014007F958                 movaps  xmmword ptr [rbp+10h], xmm0
.text:000000014007F95C                 movaps  xmmword ptr [rbp+20h], xmm0
.text:000000014007F960                 movaps  xmmword ptr [rbp+30h], xmm0
.text:000000014007F964                 movaps  xmmword ptr [rbp+40h], xmm0
.text:000000014007F968                 mov     ecx, 1
.text:000000014007F96D                 mov     cr8, rcx
.text:000000014007F971                 sti
.text:000000014007F972                 call    KiInitiateUserApc ; 处理 User APC
.text:000000014007F977                 cli
.text:000000014007F978                 mov     ecx, 0
.text:000000014007F97D                 mov     cr8, rcx
.text:000000014007F981                 mov     rax, [rbp-50h]
.text:000000014007F985
.text:000000014007F985 loc_14007F985:                          ; CODE XREF: KiSystemCall64+2ECj
.text:000000014007F985                 mov     rcx, gs:188h    ; Rcx = CurrentThread
.text:000000014007F98E                 test    dword ptr [rcx], 40020000h ; CurrentThread.Header.Type 与 0x40020000 比较
.text:000000014007F994                 jz      short loc_14007F9C4
.text:000000014007F996                 mov     [rbp-50h], rax
.text:000000014007F99A                 test    byte ptr [rcx+2], 2
.text:000000014007F99E                 jz      short loc_14007F9AE
.text:000000014007F9A0                 call    KiCopyCounters
.text:000000014007F9A5                 mov     rcx, gs:188h
.text:000000014007F9AE
.text:000000014007F9AE loc_14007F9AE:                          ; CODE XREF: KiSystemCall64+35Ej
.text:000000014007F9AE                 test    byte ptr [rcx+3], 40h
.text:000000014007F9B2                 jz      short loc_14007F9C0
.text:000000014007F9B4                 lea     rsp, [rbp-80h]
.text:000000014007F9B8                 xor     rcx, rcx
.text:000000014007F9BB                 call    KiUmsExit
.text:000000014007F9C0
.text:000000014007F9C0 loc_14007F9C0:                          ; CODE XREF: KiSystemCall64+372j
.text:000000014007F9C0                 mov     rax, [rbp-50h]
.text:000000014007F9C4
.text:000000014007F9C4 loc_14007F9C4:                          ; CODE XREF: KiSystemCall64+354j
.text:000000014007F9C4                 ldmxcsr dword ptr [rbp-54h]
.text:000000014007F9C8                 xor     r10, r10
.text:000000014007F9CB                 cmp     word ptr [rbp+80h], 0
.text:000000014007F9D3                 jz      short loc_14007FA13
.text:000000014007F9D5                 mov     [rbp-50h], rax
.text:000000014007F9D9                 call    KiRestoreDebugRegisterState
.text:000000014007F9DE                 mov     rax, gs:188h
.text:000000014007F9E7                 mov     rax, [rax+70h]
.text:000000014007F9EB                 mov     rax, [rax+100h]
.text:000000014007F9F2                 or      rax, rax
.text:000000014007F9F5                 jz      short loc_14007FA0F
.text:000000014007F9F7                 cmp     word ptr [rbp+0F0h], 33h
.text:000000014007F9FF                 jnz     short loc_14007FA0F
.text:000000014007FA01                 mov     r10, [rbp+0E8h]
.text:000000014007FA08                 mov     [rbp+0E8h], rax
.text:000000014007FA0F
.text:000000014007FA0F loc_14007FA0F:                          ; CODE XREF: KiSystemCall64+3B5j
.text:000000014007FA0F                                         ; KiSystemCall64+3BFj
.text:000000014007FA0F                 mov     rax, [rbp-50h]
.text:000000014007FA13
.text:000000014007FA13 loc_14007FA13:                          ; CODE XREF: KiSystemCall64+393j
.text:000000014007FA13                 mov     r8, [rbp+100h]  ; R8 = KTRAP_FRAME.Rsp = R3Rsp
.text:000000014007FA1A                 mov     r9, [rbp+0D8h]  ; R9 = KTRAP_FRAME.Rbp
.text:000000014007FA21                 xor     edx, edx
.text:000000014007FA23                 pxor    xmm0, xmm0
.text:000000014007FA27                 pxor    xmm1, xmm1
.text:000000014007FA2B                 pxor    xmm2, xmm2
.text:000000014007FA2F                 pxor    xmm3, xmm3
.text:000000014007FA33                 pxor    xmm4, xmm4
.text:000000014007FA37                 pxor    xmm5, xmm5
.text:000000014007FA3B                 mov     rcx, [rbp+0E8h] ; Rcx = KTRAP_FRAME.Rip = syscall 指令的返回地址
.text:000000014007FA42                 mov     r11, [rbp+0F8h] ; R11 = KTRAP_FRAME.EFlags
.text:000000014007FA49                 mov     rbp, r9
.text:000000014007FA4C                 mov     rsp, r8
.text:000000014007FA4F                 swapgs                  ; 置换 GS 为TEB64
.text:000000014007FA52                 sysret                  ; 返回Ring3, 该指令执行动作如下:
.text:000000014007FA52                                         ; 1. 将 Rcx 的值存入 Rip 中
.text:000000014007FA52                                         ; 2. R11 的值存入 Rflags 中
.text:000000014007FA52                                         ; 3. 将 msr[c0000081] 的 48~63 位加载到CS, SS = CS + 0x8
.text:000000014007FA55
.text:000000014007FA55 loc_14007FA55:                          ; CODE XREF: KiSystemCall64+2C0j
.text:000000014007FA55                 mov     rdx, [rbp+0B8h]
.text:000000014007FA5C                 mov     [r11+1D8h], rdx
.text:000000014007FA63                 mov     dl, [rbp-58h]
.text:000000014007FA66                 mov     [r11+1F6h], dl
.text:000000014007FA6D                 cli
.text:000000014007FA6E                 mov     rsp, rbp
.text:000000014007FA71                 mov     rbp, [rbp+0D8h]
.text:000000014007FA78                 mov     rsp, [rsp+arg_F8]
.text:000000014007FA80                 sti
.text:000000014007FA81                 retn


1. 以上为 X64 内核系统调用的过程, 与 X86 相比, Ring3和Ring0各有一套SSDT和查表方式

2. X64 内核函数地址的计算也发生了改变, 最后SSDT表数据最后4位保存内核函数参数个数, 以及拷贝Ring3数据方式通过  KiSystemServiceCopyStart 函数拷贝, X64系统调用大体就是这样了



阿里云助力开发者!2核2G 3M带宽不限流量!6.18限时价,开 发者可享99元/年,续费同价!

收藏
点赞1
打赏
分享
最新回复 (1)
雪    币: 10
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
wx_靖~live 2020-6-17 16:55
2
0
大佬X64下重写 NtReadVirtualMemory 为什么会导致线程卡死  
游客
登录 | 注册 方可回帖
返回