STM32 펌웨어 배포에 가장 많이 쓰이는 포맷. 메모장으로 열어보면:

:020000040800F2
:1000000018520020012800081F2B0008AB200008BE
:100010007920000800000000000000000000000048
...
:00000001FF

바이너리인 줄 알았는데 텍스트다. HEX는 바이너리를 텍스트로 인코딩한 것.


레코드 구조

각 줄이 하나의 “레코드”:

:LLAAAATT[DD...]CC

: = 시작 마커
LL = 데이터 길이
AAAA = 주소 (16비트)
TT = 레코드 타입
DD = 데이터
CC = 체크섬

예시:

:1000000018520020012800081F2B0008AB200008BE
 ││    ││                              ││
 ││    │└ 타입: 00 (데이터)              └┴ 체크섬
 ││    └─ 주소: 0x0000
 └┴────── 길이: 0x10 (16바이트)

레코드 타입

타입의미
00데이터
01파일 끝
0432비트 주소 확장

STM32는 32비트 주소인데 레코드의 주소 필드는 16비트다. 타입 04로 상위 16비트를 지정한다:

:020000040800F2
           └┴── 상위 16비트: 0x0800

이후 데이터의 기준 주소가 0x0800 << 16 = 0x08000000. STM32 Flash 시작 주소다.


Vector Table 확인

첫 데이터 레코드를 리틀 엔디안으로 읽으면:

18520020 → 0x20005218 (Initial SP)
01280008 → 0x08002801 (Reset_Handler)
1F2B0008 → 0x08002B1F (NMI_Handler)
AB200008 → 0x080020AB (HardFault_Handler)

0x08002801에서 마지막 1은 Thumb 모드 표시. 실제 주소는 0x08002800.


HEX → BIN 변환

Ghidra는 raw binary를 선호한다.

objcopy -I ihex -O binary 200429.hex 200429.bin

또는 Python:

from intelhex import IntelHex
ih = IntelHex('200429.hex')
ih.tobinfile('200429.bin')
print(f"Size: {ih.maxaddr() - ih.minaddr() + 1} bytes")  # 16384 = 16KB

주의: 주소 정보 손실

BIN 변환하면 시작 주소 정보가 사라진다. Ghidra 로드할 때 Base Address를 0x08000000으로 수동 지정해야 한다.


다음 글에서 Ghidra에 로드한다.

#3 - Ghidra 첫 로드