首页
社区
课程
招聘
[分享]X64系统调用_上(Ring3)
2020-6-3 21:45 7521

[分享]X64系统调用_上(Ring3)

2020-6-3 21:45
7521

相比 X86, X64的系统调用要兼容X86, 所有有些不一样

这里我写了一个X86小程序,  程序只是调用了 ReadProcessMemory 函数, 开始追踪

操作系统: Win7Sp1

核数: 2


1). 追踪 ReadProcessMemory 的系统调用 (使用EXE为 x86体系)

进入 kernel32.dll 的代码中发现, 只是一个跳转

跟随跳转来到了 kernelbase.dll, 其调用了 ntdll(32位).NtReadProcessMemory

继续跟随, 发现类似 X86 体系的系统调用流程

其中 EAX  等于系统服务号

EDX 等于函数参数起始地址

FS指向的是 TEB32 结构, TEB32[0xC0] == WOW32Reserved == 0x74C92320

之后进行了长跳, 这里 0x33 段描述符是 X86 转 X64 体系的特殊兼容段描述符, 并跳向了0x74C9271E

继续跟随发现变为X64寻址, 并进入了wow64cpu.dll

我们来分析这段代码, 用 IDA64 追踪查看 wow64cpu.dll, 在 CpuSimulate() 函数中

mov     r8d, [esp]       // R8D == WOW32Reserved 的返回地址
mov     [r13+0BCh], r8d  // 保存 WOW32Reserved 的返回地址 (猜测 R13 是个结构体, 保存在 TEB64.TlsSlots[0x1] 处)
mov     [r13+0C8h], esp  // 保存当前 R3 的ESP 
mov     rsp, [r12+1480h] // Rsp = TEB64.TlsSlots[0x0]
and     qword ptr [r12+1480h], 0 TEB64.TlsSlots[0x0] &= 0x0 (清空 TEB64.TlsSlots[0x0])
mov     r11d, edx        //  R11D == 函数参数起始地址
jmp     qword ptr [r15+rcx*8] // R15 == TurboDispatchJumpAddressEnd()函数起始地址
                              // RCX == 0x0
                              // Jmp 到 TurboDispatchJumpAddressEnd() 函数
.text:0000000078B62749                                         public TurboDispatchJumpAddressEnd
.text:0000000078B62749                         TurboDispatchJumpAddressEnd:            ; CODE XREF: CpuSimulate+32Cj
.text:0000000078B62749                                                                 ; CpuSimulate+3E6j
.text:0000000078B62749                                                                 ; DATA XREF: ...
.text:0000000078B62749 41 89 B5 A4 00 00 00                    mov     [r13+0A4h], esi  // 保存 ESI
.text:0000000078B62750 41 89 BD A0 00 00 00                    mov     [r13+0A0h], edi  // 保存 EDI
.text:0000000078B62757 41 89 9D A8 00 00 00                    mov     [r13+0A8h], ebx  // 保存 EBX
.text:0000000078B6275E 41 89 AD B8 00 00 00                    mov     [r13+0B8h], ebp  // 保存 EBP
.text:0000000078B62765 9C                                      pushfq                   // Push RFLAGS寄存器
.text:0000000078B62766 5B                                      pop     rbx              // RBX = RFLAGS寄存器
.text:0000000078B62767 41 89 9D C4 00 00 00                    mov     [r13+0C4h], ebx  // 保存 RFLAGS 寄存器
.text:0000000078B6276E 8B C8                                   mov     ecx, eax         // ECX = 系统服务号(X64 FASTCALL)
.text:0000000078B62770 FF 15 0A E9 FF FF                       call    cs:Wow64SystemServiceEx // X64的系统调用(位于 wow64.dll)
.text:0000000078B62776 41 89 85 B4 00 00 00                    mov     [r13+0B4h], eax  // 存储 Wow64SystemServiceEx 返回值 
.text:0000000078B6277D E9 8F FE FF FF                          jmp     loc_78B62611
// 分析返回流程
.text:0000000078B62611                         loc_78B62611:                           ; CODE XREF: CpuSimulate+1CDj
.text:0000000078B62611 41 83 A5 D0 02 00 00 01                 and     dword ptr [r13+2D0h], 1
.text:0000000078B62619 0F 84 AF 00 00 00                       jz      loc_78B626CE
.text:0000000078B6261F 41 0F 28 85 70 01 00 00                 movaps  xmm0, xmmword ptr [r13+170h]
.text:0000000078B62627 41 0F 28 8D 80 01 00 00                 movaps  xmm1, xmmword ptr [r13+180h]
.text:0000000078B6262F 41 0F 28 95 90 01 00 00                 movaps  xmm2, xmmword ptr [r13+190h]
.text:0000000078B62637 41 0F 28 9D A0 01 00 00                 movaps  xmm3, xmmword ptr [r13+1A0h]
.text:0000000078B6263F 41 0F 28 A5 B0 01 00 00                 movaps  xmm4, xmmword ptr [r13+1B0h]
.text:0000000078B62647 41 0F 28 AD C0 01 00 00                 movaps  xmm5, xmmword ptr [r13+1C0h]
.text:0000000078B6264F 41 8B 8D B0 00 00 00                    mov     ecx, [r13+0B0h]
.text:0000000078B62656 41 8B 95 AC 00 00 00                    mov     edx, [r13+0ACh]
.text:0000000078B6265D 41 83 A5 D0 02 00 00 FE                 and     dword ptr [r13+2D0h], 0FFFFFFFEh
.text:0000000078B62665 41 8B BD A0 00 00 00                    mov     edi, [r13+0A0h]
.text:0000000078B6266C 41 8B B5 A4 00 00 00                    mov     esi, [r13+0A4h]
.text:0000000078B62673 41 8B 9D A8 00 00 00                    mov     ebx, [r13+0A8h]
.text:0000000078B6267A 41 8B AD B8 00 00 00                    mov     ebp, [r13+0B8h]
.text:0000000078B62681 41 8B 85 B4 00 00 00                    mov     eax, [r13+0B4h]
.text:0000000078B62688 49 89 A4 24 80 14 00 00                 mov     [r12+1480h], rsp
.text:0000000078B62690 66 C7 44 24 08 23 00                    mov     [rsp+0B8h+var_B0], 23h
.text:0000000078B62697 66 C7 44 24 20 2B 00                    mov     word ptr [rsp+0B8h+var_98], 2Bh
.text:0000000078B6269E 45 8B 85 C4 00 00 00                    mov     r8d, [r13+0C4h]
.text:0000000078B626A5 41 81 A5 C4 00 00 00 FF+                and     dword ptr [r13+0C4h], 0FFFFFEFFh
.text:0000000078B626B0 44 89 44 24 10                          mov     [rsp+0B8h+var_A8], r8d
.text:0000000078B626B5 45 8B 85 C8 00 00 00                    mov     r8d, [r13+0C8h]
.text:0000000078B626BC 4C 89 44 24 18                          mov     [rsp+0B8h+var_A0], r8
.text:0000000078B626C1 45 8B 85 BC 00 00 00                    mov     r8d, [r13+0BCh]
.text:0000000078B626C8 4C 89 04 24                             mov     [rsp+0B8h+var_B8], r8
.text:0000000078B626CC 48 CF                                   iretq
.text:0000000078B626CE                         loc_78B626CE:  (兼容模式从这返回)                         ; CODE XREF: CpuSimulate+69j
.text:0000000078B626CE 41 8B BD A0 00 00 00                    mov     edi, [r13+0A0h]
.text:0000000078B626D5 41 8B B5 A4 00 00 00                    mov     esi, [r13+0A4h]
.text:0000000078B626DC 41 8B 9D A8 00 00 00                    mov     ebx, [r13+0A8h]
.text:0000000078B626E3 41 8B AD B8 00 00 00                    mov     ebp, [r13+0B8h]
.text:0000000078B626EA 41 8B 85 B4 00 00 00                    mov     eax, [r13+0B4h]
.text:0000000078B626F1 49 89 A4 24 80 14 00 00                 mov     [r12+1480h], rsp
.text:0000000078B626F9 41 C7 46 04 23 00 00 00                 mov     dword ptr [r14+4], 23hr13
.text:0000000078B62701 41 B8 2B 00 00 00                       mov     r8d, 2Bh
.text:0000000078B62707 41 8E D0                                mov     ss, r8d
.text:0000000078B6270A 41 8B A5 C8 00 00 00                    mov     esp, [r13+0C8h]
.text:0000000078B62711 45 8B 8D BC 00 00 00                    mov     r9d, [r13+0BCh]
.text:0000000078B62718 45 89 0E                                mov     [r14], r9d
.text:0000000078B6271B 41 FF 2E                                jmp     fword ptr [r14]  // 注意这个返回, 动态分析R14存储的是 0x23 : 0x772CFE92(之前保存的 WOW32Reserved 的返回地址)
                                                                                        // 0x23 这个段描述符和 0x33 相反, 是将X64寻址转为X86寻址
// 返回到了  ntdll(32位).NtReadProcessMemory 调用 WOW32Reserved 的下一个地址(WOW32Reserved 的返回地址)
// 分析 wow64.dll 的 Wow64SystemServiceEx() 函数
.text:0000000078BDCEB0                                         public Wow64SystemServiceEx
.text:0000000078BDCEB0                         Wow64SystemServiceEx proc near          ; CODE XREF: Wow64SystemService+6j
.text:0000000078BDCEB0                                                                 ; DATA XREF: .text:off_78C07E28o ...
.text:0000000078BDCEB0
.text:0000000078BDCEB0                         var_898         = dword ptr -898h
.text:0000000078BDCEB0                         var_888         = qword ptr -888h
.text:0000000078BDCEB0                         var_880         = qword ptr -880h
.text:0000000078BDCEB0                         var_878         = byte ptr -878h
.text:0000000078BDCEB0                         var_870         = qword ptr -870h
.text:0000000078BDCEB0                         var_FindServiceTableIndex= dword ptr -868h
.text:0000000078BDCEB0                         var_SerivceTableFunIndex= dword ptr -864h
.text:0000000078BDCEB0                         var_860         = dword ptr -860h
.text:0000000078BDCEB0                         var_85C         = byte ptr -85Ch
.text:0000000078BDCEB0                         var_848         = qword ptr -848h
.text:0000000078BDCEB0                         var_840         = qword ptr -840h
.text:0000000078BDCEB0                         var_28          = qword ptr -28h
.text:0000000078BDCEB0                         arg_10          = qword ptr  18h
.text:0000000078BDCEB0
.text:0000000078BDCEB0 4C 8B DC                                mov     r11, rsp        ; R11 == &(Wow64SystemServiceEx返回地址)
.text:0000000078BDCEB3 49 89 5B 18                             mov     [r11+18h], rbx  ; 保存 RFLAGS 寄存器
.text:0000000078BDCEB7 56                                      push    rsi
.text:0000000078BDCEB8 57                                      push    rdi
.text:0000000078BDCEB9 41 54                                   push    r12
.text:0000000078BDCEBB 48 81 EC A0 08 00 00                    sub     rsp, 8A0h
.text:0000000078BDCEC2 48 8B 05 37 C2 02 00                    mov     rax, cs:__security_cookie
.text:0000000078BDCEC9 48 33 C4                                xor     rax, rsp
.text:0000000078BDCECC 48 89 84 24 90 08 00 00                 mov     [rsp+890h], rax
.text:0000000078BDCED4 48 8B DA                                mov     rbx, rdx        ; Rbx == 函数参数起始地址
.text:0000000078BDCED7 44 8B C1                                mov     r8d, ecx        ; R8d == 系统服务号
.text:0000000078BDCEDA 8B D1                                   mov     edx, ecx        ; edx == 系统服务号
.text:0000000078BDCEDC C1 EA 0C                                shr     edx, 0Ch        ; 系统服务号 >> 12位
.text:0000000078BDCEDF 83 E2 03                                and     edx, 3          ; Rdx = 获取查找哪张表的(从这里可以判断最多只有3张表)
.text:0000000078BDCEE2 41 81 E0 FF 0F 00 00                    and     r8d, 0FFFh      ; R8 = 获取系统服务号低12位
.text:0000000078BDCEE9 4C 8D 0C 52                             lea     r9, [rdx+rdx*2]
.text:0000000078BDCEED 4D 03 C9                                add     r9, r9          ; R9 = 6*Rdx
.text:0000000078BDCEF0 4C 8D 15 09 DB 02 00                    lea     r10, ServiceTables
.text:0000000078BDCEF7 47 3B 44 CA 10                          cmp     r8d, [r10+r9*8+10h] ; 系统服务号 与 指定服务表的函数数量比较
.text:0000000078BDCEFC 0F 87 3F 01 00 00                       ja      loc_78BDD041    ; 越界则走向函数结束
.text:0000000078BDCF02 65 48 8B 34 25 30 00 00+                mov     rsi, gs:30h     ; Rsi = TEB64
.text:0000000078BDCF0B 48 89 74 24 38                          mov     [rsp+38h], rsi
.text:0000000078BDCF10 65 48 8B 3C 25 30 00 00+                mov     rdi, gs:30h
.text:0000000078BDCF19 48 81 C7 00 20 00 00                    add     rdi, 2000h
.text:0000000078BDCF20 48 89 7C 24 30                          mov     [rsp+30h], rdi
.text:0000000078BDCF25 48 8B 86 98 14 00 00                    mov     rax, [rsi+1498h]
.text:0000000078BDCF2C 48 89 44 24 70                          mov     [rsp+70h], rax
.text:0000000078BDCF31 48 8D 44 24 78                          lea     rax, [rsp+78h]
.text:0000000078BDCF36 49 89 83 C8 F7 FF FF                    mov     [r11-838h], rax
.text:0000000078BDCF3D 48 8D 44 24 78                          lea     rax, [rsp+78h]
.text:0000000078BDCF42 48 89 44 24 78                          mov     [rsp+78h], rax
.text:0000000078BDCF47 49 8D 43 D8                             lea     rax, [r11-28h]
.text:0000000078BDCF4B 49 89 83 D0 F7 FF FF                    mov     [r11-830h], rax
.text:0000000078BDCF52 48 8D 44 24 70                          lea     rax, [rsp+8B8h+var_848]
.text:0000000078BDCF57 48 89 86 98 14 00 00                    mov     [rsi+1498h], rax
.text:0000000078BDCF5E 4B 8B 04 CA                             mov     rax, [r10+r9*8] ; Rax = ServiceTable函数地址表
.text:0000000078BDCF62 4E 8B 24 C0                             mov     r12, [rax+r8*8] ; R12 = 获取指定服务号的函数地址
.text:0000000078BDCF66 89 54 24 50                             mov     [rsp+8B8h+var_FindServiceTableIndex], edx
.text:0000000078BDCF6A 44 89 44 24 54                          mov     [rsp+8B8h+var_SerivceTableFunIndex], r8d
.text:0000000078BDCF6F 8B 47 34                                mov     eax, [rdi+34h]
.text:0000000078BDCF72 89 46 68                                mov     [rsi+68h], eax
.text:0000000078BDCF75 48 8B 05 1C E0 02 00                    mov     rax, cs:pfnWow64LogSystemService
.text:0000000078BDCF7C 48 85 C0                                test    rax, rax
.text:0000000078BDCF7F 75 0E                                   jnz     short loc_78BDCF8F
.text:0000000078BDCF81 48 8B CB                                mov     rcx, rbx        ; Rcx =  函数参数起始地址
.text:0000000078BDCF84 41 FF D4                                call    r12             ; 调用对应的系统服务函数
.text:0000000078BDCF87 8B D8                                   mov     ebx, eax
.text:0000000078BDCF89 89 44 24 20                             mov     [rsp+8B8h+var_898], eax
.text:0000000078BDCF8D EB 31                                   jmp     short loc_78BDCFC0 // 返回
// 从上面可以看出相比X86, X64在Ring 3中也有一张 ServiceTables 用于查询3环对应的系统服务函数地址, 这里Ring 3调用的是 ReadProcessMemory() 函数
// 跟随动态调试进入会发现进入了 wow64.whNtReadVirtualMemory() 函数中, 我们接下来分析
.text:0000000078BEAC78                         whNtReadVirtualMemory proc near         ; DATA XREF: .data:0000000078C09480o
.text:0000000078BEAC78                                                                 ; .pdata:0000000078C0B948o
.text:0000000078BEAC78
.text:0000000078BEAC78                         ReturnLength64_1= qword ptr -38h
.text:0000000078BEAC78                         arg_0           = qword ptr  8
.text:0000000078BEAC78                         ReturnLength64  = byte ptr  10h
.text:0000000078BEAC78                         arg_10          = qword ptr  18h
.text:0000000078BEAC78
.text:0000000078BEAC78 48 89 5C 24 18                          mov     [rsp+arg_10], rbx ; Rbx = Rcx = 函数参数起始地址
.text:0000000078BEAC7D 56                                      push    rsi
.text:0000000078BEAC7E 57                                      push    rdi
.text:0000000078BEAC7F 41 54                                   push    r12
.text:0000000078BEAC81 41 55                                   push    r13
.text:0000000078BEAC83 41 56                                   push    r14
.text:0000000078BEAC85 48 83 EC 30                             sub     rsp, 30h
.text:0000000078BEAC89
.text:0000000078BEAC89                         loc_78BEAC89:                           ; DATA XREF: .text:0000000078C00DC8o
.text:0000000078BEAC89 4C 63 21                                movsxd  r12, dword ptr [rcx] ; ProcessHandle
.text:0000000078BEAC8C 8B 71 04                                mov     esi, [rcx+4]    ; BaseAddress
.text:0000000078BEAC8F 8B 79 08                                mov     edi, [rcx+8]    ; Buffer
.text:0000000078BEAC92 8B 59 0C                                mov     ebx, [rcx+0Ch]  ; BufferLength
.text:0000000078BEAC95 44 8B 69 10                             mov     r13d, [rcx+10h] ; ReturnLength
.text:0000000078BEAC99 49 8B D5                                mov     rdx, r13
.text:0000000078BEAC9C 48 8D 4C 24 68                          lea     rcx, [rsp+58h+ReturnLength64]
.text:0000000078BEACA1 E8 E6 04 FF FF                          call    Wow64ShallowThunkSIZE_T32TO64 ; 将32位的ReturnLength切换位64位
.text:0000000078BEACA6 4C 8B F0                                mov     r14, rax        ; R14 = ReturnLength64
.text:0000000078BEACA9 48 89 44 24 20                          mov     [rsp+58h+ReturnLength64_1], rax
.text:0000000078BEACAE 4C 8B CB                                mov     r9, rbx         ; BufferLength
.text:0000000078BEACB1 4C 8B C7                                mov     r8, rdi         ; Buffer
.text:0000000078BEACB4 48 8B D6                                mov     rdx, rsi        ; BaseAddress
.text:0000000078BEACB7 49 8B CC                                mov     rcx, r12        ; ProcessHandle
.text:0000000078BEACBA FF 15 40 64 FE FF                       call    cs:__imp_NtReadVirtualMemory ; 调用64位ntdll.dll的函数
.text:0000000078BEACC0 44 8B D8                                mov     r11d, eax
.text:0000000078BEACC3 4D 85 F6                                test    r14, r14
.text:0000000078BEACC6 75 07                                   jnz     short loc_78BEACCF
.text:0000000078BEACC8 4C 21 74 24 60                          and     [rsp+58h+arg_0], r14
.text:0000000078BEACCD EB 15                                   jmp     short loc_78BEACE4
.text:0000000078BEACCF                         ; ---------------------------------------------------------------------------
.text:0000000078BEACCF
.text:0000000078BEACCF                         loc_78BEACCF:                           ; CODE XREF: whNtReadVirtualMemory+4Ej
.text:0000000078BEACCF B8 FF FF FF FF                          mov     eax, 0FFFFFFFFh
.text:0000000078BEACD4 49 39 06                                cmp     [r14], rax
.text:0000000078BEACD7 49 0F 42 06                             cmovb   rax, [r14]
.text:0000000078BEACDB 41 89 45 00                             mov     [r13+0], eax
.text:0000000078BEACDF 4C 89 6C 24 60                          mov     [rsp+58h+arg_0], r13
.text:0000000078BEACE4
.text:0000000078BEACE4                         loc_78BEACE4:                           ; CODE XREF: whNtReadVirtualMemory+55j
.text:0000000078BEACE4                                                                 ; DATA XREF: .text:0000000078C00DC8o
.text:0000000078BEACE4 41 8B C3                                mov     eax, r11d
.text:0000000078BEACE7 48 8B 5C 24 70                          mov     rbx, [rsp+58h+arg_10]
.text:0000000078BEACEC 48 83 C4 30                             add     rsp, 30h
.text:0000000078BEACF0 41 5E                                   pop     r14
.text:0000000078BEACF2 41 5D                                   pop     r13
.text:0000000078BEACF4 41 5C                                   pop     r12
.text:0000000078BEACF6 5F                                      pop     rdi
.text:0000000078BEACF7 5E                                      pop     rsi
.text:0000000078BEACF8 C3                                      retn
.text:0000000078BEACF8                         whNtReadVirtualMemory endp
// 注意这个函数中的 Wow64ShallowThunkSIZE_T32TO64() 函数, 将用户传入的 ReturnLength 变为64位, 随后调用了64位 ntdll.dll 的 NtReadVirtualMemory() 函数
// 这里利用了 syscall 指令进入了内核, 注意 EAX 等于系统服务号
// 从这里可以看出Ring 3的 ServiceTables 和 Ring 0 的 ServiceTables 用的 系统服务号 可能不一致
.text:0000000078EA1700                 public NtReadVirtualMemory 
.text:0000000078EA1700 NtReadVirtualMemory proc near           ; CODE XREF: sub_78F222D0+24p
.text:0000000078EA1700                                         ; sub_78F28520+3F8p
.text:0000000078EA1700                                         ; DATA XREF: ...
.text:0000000078EA1700                 mov     r10, rcx        ; NtReadVirtualMemory
.text:0000000078EA1703                 mov     eax, 3Ch
.text:0000000078EA1708                 syscall
.text:0000000078EA170A                 retn
.text:0000000078EA170A NtReadVirtualMemory endp
总结:
    相比X86体系, X64体系做了一系列的扩展, Ring3 有套系统服务表寻址, 查询Ring3 系统服务号对应的函数,之后调用 64位 ntdll.dll 进入内核
总体的调用流程:
    32位的EXE调用 ReadProcessMemory --> 32位的kernel32.dll --> 32位的kernelbase.dll --> 32位的ntdll.dll -(0x3C服务号)-> 64位的wow64cpu.dll --> 64位的wow64.dll(根据服务号查询对应函数) --> 64位ntdll.dll -(0x3C服务号)-> 内核

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

最后于 2020-6-3 21:51 被灵幻空间编辑 ,原因: 排版问题
收藏
点赞3
打赏
分享
最新回复 (5)
雪    币: 62
活跃值: (657)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
dz默契 2020-6-3 22:39
2
0
这个OD是那个大番薯大佬的那个吧
雪    币: 5514
活跃值: (2254)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
敏而好学 2020-6-3 23:43
3
0
这个OD看上去很牛。
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
wx_Hugh胡晓军 2020-6-4 10:25
4
0
666
雪    币: 259
活跃值: (283)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ZwCopyAll 2020-6-4 18:01
5
0
666
雪    币: 68
活跃值: (101)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
sodarkbit 2020-6-5 12:23
6
0
dz默契 这个OD是那个大番薯大佬的那个吧
哪里有下载?
游客
登录 | 注册 方可回帖
返回