首页
论坛
课程
招聘
雪    币: 661
活跃值: 活跃值 (633)
能力值: ( LV9,RANK:160 )
在线值:
发帖
回帖
粉丝

[原创]SysWOW64的奇技淫巧

2020-7-28 16:29 2263

[原创]SysWOW64的奇技淫巧

2020-7-28 16:29
2263

我感觉这玩意儿应该有人写过,但中文互联网怎么搜都搜不到,顺便看了看英文资料。发一个自己的实现好了

这玩意儿用处:

(1)反调试

(2)能让win10 32位程序运行64位代码(其他操作系统的wow64据说实现底层不太一样,不保证同代码能完全运行)


最近在试着转二进制漏洞方向,部署的时候出现了各种版本问题和反复崩溃,看到dynamoRIO下已经有成千的issue,想让开发者来debug肯定是不可能,于是只好自己上了。

在调试的过程中,发现dynamoRIO有一段ASM特别有意思

他是用来在32位程序中执行64位function的一段loader,摘抄见附录

关键的代码只有这么几行

       RAW(ea)    
       DD offset sml_transfer_to_64    
       DB CS64_SELECTOR    
       RAW(00)

通过一个长跳转,进入CS64_SELECTOR段选择子后,进入64位模式

       /* far jmp to next instr w/ 32-bit switch: jmp 0023:<sml_return_to_32> */    
       push     offset sml_return_to_32  /* 8-byte push */    
       mov      dword ptr [esp + 4], CS32_SELECTOR /* top 4 bytes of prev push */    
       jmp      fword ptr [esp]

我试了试摘出来写成汇编,效果非常好。

在OD里不仅分析不出64位的汇编,而且单步会直接跟飞。在windbg里只有单步才能分析出x64的代码

自己写的汇编如下

.386
.model flat, stdcall  ;32 bit memory model
option casemap :none  ;case sensitive

include Test.inc

.data
strTitle db 'Helloworld!',0
.code

start:
    invoke MessageBox,0,addr strTitle,addr strTitle,0
    xor eax,eax
    mov edi,0FFFFFFFFH
    db 0eah
    dd offset sys64_start
    db 033h
    db 0
sys64_start:

    db 049h, 08bh, 0d7h ;mov rdx,r15
    
    push 0
    push offset sys32_start
    mov dword ptr[esp + 4],023h
    jmp fword ptr[esp]
    
sys32_start:
    mov eax,0
    mov ebx,0
    pop eax
    pop eax
    pop eax
    pop eax
    invoke MessageBox,0,addr strTitle,addr strTitle,0
    retn
end start




至于为什么这么改,外网有篇文章(https://www.malwaretech.com/2014/02/the-0x33-segment-selector-heavens-gate.html)写得特别好,我就不画蛇添足了,大概把大意翻译过来


首先,长跳转的机制是修改段寄存器CS来进行寻址和改变权限。段寄存器的结构分为selector、TL和RPL,selector代表段寄存器在GDT中对应的index,TL代表应该查局部表还是全局表(LDT/GDT),RPL是权限位。0x23和0x33的段寄存器如下。

我们知道段寄存器TL=0时还是要去查GDT得到完整的段描述,在GDT中,0x23和0x33的信息如下

可以看到0x23和0x33唯一的区别就是Flags和limits位。

在0x23的32位系统中,Limits位需要设为0xFFFFF来达到最大寻址空间4GB,而在x64 win10中,已经完全放弃了使用段寄存器进行寻址的方式,全部采用分页机制。因此GDT的limit和base全部设为0进行“平坦模式”。

Flags位的结构如下:

Gr(granularity)代表限长单位,在32位系统中一般都设为1代表Limits单位是4K(因此4K*0xFFFFF=4G),如果是0则Limits单位是byte,这个值在64位系统中无意义

L代表64位模式。这一位很多比较远古的书上是保留位

D/B则是32位下的操作数位数,这个和代码段、堆栈段有关系,但是在64位下也没有意义。


综上,通过切换CS段选择器可以在syswow64中左右横跳。


附录:

/* Routines to switch to 64-bit mode from 32-bit WOW64, make a 64-bit    
* call, and then return to 32-bit mode.    
*/    
/*    
* int switch_modes_and_load(void *ntdll64_LdrLoadDll,    
*                           UNICODE_STRING_64 *lib,    
*                           HANDLE *result)    
* XXX i#1633: this routine does not yet support ntdll64 > 4GB    
*/    
# define FUNCNAME switch_modes_and_load    
       DECLARE_FUNC(FUNCNAME)    
GLOBAL_LABEL(FUNCNAME:)    
       /* get args before we change esp */    
       mov      eax, ARG1    
       mov      ecx, ARG2    
       mov      edx, ARG3    
       /* save callee-saved registers */    
       push     ebx    
       /* far jmp to next instr w/ 64-bit switch: jmp 0033:<sml_transfer_to_64> */    
       RAW(ea)    
       DD offset sml_transfer_to_64    
       DB CS64_SELECTOR    
       RAW(00)    
sml_transfer_to_64:    
   /* Below here is executed in 64-bit mode, but with guarantees that    
    * no address is above 4GB, as this is a WOW64 process.    
    */    
      /* Call LdrLoadDll to load 64-bit lib:    
       *   LdrLoadDll(IN PWSTR DllPath OPTIONAL,    
       *              IN PULONG DllCharacteristics OPTIONAL,    
       *              IN PUNICODE_STRING DllName,    
       *              OUT PVOID *DllHandle));    
       */    
       RAW(4c) RAW(8b) RAW(ca)  /* mov r9, rdx : 4th arg: result */    
       RAW(4c) RAW(8b) RAW(c1)  /* mov r8, rcx : 3rd arg: lib */    
       push     0               /* slot for &DllCharacteristics */    
       lea      edx, dword ptr [esp] /* 2nd arg: &DllCharacteristics */    
       xor      ecx, ecx        /* 1st arg: DllPath = NULL */    
       /* save WOW64 state */    
       RAW(41) push     esp /* push r12 */    
       RAW(41) push     ebp /* push r13 */    
       RAW(41) push     esi /* push r14 */    
       RAW(41) push     edi /* push r15 */    
       /* align the stack pointer */    
       mov      ebx, esp        /* save esp in callee-preserved reg */    
       sub      esp, 32         /* call conv */    
       and      esp, HEX(fffffff0) /* align to 16-byte boundary */    
       call     eax    
       mov      esp, ebx        /* restore esp */    
       /* restore WOW64 state */    
       RAW(41) pop      edi /* pop r15 */    
       RAW(41) pop      esi /* pop r14 */    
       RAW(41) pop      ebp /* pop r13 */    
       RAW(41) pop      esp /* pop r12 */    
       /* far jmp to next instr w/ 32-bit switch: jmp 0023:<sml_return_to_32> */    
       push     offset sml_return_to_32  /* 8-byte push */    
       mov      dword ptr [esp + 4], CS32_SELECTOR /* top 4 bytes of prev push */    
       jmp      fword ptr [esp]    
sml_return_to_32:    
       add      esp, 16         /* clean up far jmp target and &DllCharacteristics */    
       pop      ebx             /* restore callee-saved reg */    
       ret                      /* return value already in eax */    
       END_FUNC(FUNCNAME)




HWS计划·2020安全精英夏令营来了!我们在华为松山湖欧洲小镇等你

最新回复 (13)
雪    币: 9081
活跃值: 活跃值 (425)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
pureGavin 活跃值 2020-7-28 16:38
2
0
mark,楼主辛苦了
雪    币: 1340
活跃值: 活跃值 (74)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
zhouws 活跃值 2 2020-7-28 17:21
3
0
看这用处还不错,其实他们好像是可以互相跳的,毕竟指令都支持, 只是切下模式,改好运行环境即可
PS:还能有这么折腾的人不多了
雪    币: 661
活跃值: 活跃值 (633)
能力值: ( LV9,RANK:160 )
在线值:
发帖
回帖
粉丝
NONAME剑人 活跃值 3 2020-7-28 17:41
4
0
zhouws 看这用处还不错,其实他们好像是可以互相跳的,毕竟指令都支持, 只是切下模式,改好运行环境即可 PS:还能有这么折腾的人不多了[em_1]
我没试过在raw.x64下能不能切回来,我总感觉syswow64的做的初始化细节、重定位什么的这样直接bypass过去了还是有问题的

这年头除了病毒、壳和cm,几乎很少有反调试的场景了
雪    币: 1176
活跃值: 活跃值 (78)
能力值: ( LV3,RANK:32 )
在线值:
发帖
回帖
粉丝
蜜蜂啊 活跃值 2020-7-28 19:01
5
0
大家可以参考 https://github.com/rwfpl/rewolf-wow64ext 这个库
雪    币: 661
活跃值: 活跃值 (633)
能力值: ( LV9,RANK:160 )
在线值:
发帖
回帖
粉丝
NONAME剑人 活跃值 3 2020-7-28 23:29
6
0
蜜蜂啊 大家可以参考 https://github.com/rwfpl/rewolf-wow64ext 这个库
谢谢大佬!!!
雪    币: 661
活跃值: 活跃值 (633)
能力值: ( LV9,RANK:160 )
在线值:
发帖
回帖
粉丝
NONAME剑人 活跃值 3 2020-7-29 00:08
7
0

借人气搭车求问一个非常诡异的问题……这个问题是dynamoRIO部署时AMD Ryzen特有的错误,就是和x86/x64切换有关
简而言之,在从x64切换回到x86时,dynamoRIO在执行主帖中附录的ASM程序遇到了个奇怪的错误——在程序的第61行pop ebx处出现了Access violation - code c0000005错误。而此时的ss和es值都是正常的。当程序单步调试时,一切正常,然而单独运行就会在这里崩溃


https://github.com/DynamoRIO/dynamorio/issues/4091
非常挠头,别怕又是什么处理器级别的BUG

最后于 2020-7-29 00:12 被NONAME剑人编辑 ,原因:
雪    币: 1
活跃值: 活跃值 (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
songqy 活跃值 2020-7-29 11:09
8
0
我写过一个工具可以使32bit程序链接64位的lib,最终形成一个32位与64位机器码混合的可执行文件。不过没有开源。
https://github.com/MoePus/wowHijack 这里则是另一个wow64特性的应用,32位程序可以使用WPM函数修改当前线程的eip。
雪    币: 188
活跃值: 活跃值 (58)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
wujimaa 活跃值 1 2020-7-29 11:40
9
0
标志,收藏
雪    币: 661
活跃值: 活跃值 (633)
能力值: ( LV9,RANK:160 )
在线值:
发帖
回帖
粉丝
NONAME剑人 活跃值 3 2020-7-29 15:43
10
0
songqy 我写过一个工具可以使32bit程序链接64位的lib,最终形成一个32位与64位机器码混合的可执行文件。不过没有开源。 https://github.com/MoePus/wowHijack 这里则 ...
感谢!!!!收藏了
雪    币: 2379
活跃值: 活跃值 (625)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
dayday向上8 活跃值 2 2020-7-29 21:44
11
0
希望大佬再次归来能够多多分享,菜鸟mark了
雪    币: 2144
活跃值: 活跃值 (75)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
hhkqqs 活跃值 2020-7-30 13:06
12
0
蜜蜂啊 大家可以参考 https://github.com/rwfpl/rewolf-wow64ext 这个库
这个库bug不少,尤其是调用某些参数是结构体地址并且要求地址内存对齐的,只能自己malloc一块对齐的内存存放,效率低下,而直接用汇编对齐rsp来存放兼容性又很差,不知道楼主有什么解决方案
雪    币: 256
活跃值: 活跃值 (151)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ZwCopyAll 活跃值 2020-7-30 13:49
13
0
呵呵
雪    币: 3727
活跃值: 活跃值 (75)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
MsScotch 活跃值 2020-7-30 16:35
14
0
可以试试:利用CS切入,retf 返回,指令对齐可以利用预配置去设定,或者在跳转R15的时候,Hook掉,重新写执行流程(某个AV就是这么做的)。
游客
登录 | 注册 方可回帖
返回