ARMv8.3/v8.5 아키텍처의 ROP/JOP 방어 기술: PAC와 BTI 파헤치기
🛡️ ARMv8.3-A PAC & ARMv8.5-A BTI 완전 정복 — 하드웨어가 해커를 막는 방법
ARM 프로세서의 핵심 보안 기술 PAC(Pointer Authentication)와 BTI(Branch Target Identification)의 원리, 동작 방식, 그리고 실제 적용 사례까지 깊이 있게 살펴봅니다.
⚔️ ROP와 JOP — 왜 이렇게 위험한가?
소프트웨어가 복잡해질수록 메모리 취약점은 늘어납니다. 전통적인 방어 기법인 NX(No-eXecute)와 ASLR(Address Space Layout Randomization)은 공격자가 임의의 코드를 삽입·실행하는 것을 차단합니다. 하지만 공격자들은 이를 우회하는 정교한 방법을 찾아냈습니다.
핵심 아이디어는 간단합니다. 새로운 코드를 주입하는 대신, 이미 존재하는 정상 코드 조각(Gadget)을 엮어서 원하는 동작을 수행하는 것입니다.
🔴 ROP (Return-Oriented Programming)
→ 스택 버퍼 오버플로우를 이용해 함수의 리턴 주소를 조작합니다. 함수가 끝나고 돌아갈 주소를 바꿔치기하여, 공격자가 원하는 가젯 체인으로 실행 흐름을 납치합니다.
🔴 JOP (Jump-Oriented Programming)
→ 간접 점프(Indirect Jump)나 간접 호출(Call) 명령어를 조작하여 제어 흐름을 가로챕니다. 함수 포인터나 vtable을 변조하는 방식이 대표적입니다.
이 공격이 특히 위험한 이유는 정상적인 실행 권한 범위 안에서 흐름만 바꾸는 것이기 때문입니다. DEP, ASLR 같은 기존 방어를 모두 우회할 수 있고, 소프트웨어 로직만으로는 탐지가 극도로 어렵습니다. 2026년 현재까지도 CVE 데이터베이스에 등록되는 취약점 중 메모리 안전성 관련 이슈가 약 70%를 차지하며, 이는 하드웨어 수준의 방어가 절실한 이유입니다.
🔐 PAC (Pointer Authentication) — 포인터에 디지털 서명을 새기다
2016년 발표된 ARMv8.3-A 아키텍처에서 도입된 PAC는 포인터(주소값)가 변조되지 않았음을 증명하는 하드웨어 수준의 암호학적 서명 기술입니다.
⚙️ 작동 원리
64비트 아키텍처에서는 실제 가상 주소로 사용되는 비트 외에 상위 비트들이 남습니다(보통 상위 7~16비트). PAC는 이 남는 영역에 암호화된 서명을 삽입합니다.
Step 1 — 서명 생성 (PAC 삽입)
→ 포인터 값 + 비밀 키(Key) + 컨텍스트(SP 등)를 조합하여 QARMA 암호 알고리즘으로 서명을 생성하고, 포인터 상위 비트에 저장합니다.
Step 2 — 서명 검증 (AUT 명령)
→ 해당 포인터를 사용해 점프하기 직전, 동일한 방식으로 서명을 재계산하여 저장된 값과 비교합니다.
Step 3 — 변조 감지 시
→ 공격자가 버퍼 오버플로우로 리턴 주소를 바꿨다면 서명이 불일치합니다. CPU는 포인터 상위 비트를 의도적으로 손상시켜, 해당 주소 사용 시 즉시 Segmentation Fault를 발생시킵니다.
💻 어셈블리 코드로 보는 PAC
// 함수 진입 시: 리턴 주소(LR)에 서명 추가 PACIASP // LR + SP + Key → PAC 생성 후 LR 상위 비트에 삽입 STP LR, FP, [SP, #-16]! // ... 함수 로직 실행 ... // 함수 종료 시: 리턴 주소 서명 검증 LDP LR, FP, [SP], #16 AUTIASP // 서명 검증. 변조 시 주소값이 의도적으로 깨짐 RET // 깨진 주소로 점프 → Fault 발생!
🔑 PAC에서 사용하는 5가지 키
ARM PAC는 용도별로 5개의 독립된 128비트 키를 사용합니다. 키는 프로세스별로 다르게 설정되어, 한 프로세스의 키가 유출되어도 다른 프로세스에 영향을 주지 않습니다.
| 키 이름 | 용도 | 관련 명령어 |
|---|---|---|
| APIAKey | 명령어 포인터 서명 A | PACIA, AUTIA |
| APIBKey | 명령어 포인터 서명 B | PACIB, AUTIB |
| APDAKey | 데이터 포인터 서명 A | PACDA, AUTDA |
| APDBKey | 데이터 포인터 서명 B | PACDB, AUTDB |
| APGAKey | 범용 서명 | PACGA |
🎯 BTI (Branch Target Identification) — 착륙 지점을 제한하다
PAC가 포인터의 '내용'을 보호한다면, ARMv8.5-A(2019년)에서 추가된 BTI는 점프하는 '목적지'를 제한합니다. 이 두 기술은 상호 보완적으로 동작하여 제어 흐름 무결성(CFI)을 달성합니다.
📌 핵심 개념: Landing Pad
컴파일러는 함수 시작점 등 유효한 점프 대상 위치에 BTI 명령어를 삽입합니다. 이것이 "안전한 착륙 지점(Landing Pad)"입니다.
🔍 BTI의 세 가지 변형
▶ BTI c — 간접 호출(BLR)의 대상으로만 허용. 함수 시작점에 주로 사용됩니다.
▶ BTI j — 간접 점프(BR)의 대상으로만 허용. switch-case의 점프 테이블에 사용됩니다.
▶ BTI jc — 호출과 점프 모두 허용. 범용 Landing Pad입니다.
이렇게 세분화된 이유는 공격 표면을 최소화하기 위해서입니다. 함수 시작점은 호출만 허용하고, 점프 테이블은 점프만 허용함으로써, 공격자가 사용할 수 있는 가젯의 수를 극적으로 줄입니다.
🔗 PAC + BTI = 완전한 CFI (Control Flow Integrity)
PAC와 BTI는 개별적으로도 강력하지만, 함께 사용할 때 진정한 위력을 발휘합니다. 두 기술이 각각 다른 공격 벡터를 차단하기 때문입니다.
| 비교 항목 | PAC | BTI |
|---|---|---|
| 보호 대상 | 포인터 값(내용) | 점프 목적지(위치) |
| 방어하는 공격 | ROP (리턴 주소 변조) | JOP (간접 점프 악용) |
| 검증 방식 | 암호학적 서명 비교 | Landing Pad 존재 여부 |
| 도입 아키텍처 | ARMv8.3-A (2016) | ARMv8.5-A (2019) |
| 성능 오버헤드 | 거의 없음 (~1%) | 거의 없음 (NOP 수준) |
📱 실제 적용 사례와 생태계 현황 (2026)
🍎 Apple
→ A12 칩(iPhone XS, 2018)부터 PAC를 커널과 시스템 앱에 적용
→ M1 이후 Mac에서도 PAC+BTI 적극 활용, macOS 커널 전체에 적용
→ iOS 앱 개발 시 -mbranch-protection=standard 컴파일 옵션으로 PAC+BTI 동시 활성화
🤖 Android / Linux
→ Linux 커널 5.13부터 PAC, 5.17부터 BTI 지원
→ Android 12 이후 모든 ARM64 기기에서 PAC 기본 활성화
→ Pixel, Samsung Galaxy S 시리즈 등 최신 플래그십에서 커널+유저 공간 모두 적용
☁️ 클라우드 / 서버
→ AWS Graviton3/4 프로세서에서 PAC+BTI 완전 지원
→ Microsoft Azure Cobalt, Google Axion 등 ARM 서버 칩에서도 기본 탑재
→ 서버 워크로드에서도 성능 손실 없이 보안 강화 가능
🛠️ 컴파일러 지원
→ GCC 9+, Clang/LLVM 8+에서 PAC 지원
→ -mbranch-protection=pac-ret+bti 플래그로 PAC+BTI 동시 활성화
→ Rust 컴파일러도 AArch64 타깃에서 PAC/BTI 지원
⚠️ 알아두면 좋은 한계와 주의점
PAC와 BTI는 강력하지만, 만능은 아닙니다. 개발자가 알아두어야 할 핵심 포인트를 정리합니다.
▶ PAC 키 유출 위험
커널 취약점을 통해 PAC 키가 유출되면 서명을 위조할 수 있습니다. 실제로 2020~2023년 사이 여러 연구에서 사이드 채널 공격을 통한 키 추출 가능성이 보고되었습니다. 이에 ARMv8.6-A에서는 FPAC(Faulting PAC)를 도입하여, 인증 실패 시 즉시 예외를 발생시키도록 개선했습니다.
▶ 서명 비트 수 제한
PAC에 사용할 수 있는 비트는 가상 주소 크기에 따라 7~16비트로 제한됩니다. 비트 수가 적을수록 무작위 대입(Brute Force)에 취약해질 수 있으므로, 가상 주소 공간 설정 시 이를 고려해야 합니다.
▶ 레거시 호환성
PAC/BTI를 지원하지 않는 구형 바이너리와의 호환성을 위해, 해당 기능은 ELF 노트를 통해 바이너리별로 활성화/비활성화할 수 있습니다. BTI가 활성화되지 않은 코드 페이지에서는 BTI 명령어가 단순 NOP로 처리됩니다.
✨ 핵심 정리
ARMv8.3-A와 v8.5-A의 PAC+BTI는 소프트웨어 취약점이 존재하더라도, 그것이 실제 공격(Exploit)으로 이어지는 마지막 단계를 하드웨어가 차단하는 기술입니다.
✓ PAC — 포인터에 암호학적 서명을 삽입하여 변조를 감지. ROP 방어의 핵심.
✓ BTI — 유효한 점프 목적지만 허용하여 가젯 실행을 차단. JOP 방어의 핵심.
✓ 성능 오버헤드 — 두 기술 모두 1% 미만의 성능 저하로 실용적.
✓ 생태계 — Apple, Android, AWS, 주요 컴파일러에서 이미 폭넓게 지원.
📚 References
→ ARM Developer Documentation — Pointer Authentication
→ Understanding Pointer Authentication on ARMv8.3 — Koalatea.io
→ BTI — Branch Target Identification — LWN.net
→ ARM Architecture Reference Manual (ARMv8, for ARMv8-A architecture profile)
본 콘텐츠는 정보 제공 목적으로 작성되었으며, 특정 투자 또는 기술 결정을 권유하지 않습니다.
댓글
댓글 쓰기