
디컴파일러에서 디버거로 대화형 심볼을 도입하는 플러그인
리버스 엔지니어링은 정적(디컴파일러) 분석과 동적(디버거) 분석을 모두 포함하지만, 이 두 분석 간에 지식을 공유하지 않고 사용하는 경우가 많습니다. 정적 바이너리를 리버싱할 때 디버거 어셈블리와 디컴파일에서 복구한 심볼 간의 컨텍스트 전환은 비효율적일 수 있습니다.
decomp2dbg는 디컴파일러-디버거 심볼 동기화를 위한 일반적인 API를 도입하여 디컴파일러와 디버거 간의 컨텍스트 전환 격차를 줄이는 것을 목표로 합니다. 결과적으로, 리버서는 디컴파일러에서 복구한 심볼과 디컴파일 라인을 활용하면서도 디버거의 강력한 기능을 사용할 수 있습니다.

실제로 decomp2dbg가 어떻게 작동하는지 보고 싶으신가요? CactusCon 2023에서의 발표 영상을 확인해 보세요. Ghidra 심볼을 사용하여 x64 머신에서 원격 arm32 바이너리를 디버깅하는 내용이 포함되어 있습니다.
활발한 도움을 원하시면 아래 BinSync Discord에 가입하여 decomp2dbg에 관한 질문을 하실 수 있습니다:
pip를 통해 설치한 후, 내장 설치 프로그램을 사용하여 디컴파일러용으로 설치합니다:
pip3 install decomp2dbg && decomp2dbg --install
그러면 프롬프트가 열리며 선호하는 디컴파일러와 디버거의 경로를 입력하라는 메시지가 표시됩니다. Ghidra의 경우 PyGhidra 모드로 실행하고 여기에 표시된 대로 플러그인(d2d_client.py)을 활성화해야 합니다. Binja 플러그인 관리자에서 디컴파일러 측을 설치한 경우에도 위의 방법으로 디버거 측을 설치해야 합니다. 참고: decomp2dbg를 디컴파일러 및 디버거와 동일한 Python 환경에 설치해야 합니다.
참고: decomp2dbg가 디컴파일러에 연결되도록 포트 3662(또는 사용 중인 포트)에 대한 인바운드 연결을 허용해야 할 수 있습니다. GEF 또는 pwndbg와 함께 decomp2dbg를 설치하는 경우 ~/.gdbinit에서 d2d.py 파일이 GEF 또는 pwndbg 다음에 소싱되도록 하는 것이 중요합니다.
위의 설치 방법을 오류 없이 사용할 수 있었다면 이 단계는 건너뛰십시오. 내장 스크립트를 사용할 수 없는 경우(디컴파일러의 비WSL Windows 설치), 아래 단계를 따르십시오:
디컴파일러 측만 필요한 경우, 해당 디컴파일러 플러그인을 디컴파일러의 플러그인 폴더로 복사하십시오. IDA에서의 방법은 다음과 같습니다:
먼저, 리포지토리를 클론합니다:
git clone https://github.com/mahaloz/decomp2dbg.git
설치:
pip install .
모든 서버 파일을 복사합니다:
cp ./decomp2dbg/d2d_server.py /path/to/ida/plugins/
gdb 측도 설치해야 하는 경우, 아래 줄을 사용하십시오:
cp ./decomp2dbg/d2d_client.py ~/.d2d.py && echo "source ~/.d2d.py" >> ~/.gdbinit
먼저, 디컴파일러에서 디컴파일 서버를 시작하십시오. 디컴파일러가 정상 분석을 완료한 후에 시작하는 것이 좋습니다. 정상 분석 후에는 단축키 Ctrl-Shift-D를 사용하거나 관련 플러그인 탭에서 decomp2dbg: configure 탭을 선택하여 수행할 수 있습니다. 서버를 시작한 후 디컴파일러에서 다음과 같은 메시지가 표시되어야 합니다:
[+] Starting XMLRPC server: localhost:3662
[+] Registered decompilation server!
다음으로, 디버거에서 다음을 실행하십시오:
decompiler connect <decompiler_name>
디컴파일러를 VM이나 다른 머신에서 실행 중인 경우, 연결할 호스트와 포트를 선택적으로 제공할 수 있습니다. 예시는 다음과 같습니다:
decompiler connect ida --host 10.211.55.2 --port 3662
모든 명령어를 사용하는 방법은 decompiler 명령어에 --help 플래그를 붙여 실행하면 확인할 수 있습니다.
첫 번째 연결은 바이너리의 전역 변수 양에 따라 등록하는 데 최대 30초가 걸릴 수 있습니다. 모든 것이 정상이면 다음 메시지가 표시됩니다:
[+] Connected to decompiler!
디버거가 연결된 주 바이너리가 아닌 라이브러리에 대해 decomp2dbg를 사용하는 경우, README의 고급 사용법 - 공유 라이브러리 섹션을 참조하십시오.
각 중단점 이벤트에서 디컴파일된 코드가 출력되며, 중단 주소와 관련된 현재 라인이 표시됩니다.
디컴파일의 함수 및 전역 변수는 일반 소스 수준 심볼처럼 GDB에 매핑됩니다. 따라서 일반 GDB 명령어인 print 및 examine을 기본적으로 사용할 수 있습니다:
b sub_46340
x/10i sub_46340
p dword_267A2C
x dword_267A2C
함수 내에 지역적으로 저장된 일부 변수는 스택 변수입니다. 스택이나 레지스터에 매핑할 수 있는 변수의 경우 편의 변수로 가져옵니다. 일반 GDB 편의 변수처럼 내용을 볼 수 있습니다:
p $v4
스택 변수는 항상 스택에 해당 주소를 저장합니다. 스택 변수의 실제 값을 보려면 역참조하면 됩니다:
x $v4
이것은 함수 인자에도 적용됩니다(결과는 상황에 따라 다를 수 있음):
p $a1
참고: $v4는 동일한 함수에 있는 동안에만 매핑됩니다. 함수를 벗어나면 매핑이 해제되거나 다른 값으로 다시 매핑될 수 있습니다.
주 바이너리가 아닌 메모리 영역(예: 공유 라이브러리 디버깅 시)에 대한 디컴파일 및 심볼을 표시하려면 추가 단계가 필요합니다. 현재 d2d는 한 번에 하나의 디컴파일러 연결만 지원하므로, 라이브러리가 아닌 다른 디컴파일러가 이미 연결되어 있으면 연결을 해제해야 합니다.
공유 라이브러리에 대해 d2d 서버를 실행하는 디컴파일러를 일반 설정 후에, 이 라이브러리의 기본 주소와 끝 주소를 수동으로 설정해야 합니다:
decompiler connect ida --base-addr-start 0x00007ffff7452000 --base-addr-end 0x00007ffff766d000
메모리에 로드된 라이브러리의 기본 주소를 찾으려면 GEF의 vmmap 명령어 등을 사용하여 메모리 공간에서 라이브러리 이름을 찾는 것이 좋습니다. 수동으로 설정한 주소로 연결하면 심볼이 일반 d2d처럼 작동합니다. 디컴파일은 이 주소 공간 범위 내에 있을 때만 화면에 출력됩니다.