책 소개
요약
ARM 기반 장치의 애플리케이션을 어셈블리 수준으로 분석하는 리버스 엔지니어와 보안 엔지니어를 위한 필독서이다. ARM 장치의 취약점을 찾아 그 피해를 줄이고자 하는 ARM 보안 전문가를 위해, ARMv8-A 인스트럭션 세트와 보안 및 방어를 목적으로 하는 리버스 엔지니어링 과정을 소개한다. 다음으로 ELF파일 형식과 OS 내부를 소개하고 ARM 아키텍처의 기본과 A32 및 A64 인스트럭션을 철저히 알아본다. 또한 관련 리버스 엔지니어링 과정을 깊이 있게 분석한다. 마지막으로 ARM 기반 M1 SoC로 컴파일된 macOS 멀웨어 바이너리를 간단히 들여다본다. 이 책을 통해 ARM 아키텍처용으로 컴파일된 리버스 엔지니어링 소프트웨어를 통해 ARM 인스트럭션 및 제어 흐름 패턴을 폭넓게 이해할 수 있을 것이다.
이 책의 대상 독자
초보자와 노련한 전문가 모두에게 유용한 포괄적인 안내서로, 인기와 수요가 급상승하고 있는 프로세서 언어를 직관적으로 소개하는 책이다. 독자에게 필요한 자료를 쉽게 보여주므로, 취약점 탐색 및 분석, 익스플로이트 개발, 멀웨어 분석 기술을 극적으로 향상시키는 데 도움을 준다.
이 책의 구성
인스트럭션이 무엇인지 설명하고, 어디에서 왔는지를 알아보는 책이다. 2장에서는 ELF파일 포맷과 그 섹션, 컴파일 절차 등을 간략히 소개한다. 바이너리 분석은 실행 환경을 이해하지 않고서는 완전할 수 없으므로, 3장에서는 운영체제의 기초를 다룬다.
4장에서는 위와 같은 기본 지식을 바탕으로 Arm 아키텍처에 더 깊이 다가갈 준비를 한다. 5장에서는 가장 많이 사용되는 데이터 처리 인스트럭션을 살펴보고, 6장에서는 메모리 접근 인스트럭션의 개요를 다룬다. 이 인스트럭션은 로드/스토어(Load/Store) 아키텍처로 알려져 있으며, Arm 아키텍처에서 가장 많은 부분을 차지한다. 7장과 8장에서는 조건부 실행과 흐름 제어를 논의한다. 이는 리버스 엔지니어링에서 가장 중요한 구성 요소다.
9장은 리버스 엔지니어가 특히 관심을 가질 만한 부분이다. Arm 환경은 서로 다른 형태를 지니므로 잘 알아두는 것이 중요한데, 여러분이 동적 분석을 수행하거나 실행 중에 바이너리를 분석할 필요가 있을 때 특히 더 그렇다.
지금까지 언급한 정보를 갖고 있다면, 다음 리버스 엔지니어링 모험을 나서는 데 필요한 장비를 충분히 갖춘 셈이다. 그 모험을 위해 10장에서는 일반적인 정적 분석 도구를 소개한다. 또한 한 단계씩 따라 할 수 있는 실용적이고 간단한 정적 분석 예제를 제공한다.
프로그램 실행 중에 그 동작을 관찰할 수 있는 동적 분석이 없다면 리버스 엔지니어링은 지루해진다. 11장에서는 자주 사용되는 동적 분석 도구와 분석 중 사용할 수 있는 유용한 명령어를 배우고 예제를 살펴볼 것이다. 두 가지 실용적인 디버깅(debugging) 예제를 다루면서 해당 장을 마무리 짓는데, 이는 GDB를 통해 할 수 있다. 두 예제 중 하나는 메모리 충돌 취약점 디버깅이고, 다른 하나는 프로세스 디버깅이다.
리버스 엔지니어링은 다양한 사례에 유용하다. Arm 인스트럭션 세트와 리버스 엔지니어링 테크닉을 이용하면 다른 분야로 기술을 확장할 수 있다. 예를 들면, 취약점 분석 또는 멀웨어 분석 등이다.
리버스 엔지니어링은 멀웨어 분석가에게 중요한 기술이지만, 주어진 멀웨어 샘플이 컴파일된 환경에 익숙해지는 것 역시 중요하다. 이를 위해 arm64 맥 OS 멀웨어를 분석하는 장도 포함돼 있다(12장). 이 장은 『The Art of Mac Malware』(No Starch Press, 2022)의 저자인 패트릭 워들이 기술했다. 이전 장들과 달리, 해당 장은 Arm 어셈블리에 집중하지 않는다. 그 대신에 맥 OS 멀웨어가 분석을 피하기 위해 사용하는 일반적인 분석 방지(anti-analysis) 기술을 소개한다. 이 장의 목적은 애플 실리콘 M1/M2(Apple Silicon M1/M2)와 호환되는 맥 OS 멀웨어를 살펴보는 것이다. 따라서 Arm 기반 맥 OS 멀웨어를 추적하고 분석하길 원하는 엔지니어에게는 좋은 시작점이 될 것이다.
목차
목차
- 1부. Arm 어셈블리 내부 구조
- 1장. 리버스 엔지니어링 소개
- 어셈블리 소개
- 비트와 바이트
- 캐릭터 인코딩
- 기계 코드와 어셈블리어
- 어셈블리어 프로그래밍
- 크로스 어셈블러
- 고수준 언어
- 역어셈블
- 역컴파일
- 어셈블리 소개
- 2장. ELF 파일 포맷 내부
- 프로그램 구조
- 고수준 vs. 저수준 언어
- 컴파일 절차
- 다른 아키텍처를 위한 크로스 컴파일
- 어셈블 및 링크
- ELF 파일 개요
- ELF 파일 헤더
- ELF 파일 헤더 정보 필드
- 대상 플랫폼 필드
- 진입점 필드
- 테이블 위치 필드
- ELF 프로그램 헤더
- PHDR 프로그램 헤더
- INTERP 프로그램 헤더
- LOAD 프로그램 헤더
- DYNAMIC 프로그램 헤더
- NOTE 프로그램 헤더
- TLS 프로그램 헤더
- GNUEHFRAME 프로그램 헤더
- GNU_STACK 프로그램 헤더
- GNU_RELRO 프로그램 헤더
- ELF 섹션 헤더
- ELF 메타 섹션
- 문자열 테이블 섹션
- 심볼 테이블 섹션
- 주 ELF 섹션
- .text 섹션
- .data 섹션
- .bss 섹션
- .rodata 섹션
- .tdata 및
- ELF 메타 섹션
- 심볼
- 전역 심볼 vs. 지역 심볼
- 약한 심볼
- 심볼 버전
- 심볼 매핑
- 동적 섹션과 동적 로딩
- 의존성 로딩
- 프로그램 재배치
- 정적 재배치
- 동적 재배치
- 전역 오프셋 테이블(GOT)
- 프로시저 링크 테이블(PLT)
- ELF 프로그램 초기화 및 종료 섹션
- 초기화 및 종료 순서
- 스레드 로컬 스토리지
- 지역-실행 TLS 접근 모델
- 초기-실행 TLS 접근 모델
- 일반-동적 TLS 접근 모델
- 지역-동적 TLS 접근 모델
- 3장. 운영체제 기초
- 운영체제 아키텍처 개요
- 사용자 모드 vs. 커널 모드
- 프로세스
- 시스템 콜
- 객체 및 핸들
- 스레드
- 프로세스 메모리 관리
- 메모리 페이지
- 메모리 보호
- 익명 및 메모리 매핑된 메모리
- 메모리 매핑된 파일 및 모듈
- 주소 공간 레이아웃 무작위화
- 스택 구현
- 공유 메모리
- 운영체제 아키텍처 개요
- 4장. Arm 아키텍처
- 아키텍처 및 프로파일
- Armv8-A 아키텍처
- 예외 수준
- Armv8-A 신뢰 영역 확장
- 예외 수준 변경
- Armv8-A 실행 상태
- 예외 수준
- AArch64 실행 상태
- A64 인스트럭션 세트
- AArch64 레지스터
- 프로그램 카운터
- 스택 포인터
- 제로 레지스터
- 링크 레지스터
- 프레임 포인터
- 플랫폼 레지스터(x18)
- 내부 프로시저 호출 레지스터
- SIMD 및 부동소수점 레지스터
- 시스템 레지스터
- PSTATE
- AArch32 실행 상태
- A32 및 T32 인스트럭션 세트
- A32 인스트럭션 세트
- T32 인스트럭션 세트
- 인스트럭션 세트 전환
- AArch32 레지스터
- 프로그램 카운터
- 스택 포인터
- 프레임 포인터
- 링크 레지스터
- 프로시저 내부 호출 레지스터(IP, r12)
- 현재 프로그램 상태 레지스터
- 애플리케이션 프로그램 상태 레지스터
- 실행 상태 레지스터
- 인스트럭션 세트 상태 레지스터
- IT 블록 상태 레지스터(ITSTATE)
- 엔디언 상태
- 모드 및 예외 마스크 비트
- A32 및 T32 인스트럭션 세트
- 5장. 데이터 처리 인스트럭션
- 시프트 및 로테이트 오퍼레이션
- 논리 좌측 시프트
- 논리 우측 시프트
- 산술 우측 시프트
- 우측 로테이트
- 확장 우측 로테이트
- 인스트럭션 형태
- 직접 상수 형태로 시프트
- 레지스터 형태로 시프트
- 비트필드 조작 오퍼레이션
- 비트필드 이동
- 부호 및 제로 확장 오퍼레이션
- 비트필드 추출 및 삽입
- 논리 오퍼레이션
- 비트 AND
- TST 인스트럭션
- 비트 클리어
- 비트 OR
- 비트 OR NOT
- 비트 배타적 OR
- TEQ 인스트럭션
- 배타적 OR NOT
- 비트 AND
- 산술 오퍼레이션
- 덧셈 및 뺄셈
- 역뺄셈
- 비교
- CMP 인스트럭션 오퍼레이션 동작
- 덧셈 및 뺄셈
- 곱셈 오퍼레이션
- A64에서 곱셈
- A32/T32에서 곱셈
- 최하위 워드 곱셈
- 최상위 워드 곱셈
- 하프워드 곱셈
- 벡터(듀얼) 곱셈
- 롱(64비트) 곱셈
- 나눗셈 오퍼레이션
- 이동 오퍼레이션
- 직접 상수 이동
- A32/T32에서 직접 상수 이동 및 MOVT
- A64에서 MOVZ, MOVK를 통한 직접 상수 이동
- 레지스터 이동
- NOT을 갖는 이동
- 직접 상수 이동
- 시프트 및 로테이트 오퍼레이션
- 6장. 메모리 접근 인스트럭션
- 인스트럭션 개요
- 주소 지정 모드 및 오프셋 유형
- 오프셋 주소 지정
- 직접 상수 오프셋
- 레지스터 오프셋
- 사전 인덱스 모드
- 사전 인덱스 모드 예제
- 사후 인덱스 주소 지정
- 사후 인덱스 주소 지정 예
- 문자열 상수(PC 기준) 주소 지정
- 상수 로드하기
- 주소를 레지스터에 로드하기
- 오프셋 주소 지정
- 로드 및 저장 인스트럭션
- 워드 또는 더블워드 로드 및 저장
- 하프워드/바이트 로드 및 저장
- 로드 및 저장을 사용한 예제
- 다중 로드 및 저장(A32)
- STM 및 LDM 예제
- STM과 LDM을 사용한 좀 더 복잡한 예제
- 쌍 로드 및 저장(A64)
- 7장. 조건부 실행
- 조건부 실행 개요
- 조건 코드
- NZCV 조건 플래그
- 부호 있는 정수 오버플로 vs. 부호 없는 정수 오버플로
- 조건 코드
- NZCV 조건 플래그
- 조건부 인스트럭션
- Thumb의 If-Then(IT) 인스트럭션
- 플래그 설정 인스트럭션
- 인스트럭션 ‘S’ 접미사
- 덧셈 및 뺄셈 인스트럭션의 S 접미사
- 논리적 시프트 인스트럭션의 S 접미사
- 곱셈 인스트럭션의 S 접미사
- 기타 인스트럭션의 S 접미사
- 테스트 및 비교 인스트럭션
- 비교(CMP)
- 음수 비교(CMN)
- 테스트 비트(TST)
- 동등성 테스트(TEQ)
- 인스트럭션 ‘S’ 접미사
- 조건부 선택 인스트럭션
- 조건부 비교 인스트럭션
- CCMP를 사용한 AND 논리 연산자 조건부 인스트럭션
- CCMP를 사용한 OR 논리 연산자 조건부 인스트럭션
- 8장. 제어 흐름
- 분기 인스트럭션
- 조건 분기 및 반복문
- 분기 테스트 및 비교
- 테이블 분기(T32)
- 분기 및 상태 변경
- 서브루틴 분기
- 함수와 서브루틴
- 프로시저 호출 표준
- 휘발성 vs. 비휘발성 레지스터
- 인수와 반환값
- 큰 값 전달
- 리프 및 비리프 함수
- 리프 함수
- 비리프 함수
- 프롤로그와 에필로그
- 분기 인스트럭션
- 2부. 리버스 엔지니어링
- 9장. Arm 환경
- Arm 보드
- QEMU를 사용한 에뮬레이션
- QEMU 사용자 모드 에뮬레이션
- QEMU 전체 시스템 에뮬레이션
- 펌웨어 에뮬레이션
- 10장. 정적 분석
- 정적 분석 도구
- 명령줄 도구
- 역어셈블러와 역컴파일러
- 바이너리 닌자 클라우드
- 참조에 의한 호출 예제
- 제어 흐름 분석
- Main 함수
- 서브루틴
- 캐릭터로 변환
- if 문
- 몫 나눗셈
- for 반복문
- 알고리듬 분석
- 정적 분석 도구
- 11장. 동적 분석
- 명령줄 디버깅
- GDB 명령
- GDB 다중 아키텍처
- GDB 확장: GEF
- 설치
- 인터페이스
- 유용한 GEF 명령
- 메모리 검사
- 메모리 영역 감시
- 취약점 분석기
- checksec
- 라데어2
- 디버깅
- 원격 디버깅
- 라데어2
- 아이다 프로
- 메모리 손상 디버깅
- GDB로 프로세스 디버깅
- 명령줄 디버깅
- 12장. arm64 맥 OS 멀웨어 역추적
- 배경지식
- 맥 OS arm64 바이너리
- 맥 OS Hello World(arm64)
- 악성 arm64 바이너리 사냥
- arm64 멀웨어 분석
- 분석 방지 기술
- 디버깅 방지 논리 구조(ptrace 사용)
- 디버깅 방지 논리 구조(sysctl 사용)
- VM 방지 논리 구조(SIP 상태와 VM 아티팩트 감지를 통해)
- 결론
- 배경지식
도서 오류 신고
정오표
정오표
[ p.137: 그림 3.9 우측 ]
엠티 어센딩
→
엠티 디센딩