[Rev] 리버싱 · 작성: 2026-07-19 19:32:50 · 조회 4
리버싱(리버스 엔지니어링)은 소스 코드 없이 컴파일된 바이너리(또는 앱)의 동작을 이해하는 작업이다. 악성코드 분석, 취약점 연구, 라이선스 검증 우회, 프로토콜 분석 등 목적은 다양하지만 시작점은 항상 비슷하다 — "일단 실행하지 말고 구조부터 살펴본다."
이 글은 정적 분석부터 다루고, 동적 분석은 다음 글에서 이어간다.
file ./target
ELF(Linux)인지 PE(Windows)인지, 32비트인지 64비트인지, 정적 링크인지 동적 링크인지부터 파악한다. 이것만으로도 이후 사용할 도구(디스어셈블러, 디버거)가 정해진다.
checksec ./target
NX, PIE, Stack Canary, RELRO 여부를 확인해서 이후 분석 난이도를 가늠한다 (Pwnable 카테고리 글들에서 다룬 개념과 그대로 이어진다).
strings ./target | less
에러 메시지, 하드코딩된 URL/IP, 디버그 심볼, 라이선스 키 검증 문구 같은 것들이 그대로 노출되는 경우가 많다. "어디서부터 봐야 할지 모르겠다"는 상황에서 가장 먼저 해보는 작업이다. 흥미로운 문자열을 찾으면, 그 문자열을 참조하는 코드 위치를 디스어셈블러에서 역추적(cross-reference)해서 관련 로직의 진입점을 잡는다.
프로그램이 어떤 라이브러리 함수를 쓰는지만 봐도 대략적인 동작을 추정할 수 있다.
strcmp, memcmp — 어딘가 값 비교 로직(라이선스 키 검증 등)이 있다socket, connect, send — 네트워크 통신을 한다CreateFile, WriteFile(Windows) / open, write(Linux) — 파일 입출력을 한다VirtualAlloc + VirtualProtect(Windows) — 런타임에 코드를 메모리에 새로 써서 실행하는 패턴(패킹/자기 수정 코드)일 가능성objdump -T(Linux) 또는 PE 파일이면 pefile(Python) 같은 도구로 임포트 테이블을 확인한다.
여기까지 왔으면 본격적으로 디스어셈블러/디컴파일러를 켠다.
디컴파일러가 만들어주는 C에 가까운 의사코드는 어디까지나 "추정"이다. 특히 최적화가 걸린 바이너리나 중요한 분기 조건은 실제 어셈블리와 대조해보는 습관이 필요하다 — 다음 글에서 어셈블리를 직접 읽는 법을 다룬다.
암호화/난독화되어 있거나, 조건에 따라 동작이 크게 달라지는 프로그램은 정적으로 읽기만 해서는 전체 그림을 파악하기 어렵다. 이런 경우 다음 글에서 다루는 동적 분석(디버거로 실제 실행 흐름 추적)과 병행해야 한다.