freeBuf
主站

分类

云安全 AI安全 开发安全 终端安全 数据安全 Web安全 基础安全 企业安全 关基安全 移动安全 系统安全 其他安全

特色

热点 工具 漏洞 人物志 活动 安全招聘 攻防演练 政策法规

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

Ghidra——主要窗口Decompiler介绍
2022-02-15 10:10:32
所属地 四川省

前言

在CodeBrowser默认显示的窗口中,反编译窗口一样非常显眼。我们将先对Ghidra的反编译器本身进行介绍。

一、反编译器

Ghidra自带复杂的转换引擎,能够将二进制表示的函数转化成更高层的C语言形式。Ghidra的反编译器包含以下功能:

1.还原表达式
反编译器会进行完整的数据流分析从而对函数进行切离。由编译/优化这个过程带来的复杂的表达式,会被还原成简单易读的形式。

2.还原高级变量
反编译器会有效地还原最初程序所使用的变量,最小化引入新变量的需求。

3.还原函数参数
反编译器会还原函数最初的形式。

4.自动命名
高级变量将会被合适地命名,数组的index值也会自动计算并用正确的格式显示出来,字符指针常量会被自动替换为对应的字符串。

5.自动引入数据类型与名称
当用户更改数据类型与名称的时候,反编译器会自动引入这些修改并应用,C语言输出也会随之更改。

6.局部类型传播
当信息不足的时候,反编译器会尽可能地提供相关的已知信息。因此,当遇到一个数据类型没有被确定的变量时,用户可以通过观察这个变量是如何被使用的,或者让已知的数据类型传播,来还原该变量的数据类型。

变量

反编译器会尝试结合不同位置的信息(堆、内存、寄存器)来决定函数内的变量。变量数据类型的信息也是由多个源头自动收集而来。比如,函数签名能够提供类型的信息。如果函数包含一个对全局内存位置的引用,而又有数据类型作用于这些位置上,反编译器也能从中得到信息。反编译器所得到的的信息越多,其产生出来的C代码便会更好。

未能够直接确定类型的变量可以通过局部类型传播来确定。我们往往只需要手动分配几个关键变量的类型,就能极大的提升C代码的可读性,因为反编译器可以通过局部类型传播来精确地分配其他数据类型。另外,手动分配函数签名中的类型,或是全局变量,会极为有效,因为这能同时影响多个函数。标明函数参数的数据类型非常有用。一个函数参数中定义了的数据类型会被传播到这个函数调用的所有函数当中。

如果你有程序所用API的C语言头文件,Ghidra提供了一个原型的C代码解析器。该解析器能够提取C代码中的数据类型信息并且创建一个Ghidra Data Type Archive(.gdt)文件。我们可以选择File→Parse C Source来打开该解析器。

反编译器内部函数

有时,反编译器会使用某个反编译器内部函数,这些函数没有被转化成像C代码的样子。出现这种情况通常说明产生的伪代码不正确,或者是需要被手动调整至更可读的输出。有时可能我们需要添加针对这种特定情况的额外简化规则。

SUB41(x,e) 截断操作

其中4代表着输入算子(x)的字节数,1代表着输出值的字节数。x为将被截断的值,e则是被截断的最低有效字节个数。举个例子:
SUB42(0xaabbccdd,1)=0xbbcc
当e的值为0时,该操作基本是对整数大小间的转换。
SUB41(x,0)通常是从int到char的转换
SUB42(x,0)是从int到short的转换
SUB84(x,4)可能是扩展精度乘法的一部分,但也可能出现在诸如除法的强度折减的其他操作当中。

CONCAT31(x,y) 连接两个算子

其中3代表x的字节数,1代表y的字节数。输出结果会是一个4字节的连接,x会组成结果的最高有效字节部分,而y会组成最低有效字节部分。例:

CONCAT31(0xaabbcc,0xdd)=0xaabbccdd

这个函数通常会在大小为1字节的变量(char)被储存于4字节的寄存器中出现。所有在4字节寄存器上的基本运算/逻辑操作都能够正确地作用于1字节的变量,编译器只需要保证忽略寄存器中的3个最高有效字节。

CONCACT31被反编译器用来追踪这些被编译器忽略掉的最高有效字节。再多数情况下,反编译器能够做到这一点,然而在循环结构中却不行。这是由反编译器源代码所带来的难以解决的问题。

ZEXT14(x) 0的扩展

其中1代表x的字节数,4代表输出值的字节数。该函数绝大多数情况下是对小的整型到较大的无符号整型的转换。

SEXT14(x) 有符号的扩展

其中1代表x的字节数,4代表输出值的字节数。该函数绝大多数情况下是对小的有符号整型到较大的有符号整型的转换。

SBORROW4(x,y) 判断两数相减有无运算溢出

其中4代表x与y的字节数,x,y均为有符号整型。该函数在x-y会造成运算溢出的情况下返回true。该函数一般由两个有符号整型的比较中产生。尽管反编译器中有还原比较的规则,这是一个没有被涵盖到的特殊情况。

CARRY4(x,y) 判断x+y是否进位

SCARRY4(x,y)判断x+y是否导致有符号的溢出

其中4代表x与y的字节数。如果x+y导致进位,将会返回true。

寄存器设置

有时程序会使用一个寄存器来储存一个全局常数。我们可以在陈列窗口右键菜单中选择Set Register Values来指定该值。这个常数会自动传播到反编译器中的相关函数中,我们得到的C代码也可能因此被进一步简化。
image

图1 寄存器设置

反编译器选项

如下则是一些可用的反编译器分析选项(Edit→Tool Options→Decompiler/Analysis):
image

图2 反编译器选项

Eliminate unreadable code:让反编译器去除它认为不可读的代码部分。
Ignore unimplemented instructions:让反编译器忽略那些语义被标记为未实现的指令。
Infer constant pointers:允许反编译器推断那些看起来像指针的常数的数据类型。如果常数的地址看起来像是程序中已知的数据或者函数,该常数会被假设为一个指针。
Respect read-only flags:让反编译器将被标记为只读的内存当作常数值。对那些真正只读,并且从未变化过的值,该段内存会被在Memory Manager中被标记为只读。
Simplify predication:使反编译器简化条件指令,合并使用相同判断条件的if else的代码段。
Simplify extended integer operations:使反编译器简化对整型的操作。当一个值被分为多个部分并在不同阶段操作时,反编译器会尝试将这些阶段合并,还原出单一的操作。
Use in-place assignment operators:使反编译器在输出中使用像+=这样的分配操作符。
Decompiler Timeout(seconds):设定允许有反编译器运行的秒数。目前这个时间设置不影响用户界面,用户界面会无止境的运行。这个设定目前只影响后台使用decompiler.syntax的分析进程。

二、反编译窗口

现在我们会开始介绍Ghidra反编译器所提供的用户界面,也就是反编译窗口(Decompiler Window)的使用。反编译窗口默认位于陈列窗口的右边。
image

图3 反编译窗口

如果窗口被关闭,我们也可以从Window→Decompile中将其打开。

鼠标活动

双击:导向至双击的标志
Ctrl+双击:在新窗口中导向至双击的标志
中键点击:高亮显示所有与所点击的目标相同的内容

复制

我们可以将反编译窗口中的C代码复制,选择需要复制的文本,并从右键菜单中选择Copy,也可以直接使用快捷键Ctrl+C。

重命名

我们可以重命名任意的参数或者变量,右键点击变量,选择Rename Variable(快捷键L),便可更改变量名。

image
图4 重命名变量

而重命名函数,需要点击函数名,右键菜单中选择Rename Function(快捷键L)。

重定义变量类型

尽管反编译器会尽可能地自动还原变量类型,它时常得不到足够的信息。我们可以手动变更一些变量的类型来改善所得到的C代码。右键点击变量,选择Retype Variable(快捷键Ctrl+L)。任何该程序已知的类型都可以使用。
image

图5 更改变量类型

一个简单有效的提升反编译器所生成的代码质量的方式是,找到函数有明显的字符串参数的函数,并将参数的类型改为char *。之后对任何对定义的内存的引用都会将所传递的参数显示为string。

编辑函数签名

右键菜单中选择Edit Function Signature,我们便可以更改函数签名。
image

图6 编辑函数签名

函数签名包括函数名、返回类型、参数个数、参数名、参数类型、变量参数(varargs)。

我们可以通过修改函数签名的字符串来修改以上任意内容。比如说,当我们发现某个函数实际上是printf的话,我们可以在输入void printf(char *x, ...)。

另外,我们也可以选中Calling Convention(见图6)来从一系列可用的调用约定中选择。勾选inline以指示内联函数。勾选No Return以指示该函数不返回。

查找

右键菜单中的Find功能(Ctrl+F),支持在当前函数中对正则表达式或者字符串的查找。

导出成C代码

选择下图所示图标,可将当前反编译的函数导出。如果不指定文件扩展名,Ghidra会将其保存为.c文件。
image

图7 编辑函数签名

# 逆向分析 # 逆向工具
免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
本文为 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者