逆向工程系列 | Ghidra for Beginner IV

要自行开发Ghidra脚本,需要单击脚本管理器菜单上的创建新脚本选项功能。 随后将决定使用哪种编程语言来开发对应的脚本:

逆向工程系列 | Ghidra for Beginner IV
图1 – 点击创建新的脚本按钮,会让用户选择想使用的对应编程语言的对话框


如果决定使用Java语言来编写Ghidra脚本,Ghidra脚本的大致框架将由三部分组成。 第一部分是注释信息:

//TODO write a description for this script
//@author 
//@category _NEW_
//@keybinding 
//@menupath 
//@toolbar 


有些注释是很容易理解的,但其中还是有一些值得一提。 例如,@menupath指定允许在启用脚本时将其放在菜单中的具体位置:

逆向工程系列 | Ghidra for Beginner IV

图2 – 启用脚本管理器与查看Ghidra中的具体代码


请注意,路径必须由.字符来进行拆分:

//@menupath Tools.Packt.Learn Ghidra script


之前的源代码注释生成了以下内容 并与Ghidra菜单的脚本进行集成:

逆向工程系列 | Ghidra for Beginner IV
图3- 将新写的脚本与Ghidra进行集成


接下来Ghidra脚本最重要的功能则是导入。 所有脚本必须从该类继承并实现run()方法(这是脚本的主要方法):

import ghidra.app.script.GhidraScript;
import ghidra.program.model.mem.*;
import ghidra.program.model.lang.*;
import ghidra.program.model.pcode.*;
import ghidra.program.model.util.*;
import ghidra.program.model.reloc.*;
import ghidra.program.model.data.*;
import ghidra.program.model.block.*;
import ghidra.program.model.symbol.*;
import ghidra.program.model.scalar.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.address.*;


所有导入的函数都记录在Ghidra的Javadoc文档中;在开发Ghidra脚本时可以进行参考。


Javadoc Ghidra API文档 可以通过单击帮助,然后单击Ghidra API帮助,如果Ghidra的JavaDoc文档不存在,将自动生成。 能够通过以下路径访问上述导入包的文档:

/api/ghidra/app/script/package-summary.html/api/ ghidra/program/model/.


脚本的主体继承自GhidraScript,其中run()方法必须使用自己的代码进行实现。 可以在具体实现中设置以下几种的Ghidra脚本状态:currentProgram、currentAddress、currentLocation、currentSelection和currentHighlight:

public class NewScript extends GhidraScript {

public void run() throws Exception {

//TODO Add User Code Here

 }

}


如果想使用Python来编写Ghidra脚本,其使用的API与Java相同,脚本的主要框架包含一个标头(脚本的其余部分必须用自己的代码填充),它与Java非常相似:

#TODO write a description for this script

#@author

#@category Strings

#@keybinding

#@menupath

#@toolbar

#TODO Add User Code Here


事实上,Java API可以通过使用Jython来包装 Python,Jython是设计在Java平台上运行的Python编程语言的实现。(Jython项目提供了Python在Java中的实现,为Python提供了在JVM上运行和访问用Java编写的类。)

如果转到Window,然后转到Python,将出现一个Python解释器,允许在Tab键点击时自动完成:

逆向工程系列 | Ghidra for Beginner IV

图4 – Ghidra Python解释器的自动代码提示功能


它还允许使用help()函数查看内置的文档。  在开发Ghidra脚本时可以打开Ghidra Python解释器,以快速访问文档、测试代码片段等。 对开发来说非常有用:

逆向工程系列 | Ghidra for Beginner IV

图5 – 使用Python解释器查询Ghidra帮助


在本节中,我们介绍了脚本类及其结构,如何查询使用Ghidra API文档并实现它,以及Python解释器在开发过程中如何帮助我们。 在下一节中,我们将通过编写Ghidra脚本来将其付诸实践

脚本开发

现在你知道了实现自己的Ghidra脚本所需的所有东西。 让我们从最基础的开始。 此脚本将允许在没有操作指令(NOP程序集操作码)的情况下修补字节。

现在开始编写脚本。@keybinding允许我们用Ctrl + Alt + Shift + N组合键执行脚本:

//This simple script allows you to patch bytes with NOP opcode
//@author Packt
//@category Memory
//@keybinding ctrl alt shift n
//@menupath Tools.Packt.nop
//@toolbar

import ghidra.app.script.GhidraScript;
import ghidra.program.model.util.*;
import ghidra.program.model.reloc.*;
import ghidra.program.model.data.*;
import ghidra.program.model.block.*;
import ghidra.program.model.symbol.*;
import ghidra.program.model.scalar.*;
import ghidra.program.model.mem.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.lang.*;
import ghidra.program.model.pcode.*;
import ghidra.program.model.address.*;


然后,我们的脚本需要做的就是在Ghidra(当前位置变量)中获取当前光标位置,然后获取它的地址(第03行),该地址的指令未定义(第06-08行),用NOP指令操作码修补字节,即0x90(第09-11行),然后再次拆解字节(第12行)。 这里的开发参考主要是在提到的Javadoc文档中搜索适当的API函数:

以下是nop功能的Java代码:

 
// nop_script_Java.java

public class NopScript extends GhidraScript {

    public void run() throws Exception {
        Address startAddr = currentLocation.getByteAddress();
        byte nop = (byte)0x90
        try {
            int istructionSize = getInstructionAt(startAddr).getDefaultFallThroughOffset();
            removeInstructionAt(startAddr);
            for(int i=0; i<istructionSize; i++){
                setByte(startAddr.addWrap(i), nop);
            }
            disassemble(startAddr);
        }
        catch (MemoryAccessException e) {
            popup("Unable to nop this byte");
            return;
        }
    }
}


将这段代码使用Python会更简洁。如以上代码,API的使用对两种语言都是一样的:

以下是Python代码 nop脚本的具体实现:

# nop_script_python.py

#This simple script allows you to patch bytes with NOP opcode
#@author Packt
#@category Memory
#@keybinding ctrl alt shift n
#@menupath Tools.Packt.Nop
#@toolbar 

currentAddr = currentLocation.getByteAddress()
nop = 0x90
instructionSize = getInstructionAt(currentAddr).getDefaultFallThroughOffset()
removeInstructionAt(currentAddr)
for i in range(instructionSize):
    setByte(currentAddr.addWrap(i), nop)
disassemble(currentAddr)


在本节中,我们介绍了如何用两种语言Java和Python编写简单的Ghidra脚本。

总结

在本章中,我们学习了如何使用现有的Ghidra脚本,通过修改相关脚本使其适应我们的需求。如何使用Java或Python语言开发一个非常简单的脚本来协助我们进行逆向分析。

原文始发于微信公众号(山石网科安全技术研究院):逆向工程系列 | Ghidra for Beginner IV

版权声明:admin 发表于 2023年8月3日 下午4:41。
转载请注明:逆向工程系列 | Ghidra for Beginner IV | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...