导语:恶意软件代码使用各种各样的混淆技术来保护自己,这样可以躲避一些基于静态的特征值检测的杀软,同时还可以阻止安全研究人员的逆向分析。
恶意软件代码使用各种各样的混淆技术来保护自己,这样可以躲避一些基于静态的特征值检测的杀软,同时还可以阻止安全研究人员的逆向分析。到目前为止很多常见的混淆技术已经存在解决方案了,即便混淆后的代码非常混乱,但是还有会有很多相应的技术帮助我们快速反混淆脚本文件。在这篇文章中,主要介绍对恶意脚本混淆技术的一些新研究以及如何反混淆。
攻击者利用代码混淆技术可以保护自己的真实源码,这样做的目的主要有两个:躲避杀软、IDS以及遏制安全研究人员的逆向工程。
通常情况下,代码混淆是通过自动混淆器自动完成的。目前已经有许多免费的自动混淆器:
Stunnix (Multiple Languages) Crunchcode (VBA) ScriptCryptor (VBA, JavaScript) CodeProtection (VBA) Vbad (VBA) ISESteroids(PowerShell) Scripts Encryptor(Multiple Languages)
由于混淆后的代码不会改变脚本的功能,因此是不是可以使用动态恶意软件分析方法来确定脚本的功能以及提取出IOC,然而对于安全研究人员来说,这是一件相当难的事情。事实上,动态分析方法可以作为其中的一部分环节,而反混淆以及静态分析方法可以知道脚本所有的内容以及还原整个过程。
在反混淆之前,我们头脑中需要理清一些思路:
可读性:反混淆的目的就是让代码具有可读性。 简化代码:代码越简化,可读性越强,也就越能理解脚本的控制流程和数据流。 理清控制流和数据流:理清这两点可以帮助我们静态分析脚本的可能执行流程。 获取上下文:通过脚本的上下文相关性可以帮助我们更好的理清前面的3点。
需要使用的工具:
1. 虚拟机 2. 源码编辑工具,一般最基本的要求是具备语法高亮等功能。 3. 调试器
当然如果我们对脚本语言熟悉,也能帮助我们进行反混淆,一些脚本语言的说明如下:
JScriptVBScript WindowsPowerShell Reference OfficeVBA Language Reference MozillaJavaScript Reference
在推荐一些在线的脚本调试框架,这些框架都提供单步调试功能:
JSFiddle .NET Fiddle CodingGround
混淆技术分析
1. 垃圾代码
一些混淆器会将多余的代码片段植入脚本中,例如一些变量以及函数再被定以后从来没有被引用或者调用。这些代码是可能会执行的,但是不会影响脚本的整体执行结果。如果发现这些拉架代码可以将其从代码中移除。
在下面的例子中可以看出,在子程序中的几个变量被定义,并设置为一个整数的值,加上一个整数的字符串表示。这些变量在代码中其他地方没有被引用,所以可以将他们安全地从子程序中删除,而不会影响结果。
2. 命名复杂化
最常见的混淆技术是将变量或者函数的命名过于复杂化。例如字符串由大写,小写字母,数字组成,这样子乍一看很难区分这些符号。因此这些命名可以被替换为更加具体的命名。
这里我们可以使用文本编辑器的查找/替换功能,但是当涉及到全局变量时需要小心点。
在上面的例子中,将子程序的变量重命名为一个更简单的标签。同时将程序的形参也替换成更容易理解的输入变量。
3. 间接调用和混淆控制流程
在程序的执行流程中,往往会间接调用函数,攻击者可以在调用某个函数时,不是直接调用,而是经常几次其他无功能函数的调用最终调用该函数,因此可以混淆控制流程。
在上面的例子中,有五个子程序。在这些子程序中有一个sub5。如果你通过跟踪子程序的调用可以发现子程序最终执行的是sun2。因此,调用任何一个函数都将调用sub2。因此,可以移除sub1,sub3,sun4,和sub5而不是影响程序的执行结果。
4. 序列求和
混淆器可以采用简单的算术方法来阻止逆向。除了实际的数学方法外,脚本语言还经常使用数学函数进行转化。
在上面的例子中可以看到,8个数字进行算术运算后得到的值再使用CHA函数进行转化。
在这里我们可以看到更加复杂的算术方法,接连使用了数组求值,sgn以及Abs方法对变量的值进行操作,而最终运算的结果就是escouecm=2000.
5. 混淆字符串的值
至于对字符串的混淆可以看一下下面这个例子:
其实上述代码主要是通过StrReverse VBA函数,对字符串进行倒转。空字符串可以被删除,因为他们没有任何表示。一旦字符串被倒转之后,再添加到初始的“C”字符串,可以很明显的看到,它调用一个cmd命令。
一种通用的恶意VBA宏的常用方法是使用其他脚本语言释放和调用脚本。在这种情况下,宏建立一个Windows批处理文件,稍后将被执行。虽然构建一个批处理文件比较明显,但是文件的确切目的刚开始仍然还是不清楚的。
6. 高级的方法
有一种情况是当我们尝试了各种方法后还是无法还原混淆的代码,下面介绍一种更加通用的方法。
我们可以使用调试器对混淆的脚本进行单步调试,在一些需要解码的字符串的地方插入eval方法,将其直接打印出来。这种方法可以在最短的时间内得到我们想要的数据。
在上面的代码中,绿色部分的函数被多次调用。可以看到函数的参数分别是十六进制数字和一些字母组成的字符串,函数存在一个返回值。从该函数的上下文可以看出,函数的返回值应该是一个字符串。因此我们可以借助调试器,在函数返回后下断点,这样就可以看到这个函数的返回值了。一旦得到这个返回值就可以采用前面的一些方法进行替换了,是不是很简单。
脚本反混淆技术其实也不需要借助任何过于复杂的工具。因此我们需要的是得到可读性较强的代码即可,逻辑上是相当于原来的混淆脚本。在这个过程中,可以从比较小的代码片段开始着手反混淆,先解决部分代码,再通过上下文判断整个过程他们是如何使用,删除不必要的代码和简化代码,可以使得脚本更具可读性和更容易理解。最后,需要的时候查阅官方的脚本语言文档。