一个简单而有效的RunPE技术在VBA中的实现。此代码可用于从Word或Excel的内存中运行可执行文件。兼容32位和64位版本的Microsoft Office 2010及以上版本。
更多信息请见: https://itm4n.github.io/vba-runpe-part1/ https://itm4n.github.io/vba-runpe-part2/

Exploit 过程中,设置要执行的文件路径。strSrcFile = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"
/!\ 如果你在64位操作系统上使用32位版本的Microsoft Office,则必须指定32位二进制文件。
strSrcFile = "C:\Windows\SysWOW64\cmd.exe"
strSrcFile = "C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe"
strArguments = "-exec Bypass"
这将用于形成等效于以下命令行的内容:
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -exec Bypass
(可选)启用 视图 > 立即窗口(Ctrl+G)以检查执行和错误日志。
运行 Exploit 宏!
pe2vba.py 将PE文件转换为VBA。这样,它可以直接嵌入到宏中。user@host:~/Tools/VBA-RunPE$ ./pe2vba.py meterpreter.exe
[+] Created file 'meterpreter.exe.vba'.
RunPE.vba 中的以下代码替换为上一步生成的 .vba 文件的内容。' ================================================================================
' ~~~ 嵌入的PE ~~~
' ================================================================================
' 由PE2VBA生成的代码
' ===== 开始 PE2VBA =====
Private Function PE() As String
Dim strPE As String
strPE = ""
PE = strPE
End Function
' ===== 结束 PE2VBA =====
(可选)启用 视图 > 立即窗口(Ctrl+G)以检查执行和错误日志。
运行 Exploit 宏!
/!\ 当使用嵌入的PE时,宏将自动切换到该模式,因为 PE() 方法将返回一个非空字符串。
GetThreadContext() 失败,错误代码998。如果你从 64位版本的Office 运行此宏,可能会遇到此错误。作为变通方法,你可以将代码移至 一个模块,而不是从Word对象引用中执行。感谢 @joeminicucci 提供此技巧。
================================================================================
[*] 源文件: 'C:\Windows\System32\cmd.exe'
[*] 检查源PE...
[*] 在挂起状态下创建新进程...
[*] 获取主线程的上下文...
|__ GetThreadContext() 失败 (错误: 998)
目前我尚不清楚此变通方法为何有效。不过我已对此进行了一些调查。 此错误似乎是由于在64位版本中 CONTEXT 结构未正确对齐所致。我注意到该结构的大小也不正确([VBA] LenB(CONTEXT) != [C++] sizeof(CONTEXT)),而在32位版本中则是正常的。我有一个可行的解决方案,可以使 GetThreadContext() 正常返回,但这会破坏后续执行中的其他内容。
编辑于2019-12-15:CONTEXT 结构的64位版本定义确实不正确,但修复此问题并未解决该bug。因此,我为64位版本实现了一个变通方法:我将 GetThreadContext() 和 SetThreadContext() 函数的 CONTEXT 结构参数替换为相同大小的 Byte 数组。
编辑于2019-12-17:我终于找到了问题所在。我最初的假设是正确的,CONTEXT 结构必须在内存中按16字节对齐。在C语言中,你可以通过在结构定义中使用 align(16) 来控制这一点,但在VBA中无法控制。因此,GetThreadContext() 和 SetThreadContext() 可能会“随机”失败。另一方面,Byte 数组似乎总是按16字节对齐,这就是此变通方法有效的原因,但并不能保证,除非我反向工程VBA解释器/编译器并找出原因?!
LongPtr - 用户定义类型未定义如果遇到此错误,说明你正在从旧版Office(<=2007)运行宏。LongPtr 类型是在VBA7(Office 2010)中引入的,同时提供了对64位Windows API的支持。它对于处理指针非常有用,无需担心架构(32位/64位)。
作为变通方法,你可以将所有 LongPtr 替换为 Long(32位)或 LongLong(64位)。在你喜欢的文本编辑器中使用 Ctrl+H。
@hasherezade - 完整的RunPE实现 (https://github.com/hasherezade/)
@Zer0Mem0ry - 32位RunPE的C++实现 (https://github.com/Zer0Mem0ry/RunPE)
@DidierStevens - 在VBA中嵌入PE
此代码已在以下平台上测试:
以下是一些Win32和VBA类型之间的对应关系表:
(*) LongPtr 是一种“动态”类型,在32位Office中占4字节,在64位Office中占8字节。 https://msdn.microsoft.com/fr-fr/library/office/ee691831(v=office.14).aspx
| C++ | VBA | 架构 |
|---|
| BYTE | Byte | 32 & 64 |
| WORD | Integer | 32 & 64 |
| DWORD, ULONG, LONG | Long | 32 & 64 |
| DWORD64 | LongLong | 64 |
| HANDLE | LongPtr(*) | 32 & 64 |
| LPSTR | String | 32 & 64 |
| LPBYTE | LongPtr(*) | 32 & 64 |