"코드를 실행하지 않고도, 우리는 그 안에 숨은 의도를 읽어낼 수 있다."
정적 분석의 첫 관문, radare2로 열어봅니다.
🎯 이 글에서 다루는 것
- 악성코드 PE 파일을 실행하지 않고 어셈블리를 추출하는 안전한 방법
- rabin2로 PE 헤더·임포트·문자열을 빠르게 수집하는 사전 정찰 기법
- r2의 핵심 명령어(aaa, afl, pdf)로 함수 단위 디스어셈블 하기
- 추출한 어셈블리를 깔끔한 .asm 텍스트 파일로 저장하는 배치(headless) 기법
- 분석가가 반드시 지켜야 할 격리 환경과 안전 수칙
📌 왜 radare2인가
악성코드 분석을 처음 시작하면 대부분 IDA Pro나 Ghidra를 떠올립니다. 둘 다 훌륭하지만, 무겁고 GUI 중심이라 "빠르게 한 함수만 들여다보고 싶다"는 상황에는 과한 면이 있습니다.
radare2(줄여서 r2)는 그 반대편에 있습니다. 터미널 기반의 가볍고 빠른 리버스 엔지니어링 프레임워크로, 칼리 리눅스에 기본 탑재되어 있어 별도 설치 없이 바로 쓸 수 있습니다. 무엇보다 스크립트로 자동화하기가 쉬워서, 수십 개의 샘플에서 특정 함수의 어셈블리만 일괄 추출하는 작업에 강력합니다.
핵심은 이것입니다. r2를 통한 디스어셈블은 정적 분석입니다. 즉, 악성코드를 절대 실행하지 않고 파일 내부의 기계어를 사람이 읽을 수 있는 어셈블리로 번역할 뿐입니다. 분석 자체로 시스템이 감염될 위험이 없다는 뜻입니다.

🔍 핵심 개념 정리
PE 파일이란
PE(Portable Executable) 는 윈도우의 실행 파일 포맷입니다. .exe, .dll, .sys 가 모두 PE 형식이며, 내부에는 코드가 담긴 .text 섹션, 데이터가 담긴 .data, 임포트 테이블, 엔트리 포인트 주소 등이 구조화되어 있습니다. 악성코드 대부분이 윈도우를 표적으로 하므로 PE 분석은 분석가의 기본기입니다.
디스어셈블(Disassembly)
컴파일된 바이너리 안에는 사람이 읽기 어려운 기계어(machine code) 가 들어 있습니다. 이를 mov, push, call 같은 어셈블리 명령어로 역번역하는 과정이 디스어셈블입니다. radare2는 이 작업을 명령어 한 줄로 수행합니다.
radare2 도구 묶음
- r2 — 대화형 메인 콘솔. 분석과 디스어셈블의 중심
- rabin2 — PE/ELF 등 바이너리의 메타정보(헤더, 임포트, 문자열)를 추출하는 도구
- r2 스크립팅 — -c 옵션으로 명령을 미리 넣어 자동 실행
💻 실습: 어셈블리 추출 단계별 명령어
0단계 — 격리 환경과 샘플 무결성 확인
분석은 반드시 인터넷과 분리된 격리 VM(스냅샷 복구 가능)에서 진행합니다. 먼저 샘플의 정체와 해시를 기록해 둡니다.
# 파일 유형 확인 — PE 실행 파일인지 검증
file sample.exe
# 해시 기록 — 추후 위협 인텔리전스(VirusTotal 등) 조회용
sha256sum sample.exe
해시는 분석 보고서의 식별자가 되므로 가장 먼저 남겨두는 습관이 좋습니다.
1단계 — rabin2로 사전 정찰
콘솔에 진입하기 전, rabin2로 전체 윤곽을 파악합니다. 실행 없이 헤더만 읽으므로 매우 안전합니다.
# 바이너리 기본 정보 (아키텍처, 비트, 컴파일러, 엔트리)
rabin2 -I sample.exe
# PE 헤더 필드 상세
rabin2 -H sample.exe
# 임포트 함수 목록 — 악성 행위 추정의 핵심 단서
rabin2 -i sample.exe
# 익스포트 함수 (DLL 분석 시 유용)
rabin2 -E sample.exe
# 엔트리 포인트 주소
rabin2 -e sample.exe
# 문자열 추출 — URL, 명령어, 레지스트리 키 등이 드러남
rabin2 -z sample.exe
rabin2 -i 로 보이는 임포트가 특히 중요합니다. CreateRemoteThread, VirtualAllocEx, WinHttpOpen 같은 API가 보이면 코드 인젝션이나 외부 통신을 의심할 수 있습니다.
2단계 — r2로 로딩하고 자동 분석
이제 메인 콘솔에 진입합니다. -A 옵션은 로딩과 동시에 전체 분석(aaa)을 수행합니다.
# -A : 로딩 즉시 aaa(자동 분석) 실행
r2 -A sample.exe
-A 없이 열었다면 콘솔 안에서 직접 분석을 돌립니다.
[0x00401000]> aaa
aaa(analyze all)는 함수 경계, 호출 관계, 문자열 참조를 자동으로 식별하는 r2의 핵심 분석 명령입니다. 큰 샘플은 시간이 걸리니 잠시 기다립니다.
3단계 — 함수 목록 확인
분석이 끝나면 식별된 함수들을 나열합니다.
[0x00401000]> afl
afl(analyze function list)은 각 함수의 주소, 크기, 이름을 표로 보여줍니다. 특정 이름만 보고 싶다면 r2 내장 grep(~)을 씁니다.
[0x00401000]> afl~main
[0x00401000]> afl~entry
4단계 — 어셈블리 디스어셈블
드디어 핵심입니다. 함수 단위로 어셈블리를 출력합니다.
# 엔트리 포인트 함수 전체 디스어셈블
[0x00401000]> pdf @ entry0
# 현재 위치로 이동 후 함수 출력
[0x00401000]> s entry0
[0x00401000]> pdf
# 특정 함수 디스어셈블 (afl에서 확인한 이름 사용)
[0x00401000]> pdf @ sym.malicious_routine
# 특정 주소에서 50개 명령어만 출력
[0x00401000]> pd 50 @ 0x00401230
pdf(print disassembly function)는 함수 하나를 통째로, pd N은 지정한 개수의 명령어만 디스어셈블합니다. 둘의 차이를 기억해 두면 상황에 맞게 골라 쓸 수 있습니다.
5단계 — 시각적(Visual) 모드로 흐름 보기
명령어 나열이 아니라 그래프로 제어 흐름을 보고 싶다면 비주얼 모드를 씁니다.
# 비주얼 디스어셈블 모드 (q로 종료, p로 화면 전환)
[0x00401000]> V
# 함수 제어 흐름 그래프
[0x00401000]> VV
VV의 그래프 뷰는 분기와 반복 구조를 한눈에 파악하게 해줘서, 복잡한 패킹 해제 루틴을 이해할 때 특히 유용합니다.
6단계 — 어셈블리를 파일로 추출 (자동화)
분석가의 진짜 무기는 자동화입니다. 콘솔에 들어가지 않고도 -q -c 옵션으로 명령을 주입해 결과를 텍스트 파일로 뽑을 수 있습니다.
# 엔트리 함수만 깔끔한 텍스트로 저장 (색상 코드 제거)
r2 -q -c "e scr.color=0; aaa; pdf @ entry0" sample.exe > entry0.asm
# 모든 함수를 한꺼번에 디스어셈블 — @@f 는 함수 단위 반복 실행
r2 -q -c "e scr.color=0; aaa; pdf @@f" sample.exe > all_functions.asm
# 함수 목록만 텍스트로
r2 -q -c "aaa; afl" sample.exe > functions.txt
여기서 e scr.color=0은 터미널 색상 코드를 끄는 설정입니다. 이걸 빼면 파일에 ANSI 이스케이프 문자가 섞여 지저분해지니 꼭 넣어줍니다. @@f는 r2의 반복 연산자로, 식별된 모든 함수에 대해 pdf를 차례로 실행하라는 뜻입니다.
더 읽기 좋은 출력을 원한다면 부가 설정을 조절합니다.
# 좌측 흐름선과 hex 바이트를 숨겨 순수 어셈블리만 추출
r2 -q -c "e scr.color=0; e asm.lines=false; e asm.bytes=false; aaa; pdf @@f" sample.exe > clean.asm
이렇게 추출한 .asm 파일은 grep으로 특정 API 호출을 검색하거나, 여러 변종 간 코드 유사도를 비교하는 분석 자료로 곧바로 활용할 수 있습니다.
⚠️ 주의사항과 흔한 실수
- 절대 호스트에서 직접 다루지 마세요. 분석은 스냅샷이 가능한 격리 VM에서만 진행하고, 네트워크는 차단합니다. r2 자체는 실행하지 않지만, 실수로 샘플을 더블클릭하는 사고는 언제든 일어납니다.
- 패킹된 샘플은 디스어셈블이 무의미할 수 있습니다. UPX 등으로 패킹된 경우 보이는 코드는 언패킹 스텁뿐입니다. rabin2 -I 결과의 엔트로피가 비정상적으로 높거나 섹션 이름이 UPX0 같으면 먼저 언패킹을 고려하세요.
- 색상 코드 제거를 잊지 마세요. e scr.color=0 없이 파일로 뽑으면 ^[[31m 같은 제어문자가 섞입니다.
- aaa가 모든 함수를 다 못 잡을 수 있습니다. 난독화된 코드는 자동 분석이 함수 경계를 놓치기도 합니다. 이럴 땐 의심 주소에서 af(함수 정의)를 수동으로 호출한 뒤 pdf 하세요.
- 법적·윤리적 경계를 지키세요. 정당한 권한이 있는 샘플과 환경에서만 분석합니다. 분석 목적은 방어와 탐지 역량 강화에 있습니다.
✅ 정리
오늘 다룬 흐름을 한 문장으로 요약하면 이렇습니다. 격리 환경 준비 → rabin2로 정찰 → r2 -A로 분석 → afl로 함수 식별 → pdf로 어셈블리 추출 → -q -c로 자동 저장.
radare2는 처음엔 명령어가 낯설지만, i(info), a(analyze), p(print), s(seek)라는 네 갈래로 명령 체계가 짜여 있다는 걸 알면 금세 손에 익습니다. 정적 분석으로 어셈블리를 읽어내는 감각이 쌓이면, 동적 분석(디버깅)과 행위 분석으로 넘어가는 길도 한결 수월해집니다.
다음 단계 추천
- r2의 디버거 모드(r2 -d)로 동적 분석 입문
- pdc 또는 r2dec 플러그인으로 의사 C코드 디컴파일 시도
- Cutter(radare2 GUI)로 그래프 분석 병행
- YARA 룰 작성과 연계한 변종 탐지 자동화
'일반IT > IT보안' 카테고리의 다른 글
| 보안 업무에서 활용 가능한 생성형 AI 사례 — SOC 분석부터 클라우드 보안까지 (0) | 2026.07.23 |
|---|---|
| AWS IMDSv1과 IMDSv2를 보안 관점에서 이해하기 (0) | 2026.06.11 |
| 🐍 코드로 사냥하라 — yara-python으로 만드는 자동화된 시그니처 탐지기 (0) | 2026.05.23 |
| 🎯 악성코드를 사냥하는 사냥꾼의 언어, YARA 룰 직접 만들어보기 (0) | 2026.05.23 |
| 🛡️ GHSA, 데이터베이스가 아닌 "대화"였다 — 2026년, 보안 전문가가 새로 배워야 할 메인테이너 소통의 기술 (0) | 2026.05.12 |