FLARE IDA Pro的脚本系列:自动化提取函数参数

摘要

很久以前FB发过一篇FLARE高级逆向工程团队的IDA Pro脚本系列上集,这次下集来了。所有的脚本和插件依然都可以从GitHub中下载。

自动化重复操作

本篇博客所描述的此项工作在逆向分析过程中反复出现:识别出程序中调用某个函数的所有参数。这种情况可能会在你试图做一下操作时出现:

识别大小,位置,以及解密恶意软件的恶意代码的密钥。 识别用于创建新进程的所有函数指针(即调用CreateThread或_beginthreadex函数的参数)。 识别API函数中用作指示器的的静态字符串。 识别在运行时被解析的函数(如调用GetProcAddress 的所有参数)。

为了帮助遇到类似问题的逆向工程师,我们推出一款新的IDA Python实用工具,它是FLARE IDA脚本的一部分:argtracker。这个工具并不是一个独立的插件,而是辅助你在IDA上快速编写和开发自己的分析脚本。

通过argtracker,你可以获取调用某个函数的所有参数,然后以你认为合适的任何方式进行分析,或解码。

用法

我们先从一个简单的例子出发,比如一个Gh0st变种。这个恶意软件家族一般都是通过在Win32函数_beginthreadex附近添加自己的封装函数来启动新线程。这个函数通常具有下图所示的函数原型。

FLARE IDA Pro的脚本系列:自动化提取函数参数

假设我们想要快速找到lpStartAddress参数的所有取值,以便对每个线程函数做一些自动化分析。我们就可以使用argtracker以及下图中的代码来实现。你可以在flare-ida GitHub中的examples / argtracker_example1.py找到本示例的全部源码。

FLARE IDA Pro的脚本系列:自动化提取函数参数

在这个示例代码中,我们首先创建一个新的Vivisect工作区。 Vivisect是一个Python编写的二进制分析框架,被argracker频繁调用。这个工作区包含了类似于IDA上IDB文件中的分析信息。我们使用这个工作区创建一个新的ArgTracker实例。为查找交叉引用MyCreateThread函数的全部代码,我们可以调用tracker.getPushArgs(xref,7)。此函数需要以下参数:

待分析的调用指令的位置:xref 栈上待提取参数的数量:7 一个包含待提取参数的寄存器名称的列表,此列表是可选的,默认为空。

这个恶意软件示例使用了_cdecl调用约定,全部参数都会被压入栈中,因此所有7个参数都能够被argtracker还原。第三个可选参数会在下一个示例中说明。

getPushArgs()函数返回的结果是一个结果字典的列表。每个字典都包含了从1,2,… n编号的键d值,其中n是要解析栈中参数的数目。在上图示例代码中,我们通过键值3来检索元组得到lpStartAddress值,因为lpStartAddress是我们所分析函数的第三个参数。同时元组里的值是(va, value),其中va是作为参数传递的数据的有效地址。此示例脚本只会打印这些信息,真实的脚本会通过这些结果进行实际的分析。

getPushArgs()返回一个列表是为了应对下图所示的情况:此时两条不同的代码路径可以为相同的函数调用设置参数。如果使用了不同的代码路径,那么结果列表中的每个条目都会包含所有的参数集合。

FLARE IDA Pro的脚本系列:自动化提取函数参数

举个更复杂的例子,假设有一段恶意代码只在运行时解码所有的字符串。在这个例子中,解析字符串的函数具有如下图所示的函数原型。因为它不是一个标准的调用约定,所以我们使用IDA的__usercall注释来指定两个参数存放在栈上(inptr和tempPtr),三个参数存放在寄存器中(outPtr存放在ecx中,strLen存放在edi 中的以及key存放在eax中的)。

注意:以这种方式设定函数原型对argracker来说没什么用,此处只是为了达到示范目的。

FLARE IDA Pro的脚本系列:自动化提取函数参数

flare-ida GitHub中的examples/ argtracker_example2.py向我们展示了如何这种情况下使用argtracker。在这个例子中,我们真正关心的是这三个参数:inptr,strlen和key。下图演示了我们使用jayutils文件(也在GitHub 库中)中的辅助函数来初始化  Vivisect工作区。接着从Vivisect工作区创建一个跟踪对象,然后就得到了所有指向字符串解码函数(decStringFunc)的交叉引用。

FLARE IDA Pro的脚本系列:自动化提取函数参数

下图对每个调用解码函数交叉引用执行getPushArgs()。由于只有两个函数参数是通过栈传递的,所以getPushArgs第二个参数是2。因为寄存器用于传递参数,我们需要传递包含参数的寄存器列表:[‘eax’, ‘ecx’, ‘edi’]来作为getPushArgs第三个参数。返回值仍然是字典的列表,但其键值是已恢复的参数。除了像栈上参数依次访问外(1,2- .. n),寄存器参数还可以通过使用寄存器名作为字典键值来获取。如首个示例所示,结果是一个包含了寄存器在函数调用前被修改的有效地址和取值的元组。

FLARE IDA Pro的脚本系列:自动化提取函数参数

工作原理

argtracker很大程度上依赖于Vivisect来实现恶意软件的额外分析。因此创建了一个单独的Vivisect工作区(.viv文件)来存储分析信息,如果脚本无法找这个基于IDB所存储信息的文件,你可能会被要求提供指向原始恶意样本的路径。哪怕函数在被调用过程只有一次要求提供参数,Vivisect便会对这个函数进行模拟,并追踪所有的内存读取、内存写入和寄存器修改。然后脚本从调用指令开始向后追溯,把遇到的不同分支加入队列,直到用户指定的所有条件都符合或者到达函数开始。

其中重要的一点是argtracker所使用的Vivisect模拟仅运行在函数级别。Vivisect会为函数中不是常量的数据返回伪造的存根数据,如未初始化的全局数据或函数参数,从而确保分析顺利完成。你需要仔细检查一下argtracker的结果,以确保这些值不会影响到结果。

Python脚本已成功应用在x86和x64程序的反汇编上,其中32位分析已经被广泛测试了。但其他类型的处理器还没有尝试过。

安装

和我们其他的IDA Pro插件一样,你可以从https://github.com/fireeye/flare-ida拷贝git仓库。python目录可以复制到%IDADIR%/ python目录下,或者PYTHONPATH环境变量下的任意一个目录。

https://github.com/vivisect/vivisect上拷贝Vivisect库,并将包添加到你的PYTHONPATH环境变量。

在IDP Pro中运行如下的Python命令测试插件已安装,并确保没有出现错误消息:

import vivisect import flare.argtracker

结论

argtracker确实是个很有用的工具,它所着重的是自动提取函数的参数,能提高你的分析速度。

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

很久以前FB发过一篇FLARE高级逆向工程团队的IDA Pro脚本系列上集,这次下集来了。所有的脚本和插件依然都可以从GitHub中下载。

自动化重复操作

本篇博客所描述的此项工作在逆向分析过程中反复出现:识别出程序中调用某个函数的所有参数。这种情况可能会在你试图做一下操作时出现:

识别大小,位置,以及解密恶意软件的恶意代码的密钥。 识别用于创建新进程的所有函数指针(即调用CreateThread或_beginthreadex函数的参数)。 识别API函数中用作指示器的的静态字符串。 识别在运行时被解析的函数(如调用GetProcAddress 的所有参数)。

为了帮助遇到类似问题的逆向工程师,我们推出一款新的IDA Python实用工具,它是FLARE IDA脚本的一部分:argtracker。这个工具并不是一个独立的插件,而是辅助你在IDA上快速编写和开发自己的分析脚本。

通过argtracker,你可以获取调用某个函数的所有参数,然后以你认为合适的任何方式进行分析,或解码。

用法

我们先从一个简单的例子出发,比如一个Gh0st变种。这个恶意软件家族一般都是通过在Win32函数_beginthreadex附近添加自己的封装函数来启动新线程。这个函数通常具有下图所示的函数原型。

假设我们想要快速找到lpStartAddress参数的所有取值,以便对每个线程函数做一些自动化分析。我们就可以使用argtracker以及下图中的代码来实现。你可以在flare-ida GitHub中的examples / argtracker_example1.py找到本示例的全部源码。

在这个示例代码中,我们首先创建一个新的Vivisect工作区。 Vivisect是一个Python编写的二进制分析框架,被argracker频繁调用。这个工作区包含了类似于IDA上IDB文件中的分析信息。我们使用这个工作区创建一个新的ArgTracker实例。为查找交叉引用MyCreateThread函数的全部代码,我们可以调用tracker.getPushArgs(xref,7)。此函数需要以下参数:

待分析的调用指令的位置:xref 栈上待提取参数的数量:7 一个包含待提取参数的寄存器名称的列表,此列表是可选的,默认为空。

这个恶意软件示例使用了_cdecl调用约定,全部参数都会被压入栈中,因此所有7个参数都能够被argtracker还原。第三个可选参数会在下一个示例中说明。

getPushArgs()函数返回的结果是一个结果字典的列表。每个字典都包含了从1,2,… n编号的键d值,其中n是要解析栈中参数的数目。在上图示例代码中,我们通过键值3来检索元组得到lpStartAddress值,因为lpStartAddress是我们所分析函数的第三个参数。同时元组里的值是(va, value),其中va是作为参数传递的数据的有效地址。此示例脚本只会打印这些信息,真实的脚本会通过这些结果进行实际的分析。

getPushArgs()返回一个列表是为了应对下图所示的情况:此时两条不同的代码路径可以为相同的函数调用设置参数。如果使用了不同的代码路径,那么结果列表中的每个条目都会包含所有的参数集合。

举个更复杂的例子,假设有一段恶意代码只在运行时解码所有的字符串。在这个例子中,解析字符串的函数具有如下图所示的函数原型。因为它不是一个标准的调用约定,所以我们使用IDA的__usercall注释来指定两个参数存放在栈上(inptr和tempPtr),三个参数存放在寄存器中(outPtr存放在ecx中,strLen存放在edi 中的以及key存放在eax中的)。

注意:以这种方式设定函数原型对argracker来说没什么用,此处只是为了达到示范目的。

flare-ida GitHub中的examples/ argtracker_example2.py向我们展示了如何这种情况下使用argtracker。在这个例子中,我们真正关心的是这三个参数:inptr,strlen和key。下图演示了我们使用jayutils文件(也在GitHub 库中)中的辅助函数来初始化  Vivisect工作区。接着从Vivisect工作区创建一个跟踪对象,然后就得到了所有指向字符串解码函数(decStringFunc)的交叉引用。

下图对每个调用解码函数交叉引用执行getPushArgs()。由于只有两个函数参数是通过栈传递的,所以getPushArgs第二个参数是2。因为寄存器用于传递参数,我们需要传递包含参数的寄存器列表:[‘eax’, ‘ecx’, ‘edi’]来作为getPushArgs第三个参数。返回值仍然是字典的列表,但其键值是已恢复的参数。除了像栈上参数依次访问外(1,2- .. n),寄存器参数还可以通过使用寄存器名作为字典键值来获取。如首个示例所示,结果是一个包含了寄存器在函数调用前被修改的有效地址和取值的元组。

工作原理

argtracker很大程度上依赖于Vivisect来实现恶意软件的额外分析。因此创建了一个单独的Vivisect工作区(.viv文件)来存储分析信息,如果脚本无法找这个基于IDB所存储信息的文件,你可能会被要求提供指向原始恶意样本的路径。哪怕函数在被调用过程只有一次要求提供参数,Vivisect便会对这个函数进行模拟,并追踪所有的内存读取、内存写入和寄存器修改。然后脚本从调用指令开始向后追溯,把遇到的不同分支加入队列,直到用户指定的所有条件都符合或者到达函数开始。

其中重要的一点是argtracker所使用的Vivisect模拟仅运行在函数级别。Vivisect会为函数中不是常量的数据返回伪造的存根数据,如未初始化的全局数据或函数参数,从而确保分析顺利完成。你需要仔细检查一下argtracker的结果,以确保这些值不会影响到结果。

Python脚本已成功应用在x86和x64程序的反汇编上,其中32位分析已经被广泛测试了。但其他类型的处理器还没有尝试过。

安装

和我们其他的IDA Pro插件一样,你可以从https://github.com/fireeye/flare-ida拷贝git仓库。python目录可以复制到%IDADIR%/ python目录下,或者PYTHONPATH环境变量下的任意一个目录。

https://github.com/vivisect/vivisect上拷贝Vivisect库,并将包添加到你的PYTHONPATH环境变量。

在IDP Pro中运行如下的Python命令测试插件已安装,并确保没有出现错误消息:

import vivisect import flare.argtracker

结论

argtracker确实是个很有用的工具,它所着重的是自动提取函数的参数,能提高你的分析速度。

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

发表评论

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