Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
bread — 주입 가능한 리얼 모드 x86 디버거: BIOS 리버스 엔지니어링 및 직렬 케이블을 통한 임의의 리얼 모드 코드 디버깅용, GDB 통합 및 하드웨어 중단점/와치포인트 지원. | Kitploit
도구/GitHubGitHub/theldus/bread
Reverse EngineeringDebuggersHardware SecurityBinary AnalysisFirmware Analysis
GitHubtheldus/bread

bread

주입 가능한 리얼 모드 x86 디버거: BIOS 리버스 엔지니어링 및 직렬 케이블을 통한 임의의 리얼 모드 코드 디버깅용, GDB 통합 및 하드웨어 중단점/와치포인트 지원.

저장소 보기
3261810개월 전Kitploit 검토 완료

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

🍞 BREAD

License: MIT

BREAD (BIOS Reverse Engineering & Advanced Debugger)는 다른 PC에서 시리얼 케이블을 통해 임의의 리얼 모드 코드(실제 하드웨어에서)를 디버깅할 수 있는 '주입 가능한' 리얼 모드 x86 디버거입니다.

소개

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 패킷의 복잡성을 제거하고 시스템과 통신하기 위한 더 간단한 프로토콜을 구축하는 것입니다. 또한, 더 간단한 프로토콜은 최종 코드 크기를 더 작게 만들어 디버거가 다양한 환경에 주입되기 쉽도록 합니다.

다음 다이어그램과 같습니다:

root@kitploit:~
    +---------+ 간단한 패킷  +----------+   GDB 패킷   +---------+                                       
    |         |--------------->|          |--------------->|         |                                       
    |   dbg   |                |  bridge  |                |   gdb   |
    |(실제 HW)|<---------------| (Linux)  |<---------------| (Linux) |
    +---------+    시리얼      +----------+       TCP      +---------+

기능

GDB 스텁을 구현함으로써, BREAD는 기본적으로 많은 기능을 제공합니다. 다음 명령이 지원됩니다:

  • 메모리 읽기 (x, dump, find 및 관련 명령어를 통해)
  • 메모리 쓰기 (set, restore 및 관련 명령어를 통해)
  • [레지스터] 읽기 및 쓰기
  • 단일 스텝 (si, stepi) 및 계속 (c, continue)
  • 중단점 (b, break)1
  • 하드웨어 워치포인트 (watch 및 관련 명령어)2

GDB 심볼

BIOS와 같은 원시 바이너리를 GDB에서 리버스 엔지니어링한다는 것은 자동으로 원래 심볼이 없음을 의미합니다. 그러나 RE 과정이 진행됨에 따라 사용자/프로그래머/해커는 코드의 특정 부분에 대한 이해가 높아지며, IDA, Cutter, Ghidra 등의 정적 분석 도구는 주석, 함수 정의 등을 추가할 수 있게 해줍니다. 이러한 향상은 사용자의 생산성을 크게 높여줍니다.

이를 염두에 두고, 프로젝트에는 symbolify.py라는 동반 Python 스크립트가 있습니다. 심볼 리스트(주소 레이블)가 주어지면 이들 심볼이 추가된 최소 ELF 파일을 생성합니다. 이 ELF는 나중에 GDB에 로드되어 디버깅 과정을 크게 단순화하는 데 사용될 수 있습니다.

심볼 파일은 공백, 빈 줄, 주석(#) 및 주소 줄의 주석을 포함할 수 있습니다. 주소는 10진수 또는 16진수 형식일 수 있으며, 레이블/심볼(하나 이상의 공백 문자로 구분)은 [a-z0-9_]+ 형식일 수 있습니다. 실제 예제는 symbols/ami_ipm41d3.txt에서 찾을 수 있습니다.

root@kitploit:~
#
# 이것은 주석입니다
#
0xdeadbeef my_symbol1

0x123 othersymbol # 이 함수는 xyz를 수행합니다

# 10진수 주소 예제
456 anotherone

사용법

예를 들어, symbols/ami_ipm41d3.txt에 있는 심볼 파일을 고려할 때, 사용자는 다음과 같이 할 수 있습니다:

root@kitploit:~
$ ./simbolify.py symbols/ami_ipm41d3.txt ip41symbols.elf

그런 다음 GDB에 로드합니다:

root@kitploit:~
(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 디버깅의 경우, 다른 제한 사항도 있습니다: BREAD가 올바르게 작동하려면 최소한의 설정(예: RAM)이 필요하므로 BIOS 코드를 처음부터(부트블록) 디버깅할 수 없습니다. 그러나 CS:EIP를 F000:FFF0으로 설정하여 "웜 리부트"를 수행할 수 있습니다. 이 시나리오에서 BREAD가 이미 로드되어 있으므로 BIOS 초기화를 다시 따라갈 수 있습니다. 웜 리부트 중 BIOS 초기화의 "코드 경로"는 콜드 리부트와 다를 수 있으며 실행 흐름이 정확히 같지 않을 수 있습니다.

빌드

빌드에는 GNU Make, C 컴파일러(GCC, Clang 또는 TCC 등), NASM 및 Linux 시스템만 필요합니다.

디버거에는 두 가지 작동 모드가 있습니다: 폴링(기본값) 및 인터럽트 기반:

폴링 모드

폴링 모드는 가장 간단한 접근 방식이며 다양한 환경에서 잘 작동해야 합니다. 그러나 폴링 특성으로 인해 CPU 사용량이 높습니다:

빌드

root@kitploit:~
$ git clone https://github.com/Theldus/BREAD.git
$ cd BREAD/
$ make

인터럽트 기반 모드

인터럽트 기반 모드는 지속적으로 폴링하는 대신 UART 인터럽트를 사용하여 새 데이터를 수신함으로써 CPU 사용률을 최적화합니다. 이로 인해 CPU는 디버거로부터 명령을 받을 때까지 '대기' 상태를 유지하므로 CPU 리소스를 100% 소비하지 않습니다. 그러나 인터럽트가 항상 활성화되어 있는 것은 아니므로 이 모드는 기본 옵션으로 설정되지 않았습니다:

빌드

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

사용법

BREAD를 사용하려면 시리얼 케이블(그리고 네, 마더보드에는 COM 헤더가 있습니다. 설명서를 확인하세요)과 적절한 위치에 코드를 주입하는 것만 있으면 됩니다.

주입하려면 dbg.asm(디버거의 소스)에서 최소한의 변경이 필요합니다. 코드의 'ORG'를 변경하고 코드가 어떻게 반환되어야 하는지도 변경해야 합니다(코드에서 ">> CHANGE_HERE <<"를 검색하여 변경해야 할 위치를 확인하세요).

BIOS의 경우 (예: AMI 레거시):

AMI 레거시를 예로 들면, 디버거 모듈이 BIOS 로고 위치(0x108200 또는 FFFF:8210)에 배치되고 ROM의 다음 명령어가 모듈로의 원격 호출로 대체됩니다:

root@kitploit:~
...
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
...

다음 패치로 충분합니다:

root@kitploit:~
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. DOS가 유효한 DOS 프로그램으로 인식하도록 dbg.asm 편집:

  • ORG를 0x100으로 설정
  • 유용한 코드를 파일 시작 부분에서 멀리 떨어뜨려 놓음 (times)
  • 프로그램 종료 설정 (int 0x20)

다음 패치가 이를 해결합니다:

root@kitploit:~
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 ; 약간의 거리를 유지,
+                      ; 40kB면 충분함
 
 %include "constants.inc"
 
@@ -140,7 +143,7 @@ _start:
 
 	; >> CHANGE_HERE <<
 	; Overwritten BIOS instructions below (if any)
-	nop
+	int 0x20 ; DOS 인터럽트로 프로세스 종료
 	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 사이의 접착제 역할을 하며, 실제 하드웨어 또는 가상 머신에서 다양한 방식으로 사용할 수 있습니다.

매개변수는 다음과 같습니다:

root@kitploit:~
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. VM3 열기 (make bochs 또는 make qemu 등)
  3. Single-stepped, you can now connect GDB! 메시지가 나타날 때까지 기다린 후 GDB 실행: gdb.

두 경우 모두, BRIDGE 루트 폴더 안에서 GDB를 실행해야 합니다. 이 폴더에는 GDB가 16비트에서 올바르게 작동하기 위한 보조 파일이 있습니다.

기여

BREAD는 항상 커뮤니티에 열려 있으며, 이슈, 문서, 테스트, 새로운 기능, 버그 수정, 오타 등 모든 기여를 환영합니다. 함께해 주세요.

라이선스 및 저자

BREAD는 MIT 라이선스로 제공됩니다. Davidson Francis와 (희망적으로) 다른 기여자가 작성했습니다.

Footnotes

  1. 중단점은 하드웨어 중단점으로 구현되므로 사용 가능한 중단점 수에 제한이 있습니다. 현재 구현에서는 한 번에 하나의 활성 중단점만 지원됩니다! ↩

  2. 하드웨어 워치포인트(중단점과 마찬가지로)도 한 번에 하나만 지원됩니다. ↩

  3. 디버그 레지스터는 기본적으로 VM에서 작동하지 않습니다. bochs의 경우 --enable-x86-debugger=yes 플래그로 컴파일해야 합니다. Qemu의 경우 KVM을 활성화하여 실행해야 합니다: --enable-kvm (make qemu가 이미 이 작업을 수행합니다). ↩

도구 다운로드