Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
bread — Injectable real-mode x86 debugger for BIOS reverse engineering and arbitrary real-mode code debugging via serial cable, with GDB integration and hardware breakpoint/watchpoint support. | Kitploit
Tools/GitHubGitHub/theldus/bread
Reverse EngineeringDebuggersHardware SecurityBinary AnalysisFirmware Analysis
GitHubtheldus/bread

bread

Injectable real-mode x86 debugger for BIOS reverse engineering and arbitrary real-mode code debugging via serial cable, with GDB integration and hardware breakpoint/watchpoint support.

View Repository
326183011 months agoReviewed by Kitploit

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

🍞 BREAD

License: MIT

BREAD (BIOS Reverse Engineering & Advanced Debugger) is an 'injectable' real-mode x86 debugger that can debug arbitrary real-mode code (on real HW) from another PC via serial cable.

Introduction

BREAD emerged from many failed attempts to reverse engineer legacy BIOS. Given that the vast majority -- if not all -- BIOS analysis is done statically using disassemblers, understanding the BIOS becomes extremely difficult, since there's no way to know the value of registers or memory in a given piece of code.

Despite this, BREAD can also debug arbitrary code in real-mode, such as bootable code or DOS programs too.

Quick demo:

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

Changing CPU string name via BREAD

How it works?

This debugger is divided into two parts: the debugger (written entirely in assembly and running on the hardware being debugged) and the bridge, written in C and running on Linux.

The debugger is the injectable code, written in 16-bit real-mode, and can be placed within the BIOS ROM or any other real-mode code. When executed, it sets up the appropriate interrupt handlers, puts the processor in single-step mode, and waits for commands on the serial port.

The bridge, on the other hand, is the link between the debugger and GDB. The bridge communicates with GDB via TCP and forwards the requests/responses to the debugger through the serial port. The idea behind the bridge is to remove the complexity of GDB packets and establish a simpler protocol for communicating with the machine. In addition, the simpler protocol enables the final code size to be smaller, making it easier for the debugger to be injectable into various different environments.

As shown in the following diagram:

    +---------+ simple packets +----------+   GDB packets  +---------+                                       
    |         |--------------->|          |--------------->|         |                                       
    |   dbg   |                |  bridge  |                |   gdb   |
    |(real HW)|<---------------| (Linux)  |<---------------| (Linux) |
    +---------+    serial      +----------+       TCP      +---------+

Features

By implementing the GDB stub, BREAD has many features out-of-the-box. The following commands are supported:

  • Read memory (via x, dump, find, and relateds)
  • Write memory (via set, restore, and relateds)
  • Read and write registers
  • Single-Step (si, stepi) and continue (c, continue)
  • Breakpoints (b, break)1
  • Hardware Watchpoints (watch and its siblings)2

GDB Symbols

Reverse engineering a raw binary, such as a BIOS, in GDB automatically implies not having its original symbols. However, as the RE process progresses, the user/programmer/hacker gains a better understanding of certain parts of the code, and static analysis tools like IDA, Cutter, Ghidra, and others allow for the addition of annotations, comments, function definitions, and more. These enhancements significantly boost the user's productivity.

With this in mind, there is a companion Python script in the project called symbolify.py. Given a list of symbols (address label), it generates a minimal ELF file with these symbols added. This ELF can then be loaded into GDB later and used to greatly simplify the debugging process.

The symbol file can include whitespace, blank lines, comments (#), and comments on the address line. Addresses can be in decimal or hexadecimal format, and labels/symbols (separated by one or more whitespace characters) can be of the form [a-z0-9_]+, as in (a real example can be found in symbols/ami_ipm41d3.txt):

#
# This is a comment
#
0xdeadbeef my_symbol1

0x123 othersymbol # This function does xyz

# Example with decimal address
456 anotherone

Usage

For example, considering the symbol file available at symbols/ami_ipm41d3.txt, the user can do something like:

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

Then, load it in GDB as in:

(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_

Note that even GDB auto-complete works as expected, amazing?

Limitations

How many? Yes. Since the code being debugged is unaware that it is being debugged, it can interfere with the debugger in several ways, to name a few:

  • Protected-mode jump: If the debugged code switches to protected-mode, the structures for interrupt handlers, etc. are altered and the debugger will no longer be invoked at that point in the code. However, it is possible that a jump back to real mode (restoring the full previous state) will allow the debugger to work again.

  • IDT changes: If for any reason the debugged code changes the IDT or its base address, the debugger handlers will not be properly invoked.

  • Stack: BREAD uses a stack and assumes it exists! It should not be inserted into locations where the stack has not yet been configured.

For BIOS debugging, there are other limitations such as: it is not possible to debug the BIOS code from the very beggining (bootblock), as a minimum setup (such as RAM) is required for BREAD to function correctly. However, it is possible to perform a "warm-reboot" by setting CS:EIP to F000:FFF0. In this scenario, the BIOS initialization can be followed again, as BREAD is already properly loaded. Please note that the "code-path" of BIOS initialization during a warm-reboot may be different from a cold-reboot and the execution flow may not be exactly the same.

Building

Building only requires GNU Make, a C compiler (such as GCC, Clang, or TCC), NASM, and a Linux machine.

The debugger has two modes of operation: polling (default) and interrupt-based:

Polling mode

Polling mode is the simplest approach and should work well in a variety of environments. However, due the polling nature, there is a high CPU usage:

Building

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

Interrupt-based mode

The interrupt-based mode optimizes CPU utilization by utilizing UART interrupts to receive new data, instead of constantly polling for it. This results in the CPU remaining in a 'halt' state until receiving commands from the debugger, and thus, preventing it from consuming 100% of the CPU's resources. However, as interrupts are not always enabled, this mode is not set as the default option:

Footnotes

  1. Breakpoints are implemented as hardware breakpoints and therefore have a limited number of available breakpoints. In the current implementation, only 1 active breakpoint at a time! ↩

  2. Hardware watchpoints (like breakpoints) are also only supported one at a time. ↩

Download Tool