分析最近TrickBot的马时遇到了32位进程通过0x33段进入64位环境执行一段64位shellcode,直接让我放弃了用x32调试器继续调试的想法,指令、寄存器面目全非。以此开始了解了名为“HEAVEN'S GATE”的技术。
首先先了解一下什么是wow64。
Windows on Windows64:64位进程中的32位子系统(https://zh.wikipedia.org/wiki/WoW64)。
完整的子系统包括32位主映像、32位DLL,都运行在进程的32位地址空间中。
通过NTDLL、其他DLL与64位环境通信,使WOW64子系统兼容于64位进程中。
每个WoW64进程都包含NTDLL的本机版本,WoW64使用三个动态链接库(wow64.dll、wow64cpu.dll、wow64win.dll)实现兼容必需的接口。
32位ntdll不以任何方式发送系统调用或直接与操作系统通信。相反,它调用这些作为兼容的DLL,它们启动一系列调用和跳转,切换到64位模式,并修改函数参数以使它们兼容64位。
在64位NTDLL内部的API调用中调度syscall,完成调用。
查看一个32位进程模块列表,其中有前面提到了3个wow64接口dll,并且存在俩个NTDLL.dll,其中之一位于64位地址空间中。
在32位API函数中放置一个断点,并查看它的调用(https://docs.microsoft.com/en-us/windows/win32/winprog64/debugging-wow64):
0:000>.reload /f0:000>.load wow64exts0:000> !wow64exts.swSwitched to Guest (WoW) mode0:000:x86> bp NtAllocateVirtualMemory...ntdll_77a90000!NtAllocateVirtualMemory:77afde70 b818000000 mov eax,18h0:000:x86> untdll_77a90000!NtAllocateVirtualMemory:77afde70 b818000000 mov eax,18h77afde75 ba3024b177 mov edx,offset ntdll_77a90000!Wow64SystemServiceCall (77b12430)77afde7a ffd2 call edx77afde7c c21800 ret 18h
API函数没有执行syscall,而是调用Wow64SystemServiceCall:
0:000:x86> u ntdll_77a90000!Wow64SystemServiceCallntdll_77a90000!Wow64SystemServiceCall:77b12430 ff251812ba77 jmp dword ptr [ntdll_77a90000!Wow64Transition (77ba1218)]
导出函数Wow64Transition指向wow64cpu!KiFastSystemCall,该函数实现从x86到x64模式的转换(https://bbs.pediy.com/thread-189808.htm)。
0:000:x86> u poi(ntdll_77a90000!Wow64Transition)wow64cpu!KiFastSystemCall:729f7000 ea09709f723300 jmp 0033:729F7009729f7007 0000 add byte ptr [eax],al729f7009 41 inc ecx729f700a ffa7f8000000 jmp dword ptr [edi+0F8h]
跳转CS:0x33段,下面继续单步。
0:000:x86> pwow64cpu!KiFastSystemCall:6e967000 ea0970966e3300 jmp 0033:6E9670090:000:x86> pwow64cpu!KiFastSystemCall+0x9:00000000`6e967009 41ffa7f8000000 jmp qword ptr [r15+0F8h] ds:00000000`6e9646c8={wow64cpu!CpupReturnFromSimulatedCode (00000000`6e961cb6)}0:000> uwow64cpu!KiFastSystemCall+0x9:00000000`6e967009 41ffa7f8000000 jmp qword ptr [r15+0F8h]00000000`6e967010 0000 add byte ptr [rax],al00000000`6e967012 0000 add byte ptr [rax],al00000000`6e967014 0000 add byte ptr [rax],al00000000`6e967016 0000 add byte ptr [rax],al00000000`6e967018 0000 add byte ptr [rax],al00000000`6e96701a 0000 add byte ptr [rax],al00000000`6e96701c 0000 add byte ptr [rax],al
现在开始使用单步(p)和运行到分支(ph)命令执行寻找NtAllocateVirtualMemory。
0:000:x86> pwow64cpu!KiFastSystemCall+0x9:00000000`6e967009 41ffa7f8000000 jmp qword ptr [r15+0F8h] ds:00000000`6e9646c8={wow64cpu!CpupReturnFromSimulatedCode (00000000`6e961cb6)}0:000> pwow64cpu!CpupReturnFromSimulatedCode:00000000`6e961cb6 4987e6 xchg rsp,r140:000> phwow64cpu!TurboDispatchJumpAddressStart+0x5:00000000`6e961ce8 41ff24cf jmp qword ptr [r15+rcx*8] ds:00000000`6e9645d0={wow64cpu!ServiceNoTurbo (00000000`6e961cec)}0:000> pwow64cpu!ServiceNoTurbo:00000000`6e961cec 8bc8 mov ecx,eax0:000> uwow64cpu!ServiceNoTurbo:00000000`6e961cec 8bc8 mov ecx,eax00000000`6e961cee 498bd3 mov rdx,r1100000000`6e961cf1 ff1569240000 call qword ptr [wow64cpu!_imp_Wow64SystemServiceEx (00000000`6e964160)]00000000`6e961cf7 41894534 mov dword ptr [r13+34h],eax00000000`6e961cfb e9dffeffff jmp wow64cpu!RunSimulatedCode+0x2f (00000000`6e961bdf)wow64cpu!ThunkNone:00000000`6e961d00 cc int 3wow64cpu!GetCurrentProcessorNumber:00000000`6e961d01 b853000000 mov eax,53h00000000`6e961d06 0f03c0 lsl eax,eax0:000> phwow64cpu!ServiceNoTurbo+0x5:00000000`6e961cf1 ff1569240000 call qword ptr [wow64cpu!_imp_Wow64SystemServiceEx (00000000`6e964160)] ds:00000000`6e964160={wow64!Wow64SystemServiceEx (00000000`6e976d50)}0:000> twow64!Wow64SystemServiceEx:00000000`6e976d50 48895c2418 mov qword ptr [rsp+18h],rbx ss:00000000`0009ef80=0000000000500fe80:000> phwow64!Wow64SystemServiceEx+0x7b:00000000`6e976dcb 0f87883c0100 ja wow64!Wow64KiUserCallbackDispatcher+0x2c09 (00000000`6e98aa59) [br=0]0:000> phwow64!Wow64SystemServiceEx+0xa1:00000000`6e976df1 740a je wow64!Wow64SystemServiceEx+0xad (00000000`6e976dfd) [br=0]0:000> phwow64!Wow64SystemServiceEx+0xa3:00000000`6e976df3 0f88513c0100 js wow64!Wow64KiUserCallbackDispatcher+0x2bfa (00000000`6e98aa4a) [br=0]0:000> phwow64!Wow64SystemServiceEx+0x112:00000000`6e976e62 756a jne wow64!Wow64SystemServiceEx+0x17e (00000000`6e976ece) [br=0]0:000> phwow64!Wow64SystemServiceEx+0x121:00000000`6e976e71 7438 je wow64!Wow64SystemServiceEx+0x15b (00000000`6e976eab) [br=0]0:000> phwow64!Wow64SystemServiceEx+0x12d:00000000`6e976e7d 7433 je wow64!Wow64SystemServiceEx+0x162 (00000000`6e976eb2) [br=0]0:000> phwow64!Wow64SystemServiceEx+0x139:00000000`6e976e89 742e je wow64!Wow64SystemServiceEx+0x169 (00000000`6e976eb9) [br=0]0:000> phwow64!Wow64SystemServiceEx+0x145:00000000`6e976e95 7429 je wow64!Wow64SystemServiceEx+0x170 (00000000`6e976ec0) [br=0]0:000> phwow64!Wow64SystemServiceEx+0x151:00000000`6e976ea1 7424 je wow64!Wow64SystemServiceEx+0x177 (00000000`6e976ec7) [br=0]0:000> phwow64!Wow64SystemServiceEx+0x153:00000000`6e976ea3 ffd6 call rsi {wow64!whNtAllocateVirtualMemory (00000000`6e976a40)}
单步,看到call [wow64cpu!_imp_Wow64SystemServiceEx],步入,运行到call中断。
0:000> pcwow64!Wow64SystemServiceEx+0x153:00000000`6e976ea3 ffd6 call rsi {wow64!whNtAllocateVirtualMemory (00000000`6e976a40)}
运行到分支处中断:_imp_NtAllocateVirtualMemory
0:000> phwow64!whNtAllocateVirtualMemory+0xa2:00000000`6e976ae2 ff15c8f50200 call qword ptr [wow64!_imp_NtAllocateVirtualMemory (00000000`6e9a60b0)] ds:00000000`6e9a60b0={ntdll!NtAllocateVirtualMemory (00007ffc`b1555150)}
查看地址指向的汇编指令:_imp_NtAllocateVirtualMemory,在这里调用syscall。
0:000> u poi(wow64!_imp_NtAllocateVirtualMemory)ntdll!NtAllocateVirtualMemory:00007ffc`b1555150 4c8bd1 mov r10,rcx00007ffc`b1555153 b818000000 mov eax,18h00007ffc`b1555158 f604250803fe7f01 test byte ptr [SharedUserData+0x308 (00000000`7ffe0308)],100007ffc`b1555160 7503 jne ntdll!NtAllocateVirtualMemory+0x15 (00007ffc`b1555165)00007ffc`b1555162 0f05 syscall00007ffc`b1555164 c3 ret00007ffc`b1555165 cd2e int 2Eh00007ffc`b1555167 c3 ret
查看堆栈有如下调用关系
0:000> tntdll!NtAllocateVirtualMemory:00007ffc`b1555150 4c8bd1 mov r10,rcx0:000> k# Child-SP RetAddr Call Site00 00000000`0009e5f8 00000000`6e976ae8 ntdll!NtAllocateVirtualMemory01 00000000`0009e600 00000000`6e976ea5 wow64!whNtAllocateVirtualMemory+0xa802 00000000`0009e6b0 00000000`6e961cf7 wow64!Wow64SystemServiceEx+0x15503 00000000`0009ef70 00000000`6e98bfa1 wow64cpu!ServiceNoTurbo+0xb04 00000000`0009f020 00000000`6e97cbb0 wow64!Wow64KiUserCallbackDispatcher+0x415105 00000000`0009f0a0 00007ffc`b1541791 wow64!Wow64LdrpInitialize+0x12006 00000000`0009f350 00007ffc`b1577b28 ntdll!LdrpInitializeProcess+0x155107 00000000`0009f750 00007ffc`b1528d6e ntdll!_LdrpInitialize+0x4ed6408 00000000`0009f7d0 00000000`00000000 ntdll!LdrInitializeThunk+0xe
在64位窗口上的每个进程中有2个代码段:
0x23=x86模式
0x33=x64模式
这里call far 33:xxxx,使处理器切换到x64。从这里开始,我们可以与64位函数通信并执行syscall。
应用程序怎么知道天堂之门在哪里的:通过FS寄存器,FS:0xC0 or TIB + 0xC0(https://en.wikipedia.org/wiki/Win32_Thread_Information_Block)。
许多安全产品都了安装钩子来监视系统函数,在WoW64进程中,这些钩子只安装在32位函数上,WoW64过渡的整个阶段是不受监控的。
将X86代码转换为X64模式
查找NTDLL中64位API函数的地址并跳转到它,不经过32位NTDLL
绕过钩子,避免监测
可以用来注入一个64位DLL,该文件不会被监视到
https://github.com/rwfpl/rewolf-wow64ext/
https://github.com/orca-eaa5a/HeavensGate_PoC/
https://github.com/yusakul/HEAVEN-S-GATE
创建notepad进程写入数据
写入成功
火绒剑监控事件如下
hook HEAVEN'S GATE,判断调用号筛选目标函数
缓解措施
Kernel hooks
Kernel callbacks
Hook 64-bit NTDLL
更多学习教程,github.com/haidragon。