Skip to content
KitploitKITPLOIT
工具漏洞利用博客
Log in
提交
工具漏洞利用博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
vbSparkle — VBScript 与 VBA 的源代码到源代码反混淆器,支持部分求值 | Kitploit
工具/GitHubGitHub/airbus-cert/vbsparkle
防御工具静态代码分析 (SAST)代码分析逆向工程恶意软件分析
GitHubairbus-cert/vbsparkle

vbSparkle

VBScript 与 VBA 的源代码到源代码反混淆器,支持部分求值

查看仓库
8213142年前Kitploit 审核通过

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

.NET NuGet NuGet Download

什么是 vbSparkle?

vbSparkle 是一个基于部分求值(partial-evaluation)的跨平台 Visual Basic 反混淆器,主要致力于分析使用 VBScript 和 VBA(Office 宏)编写的恶意代码。

它使用原生 C# 编写,提供 .Net Standard 库,并可在 Windows、Linux、MacOS 等系统上运行。

Visual Basic Script 和 VBA 的解析通过使用 ANTLR 语法和词法解析器完成。

安装

包管理器

Install-Package vbSparkle

.Net CLI

dotnet add package vbSparkle

如何使用?

作为库使用

一旦你将 vbSparkle 库添加到项目中,只需调用静态类 VbPartialEvaluator 中的函数 PrettifyEncoded:

string obfuscatedVB = "msgbox(chr(65)&chr(66)&(chr(67))"
string deobfuscated = VbPartialEvaluator.PrettifyEncoded(obfuscatedVB);

... 将返回 MsgBox("ABC")。

作为命令行工具

附带项目 vbSparkle.CLI 是将 vbSparkle 用作命令行工具的一个示例。 当前示例接受一个路径作为参数,或从 StdIn 读取完整二进制,并返回反混淆结果。 Railroad Diagram

Web UI

附带项目 vbSparkle.Web 是在 Web UI 中使用 vbSparkle 的一个示例。 Railroad Diagram

为什么要编写基于部分求值的 VBScript 反混淆器?

VBScript 和 VBA 代码混淆在攻击者中非常流行,可以逃避检测措施、杀毒软件、防火墙、EDR,并使恶意软件分析变得更加困难。

因此,在机器遭到入侵的最初阶段,经常能看到混淆的 VBScript。

一种典型的 VBScript 代码混淆技术是将脚本封装在一个混淆字符串中,并在解码/求值后通过 Execute("...code..." function) 函数执行。

让我们看一个示例:

Execute(chr( 456127/3833 ) & chr( 817650/7110 ) & chr( 759429/7671 ) & chr( 834138/7317 ) & chr( 57960/552 ) & chr( 2549-2437 ) & chr( 1078568/9298 ) & chr( 5143-5097 ) & chr( -8682+8783 ) & chr( 529-430 ) & chr( 673088/6472 ) & chr( 761682/6862 ) & chr( 302336/9448 ) & chr( 9427-9393 ) & chr( 410176/3944 ) & chr( -5271+5372 ) & chr( 796608/7376 ) & chr( 2896-2788 ) & chr( 318792/2872 ) & chr( 1076-1042 ) &  vbcrlf  ) 

这里,攻击者使用了:

  • chr(CHAR_CODE) 函数来求值一个字符串字符(例如 chr(65) = "A")
  • 算术运算(例如 456127/3833)来求值字符值
  • 字符串连接 & 来组装所有解码后的字符
  • 调用 Execute(..) 函数来执行解码后的脚本。

如果我们跟踪脚本执行过程:

  • 456127/3833 => 119
  • chr(119) => "w"
  • 817650/7110 => 115
  • chr(115) => "s"
  • "w" & "s" => "ws"
  • Execute("ws.....

以下是原始脚本: wscript.echo "hello"

手动反混淆对于大型脚本来说非常困难且耗时。 一种常见的 VBScript 反混淆技术是简单地将 Execute() 函数替换为 WScript.Echo(,然后运行脚本以获取输出。

最后这种技术虽然简单,但也有一些缺点:

  • 至少需要一个虚拟机/沙箱来安全地执行脚本;
  • 这种技术的自动化是危险且随机的;
  • 无法理解整个代码及其副作用;
  • 某些条件性任务可能会因运行环境不同而被遗漏;

而且,在本项目启动时,除了这两种技术之外没有其他替代方案。

编写 Visual Basic 部分求值器

部分求值并不是一个新概念,它主要用于编译器在预编译过程中的代码优化(例如 https://en.wikipedia.org/wiki/Partial_evaluation)。

部分求值器读取一个程序(称为主题程序)以及该程序的一些输入,并且只对程序中依赖于所提供输入的部分进行求值。 一旦所有这些部分都被求值,剩余的程序(称为剩余程序)将作为输出发出。

例如,预编译过程会将以下主题代码:

var1 = 3*3 
var2 = sin(arg1)
var3 = var1 + func_xx(2 * var1 + var2)

转换为以下剩余代码:

var2 = sin(arg1)
var3 = 9 + func_xx(18 + var2)

代码在编译前已被部分求值,以优化性能。

我们看到这个过程简化了代码,并消除了不必要的操作。 这很有意思,因为混淆通过添加对代码执行不必要的新代码和操作来隐藏代码。

如果我们逐步检查最初的示例:

  • 像 456127/3833 这样的算术运算可以被部分求值:没有副作用
  • chr(119) 可以被部分求值:119 是一个常量,并且这是一个原生函数,没有副作用
  • "w" & "s" 可以被部分求值:这是常量字符连接,没有副作用
  • "Execute(" 具有已知的副作用(脚本执行),它不会被求值,除非函数的副作用可以被管理/模拟

对该示例进行部分求值将得到: Execute("wscript.echo ""hello""" & vbCrLf)

你猜怎么着?哦,我们刚刚对示例进行了反混淆。

理论很好,但实际呢?

嗯,在实践中,情况要复杂得多:

  • 要实现部分求值器,你需要一个解析器。
  • 要获得解析器,你需要一个词法分析器和一个语法。

幸运的是,ANTLR 是一个强大的解析器生成器,用于读取、处理、执行或翻译结构化文本或二进制文件。它以广泛用于构建语言、工具和框架而闻名。ANTLR 从语法生成解析器,该解析器可以构建解析树,并生成监听器接口(或访问者),从而易于响应感兴趣短语的识别。

ANTLR 可以生成词法分析器、解析器、树解析器以及组合的词法分析器-解析器。解析器可以自动生成解析树或抽象语法树,这些树可以进一步用树解析器处理。ANTLR 为指定词法分析器、解析器和树解析器提供了一种一致统一的表示法。

默认情况下,ANTLR 读取语法并为该语法定义的语言生成识别器(即,一个读取输入流并在输入流不符合语法指定的语法时生成错误的程序)。

为了对该语言进行一些有用的操作,可以在语法中为语法元素附加动作。这些动作以正在生成识别器的编程语言编写。生成识别器时,这些动作会在适当位置嵌入识别器的源代码中。

基本工作原理

得益于 ANTLR,利用 Ulrich Wolffgang 编写的现有语法,快速轻松地生成了第一版 AST、词法分析器和解析器。

来自 VB 语法的 Railroad 示例: Railroad Diagram

这个语法在部分特定的 Visual Basic 语法(内联代码、某些运算符问题)上不能完全正常工作,需要进行一些修改以提供完全兼容的 VBS 和 VBA 语法。修改后的语法可以在这里找到:Visual Basic Grammar

以下是以下代码片段的可视解析树示例:

Msgbox("Hello world " & Chr(33), vbCritical, "The Title")

Parse tree sample

一旦解析器和 AST 生成,我们就可以开始使用它并 探索 我们的代码:

using Antlr4.Runtime;
using System.Linq;

namespace vbSparkle
{
    public class PartialEvaluator
    {
        public static string Prettify(string script)
        {
            var inputStream = new AntlrInputStream(script);

            // Create the lexer
            var lexer = new VBScriptLexer(inputStream);

            // Instanciate of common token from lexer
            var commonTokenStream = new CommonTokenStream(lexer);

            // Create the parser
            var parser = new VBScriptParser(commonTokenStream);

            // Get the start rule (root element of our AST) 
            VBScriptParser.StartRuleContext stContext = parser.startRule();

            // Instanciate the visitor
            VbAnalyser analyser = new VbAnalyser();

            // Visit the AST
            analyser.Visit(stContext);

            // Root AST element of a vbScript being a "Module", we get it
            var module = analyser.Modules.FirstOrDefault();

            // Then we partially evaluate our module
            string result = module.Prettify(partialEvaluation: true);
            return result;
        }
    }
}

一个访问者负责遍历 AST,并创建每个节点的部分求值器/美化器。 这些节点将递归地进行求值: Workflow

例如,这是我们的访问者,它实例化了一个 VbModule 求值器:

    public class VbAnalyser
    {
        public List<VbModule> Modules { get; set; } = new List<VbModule>();

        internal void Visit(VBScriptParser.StartRuleContext stContext)
        {
            var moduleContext = stContext.module();

            VbModule module = new VbModule(this, moduleContext);
            Modules.Add(module);
        }
    }

以下是一个带有 Prettify 函数的节点示例:

    public class VbOnGotoStatement : VbStatement<VBScriptParser.OnGoToStmtContext>
    {
        public VBValueStatement OnValue { get; set; }
        public VBValueStatement[] GotoValues { get; set; }

        public VbOnGotoStatement(IVBScopeObject context, VBScriptParser.OnGoToStmtContext bloc)
            : base(context, bloc)
        {
            OnValue = VBValueStatement.Get(context, bloc.valueStmt().First());
            GotoValues = bloc.valueStmt().Skip(1).Select(v => VBValueStatement.Get(context, v)).ToArray();
        }

        public override DExpression Prettify(bool partialEvaluation = false)
        {
            return new DCodeBlock($"On {OnValue.Prettify(partialEvaluation)} Goto {string.Join(", ", GotoValues.Select(v=> v.Prettify(partialEvaluation)))}");
        }
    }

当节点通过构造函数 VbOnGotoStatement( 被访问时,它会递归访问子节点并创建它们自己的访问者实例。 然后,当调用 Prettify 方法时,子元素会以相同的部分求值级别进行美化。

致谢

  • 本项目版权归 Airbus CERT 所有,并根据 Apache 2.0 许可证 分发。
下载工具