[Tool] 소스코드 없이 프로그램을 읽는 법 — NSA의 Ghidra
NSA가 공개한 오픈소스 리버스 엔지니어링 프레임워크 Ghidra를 통해, 소스코드가 없는 실행 파일에서 무엇을 확인할 수 있고 무엇을 추론에 맡겨야 하는지 정리합니다.
실행 파일 하나가 있다. 소스코드는 없고, 만든 사람에게 물어볼 수도 없다. 그래도 이 파일이 어떤 운영체제와 CPU를 대상으로 했는지, 어떤 라이브러리를 부르는지, 입력에 따라 어느 함수로 흘러가는지는 읽어낼 수 있다.
Ghidra는 미국 국가안보국(NSA)이 공개한 오픈소스 소프트웨어 리버스 엔지니어링 프레임워크다. 바이너리를 역어셈블하고, 함수와 제어 흐름을 정리하고, C와 비슷한 의사 코드로 보여 준다. 하지만 여기서 가장 중요한 단어는 ‘복원’이 아니라 ‘추론’이다.
이 글에서 말하는 분석 대상은 본인이 소유했거나 분석 권한을 받은 프로그램이다. 취약점 악용, 보안 우회, 악성코드 무기화 절차는 다루지 않는다.
컴파일 뒤에 남는 것과 사라지는 것
사람이 쓰는 소스코드는 컴파일을 거치며 CPU가 실행할 명령어와 데이터로 바뀐다. 그 과정에서 분석에 쓸 단서는 꽤 남지만, 사람이 붙인 맥락은 대개 사라진다.
| 실행 파일에서 비교적 확인하기 쉬운 것 | 그대로 되돌릴 수 없는 것 |
|---|---|
| CPU 아키텍처, 파일 형식, 외부 라이브러리 | 원래 변수명과 함수명 |
| 문자열, 상수, API 호출 흔적 | 주석과 설계 문서 |
| 함수 사이의 호출 관계와 분기 | 왜 그 코드를 작성했는지에 대한 의도 |
| 기계어 명령과 메모리 접근 패턴 | 원본 프로젝트 구조와 빌드 환경 |
예를 들어 send_report()라는 함수명이 있었다고 해도, 배포본에서는 이름이 사라지고 주소만 남을 수 있다. Ghidra가 의사 코드에 FUN_00401230 같은 이름을 붙이는 이유다. 분석자가 호출 관계와 문자열을 읽고 의미 있는 이름으로 바꾸는 일은 가능하지만, 그것은 확인된 사실이 아니라 해석을 더한 작업이다.
Ghidra가 던지는 세 가지 질문
Ghidra를 열어 보는 목적은 ‘원본 소스를 되찾는 것’보다 다음 질문에 단계적으로 답하는 데 가깝다.
- 이 파일은 무엇인가? 파일 헤더, 대상 아키텍처, 포함된 라이브러리와 문자열에서 출발한다.
- 어떻게 움직이는가? 함수, 분기, 호출 관계, 데이터 참조를 따라 실행 흐름을 살핀다.
- 왜 이렇게 만들었는가? 이 질문에는 도구만으로 답할 수 없다. 제품 문서, 정상 동작의 관찰, 권한 있는 테스트 환경, 도메인 지식이 함께 필요하다.
첫 두 질문에서 Ghidra는 특히 강하다. 역어셈블러는 기계어를 명령어 단위로 보여 주고, 디컴파일러는 그것을 C와 비슷한 형태로 재구성한다. 함수 그래프와 참조 탐색을 이용하면 한 문자열이나 API 호출에서 출발해 주변 로직을 넓혀 갈 수 있다.
반대로 세 번째 질문을 도구 출력만으로 단정하면 위험하다. if 문 하나는 인증 검사일 수도, 단순한 환경 확인일 수도 있다. 의사 코드는 읽기 편한 표현일 뿐, 개발자가 작성한 원문도 정답을 보장하는 번역문도 아니다.
‘C처럼 보인다’는 말의 함정
디컴파일 결과는 매우 설득력 있어 보인다. 반복문은 while처럼, 조건 분기는 if처럼, 구조체 접근은 필드 이름이 있는 것처럼 나타난다. 그러나 이 모습은 Ghidra가 명령어와 제어 흐름을 바탕으로 만든 분석용 표현이다.
그래서 좋은 분석은 화면의 의사 코드를 그대로 인용하지 않는다. 적어도 다음 단서를 서로 맞춰 본다.
- 의사 코드와 실제 어셈블리의 대응
- 함수가 참조하는 문자열·상수·외부 API
- 호출하는 쪽과 호출되는 쪽의 맥락
- 같은 동작을 보이는 다른 경로
이 교차 확인은 ‘그럴듯한 코드’를 ‘설명 가능한 결론’으로 바꾸는 과정이다. 리버스 엔지니어링의 실력은 디컴파일 버튼을 누르는 데보다, 확신의 정도를 구분하는 데서 드러난다.
GUI를 넘어 반복 분석으로
Ghidra는 화면에서 탐색하는 도구로 먼저 알려졌지만, 공식 문서는 명령줄 기반의 Headless 분석도 제공한다. 반복되는 사내 호환성 점검이나, 권한 있는 소프트웨어 자산의 분류처럼 같은 규칙을 여러 파일에 적용해야 할 때 유용하다.
확장 지점도 넓다. Java 기반 확장과 스크립팅을 지원하고, 공식 문서는 네이티브 CPython 3와 연결하는 PyGhidra도 안내한다. 여기서 자동화의 목표는 ‘도구가 결론을 대신 내리게 하기’보다, 사람이 검토해야 할 후보를 빠르게 모으는 데 두는 편이 안전하다.
운영체제 지원은 한 문장으로 뭉뚱그리기보다 릴리스별 설치 문서를 확인해야 한다. 현재 공식 안내는 Windows와 Linux용 사전 빌드 네이티브 구성요소를 제공하며, macOS 같은 추가 플랫폼은 네이티브 구성요소를 사용자가 빌드해야 하는 경우를 구분해 설명한다.
분석 도구도 입력을 신뢰하지 않는다
Ghidra 프로젝트 파일과 도구 자체도 최신 상태로 유지해야 한다. 프로젝트를 여는 과정과 관련된 보안 수정이 과거 릴리스에 포함된 바 있으므로, 출처가 불분명한 프로젝트는 열지 않고 공식 릴리스의 패치된 버전을 쓰는 편이 좋다.
이 원칙은 분석 대상에도 그대로 적용된다. 실행 파일을 ‘읽기만 한다’고 느껴도, 가져온 프로젝트·스크립트·확장 기능까지 신뢰해도 된다는 뜻은 아니다. 분석 환경을 분리하고, 파일의 출처와 권한을 먼저 확인하는 습관이 도구 숙련보다 앞선다.
정리: Ghidra는 답안지가 아니라 현미경이다
Ghidra는 소스가 없는 프로그램을 이해하는 출발점을 크게 낮춘다. 함수 구조, 호출 관계, 문자열, 기계어와 의사 코드를 한곳에 모아 주기 때문이다.
하지만 현미경이 표본의 목적을 말해 주지 않듯, Ghidra도 개발자의 의도와 원본 소스를 돌려주지는 않는다. 도구가 보여 준 사실과 분석자가 붙인 해석을 분리하고, 권한 있는 대상만 다루며, 최신 공식 릴리스를 유지하는 것. 이것이 소스 없는 프로그램을 읽을 때 가장 먼저 갖춰야 할 태도다.