在本章中,我们将通过编写 Ghidra 脚本来介绍逆向工程(RE)的自动化。首先可以使用Ghidra工具中内置的脚本库,这些脚本具备良好的代码编写规范,并且很值得大家借鉴学习。具体包含了近几百个自动化脚本,通常来说,这些已经足以满足主要的逆向工程自动化分析的需求。
一旦了解了该集成化逆向框架的基础,可能也想知道它的具体底层实现。通过了解 Ghidra 脚本中类的具体实现来了解其内部结构实现原理,通过掌握这些背景知识,为本文最后一部分内容的理解做好铺垫。
随后,我们将学习如何开发属于自己的Ghidra脚本。为此,有必要对Ghidra API有一个简单的理解。根据自己的编程语言喜好,通过使用Java或Python语言对Ghidra脚本进行编程,得益于Ghidra API的兼容扩展性,脚本的实现在这两种编程语言下都具备相同的结果。
在本章中,我们将介绍以下主要内容
-
学习使用Ghidra脚本库
-
Ghidra 脚本类和 API的分析
-
自行编写Ghidra脚本
1
技术要求
在 GitHub 仓库可以找到包含本章所有必要代码:
https://github.com/PacktPublishing/Ghidra-Software-ReverseEngineering-for-Beginners/tree/master/Chapter02。
具体代码实现可见: https://bit.ly/3mZbdAm
2
使用和修改现有脚本
Ghidra 脚本可以在分析二进制文件时自动执行逆向工程任务。之前我们在hello world程序中使用CodeBrowser中的脚本实现了对该程序的反编译。开始是先加载到 Ghidra CodeBrowser 中的 hello world 程序,如第 1 章 开始使用 Ghidra 中Ghidra 功能概述部分所述。
正如本章引言中提到的,Ghidra包括一个真正的脚本库。要访问它,请转到窗口,然后转到脚本管理器。或者,单击以下屏幕截图中突出显示的按钮:
图 1 – 快速访问栏中突出显示的运行脚本按钮
在文件夹浏览器左侧可以看到所有的这些脚本均按文件夹分类,在左侧选择对应的文件夹则会显示选择时的文件夹里包含的每个脚本:
图 2 – 脚本管理器
图 3 – 脚本目录
现在可以测试调试目前的现有脚本。可以使用 Ghidra 分析和编辑这些所有的脚本。通过调试,它将使您能够了解它们的工作原理以及如何修改从而使它们适应您的需求。使用以下屏幕截图中显示的突出图标来编辑脚本或创建新脚本:
图 4 – 快速访问栏中突出显示的编辑脚本和创建新脚本按钮
其中 1编辑脚本 2创建新脚本
当我们分析一个过去的CTF逆向程序hero时,我们可以选择一个与字符串相关的Ghidra脚本,然后通过脚本加快分析速度。如以下屏幕截图所示,Python 和 Java 脚本在脚本管理器中混合使用:
图 5 – 脚本管理器中可用的字符串相关脚本
例如,RecursiveStringFinder.py 文件可以通过显示所有函数及其关联的字符串来加快分析速度。它可以加快分析速度,因为字符串可以揭示函数的用途,甚至不需要读取任何代码。
让我们执行上述脚本,将 hero 程序的 main() 函数作为输入(您需要将光标放在此函数上),同时在脚本控制台中查看输出。
如以下屏幕截图所示,RecursiveStringFinder.py 打印出一个缩进(根据调用深度)函数列表,每个函数都包含自己的引用字符串。
例如,main() 函数是第一个将被执行的函数(我们知道这一点是因为缩进;它是最左边的函数)。之后,将调用编译器引入的其他函数。该函数包含字符串" "Day %d , You want to:n"。在编译器也引入的一些函数和字符串之后,您可以看到包含程序运行时的其他字符串,也把程序的主要功能进行了展示:
图 6 – 在 Hero 程序上运行 RecursiveStringFinder.py 脚本的结果
该脚本是用 Python 开发的,它使用 getStringReferences() 函数(第 04 行)来获取引用某些内容(第 10 行)的指令的操作数(第 07 行)。当引用的内容是数据,更准确地说,是一个字符串(第 12-14 行)时,它将被附加到结果列表中,最终显示在脚本控制台中。
我们修改了此脚本,以便在将字符串附加到 isAnInterestString() 中的结果列表(第 15 行)时实现过滤器,以确定是否将其附加到结果列表(第 16-20 行)。
想象一下,您正在分析的程序的代码中查找URL,这在实践中在分析恶意软件时非常有用,因为它可以揭示攻击者的服务器。您需要做的就是打开脚本管理器并转到字符串文件夹(此脚本适用于字符串)。然后,打开 RecursiveStringFinder.py 脚本,并通过实现 isAnInterestString() 函数(以下代码片段中的第 00-02 行)向其添加筛选条件。
作为一般规则,在没有首先检查 Ghidra 的武器库中是否已经存在类似的东西之前,先不要自行编写脚本:
def isAnInterestingString(string):
"""Returns True if the string is interesting for us"""
return string.startswith("http")
def getStringReferences(insn):
"""Get strings referenced in any/all operands of an instruction, if present"""
numOperands = insn.getNumOperands()
found = []
for i in range(numOperands):
opRefs = insn.getOperandReferences(i)
for o in opRefs:
if o.getReferenceType().isData():
string = getStringAtAddr(o.getToAddress())
if string is not None:
found.append( StringNode(insn.getMinAddress(), o.getToAddress(), string) )
return found
可以轻松修改此脚本以在代码中搜索URL,这在分析恶意软件时非常有用。您需要做的就是将 isAnInterestString() 中的条件替换为适当的正则表达式。
以前的脚本是用Python编程语言开发的。如果你想尝试Java,那么你可以在TranslateStringsScript中分析代码。.java。为简洁起见,以下代码清单中省略了导入函数:
public class TranslateStringsScript extends GhidraScript {
private String translateString(String s) {
// customize here
return "TODO " + s + " TODO";
}
@Override
public void run() throws Exception {
if (currentProgram == null) {
return;
}
int count = 0;
monitor.initialize(currentProgram.getListing().getNumDefinedData());
monitor.setMessage("Translating strings");
for (Data data : CollectionUtils.asIterable(
DefinedDataIterator.definedStrings(currentProgram, currentSelection))) {
if (monitor.isCancelled()) {
break;
}
StringDataInstance str = StringDataInstance.getStringDataInstance(data);
String s = str.getStringValue();
if (s != null) {
TranslationSettingsDefinition.TRANSLATION.setTranslatedValue(data,
translateString(s));
TranslationSettingsDefinition.TRANSLATION.setShowTranslated(data, true);
count++;
monitor.incrementProgress(1);
}
}
println("Translated " + count + " strings.");
}
}
前面的脚本允许您修改程序中引用的字符串,方法是将 TODO 字符串作为前缀和后缀(第 04 行)。提到的脚本在某些情况下可能很有用。例如,如果您需要解码大量 Base64 编码的字符串或击败一些类似的恶意软件混淆,则修改 translateString() 函数,该函数负责获取输入字符串,应用一些转换并返回它。
run() 函数是 Ghidra 脚本的主要函数(第 08 行)。在这种情况下,字符串计数器首先初始化为零(第 14 行),然后,对于每个字符串(第 20 行),计数器在生成字符串转换(第 30-32 行)并显示(第 34-34 行)时递增。35) 在每次循环迭代上。
按原样执行此脚本会通过在所有程序字符串中添加 TODO 前缀和后缀来更改它们。正如你在下面的截图中看到的,我们的hero程序中的字符串被这样修改了。该脚本还计算了转换后的字符串的数量:
图 7 – 在 Hero 程序上运行 TranslateStringsScript .java 的结果
总共显示了151个字符串。至此,我们已经了解了如何使用Ghidra中自带的脚本功能,以及如何修改这些脚本并使它们适应我们的其他需求。之后,我们将了解 学习Ghidra 脚本中类的实现原理。
原文始发于微信公众号(山石网科安全技术研究院):逆向工程系列 | Ghidra for Beginner III
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论