bindiff툴, ghidra 사용해보기
Diffing
컴퓨터에서 두 파일의 차이를 보여주는 용어로 패치 전,후의 바이너리를 비교해서 어떤 코드가 변경되었는지 차이점을 알 수 있는 분석 기법이다.
이를 통해 새로운 취약점을 효율적으로 발견할 수 있다.
Ghidra와 bindiff를 설치한 상태에서 시작한다.
Ghidra로 바이너리 분석 및 비교해보기
1.exe 파일 만들기
- visual studio를 사용해 C++파일을 실행한다.
- 아래와 같은 간단한 코드를 작성, 상단바 드롭다운 메뉴를 Debug -> Release로 변경 후 ctrl + shift + B로 빌드한다.
#include <iostream>
#include <stdio.h>
using namespace std;
int main() {
printf("Hello, Binary Diffing!\n");
return 0;
}
- 해당 경로의 .exe파일을 복사해 보관할 폴더에 저장한다.
(C:\사용자\sourse\repos\C++\x64\Release\hello.exe)
- 코드를 아래처럼 조금 수정한 뒤 동일하게 파일을 복사해 저장해준다.
#include <iostream>
#include <stdio.h>
using namespace std;
int main() {
printf("Hello, Bindiff!\n");
return 0;
}
2.Ghidra 실행
- ghidraRun을 관리자 권한으로 실행한다.
(C:\Program Files\Ghidra\ghidra_11.3.1_PUBLIC\ghidraRun.bat)
- 새 프로젝트 생성 File -> New Project -> Non-Shared Project
- 프로젝트명: BindiffTest(D:GhidraProject)
3.실행 파일 로드
- File -> Import File -> hello_v1.exe 파일 선택 -> OK -> 용이 불뿜음

🔍 분석된 주요 정보
파일 포맷: Portable Executable (PE) → Windows 실행 파일
아키텍처: x86-64 (LE) → 64비트 리틀 엔디언
컴파일러: visualstudio:unknown → Visual Studio로 빌드됨
바이너리 크기: 11832 bytes → 파일 크기
함수 개수: 2 → 분석된 함수 개수 (아직 제대로 분석되지 않았을 가능성 있음)
정의된 데이터: 285 → 문자열, 상수 등의 개수
SHA256 해시 값: e7985b080295030d90111a22abd6f88bd1df254417e9c1d426d041621ac9f008
바이너리가 변조되지 않았는지 확인할 때 유용
이제 "OK"를 누르고 Import 파일을 누르면 Ghidra의 분석 화면으로 이동하게 된다.


4.디컴파일 코드 분석하기
v1.exe 파일 분석하기
- 상단 메뉴에서 window -> Decompile 클릭해 C스타일로 변환된 코드를 확인할 수 있다.
- main()함수 코드를 확인하기 위해서, window -> Defined Strings 창 열고, Hello, Binary Diffing을 검색한다.

- main함수의 위치를 정확히 알기 위해 찾은 문자열 (s_Hello_Binary_Diffing)을 우클릭, "References" 또는 "Find References to" 선택
이 문자열이 사용된 어셈블리 코드(주소)로 이동

- 현재 창에서 140001074 주소 클릭, 코드가 있는 어셈블리 창 (Listing 창)으로 이동, 스크롤을 위로 올려서 함수의 시작 부분을 찾기
*보통 PUSH RBP 또는 SUB RSP, XX 같은 명령어가 함수의 시작 부분
- SUB RSP, 0x28 → 스택 프레임 할당
- LEA param_1, [s_Hello_Binary_Diffing] → 문자열 로드 (printf를 호출하기 위함)
- CALL FUN_140001010 → 이 함수가 printf()일 가능성이 높음
- XOR EAX, EAX → 일반적인 반환값 설정 (return 0;)
- ADD RSP, 0x28 → 스택 프레임 해제
- RET → 함수 종료

- 이제 해당 주소를 Symbol Tree에서 찾아 main으로 Rename해준다.

- main을 더블클릭 후 window -> Decompile 해주면 오른쪽에 아래와 같이 C스타일로 디컴파일된 코드를 볼 수 있다.

- 원래 작성했던 C언어 코드와 거의 일치하는 것을 볼 수 있다.
int main() {
printf("Hello, Binary Diffing!");
return 0;
}
v2.exe파일 분석하기
- 이번에도 동일하게 .exe파일을 Ghidra에서 Import File 해준다.

- 위 파일을 더블클릭해 실행해주고, yes -> Analyze 해준다.

- 이번에는 직접 검색해보지 않고, v1.exe파일의 main함수 주소인 140001070번지로 가보니 Hello,Bindiff!라는 String을 볼 수 있었다.

- Symbol Tree에서 해당 주소를 main으로 Rename해주고 더블클릭, window -> Decompile 해보면 아래와 같이 C스타일의 코드가 잘 나온다.

5.두 실행 파일 비교
1.디컴파일된 코드 비교
- hello_v1.exe파일

- hello_v2.exe파일

"Hello, Binary Diffing!" → "Hello, BinDiff!" 로 잘 바뀐것을 볼 수 있다.
2.어셈블리 비교
- hello_v1.exe파일

- hello_v2.exe파일

6.최종 정리: Ghidra를 사용한 실행 파일(Binary) 비교 과정
🔹 1. 실행 파일 Import & 분석
✔ hello_v1.exe와 hello_v2.exe를 각각 Ghidra에 Import
✔ "Auto Analysis" 실행하여 자동 분석
🔹 2. 문자열 기반 변경점 찾기
✔ Window → "Defined Strings" 창 열기
✔ "Hello, Binary Diffing!"과 "Hello, BinDiff!" 검색
✔ "Find References To" 기능으로 참조 코드 찾기
🔹 3. 어셈블리 코드(Assembly) 비교
✔ LEA 명령어에서 변경된 문자열 확인
✔ CALL printf 명령어가 있는지 확인
✔ hello_v1.exe와 hello_v2.exe의 어셈블리 코드 비교
🔹 4. 디컴파일된 C 코드 비교 (Decompile)
✔ Window → "Decompile" 창에서 main() 코드 확인
✔ printf()에 사용된 문자열이 변경된 것 확인
🎯 결론: 실행 파일 비교 분석 성공!
✔ hello_v1.exe와 hello_v2.exe의 차이점을 Ghidra에서 완벽하게 비교 완료 🎉
✔ 실제 변경된 문자열 및 코드 흐름을 추적하는 방법을 배움
✔ 이제 다른 실행 파일도 같은 방법으로 비교 가능!
BinDiff를 사용해 자동으로 .exe파일 비교하기
- 앞서 실행파일의 변경된 코드를 수동으로 비교했지만, Bindiff를 사용해서 변경점을 자동으로 분석할 수 있다.
1.Ghidra에서 .BinExport 파일 생성
- 먼저 링크에서 BinExport_Ghidra-Java.zip을 설치한다.
링크텍스트
- zip파일을 Ghidra안 Extensions 폴더에 압축해제 한다.
(C:\Program Files\Ghidra\ghidra_11.3.1_PUBLIC\Extensions)
- Ghidra를 관리자 권한으로 실행 -> File -> Install Extensions -> BinExport 폴더를 클릭 후 OK
- hello_v1.exe 실행 -> "File" → "Export Program" 클릭
- 아래와 같이 Format 설정 후 ok

- 같은 방식으로 v2.exe 파일도 export, 정상 저장되었는지 확인

2.Bindiff 실행
- Bindiff.exe 실행 후 "File" → "New Workspace"를 생성
- 파일명: Bindiff_Project.bdif
(C:\Program Files\BinDiff\bin\bindiff.exe)
- 마우스 우클릭 New Diff -> .BinExport 파일을 각각 선택 -> Diff

- 비교된 정보들이 이제 나올 것이다.
3.Bindiff로 .BinExport 차이점 분석해보기
1. 변경된 main 함수 찾기
- 왼쪽 패널을 보면 아래같은 정보가 있다.
Matched Functions (79) → 79개의 함수가 일치함.
Primary Unmatched Functions (28/107) → v1에만 있는 28개의 함수.
Secondary Unmatched Functions (24/103) → v2에만 있는 24개의 함수.

- Call Graph를 통해 분석해보면 아래와 같다.
전체 함수 중 일치한 함수: 79개 (73.8%)
hello_v1.exe에만 존재하는 함수: 28개 (26.2%)
hello_v2.exe에만 존재하는 함수: 24개 (23.3%)

- 호출(Call) 변화:
hello_v1.exe: 94개 호출 -> hello_v2.exe: 90개 호출로 줄어들었다.
hello_v1.exe에서만 존재하는 호출: 20개 -> hello_v2.exe에서만 존재하는 호출: 20개
=> 출력할 string만 변경했기에 거의 유사한 양상을 띄는 것을 볼 수 있다.
- 이제 main 함수의 Adress: 140001070을 찾아 더블클릭 해준다.
그럼 아래와 같이 어셈블리 형태로 비교할 수 있다.

결론
✅ Binary Diffing을 통해 문자열 변경을 정확히 찾아냈음
✅ 어셈블리 코드의 논리적 구조는 동일하므로 실행 흐름에는 변화 없음
숨이 턱막히네요 벽느끼고 갑니다ㅠㅠ