做校园二手交易网站的目的,海淀团队组建网站,wordpress新建header,网站建设架Ghidra101再入门(上#xff1f;)-Ghidra架构介绍
最近有群友问我#xff0c;说#xff1a;“用了很多年的IDA#xff0c;最近想看看Ghidra#xff0c;这应该怎么进行入门#xff1f;“这可难到我了。。
我发现#xff0c;市面上虽然介绍Ghidra怎么用的文章和书籍很多)-Ghidra架构介绍
最近有群友问我说“用了很多年的IDA最近想看看Ghidra这应该怎么进行入门“这可难到我了。。
我发现市面上虽然介绍Ghidra怎么用的文章和书籍很多但是结构化介绍Ghidra本身以及它的架构的文章很少几乎没有。对于熟悉IDA的群友反编译器的使用肯定不存在问题他们需要的是更加深层的知识。
那我就小写几篇文章希望不会挖坑不填这一篇就从先Ghidra的架构开始说起吧希望能给已经熟悉或者正在研究静态逆向的朋友们些许帮助。
——————————————————————
这篇文章将讨论下面这些问题如果有写的不清楚/不对的地方希望大家告诉我
为什么要整理这些知识什么是反编译Ghidra反编译器的主要架构是什么样Ghidra的主要模块有哪些都是干啥用的Ghidra这套框架牛逼在哪里在哪里有很大的缺陷Ghidra相比于IDA有什么区别/优点/缺点为什么Ghidra会设计成这个样子其它。。。。
1、为什么要整理这方面的知识
学习静态逆向大家都是从使用IDA/Ghidra这类反编译器的使用开始。然后逐步的深入到各种复杂的场景。
现代静态逆向的工作越来越复杂对抗越发深入梳理反编译器架构的知识学习程序分析技术在日常工作生活中一旦反编译器出现什么问题能够知道如何对反编译器进行修改与优化多一条解决问题的路子。
可惜市面上能够供我们学习的反编译框架并不多反编译软件开发的难度高、工作量大IDA和Ghidra都已经持续开发了近30年IDA对外提供的资源又非常的少。幸好Ghidra开源了给我们提供了一个了解这方面知识的门道。
2、什么是反编译
所谓反编译有广义狭隘的两层含义
从广义上反编译指的是将低级语言、机器语言转换成高级语言一系列技术的集合。技术落地的产品就是反编译器。
当然这篇文章中的反编译更加接地气一点所谓反编译-~反编译~~反的是什么呢当然是编译器啊
所以从狭隘的角度来看反编译技术指的是识别编译器优化算法特征基于程序分析技术编写反向算法从编译产物中还原被编译器隐藏的高层次抽象。
这种反向算法的集大成者我们就称为反编译器因此这篇文章就是参考Ghidra介绍这一集大成者的主要架构与功能。
如果从正向写代码的角度来看整个Ghidra对应的应该是IDE集成开发环境Ghidra中的反编译器对应的是gcc这类编译器。
3、Ghidra整体架构/主要模块简述
如下图这是我大概画的Ghidra反编译器主要模块结构。
我画的比较粗糙一定会有比较多的遗漏的点。先简单介绍一下各个子模块的作用从上到下从左到右
Ghidra反编译框架插件可以在Ghidra的tool目录中找到这些功能和IDA中的plugin功能类似Ghidra提供了一套专门的脚本管理页面。Ghidra配套脚本用于兼容多个平台、headless模式等等的打包后的脚本。Ghidra-Java-Frameword软件主程序Ghidra的主程序包含了绝大多数的组件。SoftwareModeling上层二进制抽象Java代码中对于二进制的抽象包括了反汇编、中间语言、函数CFG、二进制内存模型等等逆向工程的主要工作之一就是从二进制中还原这些上层信息。Ghidra-Decompiler反编译进程Ghidra的F5功能将中间语言转换为类C的伪代码他是一个完全独立的模块与Java主进程通过自定义的”字符流“交互。Ghidra-Decompiler命令行程序Ghidra的F5功能完全独立因此它可以自己以命令行形式启动并加载二进制独立的完成反编译的工作。Sleigh-Processor编译器将Sleigh编译成.sla的支持组件Sleigh-Processor描述模块Ghidra的核心功能用于支持x86、arm、mips等数十种指令集架构GCC、MSVC、GO、Java等多种编译器的描述模块。Ghidra开发者套装包括Sleigh以及Ghidra插件的eclipse-IDE开发支持套件但是我用IDEAvscode喂喂eclipse都啥时候的老古董了啊
下面的重心放在三个最重要的组件Ghidra-Framework主程序、Decompiler反编译器、Sleigh-Processor指令集架构描述配置。
4、Ghidra-Framework软件主程序
这个组件是Ghidra的主程序使用Java编写也就是我们反编译时所使用的Ghidra那一整套界面Ghidra啥时候找个产品经理和设计师把你那破UI修一下啊
主程序的功能十分的复杂这里只说两个关键模块
4-1、Analysis分析器
与IDA不同Ghidra虽然负责载入可执行文件但是对于函数识别、反汇编、栈平衡、指令等等解析与处理都需要分析器完成IDA会自动的完成这部分工作。
可以说Analysis模块除了不负责F5其它啥功能都要做
但对于反编译器核心的Analysis有那么几个
匹配查找函数头function start search通过编译器的配置以及特定的二进制信息查找函数起始位置配置文件可以在Processor中的xxxxpattern.xml中找到递归下降反编译Symbol/Disassemble/Subroutine从已知的函数头执行递归下降的反编译已知的函数头通过匹配查找、符号信息、start函数入口等等方法获取。No-Return函数处理No-Return Function通过规则识别并传播标记no-return函数。数据引用Reference:反编译过程中对于数据地址、字符串、常量的引用信息 4-2、SoftwareModeeling二进制抽象
这个模块是上层java进程中的二进制抽象所谓二进制的抽象指的是从二进制中还原出高层的信息包括二进制内存结构、函数、导入表、导出表、反汇编指令、中间语言、数据与交叉引用等等。
因此反编译器的界面和写代码时的IDE很相似(个人看法)。
5、Sleigh-Processor指令集架构描述
这个模块是Ghidra最牛逼的东西它继承了反编译技术奠基者Cifuentes, C博士和M. Van Emmerik博士的QUBT框架。
在反编译器开发的过程总最麻烦的事情之一就是对不同指令集架构、编译器、ISA的适配并且这个工作还没有讨巧的办法就是纯纯的苦力活。
例如在IDA中如果需要支持一个新的指令集就必须编写一个叫做processor的模块。而在Ghidra中不需要写代码通过这一套描述语言实现了多架构的支持功能。
5-1、binary-rewrite技术简述
在上个世纪末操作系统、指令集、ISA并没有现在这么统一。 那时候的程序员也遇到了多架构的麻烦给特定平台开发的程序换个平台就用没法用了需要重新写。
学术界就提出了Binary-rewrite技术通过一套系统将程序从一个平台转换为另一个平台例如将C语言编写的程序转换到JVM上运行 UQBT框架实现了将二进制转换为中间语言再将中间语言重编译成其它平台的能力。 为了降低从二进制到中间语言的转换成本UQBT框架提供了一种叫做通用描述语言Semantic Syntax Language (SSL)的描述类型语言 通过写对指令集、操作系统、调用约定的描述配置不用写代码就可以实现从二进制到中间语言的转换。
5-2、Ghidra-Sleigh描述语言概述
同样Ghidra这套描述语言的原型来自Binary-rewrite技术中的SSL类描述语言。
介绍Sleigh编写与适配指令集的文章已经很多了这里我也就简单的介绍一下有需要可以去看Ghidra的官方文档。
总得来说一套完整的Processor描述应该由这么几部分组成
语言总描述.ldefs描述这是什么架构、大小端、编译器等等ISA描述(.slaspec/.sinc/.pspec)最主要的模块描述指令集、寄存器、中间语言对应关系等等复杂的情况编译器/调用约定描述(.cspec)主要是描述不同编译器的调用约定比如x86就有MSVC、GCC、Go等很多种可能的编译器不同编译器都有单独的配置。函数匹配xxxpattern.xml二进制形式的函数匹配一般是用于匹配函数头。
5-3、对比IDA-ProcessorSleigh的优势是什么
这是个很有意思的问题我也不是编译领域的专家如果说的不对麻烦大佬们指教指教。
在最初的binary-rewrite的QUBT论文中作者提出了相比于编写Processor代码使用SSL描述语言工作量能减少一个数量级的观点。
但是在我把两边都尝试过之后发现其实对于不熟悉的新手两边的学习成本都很高。
IDA需要了解清楚Processor框架中并且IDA的资料很少。还有一点IDA缺少很多通用能力比如IDA似乎没有提供通用间接跳转处理的代码恢复switch间接跳转的代码是非常难写的。
而Ghidra-Sleigh等于重新学习了一种语言不过由于它和指令集架构很像所以没有那么困难。并且Ghidra的反编译做了很多的工作开发者不需要考虑别的只需要”描述清楚“剩下的交给反编译就行了。
所以我个人觉得在Processor编写中并不能减少什么工作量还是一个体力工作。Sleigh的优势在于他的格式很规范谁写都一样因此写问题也很容易修。并且反编译器承担了很多麻烦的工作我们只需要按部就班的描述就好了。
6、Decompiler反编译器
如果对反编译的实现细节有兴趣可以先看看官方文档或者等我下一篇文章但是不知道什么时候填好坑
Ghidra提供了和IDA-F5同样的将中间语言lift到类C语言伪代码的功能。
但是和IDA的架构不同Ghidra的反编译器是一个完全独立的进程并且是一个完全独立的模块。而IDA中反编译模块是集成在主程序中。
并且Ghidra反编译器在设计时就是架构无关的无论是什么指令集哪怕是VMP)只要写好中间语言p-code的转换功能Ghidra都能把他翻译成类C的伪代码。你看看隔壁IDA一个指令集的F5支持都能卖个好几万。
6-1、完全独立反编译器的架构缺陷
完全独立的反编译器/进程意思是反编译器可以独立编译并运行上层Java应用通过开启进程并使用字符流与反编译进程进行交互。
但是这种做法引入了很多的架构问题我个人看法啊
进程间通信会有很多额外的开销。主Java程序和反编译模块主Java程序和和反编译模块需要同时维护两套二进制抽象无法互相复用。每当反编译需要上层的数据比如我手动修改了函数签名只能通过进程间通信获得这使得类似功能开发十分的麻烦。主Java功能和native反编译功能同时实现了一些功能类似的分析无法重用代码。无法展示反编译结果与汇编/中间语言的对应关系。Ghidra的字符流好奇怪比较难看懂。
可以说所有的麻烦都是因为两边完全独立导致没法共享资源导致的。
6-2、从架构上对比IDA与Ghidra反编译的F5能力
个人感觉无论是从反编译的效率还是准确率来说毫无疑问IDA就是这个领域的行业标准
但是如果需要重头支持一套新的指令集那我一定选择Ghidra毕竟IDA没有F5给我用。
大家都知道IDA的反编译中层优化使用了8层转换每向上一层中间语言就能缩减一部分从下到上依次为
MMAT_GENERATED类似于汇编MMAT_PREOPTIMIZED在basic-block上构造defusekill关系MMAT_LOCOPT在basic-block完成局部优化构造CFG处理基于规则的窥孔优化MMAT_CALLS基于调用约定识别函数调用、参数、返回值MMAT_GLBOPT1将call的各种block进行合并全局优化全局死代码消除MMAT_GLBOPT2全局优化全局常量传播与条件优化MMAT_GLBOPT3全局窥孔优化MMAT_LVARS局部变量还原
但是Ghidra不同Ghidra将所有的优化代码全部塞到了coreation.cc一个文件里面。并且使用了类似于“不动点算法”的工作原理不断的优化直到中间语言无法优化下去位置不再改变
我按照个人的经验将Ghidra的反编译器中端从里到外、从前到后整理依次为
action-base通过流敏感技术将机器码翻译成中间语言识别函数处理间接跳转等等。action-stackstall抽象操作栈信息恢复栈变量Varnode还原高层变量信息action-rule窥孔优化通过预置的规则对语义进行等价还原typerecovery还原类型信息struct: 还原控制流信息
Ghidra这种不断循环的算法存在很大的性能问题对于超大的函数往往会反编译超时。并且这种将优化代码全部塞到coreation.cc的做法。。。使得代码层次十分混乱。
这一篇文章就到这吧后面是反编译器设计的内容了再写下去太长了留到以后的文章吧。
7、之后的内容
如果有时间填坑
后面将会详细说说Ghidra-decompiler反编译器F5组件的实现细节以及架构。
以及当反编译器出现问题的时候比如花指令等混淆如何进行修复。