Skip to content
KitploitKITPLOIT
工具漏洞利用博客
Log in
提交
工具漏洞利用博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

订阅源联系隐私© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
bread — 可注入的实模式 x86 调试器,用于 BIOS 逆向工程和通过串行线调试任意实模式代码,支持 GDB 集成和硬件断点/观察点。 | Kitploit
工具/GitHubGitHub/theldus/bread
逆向工程调试器硬件安全二进制分析固件分析
GitHubtheldus/bread

bread

可注入的实模式 x86 调试器,用于 BIOS 逆向工程和通过串行线调试任意实模式代码,支持 GDB 集成和硬件断点/观察点。

查看仓库
32618660年前Kitploit 审核通过

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

🍞 BREAD

License: MIT

BREAD(BIOS 逆向工程与高级调试器)是一个“可注入”的实模式 x86 调试器,能够通过串口线从另一台 PC 调试任意实模式代码(在真实硬件上)。

简介

BREAD 源于多次尝试逆向传统 BIOS 的失败经历。鉴于绝大多数(如果不是全部)BIOS 分析都是使用反汇编器静态完成的,理解 BIOS 变得极其困难,因为无法知道给定代码段中寄存器或内存的值。

尽管如此,BREAD 也可以调试实模式下的任意代码,例如可引导代码或 DOS 程序。

快速演示:

https://user-images.githubusercontent.com/8294550/217709970-9007a1e3-7352-470d-a22f-cbb5219d5547.mp4

通过 BREAD 更改 CPU 字符串名称

工作原理

此调试器分为两部分:调试器(完全用汇编编写,运行在被调试的硬件上)和桥接器,用 C 编写并运行在 Linux 上。

调试器是可注入的代码,以 16 位实模式编写,可以放置在 BIOS ROM 或任何其他实模式代码中。当执行时,它会设置适当的中断处理程序,将处理器置于单步模式,并通过串口等待命令。

另一方面,桥接器是调试器与 GDB 之间的链接。桥接器通过 TCP 与 GDB 通信,并通过串口将请求/响应转发给调试器。桥接器的目的是消除 GDB 数据包的复杂性,并建立更简单的协议与机器通信。此外,更简单的协议使最终代码体积更小,使调试器更容易注入到各种不同的环境中。

如下图所示:

    +---------+ 简单数据包 +----------+   GDB 数据包  +---------+                                       
    |         |--------------->|          |--------------->|         |                                       
    |   dbg   |                |  bridge  |                |   gdb   |
    |(真实硬件)|<---------------| (Linux)  |<---------------| (Linux) |
    +---------+    串口        +----------+       TCP      +---------+

特性

通过实现 GDB 存根,BREAD 具备许多开箱即用的特性。支持以下命令:

  • 读取内存(通过 x、dump、find 及相关命令)
  • 写入内存(通过 set、restore 及相关命令)
  • 读写 registers
  • 单步执行 (si、stepi) 和继续执行 (c、continue)
  • 断点 (b、break)1
  • 硬件监视点 (watch 及其同类)2

GDB 符号

在 GDB 中逆向分析原始二进制文件(如 BIOS)自然意味着没有其原始符号。然而,随着逆向分析过程的推进,用户/程序员/黑客对代码的某些部分有了更好的理解,而静态分析工具(如 IDA、Cutter、Ghidra 等)允许添加注释、函数定义等功能。这些增强显著提高了用户的生产力。

考虑到这一点,项目中提供了一个名为 symbolify.py 的辅助 Python 脚本。给定一个符号列表(地址 标签),它会生成一个最小的 ELF 文件,其中包含这些符号。这个 ELF 文件随后可以加载到 GDB 中,极大地简化调试过程。

符号文件可以包含空白字符、空行、注释(#)以及地址行上的注释。地址可以是十进制或十六进制格式,标签/符号(由一个或多个空白字符分隔)的形式为 [a-z0-9_]+,实例如下(实际示例可在 symbols/ami_ipm41d3.txt 中找到):

#
# 这是一个注释
#
0xdeadbeef my_symbol1

0x123 othersymbol # 这个函数做 xyz

# 十进制地址示例
456 anotherone

用法

例如,考虑 symbols/ami_ipm41d3.txt 中的符号文件,用户可以执行类似以下操作:

$ ./simbolify.py symbols/ami_ipm41d3.txt ip41symbols.elf

然后,在 GDB 中加载它,如下所示:

(gdb) add-symbol-file ip41symbols.elf 0
add symbol table from file "ip41symbols.elf" at
	.text_addr = 0x0
(y or n) y
Reading symbols from ip41symbols.elf...
(No debugging symbols found in ip41symbols.elf)
(gdb) p cseg_
cseg_change_video_mode_logo  cseg_get_cpuname             
(gdb) p cseg_

注意,即使 GDB 的自动补全也能正常工作,是不是很神奇?

局限性

有多少?是的。 由于被调试的代码不知道自己在被调试,它可能以多种方式干扰调试器,仅举几例:

  • 保护模式跳转:如果被调试的代码切换到保护模式,中断处理程序等结构会被改变,调试器将不再被调用。然而,如果跳回实模式(恢复完整先前状态),调试器可能再次工作。

  • IDT 更改:如果被调试的代码因任何原因更改了 IDT 或其基地址,调试器处理程序将无法正确调用。

  • 栈:BREAD 使用栈并假定栈存在!不应将其插入到栈尚未配置的位置。

对于 BIOS 调试,还有其他限制,例如:无法从最开头(bootblock)调试 BIOS 代码,因为 BREAD 正确运行需要最低限度的设置(如 RAM)。但是,可以通过将 CS:EIP 设置为 F000:FFF0 来执行“热重启”。在这种情况下,可以再次跟踪 BIOS 初始化过程,因为 BREAD 已经正确加载。请注意,热重启期间的 BIOS 初始化“代码路径”可能与冷重启不同,执行流程可能不完全相同。

构建

构建仅需要 GNU Make、C 编译器(如 GCC、Clang 或 TCC)、NASM 以及 Linux 机器。

调试器有两种操作模式:轮询模式(默认)和中断模式:

轮询模式

轮询模式是最简单的方法,在各种环境中应该都能正常工作。然而,由于轮询的特性,CPU 使用率较高:

构建

$ git clone https://github.com/Theldus/BREAD.git
$ cd BREAD/
$ make

中断模式

中断模式通过使用 UART 中断接收新数据来优化 CPU 利用率,而不是不断轮询。这导致 CPU 保持在“暂停”状态,直到接收到调试器的命令,从而防止 CPU 占用 100% 的资源。但是,由于中断并非始终启用,此模式未设置为默认选项:

构建

$ git clone https://github.com/Theldus/BREAD.git
$ cd BREAD/
$ make UART_POLLING=no

使用

使用 BREAD 只需要一根串口线(是的,你的主板 有 COM 接口,请查阅手册)并将代码注入到适当的位置。

要注入,必须在 dbg.asm(调试器的源文件)中进行最小修改。需要更改代码的 'ORG' 以及代码返回的方式(在代码中查找 “>> CHANGE_HERE <<” 以及需要更改的位置)。

对于 BIOS(例如 AMI Legacy):

以 AMI legacy 为例,将调试器模块放置在 BIOS 徽标位置(0x108200 或 FFFF:8210),并且 ROM 中的以下指令已被替换为对模块的远调用:

...
00017EF2  06                push es
00017EF3  1E                push ds
00017EF4  07                pop es
00017EF5  8BD8              mov bx,ax     -┐ 替换为:call 0xFFFF:0x8210 (dbg.bin)
00017EF7  B8024F            mov ax,0x4f02 -┘
00017EFA  CD10              int 0x10
00017EFC  07                pop es
00017EFD  C3                ret
...

以下补丁就足够了:

diff --git a/dbg.asm b/dbg.asm
index caedb70..88024d3 100644
--- a/dbg.asm
+++ b/dbg.asm
@@ -21,7 +21,7 @@
 ; SOFTWARE.
 
 [BITS 16]
-[ORG 0x0000] ; >> CHANGE_HERE <<
+[ORG 0x8210] ; >> CHANGE_HERE <<
 
 %include "constants.inc"
 
@@ -140,8 +140,8 @@ _start:
 
 	; >> CHANGE_HERE <<
 	; Overwritten BIOS instructions below (if any)
-	nop
-	nop
+	mov ax, 0x4F02
+	int 0x10
 	nop
 	nop

值得注意的是,如果你修改了 ROM 中的几条指令来调用调试器代码,那么在从调试器返回之前必须恢复它们。

替换这两条指令的原因是它们在 BIOS 显示徽标之前执行,而徽标现在是调试器,这确保了几个关键点:

  • 徽标模块(即调试器)已经加载到内存中
  • BIOS 的视频中断已经工作
  • 周围的代码表明栈已经存在

找到一个好的位置来调用调试器(BIOS 已充分初始化但不过晚)可能具有挑战性,但这是可能的。

之后,dbg.bin 就可以插入到 ROM 中的正确位置了。

对于 DOS

使用 BREAD 调试 DOS 程序有点棘手,但可行:

1. 编辑 dbg.asm,使 DOS 将其识别为有效的 DOS 程序:

  • 将 ORG 设置为 0x100
  • 使有用代码远离文件开头(times)
  • 设置程序退出(int 0x20)

以下补丁解决了此问题:

diff --git a/dbg.asm b/dbg.asm
index caedb70..b042d35 100644
--- a/dbg.asm
+++ b/dbg.asm
@@ -21,7 +21,10 @@
 ; SOFTWARE.
 
 [BITS 16]
-[ORG 0x0000] ; >> CHANGE_HERE <<
+[ORG 0x100]
+
+times 40*1024 db 0x90 ; keep some distance,
+                      ; 40kB should be enough
 
 %include "constants.inc"
 
@@ -140,7 +143,7 @@ _start:
 
 	; >> CHANGE_HERE <<
 	; Overwritten BIOS instructions below (if any)
-	nop
+	int 0x20 ; DOS interrupt to exit process
 	nop

2. 创建最小的可引导 DOS 环境并运行

创建一个可引导的 FreeDOS(或 DOS)软盘映像,仅包含内核和终端:KERNEL.SYS 和 COMMAND.COM。还要将待调试的程序和 DBG.COM(dbg.bin)添加到该软盘映像中。

创建映像后,应按照以下步骤操作:

  • 启动它,同时 bridge 已经打开(请参考下一节的说明)。
  • 执行 DBG.COM。
  • 执行停止后,使用 GDB 添加任何所需的断点和监视点,这些断点和监视点相对于接下来要调试的进程。然后,让 DBG.COM 进程继续执行直到结束。
  • 运行你想要调试的程序。先前配置的断点和监视点应该会按预期触发。

需要注意的是,DOS 在进程退出后不会擦除进程映像。因此,调试器可以像任何其他 DOS 程序一样配置,并设置适当的断点。调试器的开头填充了 NOP,因此预计新进程不会覆盖调试器的内存,使其在看似“结束”后仍能继续工作。这使得 BREAD 能够调试其他程序,包括 DOS 本身。

桥接器

桥接器是调试器与 GDB 之间的粘合剂,可以通过不同方式使用,无论是真实硬件还是虚拟机。

其参数如下:

Usage: ./bridge [options]
Options:
  -s 启用通过套接字(而非设备)的串口
  -d <path> 替换默认设备路径 (/dev/ttyUSB0)
            (如果启用 -s 则无效)
  -p <port> 串口(作为套接字),默认:2345
  -g <port> GDB 端口,默认:1234
  -h 帮助信息

如果未传递任何选项,默认行为是:
  ./bridge -d /dev/ttyUSB0 -g 1234

推荐的最小用法:
  ./bridge -s (套接字模式,串口在 2345,GDB 在 1234)
  ./bridge    (设备模式,串口在 /dev/ttyUSB0,GDB 在 1234)

真实硬件

要在真实硬件上使用,只需不带参数调用即可。可选地,可以使用 -d 参数更改设备路径:

执行流程:
  1. 将串口线连接到 PC
  2. 运行桥接器(./bridge 或 ./bridge -d /path/to/device)
  3. 打开要调试的 PC
  4. 等待消息:Single-stepped, you can now connect GDB!,然后启动 GDB:gdb。

虚拟机

在虚拟机中使用时,执行顺序略有变化:

执行流程:
  1. 运行桥接器(./bridge 或 ./bridge -d /path/to/device)
  2. 打开虚拟机[^vm_note](例如:make bochs 或 make qemu)
  3. 等待消息:Single-stepped, you can now connect GDB!,然后启动 GDB:gdb。

在这两种情况下,请确保在 BRIDGE 根目录下运行 GDB,因为该文件夹中有辅助文件,以便 GDB 在 16 位模式下正常工作。

Footnotes

  1. 断点作为硬件断点实现,因此可用断点数量有限。在当前实现中,一次仅支持 1 个活动断点! ↩

  2. https://raw.githubusercontent.com/theldus/bread/master/%E7%A1%AC%E4%BB%B6%E7%9B%91%E8%A7%86%E7%82%B9%EF%BC%88%E5%A6%82%E6%96%AD%E7%82%B9%EF%BC%89%E4%B8%80%E6%AC%A1%E4%B9%9F%E5%8F%AA%E6%94%AF%E6%8C%81%E4%B8%80%E4%B8%AA%E3%80%82 ↩

下载工具