Galaxy Watch5의 센서 샘플링 레이트 변경 경로를 AP–Sensor Hub–LSM6DSO32까지 역추적하고, 수제 JIG와 2차 납땜으로 물리 USB 연결 및 Odin 플래싱에 성공했습니다.
일반 커널 드라이버에서 시작한 분석을 Samsung Sensor Hub 펌웨어의 ODR 설정 함수와 레지스터
0x10까지 좁혔습니다. 수정한 펌웨어는 단 1바이트를 바꾼 경우에도 부팅 단계에서 거부되어 실제 ODR 변경 측정에는 이르지 못했지만, 마지막 미해결 지점을 센서 제어 코드가 아니라 펌웨어 무결성·서명 검증 경계로 분리했습니다.왜 이 프로젝트를 시작했는가
처음 받은 질문은 단순했습니다. “Galaxy Watch5의 센서 샘플링 레이트를 바꿀 수 있는가?” 처음에는 커널 드라이버에서 숫자 하나를 찾아 바꾸면 된다고 생각했습니다. 그러나 앱이 센서 값을 요청하는 계층, AP가 Sensor Hub에 명령을 전달하는 계층, Sensor Hub가 실제 센서 레지스터를 쓰는 계층, 수정한 이미지를 기기에 넣는 계층은 서로 분리되어 있었습니다.
연구가 길어질수록 저는 세 가지 질문을 먼저 하게 됐습니다. 지금 확인한 것은 사실인가, 아직 가설인가? 실패했을 때 복구할 수 있는가? 어느 경계까지 성공했고 어디서부터 실패했는가? 이 기준 때문에 공개 소스의 함수 분석을 실제 기기 적용 성공으로 포장하지 않았고, system 권한을 얻은 것을 root 성공이라고 부르지 않았으며, Odin의
PASS!도 수정 펌웨어의 정상 부팅과 구분했습니다.결국 이 프로젝트는 센서의 숫자 하나를 바꾸는 작업이 아니라, 불완전한 문서와 닫힌 플랫폼을 상대로 가설을 세우고 틀린 가정을 수정하며 소프트웨어와 하드웨어의 경계를 하나씩 통과한 연구가 되었습니다.
PROJECT OVERVIEW
항목 | 내용 |
기간 | 2024.05.20–2025.03.08 · 약 8개월의 인턴 연구와 최종 발표·기록 정리 |
수행 형태 | CASO Lab 개인 주도 연구 · 지도교수 및 공동 연구 학생과 주간 검토 |
문제 | Galaxy Watch5 가속도계의 ODR을 결정하는 코드는 어디에 있으며, 수정한 펌웨어를 실제 기기에 안전하게 전달해 동작을 검증할 수 있는가 |
대상·환경 | Galaxy Watch5 SM-R910 · Exynos W920 · Wear OS/Android 11 · Samsung 공개 커널 소스와 순정 펌웨어 · LSM6DSO32 계열 6축 센서 |
분석·구현 범위 | boot.img·vbmeta.img·AVB, OEM Unlock, 커널 재현 빌드, sysfs·SSP·CIPC·MMIO, Sensor Hub 펌웨어 리버싱, 회로도·USB 테스트 포인트, 납땜 공정·JIG·Odin 플래싱 |
근거 자료 | 원본 Notion HTML 74개, PDF 14개 262쪽, PPTX 1개 25장, Drive 발표자료 4개 105장 전수 검토 · 중복본을 제외한 PDF·슬라이드 약 318면 |
결과 | ODR 설정 함수와 레지스터 쓰기 후보 확인 · AP→Sensor Hub 명령 경로 추적 · 수제 JIG와 2차 납땜 성공 · Odin 순정 boot.tar 플래싱 PASS! · 수정 펌웨어 부팅 거부로 최종 보안 경계 식별 |
핵심 질문 — 센서 샘플링 레이트를 바꾸라는 한 문장을, 제어 지점 탐색·권한 확보·펌웨어 수정·물리 연결·안전한 플래싱·부팅 검증으로 어떻게 분해할 것인가?
Project Flow
전체 연구 흐름. 검정 실선은 단계의 진행, IEEE blue 점선은 실패·반례가 만든 연구 경로의 전환을 뜻합니다. 파란 테두리는 검증된 기준점·성과, 회색 면은 반례·실패, 점선 테두리는 가설·미결 상태입니다.
이 프로젝트는 한 방향으로만 진행되지 않았습니다. 복구 기준을 유지한 채 부팅·보안, 커널·센서 제어, 하드웨어·실기기 검증을 병렬로 진행했고, 한 경로의 실패가 다른 경로를 여는 방식으로 전개됐습니다. 예를 들어 netOdin의
Secure failed는 일반 Odin을 위한 물리 USB 경로로, LSM6DSX 소스 수정 미반영은 Samsung SSP와 Sensor Hub 펌웨어 분석으로 연구를 전환시켰습니다.단계·분기 | 실제로 시도한 것 | 관찰·반례 | 다음 전환 |
1. 방법론 탐색 | 외부 커널 빌드·플래싱, 기기 내부 빌드, ADB·Fastboot·루팅 비교 | 기기 내부 빌드는 툴체인·root·자원 제약, Fastboot/TWRP는 미지원 | 외부 수정 이미지와 순정 ROM을 이용한 실험 채택 |
2. 테스트베드 | 기기 추출 ROM과 온라인 ROM, soft/hard brick, Download Mode·JTAG 복구 비교 | 기기 추출은 root·하드웨어 의존성이 너무 큼 | 온라인 순정 펌웨어를 복구 기준점으로 보존 |
3. boot.img 재현 | unpack → 같은 kernel·ramdisk로 repack → 원본과 binary diff | byte 41부터 차이, 일부 바이트 수정 뒤에도 다음 구간에서 계속 불일치 | offset만이 아니라 Samsung 이미지 생성 조건과 AVB 구조 분석 |
4. vbmeta·AVB | IDA/Ghidra, 공식 AVB 문서, avbtool, hash·descriptor·authentication block 비교 | boot hash만 고쳐도 인증이 맞지 않고, AOSP 11/13 도구 결과도 동일 | 버전 가설 폐기, vbmeta 자체 서명과 vendor 조건을 별도 경계로 분리 |
5. OEM Unlock·netOdin | 업데이트로 OEM Unlock 재활성화, boot·vbmeta·hash 조합별 플래싱 | 잠금 해제 뒤에도 Secure failed: BOOT와 soft brick이 남음 | 부트로더 잠금·AVB·Odin secure check를 서로 다른 장벽으로 판단 |
6. 커널 재현 빌드 | Samsung 공개 소스 빌드, 대상 버전 소스 요청, vmlinux→Image 구조 분석 | 같은 버전·명목 크기를 얻어도 순정 바이너리와 끝부분이 다름 | A↔A′ 차분으로 수정 위치를 찾고 순정 B에 대응시키는 최소 패치 구상 |
7. 일반 IIO 드라이버 | LSM6DSX ODR table·WHO_AM_I·regmap 경로 추적과 소스 상수 수정 | 빌드는 되지만 기대한 센서 코드 변화가 바이너리에 나타나지 않음 | 공개 IIO 드라이버가 실제 제어 계층이라는 가설 폐기 |
8. Samsung 센서 경로 | sysfs → SSP → CIPC → AP2CHUB data channel → MMIO·mailbox·SRAM 추적 | AP가 직접 레지스터를 쓰지 않고 CHUB에 명령을 전달하는 구조 확인 | Sensor Hub 펌웨어와 물리 센서 연결 분석 |
9. Sensor Hub 리버싱 | Ghidra Thumb 분석, 문자열·호출 관계·LSM6DSO32 데이터시트 교차검증 | FUN_0005f03c와 CTRL1_XL(0x10), 호출 상수를 수정 후보로 좁힘 | 수정 펌웨어 실기기 플래싱 준비 |
10. 소프트웨어 권한 우회 | SMT Shell로 UID 1000 system shell 확보 후 센서 sysfs 접근 | system 권한에서도 접근 거부 지속 | UID·root·SELinux를 별도 경계로 분리하고 물리 경로 병행 |
11. 유선 Odin 경로 | 회로도·USB pad 분석, 납땜 연습, 커버 충전 문제 분석, 1차 실기기 납땜 | 납 불착·제거 실패·금도금 패드와 DATA− 트레이스 손상 | 플럭스·온도·시간·힘·고정 변수를 재설계하고 JIG 제작 |
12. 2차 납땜·검증 | 대체 접점 측정, JIG 고정, 2차 납땜, USB Download Mode, 일반 Odin | 순정 boot.tar는 PASS!, 1바이트 수정도 부팅 거부 | 물리·전송 성공과 수정 펌웨어·ODR 실패를 분리해 최종 경계 확정 |
ROLE
Embedded Security Research Intern · Firmware Reverse Engineer- 연구 설계: 센서 샘플링 레이트 변경 목표를 부팅·권한·통신·펌웨어·물리 접근 문제로 분해하고, 복구 가능성과 검증 수준을 기준으로 다음 실험을 선택했습니다.
- 소프트웨어 분석: Android 부팅 이미지와 AVB를 분석하고, Linux 커널의 sysfs/SSP/CIPC 경로와 Samsung Sensor Hub 펌웨어의 ODR 설정 후보를 정적 분석했습니다.
- 하드웨어 실험: 회로도와 멀티미터로 USB 테스트 포트를 교차검증하고, 납땜 연습·장비 선정·수제 JIG 제작·2차 납땜·Odin 플래싱을 수행했습니다.
- 협업 범위: 지도교수와 주간·중간·최종 발표로 가설과 진행 상황을 검토했습니다. 다른 연구자가 만든 커널 이미지 등 선행 결과는 의존성으로 구분하고, 제가 직접 분석·실험한 범위와 분리해 기록했습니다.
TECH STACK
C · Linux Kernel / IIO · Android / Wear OS · ADB · Odin / netOdin · AOSP mkbootimg / avbtool · Ghidra · IDA · Cscope · SSP / CIPC · MMIO / Mailbox · SPI · LSM6DSO32 · Multimeter · HAKKO FX-600 · xinzhizaoMY WORK
이 기록은 결과만 역순으로 설명하지 않습니다. 당시 세운 가설, 직접 확인한 증거, 가설을 폐기한 이유, 다음 경로로 이동한 판단을 프로젝트가 진행된 순서대로 남겼습니다. 플래싱 성공과 정상 부팅, system shell과 root, 공개 소스 분석과 실기기 적용을 서로 다른 성공 조건으로 구분했습니다.
1. 연구 방법론과 testbed 설계
처음 받은 질문은 “Galaxy Watch5의 sensor sampling rate를 바꿀 수 있는가?”였습니다. 저도 처음에는 “커널 드라이버에서 ODR 상수 하나를 찾아 바꾸면 끝나지 않나?” 라고 생각했습니다. 하지만 해당 상수가 들어간 코드를 찾는 것과 그 수정된 binary를 만들어서 image로 바꾸는 것, 수정 image를 Watch에 쓰는 것, 기기가 정상적으로 부팅되는 것, 실제 센서 출력이 달라지는 것은 모두 다른 문제였습니다. 그래서 목표를 제어 지점 탐색 → 수정 가능한 binary 확보 → 기기 전달 → 부팅 → 센서 출력 측정으로 슬라이스를 나누었습니다.
Galaxy Watch5의 제약 확인
대상은 Galaxy Watch5 44 mm
SM-R910, Exynos W920, Wear OS 기반 Android 11 환경이었습니다. 일반 Android 기기처럼 외부 USB connector가 노출되어 있지 않았고, Samsung의 boot chain과 전용 flashing 도구를 사용했습니다. 이 조건에서는 “Android니까 Fastboot를 쓰면 된다”는 식으로 접근할 수 없었습니다. 기기 model·build·지원 도구·firmware 입수 경로를 먼저 조사한 뒤, 실제로 실행 가능한 방법을 제외하고 하나씩 소거해가면서 진행했습니다.다양한 방법론 탐색
처음에는 Watch 안에서 직접 kernel을 빌드하면 위험한 flashing 단계를 피할 수 있다고 생각했습니다. 그러나 ADB shell에는
gcc, make, cross toolchain이 없었고, 이를 준비하거나 보호된 영역에 접근하려면 다시 root가 필요했습니다. 1.5 GB memory와 제한된 storage도 장시간 kernel build에 불리했습니다. 이 경로는 단순한 우회가 아니라 별도의 root·toolchain 프로젝트가 된다고 판단해 주 경로에서 제외했습니다.ADB는 실행 중인 Watch의 build 정보와 partition을 관찰하는 데 유용했지만, 연결만으로 root file이나 sensor control이 열리지는 않았습니다. TWRP는 backup·root shell·custom image 설치에, Fastboot는 partition flashing과 bootloader unlock에 유용한 일반적인 선택지였지만 Galaxy Watch5를 지원하지 않았습니다. 결국 Samsung 기기에서 실제로 사용할 수 있는
Odin·netOdin을 image 전달 경로로 선택했습니다.접근 | 기대했던 이점 | 먼저 해결해야 할 조건 | 초기 판단 |
외부 build 후 image flashing | kernel과 firmware를 binary 수준에서 직접 변경 | image 재패키징, secure boot, 복구 경로 | 주 경로 |
Watch 내부에서 직접 build | 별도 image 전달 과정 생략 | root, compiler·toolchain, 저장공간·메모리 | 보류 |
ADB·root로 runtime 접근 | 빠른 관찰과 설정 변경 | 권한, SELinux, 대상 interface 존재 여부 | 관찰 경로 |
Testbed 제작
Odin·netOdin으로 수정 image를 올리는 방향을 정하자, 다음 질문은 “부팅(플래싱)에 실패하면 어떻게 돌아올 것인가?”였습니다. 첫 실패가 곧 기기 손실(hard brick)로 이어진다면 kernel을 바꿔가며 비교할 수 없기 때문입니다. 이 부분에 대해서 교수님과 회의를 하면서 “보통 반복 가능한 실험 환경을 구성” 일명 Testbed를 제작 해야한다고 배웠습니다.중간 발표 원본 슬라이드 07 — 수정 kernel을 올리기 전에 복구 가능한 실험 루프를 먼저 정의한 초기 설계.
연구에서 Testbed는, 기준 image 확보 → 수정 image 전송 → 부팅 확인 → 실패 시 복구를 반복할 수 있는 구조였습니다. 이후 저는 기준 image 확보 방법을 생각하면서 현재 image를 추출해 backup할 수 있는가?” 또는 “이미 인터넷 상에 존재하는 image을 사용해도 되는가?” 라는 두 질문으로 좁혔습니다.
기준 image 확보
기준 firmware를 확보하는 방법또한 난해했습니다. 기기에서 직접 추출하면 현재 상태를 가장 정확하게 보존할 수 있지만, software 방식은 root와
dd가 먼저 필요했고 hardware 방식은 test point와 JTAG·SWD 지식이 필요했습니다. 반면 삼성 커뮤니티인 XDA 포럼에서 구한 firmware ( 이하 XDA firmware)는 storage 전체 dump는 아니어도 바로 분석할 수 있었고, 연구실 안팎에 netOdin 복구 선례가 있었습니다.기준점 후보 | 장점 | 한계 | 판단 |
기기에서 직접 추출 | 현재 장치 상태를 가장 가깝게 보존 | root 또는 hardware access가 testbed보다 먼저 필요 | 후순위 |
XDA firmware | 즉시 분석 가능, 기존 flashing·복구 사례 존재 | 전체 dump가 아니며 model·version·출처 검증 필요 | 1차 기준점 |
완전성만 보면 기기에서 firmware를 직접 추출하는 편이 나았습니다. 하지만 이 방법은 root나 JTAG를 먼저 해결해야 했습니다. 그래서 초기 testbed에서는 직접 추출을 포기하고,XDA firmware를 사용하는 방법을 택했습니다. 당시 계획은 이 package의
boot.img를 수정본으로 교체해 netOdin으로 flashing하고, 실패하면 원본 package로 돌아오는 것이었습니다.순정 기준본은 고정하고, 실험 입력만 바꿨습니다
XDA firmware를 기준본 Package와 , 실험용 package로 나누었고 실험용 package 에서
boot·vbmeta· hash 조합만 바꿨습니다. 각 시도에서는 netOdin의 반응과 Watch의 부팅 상태를 따로 기록했습니다. 실패하면 순정 firmware로 돌아온 뒤 다음 조합을 시험했습니다.변경 조건 | 실제 관찰 결과 | 멈춘 지점 | 복구·다음 조치 |
boot 수정 | Secure failed: BOOT | 쓰기 전 secure check | 순정 기준본 유지 |
vbmeta 수정 | flashing success → soft brick | 쓰기는 완료, 부팅 실패 | 순정 firmware 재플래싱 |
boot + vbmeta 수정 | 순정 vbmeta 재플래싱 후 Odin mode | 복구 도중 Odin mode 진입 | 순정 firmware로 복구 계속 |
boot + hash 수정 | Secure failed: BOOT | 쓰기 전 secure check | 순정 기준본 유지 |
vbmeta + hash 수정 | flashing success → soft brick | 쓰기는 완료, 부팅 실패 | 순정 firmware 재플래싱 |
OEM Unlock + boot + vbmeta 수정 | 기존과 다른 soft brick | 부팅 실패 | 전체 순정 firmware로 복구 |
복구 범위는 Download Mode가 살아 있는 soft brick까지였습니다. hard brick 복구나 modified image의 정상 부팅까지 해결한 환경은 아니었지만, 실패 뒤 같은 기준점에서 다음 실험을 시작할 수 있는 상태는 만들었습니다.
근거 기록 — 5월 27일 개인 보고서 · Galaxy Watch5를 실험 가능한 기기로 만들기
2. Firmware·partition 구조 — 수정할 파일과 복구할 파일을 분리했습니다
firmware tar를 파일 목록이 아니라 부팅 구성요소로 읽었습니다
firmware 패키지 안의
sboot.bin, boot.img, dtbo.img, vbmeta.img, recovery.img를 먼저 분류했습니다. 이름을 나열하는 데서 끝내지 않고 각 이미지가 bootloader, kernel, device tree overlay, verified boot, recovery 중 어느 책임을 갖는지 연결했습니다.tar package와 실제 block device를 구분했습니다
Odin에 넣는 tar는 전달 단위이고, 실제 기기에서는 각 이미지가 별도 partition에 기록됩니다. 따라서 tar 안의 파일명만 보고 대상을 정하지 않고, 실행 중인 기기와 공개 자료를 대조해 실제 block device를 확인했습니다.
boot가 실제로 mmcblk0p18임을 확인했습니다
중간 발표 원본 슬라이드 15 — Watch5에서 확인한 실제 boot partition과 block device.
이 확인으로 분석 대상이 추상적인
boot.img 파일에서, 실제 부팅 시 읽히는 boot partition으로 연결됐습니다. 동시에 잘못된 partition에 쓰는 위험과 복구에 필요한 이미지를 구분할 수 있었습니다.부팅 이미지의 역할을 의존성으로 정리했습니다
sboot.bin: 초기 bootloader와 secure boot 단계
boot.img: kernel과 초기 ramdisk
dtbo.img: 하드웨어 구성을 보완하는 device tree overlay
vbmeta.img: 다른 partition의 검증 metadata와 signature chain
recovery.img: 정상 부팅 실패 시 복구 경로
센서 변경 대상은 boot.img로 좁혀졌지만 독립적이지 않았습니다
초기 목표였던 kernel과 Sensor Hub 관련 구성요소는
boot.img 안에 있었습니다. 하지만 boot.img는 vbmeta와 bootloader 검증의 대상이므로, 파일 내부를 수정하는 문제와 수정본이 신뢰되는 문제를 분리해야 했습니다.다음 전환 — 수정 위치는
boot.img로 좁혀졌지만, 동일한 이미지를 다시 만드는 재패키징 문제부터 해결해야 했습니다.3. boot.img 구조와 재패키징 — 같은 재료를 넣어도 같은 이미지가 되지 않았습니다
boot.img를 kernel·ramdisk·header로 분해했습니다
unmkbootimg와 mkbootimg를 이용해 순정 이미지를 분해하고 Image.gz, ramdisk, command line, page size와 offset을 확인했습니다. 먼저 수정하지 않은 구성요소를 그대로 재조립해 원본과 동일한 이미지가 만들어지는지 검증했습니다.중간 발표 원본 슬라이드 21 —
boot.img에서 kernel과 ramdisk를 분리해 다시 패키징하는 실험.“같은 구성요소면 같은 결과”라는 가설이 첫 비교에서 깨졌습니다
수정하지 않은
Image.gz와 ramdisk를 다시 넣었는데도 repack 이미지가 원본과 달랐습니다. 차이는 후반부가 아니라 초반 byte부터 나타났습니다. 즉 kernel 코드 변경 전에 이미 image 생성 과정 자체가 재현되지 않는 상태였습니다.중간 발표 원본 슬라이드 27 — 순정 이미지와 repack 이미지가 41번째 byte 부근부터 달라진 첫 binary comparison.
offset 문제라는 초기 가설을 검증했습니다
처음에는 header offset, padding, Samsung과 AOSP의
mkbootimg 차이를 의심했습니다. 각 구성요소의 크기와 시작 위치를 대조하고, ramdisk와 dtb가 밀리는지 확인했습니다. 그러나 단순 offset만으로 전체 차이를 설명할 수 없었습니다.Android 11과 13 도구를 교차 사용했습니다
대상 기기의 Android 버전과 도구 버전 불일치가 원인일 수 있다고 보고 Android 11·13의 AOSP 도구로 각각 repack했습니다. 두 결과가 사실상 동일하게 달랐기 때문에 “도구 버전 하나가 틀렸다”는 가설을 폐기했습니다.
단독 도구의 한계를 platform build 가설로 확장했습니다
mkbootimg.py, mkdtbimg.py, avbtool.py를 각각 실행하면 각 이미지의 입력은 줄 수 있지만, 실제 제품 빌드가 사용하는 도구 간 의존성과 추가 metadata까지 같은 순서로 재현된다는 보장은 없었습니다. 그래서 boot.img·dtbo.img·vbmeta.img를 하나의 build graph 안에서 만드는 AOSP platform build가 독립 실행에서 빠진 정보를 보완할 수 있다는 가설을 세웠습니다.Platform build 원본 슬라이드 04 — 단독 mkbootimg.py와 platform build가 만드는 정보 흐름을 비교한 가설.Android.bp와 source에서 mkbootimg–avbtool 의존성을 확인했습니다
Android 7 이후 Make 기반 경로가 Soong과
Android.bp로 이동한 구조를 따라가며 build definition을 확인했습니다. mkbootimg 모듈은 generate_gki_certificate.py를 source로 포함하고 avbtool을 required tool로 선언하고 있었습니다. 이어 mkbootimg.py의 add_boot_image_signature()가 generate_gki_certificate()에 avbtool 경로와 signing parameter를 넘기는 코드까지 확인했습니다. 단독 재패키징에서 보이지 않던 AVB 연계가 platform build의 dependency 안에는 명시돼 있었습니다.Platform build 원본 슬라이드 05 — Make에서 Soong·Android.bp로 이어지는 build graph와 dependency 조사.Platform build 원본 슬라이드 07 — mkbootimg.py가 GKI certificate 생성 과정에 avbtool을 전달하는 source evidence.platform build는 VNDK 28에서 막혀 해결책으로 확정하지 않았습니다
dependency를 확인한 뒤
BOARD_VNDK_VERSION=28을 지정하고 platform build를 실행했습니다. 그러나 build/make/core/board_config.mk에서 VNDK version 28 not found가 발생했고, dumpvars가 exit status 1로 끝나 target build가 시작되지 못했습니다. 이 실패는 platform build 가설 자체의 반례가 아니라 대상 제품과 일치하는 AOSP·vendor build environment를 재현하지 못했다는 경계였습니다. 따라서 이를 성공한 packaging 경로로 포장하지 않고, 다시 실제 image의 byte layout과 AVB metadata를 역추적했습니다.Platform build 원본 슬라이드 08 — BOARD_VNDK_VERSION=28에서 중단된 실제 platform build 결과.뒤쪽 미지 영역을 역으로 추적했습니다
공식 이미지와 repack 이미지의 끝부분을 비교하면서 kernel·ramdisk 외에 추가된 영역을 찾았습니다. 그 결과 AVB footer와 인증 metadata가 이미지 레이아웃에 포함된다는 사실을 확인했고, 재패키징 불일치는 AVB 분석으로 이어졌습니다.
이 단계에서 남긴 것 — 코드 수정 전에도 원본 생성 조건이 재현되지 않음을 확인하고, packaging 문제를 AVB·signature 문제와 연결했습니다.
4. vbmeta·AVB·signature — hash를 고치는 일과 신뢰를 다시 만드는 일을 분리했습니다
부팅 검증의 실행 순서를 먼저 그렸습니다
중간 발표 원본 슬라이드 31 — bootloader가 AVB를 통해
vbmeta와 boot를 검증한 뒤 kernel로 넘어가는 순서.전원을 켠 뒤 bootloader가
vbmeta를 신뢰하고, 그 안의 descriptor로 boot와 다른 partition을 검증한 다음 kernel을 실행한다는 흐름을 기준으로 삼았습니다. 이 구조에서는 boot의 hash를 바꾸는 것만으로는 충분하지 않을 수 있었습니다.vbmeta를 세 블록으로 나눠 읽었습니다
중간 발표 원본 슬라이드 34 — vbmeta header, authentication block, auxiliary block 구조.
header의 offset·size 정보, authentication block의 hash·signature, auxiliary block의 public key·descriptor를 byte 단위로 대조했습니다. 문서의 구조 설명과 실제 Watch5 이미지의 위치가 일치하는지
avbtool info_image 결과로 교차확인했습니다.descriptor의 책임을 구분했습니다
Hash descriptor는 boot 같은 작은 partition, Hashtree descriptor는 block 단위 검증이 필요한 partition, Chain partition descriptor는 하위 키와 검증 체인을 연결합니다. 이 구분으로 어떤 byte를 바꿀 때 어떤 metadata가 함께 달라져야 하는지 실험 범위를 좁혔습니다.boot hash만 갱신하면 된다는 가설을 세웠습니다
수정한
boot.img의 digest를 다시 계산해 descriptor에 반영하면 검증을 통과할 수 있다고 예상했습니다. descriptor 위치와 원본 hash가 실제 byte와 일치하는 것을 확인한 뒤 최소 변경을 시도했습니다.반례는 authentication block에 남았습니다
중간 발표 원본 슬라이드 45 — 수정된 boot hash만으로는 원본의 인증 관계가 재현되지 않았던 교차검증.
descriptor hash를 바꾼 뒤에도 secure failure가 남았습니다.
vbmeta 내용이 변하면 authentication block의 hash와 signature도 함께 달라져야 했고, vendor가 신뢰하는 키까지 연결됐습니다. 내용의 무결성을 맞추는 것과 제조사가 신뢰하는 signature를 만드는 것은 다른 문제였습니다.AVB라는 한 단어로 모든 실패를 설명하지 않았습니다
이후 실험에서는 bootloader lock, AVB descriptor, vbmeta self-authentication, netOdin secure check, Samsung vendor signature를 가능한 한 분리해 기록했습니다. 같은 ‘secure failure’처럼 보여도 발생 시점과 입력 조합이 달랐기 때문입니다.
다음 전환 — 소프트웨어에서 AVB를 이해하는 것만으로는 실제 플래싱 경로의 검사를 우회할 수 없었습니다.
5. OEM Unlock·netOdin·regular Odin — 잠금 해제 후에도 남는 검사를 입력별로 분리했습니다
사라진 OEM Unlock을 복구 경로 안에서 다시 찾았습니다
시험 플래싱 뒤 특정 firmware에서 OEM Unlock 항목이 보이지 않았습니다. 무작정 초기화하지 않고 software update 단계를 나눠 진행하며 옵션이 다시 나타나는 버전을 확인했습니다. 이후 bootloader unlock을 완료한 상태와 그렇지 않은 상태를 구분해 실험했습니다.
순정 이미지로 soft brick을 복구할 수 있음을 먼저 확인했습니다
OEM unlock 원본 슬라이드 08 — modified image 실험 뒤 순정 firmware로 돌아오는 recovery testbed.이 기준점 덕분에
boot, vbmeta, hash 조합을 바꾸는 실험을 반복할 수 있었습니다. 복구 성공은 수정 이미지 성공이 아니라 다음 실험을 가능하게 하는 별도 성과로 기록했습니다.boot와 vbmeta 조합별 반응을 표로 만들었습니다
OEM unlock 원본 슬라이드 14 — 입력 이미지와 Secure failure·soft brick 반응을 나눈 실험 기록.수정
boot는 쓰기 전 Secure failed: BOOT, 수정 vbmeta는 플래싱 뒤 soft brick, hash를 함께 바꾼 경우에도 서로 다른 반응을 보였습니다. 이 차이로 netOdin의 secure check와 실제 부팅 시 AVB가 동일한 한 단계가 아닐 가능성을 남겼습니다.OEM Unlock이 모든 검사를 제거한다는 가설을 폐기했습니다
bootloader를 unlock한 뒤에도 같은 계열의 오류가 남았습니다. OEM Unlock은 필요조건일 수 있지만 Samsung의 플래싱·부팅 검증 전체를 비활성화하는 충분조건은 아니었습니다.
netOdin과 regular Odin을 다른 전송 경로로 보았습니다
netOdin은 무선으로 접근할 수 있지만 modified image에서 secure check를 통과하지 못했습니다. 반면 regular Odin은 유선 Download Mode를 통해 다른 전송 경로를 사용합니다. 소프트웨어 설정을 더 반복하는 대신 물리 USB 접점을 연결하는 경로를 조사했습니다.
AVB bypass via Odin 원본 슬라이드 04 — regular Odin을 사용하기 위한 하드웨어 경로 조사.소프트웨어 연구가 하드웨어 작업으로 전환됐습니다
regular Odin을 쓰려면 Watch5 기판의
5V, D+, D−, GND를 외부 USB에 연결해야 했습니다. 이 결정으로 schematic·POGO·test pad 분석과 납땜이 프로젝트의 핵심 경로에 들어왔습니다.이 단계에서 남긴 것 — unlock·무선 전송·부팅 검증을 분리했고, 유선 Odin이라는 새 실험 경로를 선택했습니다.
6. Kernel build 재현성과 binary diff — ‘빌드 성공’을 곧바로 비교 가능한 바이너리로 보지 않았습니다
vmlinux에서 Image가 만들어지는 과정을 확인했습니다
Samsung 공개 문서와 Makefile을 따라 kernel을 빌드하고, link된
vmlinux에서 .head.text, .text, .rodata 등이 ARM64 Image로 배치되는 과정을 추적했습니다. 초기에 찾던 zImage가 아니라 Image/Image.gz가 대상임을 수정했습니다.초기에는 공개된 성공 사례의 Makefile도 재현해 보았지만,
CLANG_TRIPLE과 CROSS_COMPILE이 기대하는 /toolchain 경로가 공개된 작업 디렉터리에는 존재하지 않았습니다. 스크립트가 있다는 사실과 같은 build environment를 재현할 수 있다는 사실을 분리했고, 이후에는 source·toolchain·config를 하나의 비교 단위로 다뤘습니다.공개 소스와 실제 firmware의 version·size가 맞지 않았습니다
최초 공개 소스로 만든 kernel은 대상 firmware와 version string과 크기가 달랐습니다. 이 상태에서 binary diff를 하면 코드 수정이 아니라 source revision과 build environment의 차이를 보고 있을 가능성이 컸습니다.
Samsung에 대상 소스를 직접 요청했습니다
문서에 없는 차이를 추측으로 채우지 않고 Samsung Open Source Team에 firmware version에 맞는 소스를 요청했습니다. 이후 AVG6 소스가 추가됐고, 같은 version과 명목상 같은 image size를 얻었습니다.
about Kernel Compile 원본 슬라이드 07 — firmware와 kernel source version·image size를 맞추는 과정.같은 version과 크기도 byte-level 동일성을 보장하지 않았습니다
새 소스로 만든 이미지도 순정 이미지의 후반 section 배치와 달랐습니다. “컴파일됐다”와 “순정과 비교 가능한 바이너리가 만들어졌다”를 구분해야 했습니다.
A·A′·B 비교 전략을 설계했습니다
- A: 공개 소스로 만든 기준 kernel
- A′: 상수 하나만 바꾼 kernel
- B: 순정 firmware의 kernel
A와 A′의 차이에서 실제 코드 변경으로 생긴 byte pattern을 찾고, 그 pattern이 B의 어디에 존재하는지 확인해 최소 patch 후보를 좁히려 했습니다. 이 방식은 전체 바이너리가 다르더라도 변경의 국소 효과를 찾기 위한 전략이었습니다.
재현되지 않은 영역을 숨기지 않았습니다
toolchain·config·link order·padding이 모두 동일하다고 증명하지 못했기 때문에 “순정 kernel 재현 성공”이라고 쓰지 않았습니다. 통제한 것은 version과 명목 크기였고, 통제하지 못한 것은 byte layout이었습니다.
이 단계에서 남긴 것 — 변경 byte와 빌드 비결정성의 차이를 먼저 묻는 binary diff 방법론.
7. IIO·LSM6DSX 분석과 가설 폐기 — 가장 그럴듯한 드라이버를 증거로 버렸습니다
Linux IIO의 ODR table에서 시작했습니다
AOSP tool 원본 슬라이드 45 — LSM6DSX ODR table과 수정 후보를 찾던 초기 분석.공개
st_lsm6dsx 드라이버에서 13·26·52·104·208·416 Hz table을 확인하고, st_lsm6dsx_set_odr()가 st_lsm6dsx_check_odr()와 regmap_update_bits()를 거쳐 register를 갱신하는 흐름을 추적했습니다.WHO_AM_I register로 대상 sensor를 식별하려 했습니다
about kernelAnalyze 원본 슬라이드 12 — WHO_AM_I 값으로 driver와 실제 sensor를 연결하던 초기 접근.처음에는 AP가 I²C로 sensor의 WHO_AM_I register를 읽고, 일치하는
st_lsm6dsx device를 선택한다고 이해했습니다. 이 모델을 기준으로 kernel source의 chip ID와 실제 기기 정보를 대조했습니다.menuconfig와 built-in 여부를 확인했습니다
소스에 파일이 존재하는 것과 대상 kernel에 코드가 포함되는 것은 다릅니다. config와 symbol을 검색한 결과 일반 LSM6DSX IIO driver가 원본 구성에서 실제 built-in 대상이 아니라는 정황이 나타났습니다.
driver를 강제로 enable해 binary 변화부터 확인했습니다
LSM6DSX를 enable하고 ODR table을 수정한 뒤 kernel을 빌드했습니다. 변경된 코드가 어떤 byte pattern을 만드는지 A/A′ diff로 확인하고, 순정 kernel B에서 동일한 pattern을 찾았습니다.
원본 kernel에 기대한 코드가 없다는 반례를 얻었습니다
강제로 포함한 빌드에서는 차이가 생겼지만 순정 image에서는 해당 pattern을 확인할 수 없었습니다. 공개 드라이버의 구조는 참고 모델이었지만 실제 Watch5의 센서 제어 지점이라는 증거가 아니었습니다.
about kernelAnalyze 원본 슬라이드 16 — custom kernel·root·I²C API를 최종 경로로 예상했던 당시 모델.초기 모델을 사후적으로 지우지 않았습니다
0x10을 가장 빠른 ODR 값으로 오해했던 기록, I²C가 직접 연결이라고 본 가정, 공개 IIO driver를 최종 수정 대상으로 본 판단을 남겼습니다. 이후 datasheet·binary·schematic이 이 가정과 충돌했기 때문에 분석 층을 Samsung SSP와 Sensor Hub로 이동했습니다.이 단계의 성과 — 정답을 찾은 것이 아니라, 그럴듯했던 kernel-driver 가설을 재현 빌드와 binary evidence로 폐기했습니다.
8. Samsung SSP·CIPC·MMIO·mailbox — sysfs 요청이 CHUB memory에 도달할 때까지 추적했습니다
AP–Sensor Hub–Sensor의 계층을 새 기준 모델로 삼았습니다
Sensor Hub & Mailbox 원본 슬라이드 02 — AP ↔ Sensor Hub ↔ Sensors 계층.Watch5에서는 AP가 sensor register를 직접 쓰는 대신 Sensor Hub에 명령을 보내고, Sensor Hub가 실제 sensor와 통신한다는 모델을 세웠습니다. 이제 질문은 “어떤 kernel 함수가 ODR 값을 쓰는가”에서 “AP의 delay 요청이 어떤 message로 CHUB에 전달되는가”로 바뀌었습니다.
sysfs attribute의 시작점을 확인했습니다
show_acc_delay()와 set_acc_delay()가 DEVICE_ATTR로 attribute를 만들고, 사용자가 쓴 값이 change_sensor_delay()로 전달되는 것을 확인했습니다. sysfs 파일은 최종 제어점이 아니라 명령 생성의 입구였습니다.SSP message의 전체 call chain을 따라갔습니다
Sensor Hub & Mailbox 원본 슬라이드 07 — send_instruction에서 cipc_write_data까지 이어지는 실제 call chain.send_instruction → ssp_send_command → do_transfer → sensorhub_comms_write → contexthub_ipc_write → cipc_write_data 순으로 구조체와 parameter가 어떻게 바뀌는지 추적했습니다. 함수 이름만 연결하지 않고 ssp_msg, ssp_data, ssp_cmd_data, tx가 어느 단계에서 생성되고 전달되는지 기록했습니다.AP2CHUB data channel의 최종 copy를 찾았습니다
Sensor Hub & Mailbox 원본 슬라이드 08 — CIPC_USER_MEMCPY가 command buffer를 data_ch->buf에 복사하는 지점.cipc_write_data(CIPC_REG_DATA_AP2CHUB, tx, length)와 CIPC_USER_MEMCPY를 기준으로 AP가 만든 명령이 실제 shared buffer에 들어가는 지점을 확인했습니다. 이 단계부터는 함수 호출이 아니라 memory mapping이 다음 질문이 됐습니다.cipc_info와 map 초기화를 역추적했습니다
cipc_set_info, cipc_set_map, cipc_init, contexthub_chub_ipc_init을 따라가며 CIPC data region과 register base가 언제 설정되는지 확인했습니다. pdev가 어떤 device tree node와 결합되는지도 함께 추적했습니다.device tree에서 mailbox와 SRAM을 실제 주소 영역으로 연결했습니다
Sensor Hub & Mailbox 원본 슬라이드 20 — device tree의 mailbox·SRAM resource와 MMIO mapping.samsung,exynos-nanohub compatible node를 찾아 decompile한 device tree와 source의 get_iomem() 흐름을 대조했습니다. 이로써 mailbox와 sram이 막연한 IPC 개념이 아니라 AP와 CHUB가 공유하는 MMIO resource라는 것을 확인했습니다.소스·device tree·firmware·schematic을 하나의 경로로 연결했습니다
Sensor Hub & Mailbox 원본 슬라이드 22 — AP의 sysfs 요청부터 Sensor Hub와 sensor까지 연결한 최종 시스템 모델.AP/sysfs → SSP → CIPC/AP2CHUB → MMIO mailbox·SRAM → Sensor Hub firmware → SPI → LSM6DSO32라는 전체 경로를 만들었습니다. 각 화살표는 소스 코드, device tree, firmware string, schematic 중 하나 이상의 증거에 대응합니다.
이 단계에서 남긴 것 — “sysfs로 센서를 바꾼다”는 설명을 실제 함수·구조체·memory resource의 연속 경로로 바꿨습니다.
9. LSM6DSO32·Sensor Hub firmware 리버싱 — 문자열에서 register write까지 좁혔습니다
실제로 사용되는 Sensor Hub image를 config에서 선택했습니다
Sensor Hub Firmware Analyze 원본 슬라이드 05 — 다섯 binary header와 CONFIG_SENSORS_SSP_HEART를 대조해 실제 image를 고른 과정.drivers/sensorhub/slsi 안의 여러 header가 각각 binary array를 포함하고 있었습니다. build config의 CONFIG_SENSORS_SSP_HEART를 근거로 os_one_image_heart.h가 대상 firmware임을 확인했습니다.binwalk 실패를 format 부재로 기록하고 분석 도구를 바꿨습니다
Sensor Hub Firmware Analyze 원본 슬라이드 06 — boot.img에는 동작한 binwalk가 Sensor Hub firmware에는 의미 있는 구조를 내지 못한 결과.binwalk가 알려진 container나 filesystem을 찾지 못했기 때문에 파일이 없다고 판단하지 않았습니다. raw firmware로 보고 Ghidra에 ARM Cortex/Thumb code로 직접 로드했습니다.
sensor 이름보다 동작을 드러내는 문자열을 anchor로 사용했습니다
Sensor Hub Firmware Analyze 원본 슬라이드 08 — XL ODR SET 문자열에서 FUN_0005f03c로 이동한 지점.LSM6DSO, accelerometer, XL ODR SET, XL FS SET 문자열을 검색했습니다. debug string을 참조하는 함수를 따라가면서 ODR과 full-scale 설정 함수 후보를 분리했습니다.먼저 full-scale 함수로 register 접근 규칙을 검증했습니다
Sensor Hub Firmware Analyze 원본 슬라이드 10 — FUN_0005efea가 register 0x10의 FS bit를 read-modify-write하는 과정.FUN_0005efea에서 register 0x10을 읽고 5·6 bit를 수정한 뒤 다시 쓰는 동작을 확인했습니다. LSM6DSO32 datasheet의 CTRL1_XL full-scale field와 일치해, decompiler에서 본 함수의 의미를 외부 문서로 교차검증할 수 있었습니다.같은 register의 ODR bit를 갱신하는 함수를 찾았습니다
Sensor Hub Firmware Analyze 원본 슬라이드 16 — FUN_0005f03c가 CTRL1_XL의 하위 ODR field를 갱신하는 최종 분석.FUN_0005f03c도 register 0x10을 read-modify-write했지만 parameter가 들어가는 bit field가 달랐습니다. 여기서 0x10은 가장 빠른 ODR 값이 아니라 가속도계 CTRL1_XL register 주소이고, ODR은 그 안의 field라는 것으로 초기 해석을 수정했습니다.함수의 reference와 호출 parameter를 수집했습니다
Sensor Hub Firmware Analyze 원본 슬라이드 17 — ODR 함수의 네 reference를 찾아 호출 맥락을 좁힌 결과.네 호출 지점과
0x14, 0, 0x87, 0x14 등의 상수를 확인했습니다. 이 값은 patch 후보를 좁히는 근거였지만, 정상 부팅과 실제 sensor output 측정 전에는 “ODR 변경 성공”으로 확정하지 않았습니다.확인한 사실과 남은 가설을 분리했습니다
- 확인: 대상 Sensor Hub image, ARM/Thumb code, ODR/FS 문자열, register
0x10read-modify-write, 함수 reference
- 가설: 어느 호출 상수가 실제 사용 scenario의 ODR을 결정하는지
- 미검증: 수정 firmware 정상 부팅과 실제 output timestamp 변화
이 단계에서 남긴 것 — 공개 kernel driver 밖에 있던 실제 ODR 제어 후보를 Sensor Hub binary의 함수와 register 수준까지 좁혔습니다.
10. Schematic·WPC·POGO·USB pad — 도면을 결론이 아니라 작업 지도로 사용했습니다
구하지 못하던 SM-R910 도면을 XZZ에서 확보했습니다
xinzhizao에서 전체 component placement와 schematic을 확보했습니다. 도면을 얻었다는 사실보다, 전체 배치도에서 관심 block을 찾고 net을 따라가며 실기기 측정과 연결하는 절차가 중요했습니다.6-axis sensor block과 실제 부품 식별을 교차검증했습니다
ADB와 Android Studio에서 Samsung 전용
LSM6DSO 32G 식별자를 확인하고, schematic의 6-axis block 및 LSM6DSO32 signal과 대조했습니다. 이 과정에서 AP와 sensor의 직접 I²C 모델을 버리고 Sensor Hub를 거치는 SPI 연결로 수정했습니다.WPC·cover ground 문제를 병렬 가설로 분리했습니다
후면 cover를 분리했을 때 charging이 멈추는 현상을 해결하기 위해 접지 지점을 구간별로 나눴습니다. 온도 sensor, signal conditioning, GPS antenna, speaker 경로를 제거하고
CPS4019 WPC receiver와 ground 구조를 남겼습니다. 이 분기는 USB 경로의 직접 결론은 아니었지만, board를 열어 둔 상태에서 반복 실험하기 위한 조건을 이해하는 데 필요했습니다.POGO signal과 PCB test pad를 연결했습니다
Watch4·Watch5 forum 자료를 그대로 복사하지 않고 schematic net, board orientation, ground continuity를 교차확인했습니다. 후보 pad의 방향이 뒤집히면 전원과 data를 잘못 연결할 수 있기 때문에 GND를 먼저 확정하고 나머지 signal을 대칭적으로 비교했습니다.
Soldering Process 원본 슬라이드 03 — regular Odin을 위해 실제로 연결해야 했던 Watch5 target port.5V·D+·D−·GND를 측정 가능한 가설로 바꿨습니다
pad 간 저항과 diode-mode 값을 양방향으로 기록해 data line의 대칭성, power line의 방향성, direct short 여부를 확인했습니다. 이 측정은 이후 들린 DATA− pad의 대체 접점을 찾는 기준으로 재사용됐습니다.
이 단계에서 남긴 것 — schematic의 net 이름을 실제 board 위의 납땜 위치와 measurement point로 변환했습니다.
11. 납땜 연습·1차 실패·JIG·2차 성공 — 실패를 손재주가 아니라 공정 변수로 바꿨습니다
0.8 mm 연습에서 0.6 mm target으로 접근했습니다
실기기 pad에 바로 인두를 대지 않고 연습 PCB의 0.8 mm 접점에서 반복했습니다. 납을 위에서 떨어뜨리는 것이 아니라 flux와 열을 이용해 pad에 얇게 바르는 감각, wire를 먼저 고정하는 순서, short 검사와 smoke 관리까지 작업 조건으로 기록했습니다.
납땜 없는 JIG 가능성을 먼저 검토했습니다
Soldering Process 원본 슬라이드 04 — pogo 접촉만으로 연결하는 no-risk JIG를 먼저 검토한 과정.기판 손상을 피하기 위해 spring contact와 pressure jig를 먼저 고려했습니다. 그러나 당시 확보한 부품과 0.6 mm pad 간격으로는 안정적인 접촉과 strain relief를 동시에 만들기 어려워, 납땜 경로를 선택하되 고정 장치를 별도로 만들기로 했습니다.
1차 실기기 납땜은 명확히 실패했습니다
Soldering Process 원본 슬라이드 06 — gold plating과 trace가 함께 들린 1차 실패.납이 pad에 올라가지 않았고 제거하려 해도 잘 녹지 않았습니다. 힘을 주는 과정에서 금도금 pad와 trace 일부가 박리됐습니다. 즉 단순히 연결에 실패한 것이 아니라 기판에 물리 손상을 만들었습니다.
실패를 다섯 개의 통제 변수로 분해했습니다
관찰 | 원인 가설 | 2차 조건 |
납이 붙지 않음 | 표면 오염·coating·flux 부족 | 세척, 필요한 범위만 표면 처리, flux 후 예열 |
납 제거가 어려움 | 온도 제어 불가 | HAKKO FX-600과 적합한 tip 사용 |
pad·trace 박리 | 긴 접촉 시간과 기계적 힘 | 접촉 시간 단축, wire 선고정 |
배선 이동 | strain relief 부재 | JIG와 얇은 wire로 힘 분리 |
short 위험 | 0.6 mm 간격과 시야 부족 | 확대, continuity·저항 측정 후 전원 연결 |
손상 구간이 DATA−라는 것을 외관이 아니라 측정으로 확인했습니다
Soldering Process 원본 슬라이드 07 — trace와 multimeter로 들린 구간이 DATA−임을 확인한 과정.박리된 pad에서 이어지는 trace를 schematic과 대조하고, 후보 접점 사이의 continuity와 저항을 양방향으로 측정했습니다. 이 결과를 근거로 DATA−의 대체 접점을 선택했습니다.
수제 JIG로 손과 wire의 움직임을 분리했습니다
본체와 열린 cover를 동시에 고정하고, USB cable과 가는 wire가 pad를 당기지 않도록 나무 막대와 접착제로 JIG를 만들었습니다. 정밀 치구는 아니지만 납땜 중 상대 움직임과 반복 strain을 줄이는 위험 저감 시제품이었습니다.
2차 시도에서 네 USB 선을 연결했습니다
Soldering Process 원본 슬라이드 08 — DATA− 대체 접점을 포함한 2차 납땜과 4선 연결.5V, D+, D−, GND를 연결한 뒤 전원을 넣기 전에 line-to-line short와 ground 기준값을 다시 확인했습니다. 1차 실패에서 만든 공정 조건이 실제 USB 인식으로 이어졌습니다.이 단계의 성과 — 기판 손상을 숨기지 않고 trace recovery, 장비 변경, JIG, measurement를 통해 물리 USB 경로를 완성했습니다.
12. SMT Shell·SELinux·Odin 검증·무결성 경계 — 성공을 네 단계로 나눠 마지막 실패 지점을 남겼습니다
sysfs permission 문제를 두 경로로 나눴습니다
Sensor Hub & Mailbox 원본 슬라이드 23 — SELinux 완화와 exploit/root 확보를 병렬 경로로 나눈 판단./sys/class/sensors/accelerometer_sensor attribute에 접근할 수 없었기 때문에 SELinux policy를 바꾸는 경로와 더 높은 privilege를 얻는 경로를 분리했습니다. Android·Wear OS·One UI version을 확인해 적용 가능한 SMT Shell 조건도 함께 조사했습니다.SMT Shell로 UID 1000을 얻었지만 목표 파일은 열리지 않았습니다
Sensor Hub & Mailbox 원본 슬라이드 25 — SMT Shell을 통한 system privilege 확보.exploit으로
uid=1000(system) shell을 얻었고 대상 attribute의 DAC owner도 system 계열임을 확인했습니다. 그러나 실제 read/write에서는 Permission denied가 남았습니다.system·root·SELinux bypass를 같은 권한으로 보지 않았습니다
UID 상승이 성공했는데도 접근이 거부된 결과는 exploit 전체의 실패가 아니었습니다. system UID, full root, SELinux policy 허용은 서로 다른 조건이라는 반례였습니다. 이 경로는 별도 과제로 남기고 병렬로 준비한 물리 Odin 경로를 검증했습니다.
JIG 연결 뒤 USB Download Mode에 진입했습니다
두 버튼을 길게 눌러 재부팅한 뒤
rebooting... 시점에 power button을 세 번 눌러 USB Download Mode에 들어갔습니다. PC에서 Odin port가 활성화되면서 JIG·배선·USB data path가 실제로 동작한다는 첫 실기기 증거를 얻었습니다.순정 boot.tar로 전송과 쓰기를 분리 검증했습니다
Soldering Process 원본 슬라이드 10 — regular Odin에서 순정 boot.tar가 PASS!, succeed 1 / failed 0으로 끝난 결과.약 36 MB의 순정 image가 기록되고 정상적으로 부팅됐습니다. 이 결과로 물리 연결, Download Mode, Odin protocol, partition write, 순정 boot를 각각 확인했습니다.
수정 내용의 논리 오류와 image 변경 자체를 구분했습니다
Soldering Process 원본 슬라이드 11 — Sensor Hub firmware, 단일 byte, 문자열 영역 변경을 나눈 control experiment.ODR 후보만 바꾸면 함수 논리 오류 때문에 부팅하지 못할 수 있습니다. 그래서 Sensor Hub firmware 수정, 임의의 1 byte 변경, 동작과 직접 관련이 적은 문자열 변경을 따로 시도했습니다. 변경 위치와 무관하게 부팅이 거부됐기 때문에 특정 ODR patch의 오류보다 image 변경 자체를 감지하는 검증이 먼저 작동한다고 판단했습니다.
공식 software 경고와 recovery 화면을 최종 경계로 기록했습니다
Soldering Process 원본 슬라이드 12 — 수정 image 기록 뒤 나타난 공식 software 경고와 recovery/soft-brick 상태.수정 image는 쓰기 이후 부팅 단계에 진입했지만 “Samsung 공식 software가 아니다”라는 경고와 recovery로 이어졌습니다. 순정 image는 같은 JIG와 Odin에서 정상 동작했으므로 물리 전송 실패와 수정 image 무결성 실패를 분리할 수 있었습니다.
최종 성공 조건을 한 단어로 합치지 않았습니다
검증 단계 | 상태 | 근거 |
물리 USB 연결 | 성공 | USB Download Mode와 Odin port 활성화 |
순정 image 전송·쓰기 | 성공 | PASS!, succeed 1 / failed 0 |
순정 image 정상 부팅 | 성공 | 복구 기준점 재확인 |
수정 image 기록 후 부팅 | 실패 | 공식 software 경고와 recovery |
실제 ODR 변화 측정 | 미완료 | 수정 firmware 정상 부팅 전제 미충족 |
프로젝트의 마지막 미해결 지점을 정확히 남겼습니다
LSM6DSO32의 ODR register write 후보, AP→CHUB command path, 유선 Odin write path까지는 확인했습니다. 그러나 modified Sensor Hub firmware가 정상 부팅하지 못했기 때문에 실제 sampling rate 변화는 측정하지 못했습니다. 마지막 미해결 지점은 “센서 제어 코드가 어디인지 모른다”가 아니라 수정 firmware가 통과하지 못하는 vendor integrity·signature boundary입니다.
제가 이 프로젝트에서 지킨 결론 — 연구의 진전은 처음부터 맞는 답을 말하는 것이 아니라, 어떤 증거로 무엇을 더 이상 믿지 않게 되었는지 설명할 수 있는 상태입니다. 이 기준으로 kernel에서 Sensor Hub로, netOdin에서 regular Odin으로, 손 납땜에서 JIG 기반 공정으로 이동했습니다.
RESULTS
- 센서 제어 구조: Galaxy Watch5의 센서 경로를 AP → sysfs/SSP → CIPC → AP2CHUB mailbox·SRAM → Sensor Hub firmware → SPI → LSM6DSO32로 정리했습니다.
- ODR 수정 지점: Sensor Hub 펌웨어의
FUN_0005f03c가 레지스터0x10의 ODR 비트를 갱신하는 후보임을 확인하고, 네 호출 지점의 상수값을 수정 후보로 좁혔습니다.
- 가설 교정: 일반 LSM6DSX IIO 드라이버가 실제 대상 제어 계층이라는 가정과 I²C 통신 가정을 각각 Samsung Sensor Hub·SPI 구조로 수정했습니다.
- 접근 제어 분리: UID 1000 system shell 확보 뒤에도 sysfs 접근이 거부되는 것을 확인해 Linux 권한과 SELinux 정책을 별개의 장벽으로 분리했습니다.
- 하드웨어 구현: 1차 납땜 실패를 표면 준비·온도·접촉 시간·기계적 힘·고정 문제로 분석하고, 장비 재구성·수제 JIG·트레이스 측정으로 2차 납땜과 USB 연결에 성공했습니다.
- 플래싱 검증: 일반 Odin에서 순정
boot.tar플래싱PASS!를 얻어 물리 통신과 쓰기 경로를 검증했습니다.
- 보안 경계 식별: ODR 후보·단일 바이트·문자열 변경 모두 부팅에서 거부되는 비교 실험으로, 마지막 차단 지점을 수정 코드의 기능이 아니라 이미지 무결성·서명 검증으로 좁혔습니다.
- 한계: 수정 Sensor Hub 펌웨어의 정상 부팅, AVB·vendor 서명 체인의 정확한 실패 지점 규명, 실제 ODR 변화의 계측은 완료하지 못했습니다. 수제 JIG도 정밀도·재사용성·절연·스트레인 릴리프가 검증된 제작물은 아닙니다. 공개 커널 소스와 대상 펌웨어의 재현 빌드 차이도 남아 있습니다.
배운 점과 다음 단계
이 프로젝트를 하며 “성공”은 한 단어가 아니라는 것을 배웠습니다. 권한 상승, 파일 쓰기, 플래싱, 부팅, 센서 동작은 각각 다른 성공 조건입니다. 중간 단계가 성공했다고 다음 단계까지 성공한 것처럼 말하면 연구는 앞으로 나아가지 못합니다. 반대로 실패를 계층별로 기록하면 다음 실험의 시작점이 됩니다.
1차 납땜에서 패드가 떨어졌을 때는 손재주가 없다고 결론내릴 수도 있었습니다. 대신 플럭스·온도·시간·힘·고정이라는 변수로 분해했고, 그 결과 2차 납땜과 JIG, Odin 플래싱까지 이어졌습니다. 소프트웨어 분석에서도 같은 태도를 적용했습니다. 공개 소스가 있다는 사실과 재현 가능한 바이너리가 있다는 사실, system shell과 root, Odin
PASS!와 정상 부팅을 끝까지 구분했습니다.다음 단계는 먼저 순정 이미지의 서명·해시·패키징 경로를 재현하고, 동일 크기의 무해한 변경을 이용해 검증이 발생하는 정확한 계층을 찾는 것입니다. 이후 최소 변경 Sensor Hub 펌웨어를 정상 부팅시키고, sysfs 요청 주기·Sensor Hub 명령·센서 출력 타임스탬프를 함께 수집해 ODR 변화를 정량 검증해야 합니다. 하드웨어 쪽은 pogo pin 기반의 절연된 재사용 JIG로 바꾸어 기판 손상 없이 반복 측정할 수 있는 환경을 만드는 것이 우선입니다.
전체 기록과 원본
전수 검토한 자료 범위
- Notion HTML 내보내기 74개: 프로젝트 관리 페이지, 개인·주간·월간 보고서, 장기 함수 추적 노트, 1·2차 납땜 기록과 30여 개의 세부 작업 페이지
- PDF 14개, 총 262쪽:
2024.05.20(월) 발표자료,[하태구] Research Slide,Research slide 5.27~,Middle Presentation,vbmeta.img analyze1·2,AOSP tool,Platform build,about Kernel Compile,about kernelAnalyze,OEM unlock,AVB bypass via Odin, GitHubmkbootimg예제와 XDA 유선 Odin 사례
- PPTX 1개, 25장:
[하태구] Research Slide원본. 같은 이름의 25쪽 PDF와 내용이 중복되어 분석 분량에는 한 번만 계산
- Google Drive 발표자료 4개, 총 105장: 중간발표 49장과 최종발표 26·12·18장. 중간발표는 내보내기의 49쪽 PDF와 사실상 동일해 한 번만 계산
- 중복 제거 기준 PDF·슬라이드 약 318면과 HTML 원문 전체를 함께 읽고, 최종 결과와 충돌하는 초기 해석은 ‘당시 가설’로 구분
전체 연구 공간과 사고 기록
- 전체 연구 공간 ·
- 장기 분석 노트 ·
- 초기 방법론과 테스트베드 ·
부팅·커널·권한
센서·펌웨어·하드웨어
- · ·
- · ·
발표자료·장비 기록
- 초기 발표 —
2024.05.20(월) 발표자료, 13쪽
- 초기 방법론 —
[하태구] Research Slide, 25장
- 주차 연구 —
Research slide 5.27~, 20쪽
- 부팅·AVB 연속 분석 —
vbmeta.img analyze20쪽 ·Vbmeta.img analyze 215쪽 ·AOSP tool48쪽 ·Platform build8쪽
- 커널 연속 분석 —
about Kernel Compile14쪽 ·about kernelAnalyze17쪽 ·OEM unlock15쪽 ·AVB bypass via Odin8쪽