Windows操作系统——WoW64

简介

64位操作系统的底层都是64位的,而在64位的Windows中是可以运行32位的应用程序。

为此提供支持的就是所谓的WoW64技术,全称即Windows 32-bit(Applications) on Windows 64-bit(OS)。

核心就是,在系统中同时包含32位程序和64位程序的运行环境(依赖的各种dll、注册表里的配置项),32位程序对系统运行环境的引用都被重定向到32位的运行环境。具体包括:

  • system32重定向到SysWOW64
  • Program Files重定向到Program Files(x86)
  • HKLM\SOFTWARE重定向到HKLM\SOFTWARE\Wow6432Node

如何实现

关键是如下几个要点:

1)32位代码和64位的内核之间有一个转接层,称为thunk layer。形象的说,转接层的作用是“欺上瞒下”,对于内核来说,好像上面跑得就是一个64位的应用,而对于应用来讲,也会觉得还是跑在32位的内核上。

2)转接层本身主要是64位代码(有一点32位指令,见下文)。除了转接层外,Wow进程中的其它用户态模块必须都是32位的,包括kernel32.dll, user32.dll等模块。也正因为此,为了支持WoW64,在Windows系统目录下的SysWow64下完完整整的安装着一套32位的系统DLL。刚刚看了下正在用的这个64 Win7的SysWow64目录,居然有1.25GB。这个目录下的模块都是32位的,是专门给32位应用程序用的,虽然目录名中有64。

顺便说下,在Win64中,system32目录下放的都是64位模块。

WoW64几个相关DLL
Wow64.dll:管理进程和线程的创建,勾住异常分发和Ntoskrnl.exe导出的基本系统调用,实现文件重定向及注册表重定向。
Wow64Cpu.dll:提供处理器体系结构相关支持。
Wow64Win.dll:截取Win32k.sys导出的GUI系统调用。
ntdll.dll:中转。

跟踪中转过程

我们从一个32位的API调用入手,来自USER32.dll,看看它在64位系统上如何中转到64位实现代码:

USER32!NtUserCallOneParam:
765e60cd b802100000      mov     eax,1002h
765e60d2 b900000000      mov     ecx,0
765e60d7 8d542404        lea     edx,[esp+4]
765e60db 64ff15c0000000  call    dword ptr fs:[0C0h]  fs:0053:000000c0=00000000
765e60e2 83c404          add     esp,4
765e60e5 c20800          ret     8

这是一个窗口API的内部实现,是一个Service Stub。所谓的Service Stub,是用来调用系统服务的,1002是服务的编号。

本来这个代码中应该使用syscall这样的指令发起系统调用的。但是这里调用的一个函数指针,位置是fs段的c0字段。fs指向的是线程的环境块,即TEB。

用windbg的Dt命令看一下TEB便知道偏移C0的地方叫WOW32Reserved:

+0x0c0 WOW32Reserved    : Ptr32 Void

从名字就可以看出,这个成员与WoW有关,它就是保存这里调用的函数地址的函数指针。

单步跟踪一下,发现这个函数指针指向的是下面这个内容:

wow64cpu!X86SwitchTo64BitMode:
74772320 ea1e2777743300  jmp     0033:7477271E

这两行的信息量很大,根据符号提示,这个代码属于wow64cpu模块,是上面提到的转接层的重要模块之一。从这条指令的“函数名”来看,X86SwitchTo64BitMode,明显是切换用的。

再看这条指令的段描述符,是33,也很特别,因为32代码用的代码段选择子总是23。其实这就是奥妙所在。对于支持Win64的x64 CPU来说,运行64位代码的叫长模式(Long mode),为了兼容32位代码,还有一个所谓的32位兼容模式。CPU可以非常轻松的在长模式和兼容模式之间切换,只要用上面这样的长跳转指令就可以了。CPU会检查段的描述符,如果描述符中有Long标志,那么就切换到长模式,否则就切换到兼容模式。

单步跟踪上面的jmp指令后,就立刻转到64位了,r看一下:

0:000> r
rax=000000000000110e rbx=0000000000000003 rcx=0000000000000005
rdx=000000000018a318 rsi=000000000018a478 rdi=0000000000000005
rip=000000007477271e rsp=000000000018a310 rbp=000000000018a46c
 r8=000000000000002b  r9=00000000765f0de3 r10=0000000000000000
r11=0000000000000246 r12=000000007efdb000 r13=000000000008fd20
r14=000000000008b100 r15=0000000074772450
iopl=0         nv up ei pl zr na po nc
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
wow64cpu!CpupReturnFromSimulatedCode:
00000000`7477271e 67448b0424      mov     r8d,dword ptr [esp] ds:00000000`0018a310=76647d6c

全是64位的了。注意指令的地址,00000000`7477271e,与上面jmp的偏移刚好一致。

这个函数名很有意思,CpupReturnFromSimulatedCode,也就是“从虚拟仿真的代码回来了”。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值