64位下 3环Wow64进程进行系统调用分析
以下将以ReadProcessMemory为例进行分析
首先进入SysWow64下的kernel32.dll
7577CFCC 8B FF mov edi,edi
7577CFCE 55 push ebp
7577CFCF 8B EC mov ebp,esp
7577CFD1 5D pop ebp
7577CFD2 E9 E6 40 jmp 757610BD
757610BD FF 25 00 jmp dword ptr ds:[<&API-MS-Win-Core-Memory-L1-1-0.ReadProcessMemory
上述跳转将会到达SysWow64下的kernelBase.dll
76F4DFC8 8B FF mov edi,edi
76F4DFCA 55 push ebp
76F4DFCB 8B EC mov ebp,esp
76F4DFCD 8D 45 14 lea eax,dword ptr ss:[ebp+0x14]
76F4DFD0 50 push eax ; 将存放读取长度的地址作为需要返回实际读取长度的地址
76F4DFD1 FF 75 14 push dword ptr ss:[ebp+0x14] ;以下是依次压入前四个参数
76F4DFD4 FF 75 10 push dword ptr ss:[ebp+0x10]
76F4DFD7 FF 75 0C push dword ptr ss:[ebp+0x0C]
76F4DFDA FF 75 08 push dword ptr ss:[ebp+0x08]
76F4DFDD FF 15 C4 call dword ptr ds:[<&ntdll.NtReadVirtualMemory>]
76F4DFE3 8B 4D 18 mov ecx,dword ptr ss:[ebp+0x18] ;取出真正要存实际读入长度的地址
76F4DFE6 85 C9 test ecx,ecx
76F4DFE8 74 05 je KernelBase.76F4DFEF
76F4DFEA 8B 55 14 mov edx,dword ptr ss:[ebp+0x14]
76F4DFED 89 11 mov dword ptr ds:[ecx],edx ;如果所给地址不为空 便将实际读取的长度写入
76F4DFEF 85 C0 test eax,eax
76F4DFF1 7D 0A jnl KernelBase.76F4DFFD
76F4DFF3 50 push eax
76F4DFF4 E8 69 86 call KernelBase.76F76662 ;如果返回值为负数 代表调用出错 将调用这个函数设置Error
76F4DFF9 33 C0 xor eax,eax
76F4DFFB EB 03 jmp KernelBase.76F4E000
76F4DFFD 33 C0 xor eax,eax
76F4DFFF 40 inc eax
76F4E000 5D pop ebp
76F4E001 C2 14 00 retn 0x0014
接下来进入SysWow64中的ntdll.dll
77BAFE80 B8 3C 00 mov eax,0x0000003C ;eax 代表此API在SSDT表中的索引值
77BAFE85 33 C9 xor ecx,ecx
77BAFE87 8D 54 24 lea edx,dword ptr ss:[esp+0x04] ;edx指向存放参数的地址
77BAFE8B 64 FF 15 call dword ptr fs:[0x000000C0] ;fs[0xC0]中存放的是755F2320
77BAFE92 83 C4 04 add esp,0x04
77BAFE95 C2 14 00 retn 0x0014
接下来便进入Wow64Cpu.dll
755F2320 EA 1E 27 jmp far 0x0033 : 0x755F271E ;该指令将Cs修改为64位的代码段,接下来的代码将全部以64位进行解析 并跳转到0x755F271E 处
00000000749C271E CpupReturnFromSimulatedCode: ; DATA XREF: CpuProcessInit+B1↑o
00000000749C271E ; CpuResetToConsistentState+B7↑o ...
00000000749C271E mov r8d, [esp] ; r8d = 返回地址
00000000749C2723 mov [r13+_MyContext._Eip], r8d ; 将Eip Esp保存在类型于Context的结构中
00000000749C272A mov [r13+_MyContext._Esp], esp
00000000749C2731 mov rsp, [r12+_TEB.TlsSlots];进行换栈操作
00000000749C2739 and [r12+_TEB.TlsSlots], 0
00000000749C2742 mov r11d, edx ; r11d = 参数位置
00000000749C2745 jmp qword ptr [r15+rcx*8];rcx从前面可知为0 所以将跳转到[r15]位置 [r15] = 0x00000000749C2749
00000000749C2749 mov [r13+_MyContext._Esi], esi;以下将保存一些寄存器到MyContext中
00000000749C2750 mov [r13+_MyContext._Edi], edi
00000000749C2757 mov [r13+_MyContext._Ebx], ebx
00000000749C275E mov [r13+_MyContext._Ebp], ebp
00000000749C2765 pushfq
00000000749C2766 pop rbx
00000000749C2767 mov [r13+_MyContext._Eflags], ebx
00000000749C276E mov ecx, eax ; eax = Index
00000000749C2770 call cs:__imp_Wow64SystemServiceEx
00000000749C2776 mov [r13+_MyContext._Eax], eax
00000000749C277D jmp loc_749C2611 ;
接下来将进入到Wow64.dll中
Wow64SystemServiceEx:
00000000749CCEB0 mov r11, rsp
00000000749CCEB3 mov [r11+18h], rbx
00000000749CCEB7 push rsi
00000000749CCEB8 push rdi
00000000749CCEB9 push r12
00000000749CCEBB sub rsp, 8A0h
00000000749CCEC2 mov rax, cs:__security_cookie
00000000749CCEC9 xor rax, rsp
00000000749CCECC mov [rsp+8B8h+var_28], rax
00000000749CCED4 mov rbx, rdx ; rbx 参数位置
00000000749CCED7 mov r8d, ecx ; r8d = ecx = Index
00000000749CCEDA mov edx, ecx ; edx = ecx = Index
00000000749CCEDC shr edx, 0Ch
00000000749CCEDF and edx, 3 ;rdx 索引中的12-13位代表选取哪张表
00000000749CCEE2 and r8d, 0FFFh ; r8d = 真正表中的索引号
00000000749CCEE9 lea r9, [rdx+rdx*2]
00000000749CCEED add r9, r9
00000000749CCEF0 lea r10, ServiceTables
00000000749CCEF7 cmp r8d, [r10+r9*8+10h];r9 = rdx * 0x30 表示的是对应表在ServiceTables中的偏移量 再加上0x10位置存放的是这个表中最大索引号
00000000749CCEFC ja loc_749CD041 ; 检验索引是否在最大索引内
00000000749CCF02 mov rsi, gs:_TEB.NtTib.Self;以下没看出来具体的用处
00000000749CCF0B mov [rsp+8B8h+TEB], rsi
00000000749CCF10 mov rdi, gs:_TEB.NtTib.Self
00000000749CCF19 add rdi, 2000h
00000000749CCF20 mov [rsp+8B8h+var_888], rdi
00000000749CCF25 mov rax, [rsi+(_TEB.TlsSlots+18h)]
00000000749CCF2C mov [rsp+8B8h+var_848], rax
00000000749CCF31 lea rax, [rsp+8B8h+var_840]
00000000749CCF36 mov [r11-838h], rax
00000000749CCF3D lea rax, [rsp+8B8h+var_840]
00000000749CCF42 mov [rsp+8B8h+var_840], rax
00000000749CCF47 lea rax, [r11-28h]
00000000749CCF4B mov [r11-830h], rax
00000000749CCF52 lea rax, [rsp+8B8h+var_848]
00000000749CCF57 mov [rsi+1498h], rax
00000000749CCF5E mov rax, [r10+r9*8] ; rax = 真正的函数表地址
00000000749CCF62 mov r12, [rax+r8*8] ; r12 = 索引对于的函数地址
00000000749CCF66 mov [rsp+8B8h+Table], edx
00000000749CCF6A mov [rsp+8B8h+Index], r8d
00000000749CCF6F
00000000749CCF6F loc_749CCF6F: ; DATA XREF: .text:00000000749F3F60↓o
00000000749CCF6F ; .text:00000000749F3F70↓o
00000000749CCF6F mov eax, [rdi+34h]
00000000749CCF72 mov [rsi+_TEB.LastErrorValue], eax
00000000749CCF75 mov rax, cs:pfnWow64LogSystemService
00000000749CCF7C test rax, rax
00000000749CCF7F jnz short loc_749CCF8F
00000000749CCF81 mov rcx, rbx
00000000749CCF84 call r12 ;将调用到表中对应的函数 在本次中这个函数为whNtReadVirtualMemory也位于Wow64.dll中
00000000749CCF87 mov ebx, eax
00000000749CCF89 mov [rsp+8B8h+Result], eax
00000000749CCF8D jmp short loc_749CCFC0
whNtReadVirtualMemory:
00000000749DAC78 mov [rsp+arg_10], rbx
00000000749DAC7D push rsi
00000000749DAC7E push rdi
00000000749DAC7F push r12
00000000749DAC81 push r13
00000000749DAC83 push r14
00000000749DAC85 sub rsp, 30h
00000000749DAC89
00000000749DAC89 loc_749DAC89: ; DATA XREF: .text:00000000749F0DC8↓o
00000000749DAC89 movsxd r12, dword ptr [rcx] ; rcx = 参数地址,依次取出参数 放入寄存器中
00000000749DAC8C mov esi, [rcx+4]
00000000749DAC8F mov edi, [rcx+8]
00000000749DAC92 mov ebx, [rcx+0Ch]
00000000749DAC95 mov r13d, [rcx+10h]
00000000749DAC99 mov rdx, r13
00000000749DAC9C lea rcx, [rsp+58h+arg_8]
00000000749DACA1 call Wow64ShallowThunkSIZE_T32TO64 ; 如果所给lpNumberOfBytesRead不为空则 选用栈上的一个地址 暂时代替这个地址
00000000749DACA6 mov r14, rax
00000000749DACA9 mov [rsp+58h+var_38], rax ;将第五个参数即rsp+58h+arg_8 压栈
00000000749DACAE mov r9, rbx ;将前四个参数放入寄存器中
00000000749DACB1 mov r8, rdi
00000000749DACB4 mov rdx, rsi
00000000749DACB7 mov rcx, r12
00000000749DACBA call cs:__imp_NtReadVirtualMemory ;接下如就是进入ntdll 调用该函数
00000000749DACC0 mov r11d, eax
00000000749DACC3 test r14, r14
00000000749DACC6 jnz short loc_749DACCF
00000000749DACC8 and [rsp+58h+arg_0], r14
00000000749DACCD jmp short loc_749DACE4
00000000749DACCF ; ---------------------------------------------------------------------------
00000000749DACCF
00000000749DACCF loc_749DACCF: ; CODE XREF: whNtReadVirtualMemory+4E↑j
00000000749DACCF mov eax, 0FFFFFFFFh
00000000749DACD4 cmp [r14], rax ;如果返回的读取地址长度部位-1 则将暂存在rsp+58h+var_38中的数据 写入到真正的所给地址中
00000000749DACD7 cmovb rax, [r14]
00000000749DACDB mov [r13+0], eax
00000000749DACDF mov [rsp+58h+arg_0], r13
00000000749DACE4
00000000749DACE4 loc_749DACE4: ; CODE XREF: whNtReadVirtualMemory+55↑j
00000000749DACE4 ; DATA XREF: .text:00000000749F0DC8↓o
00000000749DACE4 mov eax, r11d
00000000749DACE7 mov rbx, [rsp+58h+arg_10]
00000000749DACEC add rsp, 30h
00000000749DACF0 pop r14
00000000749DACF2 pop r13
00000000749DACF4 pop r12
00000000749DACF6 pop rdi
00000000749DACF7 pop rsi
00000000749DACF8 retn
接下来就进入ntdll中的对应函数
0000000077A01700 4C 8B D1 mov r10,rcx
0000000077A01703 B8 3C 00 mov eax,0x0000003C
0000000077A01708 0F 05 syscall
0000000077A0170A C3 retn
接下去就是要进入0环调用