<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

文章分类

导航

订阅

WoW64的切换细节

64位的Windows中可以运行32位的应用程序,这就是所谓的WoW64技术,全称即Windows 32-bitApplications on Windows 64-bitOS)。如何实现的呢?细说话长,关键是如下几个要点:

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

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

首先,上面是32位的代码,来自USER32.dll。是窗口API的内部实现,所谓的Service Stub,用来调用系统服务的,1002是服务的编号。本来这个代码中应该使用syscall这样的指令发起系统调用的。但是这里调用的一个函数指针,位置是fs段的c0字段。看着《软件调试》的朋友一定知道fs指向的是线程的环境块,即TEBDt一下TEB便知道偏移C0的地方叫WOW32Reserved真的与WoW有关,以前没有注意这个字段的真正用途,现在可以明确知道它保存的是一个函数指针了。

 

+0x0c0 WOW32Reserved    : Ptr32 Void

 

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

wow64cpu!X86SwitchTo64BitMode:

74772320 ea1e2777743300  jmp     0033:7477271E

 

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

再看这条指令的段描述符,是33,也很特别,因为32代码用的代码段选择子总是23。其实这就是奥妙所在。对于支持Win64x64 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从虚拟环境的代码回来了

posted on 2012年12月6日 20:32 由 Raymond

Powered by Community Server Powered by CnForums.Net