IDAPython:让你的生活更美好(五)

jopen 9年前

我们继续IDAPython让生活更美好序列,这一部分我们解决逆向工程师日常遇到的问题:提取执行的内嵌代码。

恶意软件会用各种方式存储内嵌可执行代码,有些恶意软件将内嵌代码加到文件附加段,包括PE资源区段,或者存放在恶意软件的缓冲区中。

当遇到这个情况,恶意软件分析者可以有几个选择:

可以动态运行样本在写入和提取的后面下断点或者如果文件存储在资源段,可以使用一些工具比如CFFExplorer 提取资源数据,在IDA中可以高亮选取可疑的二进制数据,然后右键保存想要的提取的数据。

虽然这几个方法都可行,但是都有一些限制。而自动化提取内嵌代码可以节省分析者大量的时间。为了实现这个目的,我们会用到IDAPython的第三方链接库组件‘pefile’。而这里也会带来一些挑战:

1. 我们必须在IDA环境中用PIP安装第三方python链接库  2. 已经标识出了内嵌代码  3. 需要计算要提取的可执行代码的大小

让我们一次性的解决这些问题吧。

在IDA PRO中加入第三方PYTHON链接库

在IDA中用PIP安装第三方python链接库之后,如何让其生效是一个有趣的挑战。而如果不修改的话是没有办法加载第三方链接库的,比如pefile的IDAPython解释中会出现如下错误。

为了修正这个错误,我们必须将PIP的‘site-packages’目录加到PYTHON的环境变量中。可以使用如下代码实现:

import sys  print sys.path    Result:  ['/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python27.zip', '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7', '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-darwin', '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac', '<Truncated>']

而这里为了包含PIP安装链接库,我们可以简单的将‘site-packages’目录加到pefile包含声明数组中。但是这个方案不太好,因为这需要分析者人工识别‘site-packages’目录,但是我没要找到跨平台的解决方案。加入相关代码之后,我们就能够加载pefile链接库了。

需要内嵌代码

为了找到恶意软件包含的所有内嵌代码,我们基于MZ头的已知字符串对二进制进行搜索。分析者请确认已经勾选了‘Load resources’选项这样才能够读取到作为资源存储的所有数据。另外的,如果内嵌文件包含在附加段中,为了在IDA中能够看到数据一定要勾选’Manual load’选项。

现在我们已经有了IDA中加载的必要信息了,现在我们可以开始在PE32文件中搜索数据了。我们有好几种方法可以实现,但我选择搜索所有MZ头中都会包含的静态信息,如下所示:

为了找到IDA中所有的字符串事件,我们可以使用循环调用FindBinary()函数来寻找二进制字符串的每一次实例。代码如下:

def find_string_occurrences(string):    results = []    base = idaapi.get_imagebase() + 1024    while True:      ea = FindBinary(base, SEARCH_NEXT|SEARCH_DOWN|SEARCH_CASE, '"%s"' % string)      if ea != 0xFFFFFFFF:        base = ea+1      else:        break      results.append(ea)    return results

当在PE32文件中寻找MZ头字符串标识时,我们需要验证‘MZ’字符存在于MZ头的开始处。由于我们之前找的字符串在静态偏移是固定的,我们只需要简单的确定‘MZ’的已知偏移就可以了。

def find_embedded_exes():    results = []    exes = find_string_occurrences("!This program cannot be run in DOS mode.")    if len(exes) > 1:      for exe in exes:        m = Byte(exe-77)        z = Byte(exe-76)        if m == ord("M") and z == ord("Z"):          mz_start = exe-77          print "[*] Identified embedded executable at the following offset: 0x%x" % mz_start          results.append(mz_start)    return results

将上面的代码组合到一起,来找到IDA中所有的内嵌代码。

确定可执行代码的大小

为了确定找到的内嵌代码的大小,我们将使用前面提到的python第三方pefile链接库。这个链接库可以解析各种可执行文件头,这样我们就能够计算PE文件的大小了。为了实现这个目的,我们会在可选头中加入’SizeOfHeaders’参数,连同每个段的’SizeOfRawData’字段。下面的代码会读出标识出的内嵌代码的前1024字节,用pefile解析这些数据,计算各个段的大小。

def calculate_exe_size(begin):    buff = ""    for c in range(0, 1024):      buff += chr(Byte(begin+c))    pe = pefile.PE(data=buff)    total_size = 0    # Add total size of headers    total_size += pe.OPTIONAL_HEADER.SizeOfHeaders    # Iterate through each section and add section size    for section in pe.sections:      total_size += section.SizeOfRawData    return total_size

最后,我们可以使用这些大小值来提取可执行代码数据然后写入我们选择的文件中。

def extract_exe(name, begin, size):    buff = ""    for c in range(0, size):      buff += chr(Byte(begin+c))    f = open(name, 'wb')    f.write(buff)    f.close()

结论

将这些组合到一起,我们将会得到下面的脚本。

https://github.com/pan-unit42/public_tools/blob/master/ida_scripts/idapython_pt5.py

在恶意样本中运行这个例子,将会得到下面的结果:

正如我们看到的,我们能够在IDA中自动提取PE文件了。通过一些小修改,这个实现能够应用到其他类型的文件中。我希望这个教程能够让逆向工程师知道IDAPython能够实现很多难以置信的功能。

*原文地址: Paloaltonetworks ,东二门陈冠希/编译,转载请注明来自FreeBuf黑客与极客(FreeBuf.COM)

来自: http://www.freebuf.com/articles/system/93440.html