记一次对Ghidra反编译的修复

本文介绍了作者在使用Ghidra进行逆向工程时遇到的反编译问题,特别是针对Rust程序分析时出现的异常。文章详细探讨了反编译原理,包括基础准备、控制流图获取、SSA生成等步骤,并分析了Ghidra的反编译引擎工作流程。作者通过调试和分析,发现问题出在栈变量恢复过程中对`and`指令处理的遗漏。最终,作者添加了一个新规则来处理这种情况,有效修复了问题。文章还讨论了IDA在相同情况下的表现,指出Ghidra仍有待改进,同时分享了作者的修复代码和学习网络安全的建议。

前言

Ghidra是NSA在2019年开源的逆向工具,可以说从开源发布开始,就基本成了开源界唯一可以与 IDA
竞争的存在,其它的工具多少总是欠点意思。不过从实际情况来看,虽然
Ghidra一直在积极维护,但是现在的Bug情况跟IDA相比,也还是差点意思。不过,开源的好处,就是可以自己研究自己修复,在我这次参加Defcon资格赛过程中碰到问题的时候,我决定,自力更生,于是有了下面的经历。

##问题

最开始发现问题是在逆Rust的时候,IDA 在逆Rust的时候一向有点问题,这次更是出现了分析出来 500
多个参数的情况,实在让人有点难受。于是我觉得尝试下ghidra ,但是打开发现,虽然没有了 500 多个参数,但是情况也好不了太多,出现了奇妙的情况:

相比之下IDA就没有这种奇怪的东西:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cSGA1AYd-1690267282860)(https://image.3001.net/images/20210620/1624195056_60cf3ff06e3e25f7d0662.png!small)]

我找了半天,当时也没能发现 0x178a97 、0x178aa9
之类的玩意儿是从哪里来的,但是这肯定是个比较严重的问题,因为这基本让反编译没法看了。比赛期间没有办法,只能继续用IDA了。但是赛后这个问题是肯定要处理处理的。

##反编译的原理

反编译基本都可分为这么几步:

基础准备

基础准备:一般就是由反汇编器 来完成的几个步骤,包括:

1. 加载镜像:将文件中的代码、数据分析出来,从而知道内存中某个地址对应文件中的什么数据。

2.
代码识别+反汇编+代码提升(lifting):猜测哪些地方应该是机器代码,然后对机器代码进行解码得到汇编语言,同时还可以将汇编语言进行代码提升,也就是liting,得到中间语言
。之后的分析一般就发生在中间语言上,这样可以避免直接对不同架构的汇编代码进行处理,从而可以方便地支持多架构。

控制流图获取

控制流图获取:这部分开始就是反编译器的工作了(一般来说是)。首先就是需要进行控制流图的获取,控制流图是一种图结构,图上的每一个节点叫做一个基本块
,也就是会连续执行的指令。例如以下的汇编程序:mov eax, 1add ebx, eax ; 假设 ebx 是外部的输入cmp ebx, 0x10jne label1mov ebx, 0x20jmp endlabel1:mov ebx, 0x30end:xor eax, eax这一段程序如果画成控制流图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XTbb28Qk-1690267282860)(https://image.3001.net/images/20210620/1624195622_60cf4226af0c03c9445f4.png!small)]

每一个基本块一旦进入就一定会执行到结尾。这样做之后,就会让分析更加方便,因为以前我们只能以一句汇编为一个单位进行分析,现在就可以一个基本块为一个单位进行分析了。另外,有了图的结构,也比较清晰的知道一个基本块之后可以走到什么分支了。最后的控制流恢复也和这个步骤息息相关。

SSA 生成

SSA,Static Single
Assignment,中文叫做静态单赋值,是说,每一个变量都只应该被赋值一次(只写入一次)。怎么做到呢?就是将变量进行改名,例如eax被写了两次,那么第一次写入,假设是
mov eax, 1 就可以表示为eax_0 = 1 ,第二次用到的eax,假设是add eax, 1 就会表示为eax_1 = eax_0 + 1
这样,一看到eax_1就知道是第二个,不会是第一个了。

但是如果出现分支,就会有一点问题,例如这样的程序:cmp ebx, 100jne L1mov eax, 1jmp endL1:mov eax, 2end:add ebx, eax

如果重新命名eax_1 = 1jmp endL1:eax_2 = 2end:ebx_1 = ? ; 这里出现了问题,应该是 eax_1 还是 eax_2?

所以在SSA里边,我们会加入一个特殊的语句,叫做phi,有时候也叫做phi-node(phi
节点),他的作用就是将分支导致的多个变量进行合并,例如上面的程序就可以被写作:if ebx_0 != 100 then jmp L1eax_1 = 1jmp endL1:eax_2 = 2end:eax_3 = phi(eax_1, eax_2)ebx_1 = eax_3

SSA的目的是让分析更加高效便捷,因为在分析的时候,你用到的变量都可以很清楚的知道是由哪一条语句进行定义的,而不需要往前挨个去找(因为只有一条语句可以定义,所以就很清楚是哪一条,就不需要全部找一遍才能确认)。

变量恢复

即,将变量进行分析恢复,这也是本次Bug的修复重点。变量分为多种可能,包括栈上的变量、寄存器里的变量等等。栈上的变量目前所使用的方法一般是找到栈指针,查看其在函数内开辟了多少空间(加、减了多大的偏移),然后对于用到这一段空间的认为是可能的变量。

类型恢复

在变量恢复之后,会进行类型恢复,也就是“猜”恢复出来的变量可能是什么类型,如果实在猜不出来,就猜一个大小,这个大小可以根据是怎么使用的来确定。例如:加载一个位于rsp

  • 0x30的 8 个字节,就会认为这个位置所对应的变量的大小是 8
    个字节。至于是指针还是整数还是浮点数,这就需要利用后续对这个变量的其他使用方式来确定了。

控制流恢复

即,将控制流图打上标记,确认控制流图所对应的程序结构,例如在上面控制流图示例中所对应的就应该是 if-else语句。

这一部分一般是通过图匹配算法来实现的,也就是根据图长什么样子来确定是什么语句。

AST 恢复

在控制

<think>我们正在处理用户的问题:"我想在单用户的前提下,解决Debian 12 WSL环境下Ghidra反编译命令出现EACCES错误的问题" 根据用户描述,错误是EACCES,即权限错误(Permission denied)。由于是单用户环境,我们不需要考虑多用户权限问题,但需要检查文件或目录的权限设置。 可能的原因: 1. Ghidra需要访问某些目录或文件,但当前用户(即使是root)可能因为WSL的文件系统权限问题而无法访问。 2. 特别是,如果Ghidra尝试访问位于/mnt/c(即Windows文件系统)下的文件,可能会遇到权限问题,因为WSL对Windows文件系统的挂载默认权限可能不足。 解决思路: 1. 确认错误发生的具体位置:是读取输入文件时出错,还是写入输出文件时出错?或者是Ghidra自身需要访问临时文件或某些目录? 2. 检查涉及的文件和目录的权限。 3. 如果文件位于Windows文件系统(如/mnt/c/...),则考虑在WSL内部复制文件到Linux文件系统(如用户家目录)再操作。 4. 检查Ghidra是否在尝试创建文件或目录,但目标位置没有写权限。 具体步骤: 步骤1:确认错误发生的上下文 运行Ghidra命令时,注意错误信息中提到的文件路径。例如: Error: EACCES: permission denied, open '/path/to/file' 步骤2:检查文件和目录权限 使用`ls -l /path/to/file`查看权限。如果是目录,确保有执行权限(x)才能进入目录;如果是文件,确保有读或写权限(根据操作)。 步骤3:处理Windows文件系统上的文件 如果文件在/mnt/c下,由于WSL挂载的Windows文件系统默认权限为777,但实际受限于Windows权限,且默认不启用执行权限。因此,建议将文件复制到WSL的Linux文件系统中(如~/ghidra_project)再操作。 步骤4:确保临时目录可访问 Ghidra可能会使用/tmp目录。在WSL中,/tmp目录通常权限为1777(drwxrwxrwt),即粘滞位已设置,但这在单用户环境下通常没有问题。如果怀疑/tmp有问题,可以设置环境变量指向另一个临时目录: mkdir ~/ghidra_tmp chmod 700 ~/ghidra_tmp export TMPDIR=~/ghidra_tmp # 然后运行Ghidra命令 步骤5:以root用户运行(如果之前不是) 尽管单用户环境,但如果你是用普通用户运行的,尝试用sudo运行。但注意,如果文件在Windows文件系统上,root用户也可能遇到同样问题。 步骤6:检查文件是否被其他进程锁定 在Windows中,如果文件被其他程序打开(如资源管理器、文本编辑器等),WSL可能无法访问。关闭所有可能占用该文件的程序。 步骤7:检查文件系统错误 如果怀疑是文件系统错误,可以尝试在Windows中运行chkdsk。 步骤8:使用strace跟踪系统调用 如果上述方法无效,使用strace跟踪Ghidra命令,查看具体是哪个系统调用返回了EACCES。 sudo apt install strace strace -f -e trace=file ghidra命令 2> strace.log 然后在strace.log中搜索EACCES错误。 考虑到用户的环境是Debian 12 WSL,我们给出具体的操作命令: 示例解决方案: 假设错误是因为操作了/mnt/c下的文件,可以将文件复制到WSL内部: 1. 在WSL中创建项目目录: ```bash mkdir ~/ghidra_projects cp /mnt/c/path/to/target_file ~/ghidra_projects/ ``` 2. 在WSL内部操作该文件。 3. 如果Ghidra需要写文件,确保目标目录可写: ```bash chmod +w ~/ghidra_projects ``` 4. 运行Ghidra命令,指定WSL内部的文件路径。 如果问题发生在Ghidra的安装目录(比如Ghidra本身没有执行权限),则需要检查Ghidra的安装目录权限。 例如,如果Ghidra安装在/opt/ghidra,则检查: ```bash ls -l /opt/ghidra ``` 确保当前用户有执行权限(如果是以普通用户运行,则需要读和执行权限)。如果没有,可以更改权限: ```bash sudo chmod -R o+rX /opt/ghidra # 或者更精细地设置,比如给当前用户所有权 ``` 另外,注意Ghidra的运行可能需要Java环境,确保Java已正确安装。 如果用户没有提供更具体的错误信息,我们只能给出一般性解决方案。 最后,我们生成相关问题: 1. 如何解决WSL中访问Windows文件系统的权限问题? 2. Ghidra在Linux中安装后需要哪些额外配置? 3. 如何调试Linux中的权限拒绝(EACCES)错误? 4. 在WSL中运行GUI应用需要注意什么? 5. 如何提高WSL与Windows文件系统交互的性能? </think>### 解决 Debian 12 WSL 环境下 Ghidra 的 EACCES 错误(单用户场景) #### 错误分析 EACCES(错误代码 13)表示**权限不足**。在单用户 WSL 环境中,主要涉及以下原因: 1. **文件系统权限问题** - Ghidra 需要访问 `/tmp` 或临时目录,但权限不足 - 反编译目标文件或输出目录权限限制 - Windows 主机文件系统(如 `/mnt/c`)的跨系统权限问题[^1] 2. **WSL 文件系统特性** ```bash $ ls -ld /tmp drwxrwxrwt 1 root root 512 Jun 10 09:00 /tmp # 注意 NTFS 挂载特性 ``` - WSL 访问 Windows 文件系统(NTFS)时权限映射异常[^2] 3. **Ghidra 运行环境** - Java 虚拟机(JVM)临时目录访问限制 - 反编译进程的用户身份问题 --- ### 解决方案(单用户优化) #### 方法 1:修正临时目录权限(推荐) ```bash # 创建专用临时目录(避免跨系统权限问题) mkdir -p ~/ghidra_tmp chmod 700 ~/ghidra_tmp # 设置环境变量(对当前会话生效) export _JAVA_OPTIONS="-Djava.io.tmpdir=$HOME/ghidra_tmp" ``` #### 方法 2:直接修复系统临时目录 ```bash # 检查当前 /tmp 权限 $ ls -ld /tmp drwxrwxrwt 1 root root 512 Jun 10 09:00 /tmp # 重置权限(单用户环境可放宽) sudo chmod 1777 /tmp # 确保粘滞位存在 ``` #### 方法 3:处理跨系统文件访问 若目标文件位于 `/mnt/c`(Windows 文件系统): ```bash # 将文件复制到 WSL 原生文件系统 cp /mnt/c/Users/yourfile ~/ghidra_workspace/ # 在 Linux 原生文件系统中操作 ghidra ~/ghidra_workspace/yourfile ``` #### 方法 4:以正确用户身份运行 ```bash # 确保使用启动 WSL 的同一用户 whoami # 验证用户名 # 避免使用 sudo(除非必要) ./ghidraRun # 而不是 sudo ./ghidraRun ``` --- ### 验证步骤 1. 创建测试环境: ```bash echo "test" > ~/test.bin ``` 2. 运行 Ghidra: ```bash ghidra ~/test.bin ``` 3. 检查日志: ```bash tail -f ~/.ghidra/.log/ghidra.log ``` > **关键提示**:在 WSL 中优先使用 Linux 原生文件系统(如 `~/`),避免直接操作 `/mnt/c` 下的文件[^1][^3]。 --- ### 根本原因分析 在单用户 WSL 环境中,EACCES 错误主要源于: $$ \text{权限问题} = \begin{cases} \text{跨系统文件操作} & (\text{NTFS 权限映射}) \\ \text{JVM 临时目录配置} & (\text{默认指向 /tmp}) \\ \text{WSL 文件系统特性} & (\text{ext4 vs NTFS}) \end{cases} $$ 通过专用临时目录和原生文件系统操作可彻底解决。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值