今天见RT系统被破解了,作为一个Win32开发者我很高兴,所以找到了原文,人工为大家翻译了一下。
其实我也看得一头晕,英语考试挂科的人,译得也许不咋样,不过原文大意算是表达的比较完整的。
原文: http://surfsec.wordpress.com/2013/01/06/circumventing-windows-rts-code-integrity-mechanism/
译文:
解决这个问题虽然用了不少时间,但我们确实搞定它了:使未经微软签名的桌面应用程序在Windows RT中运行。
很讽刺的是,这个“漏洞”已经存在了有一段时间了,就像Windows在其他平台的漏洞一样,这个漏洞也跟随母体“转移”到ARM的Windows Kernel中来了,所以让我们使这一切成为可能。
微软强制的不兼容桌面应用程序,使它们不能正常运行,但是Windows RT是个十分干净的客户端,这是一个很好的情况。我们发现,在内核深处中使用UEFI安全引导,和基于散列及签名的数据段关键保护,还有就是验证程序的二进制码最低签名等级。
【查找关键点】
以最低签名级别判断可执行文件是否可以执行是这样做的:0=没有签名,4=可信任代码(文件有签名),8=微软公司的组件,12=Windows系统组件。
而在Intel x86的Windows系统上,这个最低签名判断值为0,也就是说我们可以运行任何程序,即便这个程序没有经过数字签名。而在ARM的Windows RT上,这个值则是8。
这意味着,即使你能申请到个人签名认证,而你使用这个签名开发出来的桌面应用程序仍不能运行在其他Surface RT或Windows RT设备上。这不是用户设置的,是在内核本身内就硬编码了这个全局值。虽然不能改变这个设备启用了永久性UEFI安全引导,但是启动后我们倒可以在内存中修改它!
在内核中找到这个标示最低签名认证的字节,需要很长的一段时间,因为没有导出符号,甚至微软也没有给出符号数据库文件(pdb),可我通过使用WinDbg在一台装有Windows 8 Pro的PC上跟踪创建进程,并观察系统在创建进程时进行签名检查等一切行为,而发现这个检查在一个叫CL.dll的文件内部(译者:有这个文件?),而这个检查在Windows RT上则是如此的相似,是不是可以从ARM的代码内解决它呢,下面是代码:
SeGetImageRequiredSigningLevel+0x18
LDR R3, =0x59FFA6 -> 这是我们的字节指针, 0x19FFA6 at 0x400000(Image Base)
LDRB R3, [R3]
CMP R3, #4
BHI loc_HighSigReq
B.W loc_LowSigReq
其实在其他很多地方你都可以找到对这个字节的访问,可因为没有调试符号,这做起来十分困难。
【分析】
前段时间,我读过一篇关于如何在Windows Kernel中使通过一定地方的数据始终是完整的文章(此处翻译生硬了些),而此漏洞同样存在于Windows RT,但相比Windows 8,要实现起来还是十分的困难,因为无签名的二进制文件无法运行,以及我们也没有调试器,没有在Windows RT上调试这个系统的工具,无法附加到任何进程,十分无奈。
但是,微软却提供了一个起到了很重要作用的工具(Visual Studio 2012 Remote Tools),让这个困难的工作一下子轻松了不少,这个在x86可使用的远程调试器,使用管理员权限运行它,可以附加到RT系统当前用户的csrss进程,查看csrss操作的内存。
我们发现csrss中有大量可以被利用的NtUserSetInformationThread函数调用,以及还有它的参数等信息,利用它可以进行一些猥琐的操作,如下面这一个:
TerminalServerRequestThread+0x230
MOVS R3, #0xC
ADD R2, SP, #0x58
MOVS R1, #9
MOV R0, 0xFFFFFFFE
BL NtUserSetInformationThread (译者注:ARM汇编中的BL即跟x86的CALL指令差不多)
有一个csrss的线程会执行上面这样的代码,使用调试断点,我们可以改变执行NtUserSetInformationThread函数时的数据结构和参数,改变R2寄存器的值,可惜,这是非常不实际的,因为这个漏洞从特定的地址-1,而我们需要减去0x80000,这是因为我们不能在ARM上进行非对齐访问(译者注:4字节对齐),还记得上面没,我们的地址是0x19FFA6,我们不能进行一个非对齐访问,所以我们需要使用0x19FFA4。
我们还需要加载代码到内核映像中(跟x86的载入驱动到Ring0差不多道理),通过调用NtQuerySystemInformation,使用class的值为11,(还可以使任何Windows RT设备上运行未签名的Windows Store应用程序。如果你想知道如何使用NtQuerySystemInformation来进行这个设置,请查阅:Using the complete Windows API in store apps (mamaich at XDA-Developers)),这个11的值返回的数据为我们提供了所有加载驱动的镜像基地址,在这种情况下,绕过ASLR还是有可能的。(虽然这烦人的东西并不是什么ASLR)
(译者注:NtQuerySystemInformation的11号值在x86下为SystemModuleInformation,即获取系统所有载入的驱动设备信息,x86下流程为psapi.EnumDeviceDrivers->kernelbase.K32EnumDeviceDrivers->NtQuerySystemInformation:SystemModuleInformation)
【破解】
使用微软提供的远程调试器调试ARM本机代码,我使用了一片在winsrv.dll的空间(这个dll的基地址是0x10800)来存储这小片shellcode:
push {r5-r8}
mov r7, 0x80000
ldr r8, my_addr
loc_loop_begin:
movs r3, 0xC
add r2, sp, 0x68 ;0x58 org.
add r5, r2, 4
str r8, [r5]
movs r1, 9
mvn r0, 1
mov r12, 0x10E1
svc 1
subs r7, r7, 1
cmp r7, 0
bne loc_loop_begin
pop {r5-r8}
mov r0, r0
my_addr dcd 0x12345678 the kernel's base address + 0x18
现在我们在TerminalServerRequestThread调用NtUserSetInformationThread时设置断点,然后按下音量键,断点会被触发。这倒是十分有趣。
然后我们更改执行代码指针在内存中的地址,改到我们上面的代码,然后在mov r0, r0指令结束时设置一个断点,按F5运行,现在设置指令指针到断点前的第一个指令,再次按F5。
(可能这里译得很恶心,贴原文:Redirect the instruction pointer to the payload in memory and set a breakpoint at the mov r0, r0 instruction at the end. Press F5. Now set the instruction back to the first breakpoint and remove both. Press F5 again.)
这样做后,恭喜你,你的Windows RT设备已经解锁。
【结论】
Windows RT是一个十分干净的Windows 8客户端,看了上文,想必大家也明白,它们的内部其实十分的相像。而微软公司人为的强制进行代码完整性检查,想以此将这2个平台隔离开来,但这并不能避免Windows Store程序的被盗版和修改(及许可检查),因为Windows Store程序本来就可以未经签名执行,这与Windows 8是多么的相似。
而你甚至可以在Windows 8上开启代码完整性检查,来体验一下Windows RT的感觉。
设置这个检查的决定十分恶心,作为一个提高生产力的设备,Windows RT需要Win32的软件生态系统来完善它,市场上的消费型平板已经够多了。
微软,请让我们可以选择是否启用Windows RT的代码检查机制,这样可以增加Windows RT设备的市场价值!
【待解决的破解上的缺陷】
经过我们的修改后,有时候会让系统蓝屏(BugCheck),因为我们无法控制不写入单个字节在0x19FFA4和0x19FFA5内核基地址,而它们有时候是0,修改后则照成了0x18号的蓝屏错误。
我们现在的修改方法对大部分用户来说都是很不切实际的,因为相比PC用户来说,这些平板电脑的消费者都不太可能对计算机有深入的了解。
其实这篇文章的意愿大概就是说,VS2012虽然能编译出Native Code的桌面Windows RT应用程序(见谷歌),可我们无法运行,虽然可以申请个人签名,让这个程序能在本机运行,可发布出去别人还是没办法运行,所以有必要破解掉,这样以后我们可以用VS编译出如x86一样的原生桌面程序,并可分发给其他人在Windows RT的桌面上运行。
可见上面的Native Code都是ARM平台的,所以传统的x86应用程序是不可能运行在RT上的(就像你32系统无法运行64程序一样),即便PE格式一样,可代码完全不同,但如果上层Win32 API接口相同并且都已经实现可用,那就可以使用ARM的Native Code编译器编译到Windows RT的桌面应用程序。也许会有一些小部分的修改,但只要这个x86的Win32项目没有x86本机指令相关的代码和x86 Windows底层相关的代码,就可以比较方便的进行移植到RT设备上,让RT设备得到存在多年的Win32生态系统的强力支持,虽然Win32生态系统很老了,应用程序也没有对触摸进行优化,可在传统的键盘+鼠标模式下,这也就符合了原文作者说的“生产力”设备的概念了。
译者也就解释那么多了,如果有哪里说错,大家要喷我也认了。