SysWOW64的奇技淫巧
2020-07-28 20:24:26 Author: bbs.pediy.com(查看原文) 阅读量:364 收藏

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

这玩意儿用处:

(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)

[公告]看雪论坛2020激励机制上线了!发帖不减雪币了!如何获得积分快速升级?


文章来源: https://bbs.pediy.com/thread-260995.htm
如有侵权请联系:admin#unsafe.sh