分析最近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 /f
0:000>.load wow64exts
0:000> !wow64exts.sw
Switched to Guest (WoW) mode
0:000:x86> bp NtAllocateVirtualMemory
...
ntdll_77a90000!NtAllocateVirtualMemory:
77afde70 b818000000 mov eax,18h
0:000:x86> u
ntdll_77a90000!NtAllocateVirtualMemory:
77afde70 b818000000 mov eax,18h
77afde75 ba3024b177 mov edx,offset ntdll_77a90000!Wow64SystemServiceCall (77b12430)
77afde7a ffd2 call edx
77afde7c c21800 ret 18h
API函数没有执行syscall,而是调用Wow64SystemServiceCall:
0:000:x86> u ntdll_77a90000!Wow64SystemServiceCall
ntdll_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:729F7009
729f7007 0000 add byte ptr [eax],al
729f7009 41 inc ecx
729f700a ffa7f8000000 jmp dword ptr [edi+0F8h]
跳转CS:0x33
段,下面继续单步。
0:000:x86> p
wow64cpu!KiFastSystemCall:
6e967000 ea0970966e3300 jmp 0033:6E967009
0:000:x86> p
wow64cpu!KiFastSystemCall+0x9:
00000000`6e967009 41ffa7f8000000 jmp qword ptr [r15+0F8h] ds:00000000`6e9646c8={wow64cpu!CpupReturnFromSimulatedCode (00000000`6e961cb6)}
0:000> u
wow64cpu!KiFastSystemCall+0x9:
00000000`6e967009 41ffa7f8000000 jmp qword ptr [r15+0F8h]
00000000`6e967010 0000 add byte ptr [rax],al
00000000`6e967012 0000 add byte ptr [rax],al
00000000`6e967014 0000 add byte ptr [rax],al
00000000`6e967016 0000 add byte ptr [rax],al
00000000`6e967018 0000 add byte ptr [rax],al
00000000`6e96701a 0000 add byte ptr [rax],al
00000000`6e96701c 0000 add byte ptr [rax],al
现在开始使用单步(p)和运行到分支(ph)命令执行寻找NtAllocateVirtualMemory。
0:000:x86> p
wow64cpu!KiFastSystemCall+0x9:
00000000`6e967009 41ffa7f8000000 jmp qword ptr [r15+0F8h] ds:00000000`6e9646c8={wow64cpu!CpupReturnFromSimulatedCode (00000000`6e961cb6)}
0:000> p
wow64cpu!CpupReturnFromSimulatedCode:
00000000`6e961cb6 4987e6 xchg rsp,r14
0:000> ph
wow64cpu!TurboDispatchJumpAddressStart+0x5:
00000000`6e961ce8 41ff24cf jmp qword ptr [r15+rcx*8] ds:00000000`6e9645d0={wow64cpu!ServiceNoTurbo (00000000`6e961cec)}
0:000> p
wow64cpu!ServiceNoTurbo:
00000000`6e961cec 8bc8 mov ecx,eax
0:000> u
wow64cpu!ServiceNoTurbo:
00000000`6e961cec 8bc8 mov ecx,eax
00000000`6e961cee 498bd3 mov rdx,r11
00000000`6e961cf1 ff1569240000 call qword ptr [wow64cpu!_imp_Wow64SystemServiceEx (00000000`6e964160)]
00000000`6e961cf7 41894534 mov dword ptr [r13+34h],eax
00000000`6e961cfb e9dffeffff jmp wow64cpu!RunSimulatedCode+0x2f (00000000`6e961bdf)
wow64cpu!ThunkNone:
00000000`6e961d00 cc int 3
wow64cpu!GetCurrentProcessorNumber:
00000000`6e961d01 b853000000 mov eax,53h
00000000`6e961d06 0f03c0 lsl eax,eax
0:000> ph
wow64cpu!ServiceNoTurbo+0x5:
00000000`6e961cf1 ff1569240000 call qword ptr [wow64cpu!_imp_Wow64SystemServiceEx (00000000`6e964160)] ds:00000000`6e964160={wow64!Wow64SystemServiceEx (00000000`6e976d50)}
0:000> t
wow64!Wow64SystemServiceEx:
00000000`6e976d50 48895c2418 mov qword ptr [rsp+18h],rbx ss:00000000`0009ef80=0000000000500fe8
0:000> ph
wow64!Wow64SystemServiceEx+0x7b:
00000000`6e976dcb 0f87883c0100 ja wow64!Wow64KiUserCallbackDispatcher+0x2c09 (00000000`6e98aa59) [br=0]
0:000> ph
wow64!Wow64SystemServiceEx+0xa1:
00000000`6e976df1 740a je wow64!Wow64SystemServiceEx+0xad (00000000`6e976dfd) [br=0]
0:000> ph
wow64!Wow64SystemServiceEx+0xa3:
00000000`6e976df3 0f88513c0100 js wow64!Wow64KiUserCallbackDispatcher+0x2bfa (00000000`6e98aa4a) [br=0]
0:000> ph
wow64!Wow64SystemServiceEx+0x112:
00000000`6e976e62 756a jne wow64!Wow64SystemServiceEx+0x17e (00000000`6e976ece) [br=0]
0:000> ph
wow64!Wow64SystemServiceEx+0x121:
00000000`6e976e71 7438 je wow64!Wow64SystemServiceEx+0x15b (00000000`6e976eab) [br=0]
0:000> ph
wow64!Wow64SystemServiceEx+0x12d:
00000000`6e976e7d 7433 je wow64!Wow64SystemServiceEx+0x162 (00000000`6e976eb2) [br=0]
0:000> ph
wow64!Wow64SystemServiceEx+0x139:
00000000`6e976e89 742e je wow64!Wow64SystemServiceEx+0x169 (00000000`6e976eb9) [br=0]
0:000> ph
wow64!Wow64SystemServiceEx+0x145:
00000000`6e976e95 7429 je wow64!Wow64SystemServiceEx+0x170 (00000000`6e976ec0) [br=0]
0:000> ph
wow64!Wow64SystemServiceEx+0x151:
00000000`6e976ea1 7424 je wow64!Wow64SystemServiceEx+0x177 (00000000`6e976ec7) [br=0]
0:000> ph
wow64!Wow64SystemServiceEx+0x153:
00000000`6e976ea3 ffd6 call rsi {wow64!whNtAllocateVirtualMemory (00000000`6e976a40)}
单步,看到call [wow64cpu!_imp_Wow64SystemServiceEx],步入,运行到call中断。
0:000> pc
wow64!Wow64SystemServiceEx+0x153:
00000000`6e976ea3 ffd6 call rsi {wow64!whNtAllocateVirtualMemory (00000000`6e976a40)}
运行到分支处中断:_imp_NtAllocateVirtualMemory
0:000> ph
wow64!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,rcx
00007ffc`b1555153 b818000000 mov eax,18h
00007ffc`b1555158 f604250803fe7f01 test byte ptr [SharedUserData+0x308 (00000000`7ffe0308)],1
00007ffc`b1555160 7503 jne ntdll!NtAllocateVirtualMemory+0x15 (00007ffc`b1555165)
00007ffc`b1555162 0f05 syscall
00007ffc`b1555164 c3 ret
00007ffc`b1555165 cd2e int 2Eh
00007ffc`b1555167 c3 ret
查看堆栈有如下调用关系
0:000> t
ntdll!NtAllocateVirtualMemory:
00007ffc`b1555150 4c8bd1 mov r10,rcx
0:000> k
# Child-SP RetAddr Call Site
00 00000000`0009e5f8 00000000`6e976ae8 ntdll!NtAllocateVirtualMemory
01 00000000`0009e600 00000000`6e976ea5 wow64!whNtAllocateVirtualMemory+0xa8
02 00000000`0009e6b0 00000000`6e961cf7 wow64!Wow64SystemServiceEx+0x155
03 00000000`0009ef70 00000000`6e98bfa1 wow64cpu!ServiceNoTurbo+0xb
04 00000000`0009f020 00000000`6e97cbb0 wow64!Wow64KiUserCallbackDispatcher+0x4151
05 00000000`0009f0a0 00007ffc`b1541791 wow64!Wow64LdrpInitialize+0x120
06 00000000`0009f350 00007ffc`b1577b28 ntdll!LdrpInitializeProcess+0x1551
07 00000000`0009f750 00007ffc`b1528d6e ntdll!_LdrpInitialize+0x4ed64
08 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。