FLARE脚本系列:自动解码混淆字符串

摘要

介绍

这篇文章拓展了高级逆向工程(FLARE)脚本系列的一个工具——调试器。

像IDA Pro的调试器有一些脚本接口。一些软件也有自己的调试脚本,比如OllyDbg采用的是ASM-like脚本语言,Immunity debugger里有一个Python接口,WinDbg有它自己的脚本语言。但是这些都不是快速创建字符串解码调试脚本的好选择。Immunity和OllyDbg只支持32位的应用程序,而WinDbg的脚本语言仅仅只是服务于WinDbg。那我们来创建了一个pykd项目接口使用Python编写适用于WinDbg的调试脚本。我们在pykd里建立了一个调试器脚本库。

我们称之为flare-dbg库。该库提供了几个实用工具类和函数,以便我们快速开发脚本在WinDbg里自动调试任务。

字符串解码

恶意软件制作者喜欢通过混淆他们的字符串来隐藏他们的终极目的。快速反混淆字符串可以让你马上找出恶意软件到底在做什么。

在实际的恶意软件分析中,一般有两种反混淆字符串方法:自解码和手动编程。自解码允许恶意软件解码自己的字符串。手动编程则需要反向工程师改编解码函数逻辑。自解码方法里有一个子集是模拟,每当一个汇编指令执行时都会被模拟。其中库调用模拟是必需的操作,但是模拟每个库程序调用很困难,可能会导致结果不对。不过如果将一个调试器附加到实际运行过程中,所有的库函数都可以在没有任何问题的情况下运行。于是在这里我们使用调试器脚本来自动解码所有混淆的字符串。

挑战

我们需要找到字符串解码函数来解码所有混淆字符串,以及所有指向实例的参数。然后,我们需要运行函数读出结果。而我们面对的问题就是如何让以半自动化的方式运行。

方法

首先我们需要找到字符串译码器函数,并对该函数的输入和输出有个基本的了解。然后确定字符串解码器函数每次都被调用了并且所有的参数都指向每个命令。如果不使用IDA,可以使用分析二进制的Python项目Vivisect。 Vivisect包含了几个启发式来识别函数和交叉引用。此外,Vivisect还可以模拟或拆开一系列的操作码帮助我们确定函数参数。如果你还没有这个Vivisect,需要看一下之前的FLARE脚本系列,在里面也用到了Vivisect。

flare-dbg

flare-dbg可以方便运行WinDbg脚本。flare-dbg的重点在于DebugUtils类,它有几个函数来处理数据:

•存储器和寄存器操作 •堆栈操作 •调试器执行 •断点 •函数调用

github中可以下载flare-dbg。

除了基本的调试器的实用函数,DebugUtils类还使用Vivisect处理二进制分析部分。

案例

这里有一个简单的恶意软件通过编码隐藏了它的字符串。下图表示一个HTTP User-Agent字符串被一个string_decoder函数解码。

FLARE脚本系列:自动解码混淆字符串

让我们看一下string_decoder函数,有一个被定义为字节串的偏移量的参数,一个输出地址和长度:

FLARE脚本系列:自动解码混淆字符串

我们用WinDbg和flare-dbg测试一下。首先,我们先打开WinDbg并执行。然后在WinDbg里用pykd打开一个Python interactive shell导入flare-dbg.

FLARE脚本系列:自动解码混淆字符串

接下来,我们创建一个DebugUtils对象。

FLARE脚本系列:自动解码混淆字符串

然后,我们给内存分配0x3A个字节用于输出字符串。我们使用新分配的内存为第二个参数并设置好其他的参数。

FLARE脚本系列:自动解码混淆字符串

最后,我们在虚拟地址0×401000调用string_decoder函数读取输出的字符串缓冲区。

FLARE脚本系列:自动解码混淆字符串

证明可以通过flare-dbg解码字符串后,让我们来自动调用所有指向string_decoder的命令。下图所示是一个调试器脚本例子。完整的脚本可以在GitHub的资源库目录中找到。

FLARE脚本系列:自动解码混淆字符串

上图的代码中,我们先确定字符串解码功能的功能虚拟地址,并创建一个DebugUtils对象。然后我们每次调用string_decoder函数时使用DebugUtils函数的get_call_list找到三个对应的参数。

一旦生成了call_list,我们遍历所有调用地址和相关参数。在这个例子中,输出字符串在栈里被解码。由于我们只执行字符串解码函数,并为了防止同样的堆栈被做为恶意软件,我们必须为输出的字符串分配内存。我们使用第三个参数的长度以指定内存分配的大小。一旦我们为那些输出字符串分配了内存空间,我们就设置新分配的内存地址作为第二个参数来接收输出的字节。

最后,我们使用DebugUtils call函数运行string_decoder功能并读取分配的缓冲区结果。调用函数设置堆栈,设定任何特定的寄存器值并执行相应的函数。一旦所有的字符串被解码,最后一步就是让这些字符串返回到我们的IDB。utils脚本里有实用函数来创建IDA Python脚本。在这种情况下,我们输出一个IDA Python脚本。

运行此调试器脚本产生以下的输出:

FLARE脚本系列:自动解码混淆字符串

输出的IDA Python脚本在所有编码的字符串位置后创建了标注。

FLARE脚本系列:自动解码混淆字符串

*参考来源:fireeye,FB小编江湖小吓编译,转载请注明来自FreeBuf黑客与极客(FreeBuf.COM)

介绍

这篇文章拓展了高级逆向工程(FLARE)脚本系列的一个工具——调试器。

像IDA Pro的调试器有一些脚本接口。一些软件也有自己的调试脚本,比如OllyDbg采用的是ASM-like脚本语言,Immunity debugger里有一个Python接口,WinDbg有它自己的脚本语言。但是这些都不是快速创建字符串解码调试脚本的好选择。Immunity和OllyDbg只支持32位的应用程序,而WinDbg的脚本语言仅仅只是服务于WinDbg。那我们来创建了一个pykd项目接口使用Python编写适用于WinDbg的调试脚本。我们在pykd里建立了一个调试器脚本库。

我们称之为flare-dbg库。该库提供了几个实用工具类和函数,以便我们快速开发脚本在WinDbg里自动调试任务。

字符串解码

恶意软件制作者喜欢通过混淆他们的字符串来隐藏他们的终极目的。快速反混淆字符串可以让你马上找出恶意软件到底在做什么。

在实际的恶意软件分析中,一般有两种反混淆字符串方法:自解码和手动编程。自解码允许恶意软件解码自己的字符串。手动编程则需要反向工程师改编解码函数逻辑。自解码方法里有一个子集是模拟,每当一个汇编指令执行时都会被模拟。其中库调用模拟是必需的操作,但是模拟每个库程序调用很困难,可能会导致结果不对。不过如果将一个调试器附加到实际运行过程中,所有的库函数都可以在没有任何问题的情况下运行。于是在这里我们使用调试器脚本来自动解码所有混淆的字符串。

挑战

我们需要找到字符串解码函数来解码所有混淆字符串,以及所有指向实例的参数。然后,我们需要运行函数读出结果。而我们面对的问题就是如何让以半自动化的方式运行。

方法

首先我们需要找到字符串译码器函数,并对该函数的输入和输出有个基本的了解。然后确定字符串解码器函数每次都被调用了并且所有的参数都指向每个命令。如果不使用IDA,可以使用分析二进制的Python项目Vivisect。 Vivisect包含了几个启发式来识别函数和交叉引用。此外,Vivisect还可以模拟或拆开一系列的操作码帮助我们确定函数参数。如果你还没有这个Vivisect,需要看一下之前的FLARE脚本系列,在里面也用到了Vivisect。

flare-dbg

flare-dbg可以方便运行WinDbg脚本。flare-dbg的重点在于DebugUtils类,它有几个函数来处理数据:

•存储器和寄存器操作 •堆栈操作 •调试器执行 •断点 •函数调用

github中可以下载flare-dbg。

除了基本的调试器的实用函数,DebugUtils类还使用Vivisect处理二进制分析部分。

案例

这里有一个简单的恶意软件通过编码隐藏了它的字符串。下图表示一个HTTP User-Agent字符串被一个string_decoder函数解码。

让我们看一下string_decoder函数,有一个被定义为字节串的偏移量的参数,一个输出地址和长度:

我们用WinDbg和flare-dbg测试一下。首先,我们先打开WinDbg并执行。然后在WinDbg里用pykd打开一个Python interactive shell导入flare-dbg.

接下来,我们创建一个DebugUtils对象。

然后,我们给内存分配0x3A个字节用于输出字符串。我们使用新分配的内存为第二个参数并设置好其他的参数。

最后,我们在虚拟地址0×401000调用string_decoder函数读取输出的字符串缓冲区。

证明可以通过flare-dbg解码字符串后,让我们来自动调用所有指向string_decoder的命令。下图所示是一个调试器脚本例子。完整的脚本可以在GitHub的资源库目录中找到。

上图的代码中,我们先确定字符串解码功能的功能虚拟地址,并创建一个DebugUtils对象。然后我们每次调用string_decoder函数时使用DebugUtils函数的get_call_list找到三个对应的参数。

一旦生成了call_list,我们遍历所有调用地址和相关参数。在这个例子中,输出字符串在栈里被解码。由于我们只执行字符串解码函数,并为了防止同样的堆栈被做为恶意软件,我们必须为输出的字符串分配内存。我们使用第三个参数的长度以指定内存分配的大小。一旦我们为那些输出字符串分配了内存空间,我们就设置新分配的内存地址作为第二个参数来接收输出的字节。

最后,我们使用DebugUtils call函数运行string_decoder功能并读取分配的缓冲区结果。调用函数设置堆栈,设定任何特定的寄存器值并执行相应的函数。一旦所有的字符串被解码,最后一步就是让这些字符串返回到我们的IDB。utils脚本里有实用函数来创建IDA Python脚本。在这种情况下,我们输出一个IDA Python脚本。

运行此调试器脚本产生以下的输出:

输出的IDA Python脚本在所有编码的字符串位置后创建了标注。

*参考来源:fireeye,FB小编江湖小吓编译,转载请注明来自FreeBuf黑客与极客(FreeBuf.COM)

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: