
pbtk v1.1.3
Protobuf 기반 앱을 리버스 엔지니어링 및 퍼징하기 위한 도구 세트
pbtk - Protobuf 앱 리버스 엔지니어링
Protobuf는 Google에서 개발한 직렬화 형식으로, 점점 더 많은 Android, 웹, 데스크톱 및 기타 애플리케이션에서 사용되고 있습니다. 이는 데이터 구조를 선언하는 언어로 구성되며, 대상 구현에 따라 코드 또는 다른 종류의 구조로 컴파일됩니다.
pbtk (Protobuf 툴킷)는 통합 GUI를 통해 접근할 수 있는 완전한 기능의 스크립트 세트로, 두 가지 주요 기능을 제공합니다:
-
프로그램에서 Protobuf 구조 추출, 이를 다시 읽을 수 있는 .proto 파일로 변환하며, 다양한 구현을 지원합니다:
- 모든 주요 Java 런타임(기본, Lite, Nano, Micro, J2ME), Proguard 완전 지원 (2026: 여전히 잘 작동하지만 주로 오래된 APK에서)
- 포함된 리플렉션 메타데이터가 있는 바이너리(일반적으로 C++, 때로는 Java 및 대부분의 다른 바인딩) (2026: 여전히 잘 작동)
- JsProtoUrl 런타임을 사용하는 웹 애플리케이션 (2026: 업데이트 필요)
-
Protobuf 네트워크 엔드포인트로 전송되는 데이터 편집, 재전송 및 퍼징, Protobuf 메시지의 필드를 실시간으로 편집하고 결과를 볼 수 있는 편리한 그래픽 인터페이스를 통해 제공됩니다.
설치
PBTK는 Python ≥ 3.5, PySide 6, Python-Protobuf 3, 그리고 추출기 스크립트 실행을 위한 몇 가지 실행 프로그램(chromium, jad, dex2jar 등)이 필요합니다.
Ubuntu 사용자는 snap을 사용하여 설치할 수 있습니다:
$ sudo snap install pbtk
$ pbtk
Archlinux 사용자는 패키지를 통해 직접 설치할 수 있습니다:
$ yay -S pbtk-git
$ pbtk
대부분의 다른 배포판에서는 직접 실행하는 것이 좋습니다:
# Ubuntu/Debian 테스트 파생 버전의 경우:
$ sudo apt install python3-pip git openjdk-8-jre python3-qtpy-pyside6
# 그런 다음 UV 사용:
$ sudo snap install --classic astral-uv
$ uv tool install pbtk
$ pbtk
# 또는 pipx 사용:
$ sudo apt install pipx
$ pipx install pbtk
$ pbtk
Windows도 지원됩니다(동일한 모듈 필요). GUI를 실행하면 수행하려는 작업에 따라 무엇이 누락되었는지 경고가 표시됩니다.
명령줄 사용법 (패키지 관리자를 통해 설치)
GUI는 메인 스크립트를 통해 실행할 수 있습니다:
pbtk
다음 스크립트는 GUI 없이 독립적으로 사용할 수도 있습니다:
pbtk-jar-extract [-h] input_file [output_dir]
pbtk-from-binary [-h] input_file [output_dir]
pbtk-web-extract [-h] input_url [output_dir] # 2026년 기준 작동하려면 업데이트 필요
snap에서 설치한 경우 정확한 명령어가 다릅니다:
pbtk.jar-extract [-h] input_file [output_dir]
pbtk.from-binary [-h] input_file [output_dir]
pbtk.web-extract [-h] input_url [output_dir]
명령줄 사용법 (로컬)
GUI는 메인 스크립트를 통해 실행할 수 있습니다:
uv sync # 의존성을 .venv 폴더에 다운로드
source .venv/bin/activate # 로컬 스크립트를 현재 셸 세션의 $PATH에 추가
uv tool install -e . # 로컬 스크립트를 항상 $PATH에 추가
pbtk
다음 스크립트는 GUI 없이 독립적으로 사용할 수도 있습니다:
pbtk-jar-extract [-h] input_file [output_dir]
pbtk-from-binary [-h] input_file [output_dir]
pbtk-web-extract [-h] input_url [output_dir] # 2026년 기준 작동하려면 업데이트 필요
일반적인 워크플로
Android 애플리케이션을 리버스 엔지니어링하고 있다고 가정해 보겠습니다. 즐겨 사용하는 디컴파일러로 애플리케이션을 조금 탐색한 결과, 일반적인 방식으로 HTTPS를 통해 POST 데이터로 Protobuf를 전송한다는 것을 알아냈습니다.
PBTK를 열면 의미 있는 방식으로 환영받습니다:

첫 번째 단계는 .proto 파일을 텍스트 형식으로 가져오는 것입니다. Android 앱을 대상으로 하는 경우 APK를 드롭하고 기다리면 마법 같은 작업이 수행됩니다! (정말 이국적인 구현이 아니라면)

이 작업이 완료되면 ~/.pbtk/protos/<your APK name>으로 이동합니다(명령줄을 통해 또는 환영 화면 하단의 버튼을 통해 파일 브라우저를 여는 등 원하는 방식으로). 앱의 모든 .proto 파일이 실제로 여기에 있습니다.
디컴파일러로 돌아가서, 관심 있는 HTTPS 엔드포인트로 전송되는 데이터를 구성하는 클래스를 발견했습니다. 이 클래스는 생성된 코드로 만들어진 클래스를 호출하여 Protobuf 메시지를 직렬화합니다.

후자의 클래스는 .proto 디렉토리 내에서 완벽하게 일치해야 합니다(예: com.foo.bar.a.b는 com/foo/bar/a/b.proto와 일치합니다). 어쨌든 이름을 grep하면 참조할 수 있습니다.
좋습니다. 다음은 2단계로 이동하여 원하는 입력 .proto를 선택하고 엔드포인트에 대한 정보를 입력하는 것입니다.

또한 이 엔드포인트로 전송된 원시 Protobuf 데이터 샘플을 제공할 수도 있습니다. mitmproxy 또는 Wireshark를 통해 캡처한 후 16진수로 인코딩된 형태로 붙여넣습니다.
3단계는 버튼을 클릭하고 결과를 확인하는 재미있는 부분입니다! Protobuf 구조의 모든 필드를 나타내는 트리 뷰가 있습니다(반복 필드는 "+" 접미사, 필수 필드는 체크박스 없음).

필드 위에 마우스를 올리면 포커스가 생깁니다. 필드가 정수형인 경우 마우스 휠을 사용하여 값을 증가/감소시킬 수 있습니다. 열거형 정보도 마우스 호버 시 나타납니다.
이것으로 끝입니다! 이를 통해 각 필드의 의미를 파악할 수 있습니다. 축소된 코드에서 .proto 파일을 추출한 경우 필드 이름을 클릭하여 의미에 따라 이름을 바꿀 수 있습니다.
즐거운 리버싱 되세요! 👌 🎉
로컬 데이터 저장소
PBTK는 추출된 .proto 정보를 ~/.pbtk/protos/ (Windows의 경우 %APPDATA%\pbtk\protos)에 저장합니다.
이 디렉토리에서 파일을 이동, 제거, 이름 변경, 편집 또는 삭제하는 것은 일반 파일 브라우저와 텍스트 편집기를 통해 직접 수행할 수 있으며, 이는 예상된 방법이며 PBTK에 영향을 주지 않습니다.
HTTP 기반 엔드포인트는 JSON 객체로 ~/.pbtk/endpoints/에 저장됩니다. 이 객체는 요청/응답 정보 쌍의 배열로, 다음과 같습니다:
[{
"request": {
"transport": "pburl",
"proto": "www.google.com/VectorTown.proto",
"url": "https://www.google.com/VectorTown",
"pb_param": "pb",
"samples": [{
"pb": "!....",
"hl": "fr"
}]
},
"response": {
"format": "other"
}
}]
소스 코드 구조
PBTK는 내부적으로 두 종류의 플러그형 모듈을 사용합니다: 추출기와 전송기입니다.
- 추출기는 대상 Protobuf 구현 또는 플랫폼에서 .proto 구조를 추출하는 것을 지원합니다.
추출기는 src/pbtk/extractors/*.py에 정의됩니다. 다음과 같이 데코레이터가 앞에 붙은 메서드로 정의됩니다:
@register_extractor(name = 'my_extractor',
desc = 'Extract Protobuf structures from Foobar code (*.foo, *.bar)',
depends={'binaries': ['foobar-decompiler']})
def my_extractor(path):
# Load contents of the `path` input file and do your stuff...
# Then, yield extracted .protos using a generator:
for i in do_your_extraction_work():
yield proto_name + '.proto', proto_contents
# Other kinds of information can be yield, such as endpoint information or progress to display.
- 전송기는 네트워크를 통해 Protobuf 데이터를 역직렬화, 재직렬화 및 전송하는 방식을 지원합니다. 예를 들어 가장 일반적으로 사용되는 전송 방식은 HTTP를 통한 원시 POST 데이터입니다.
전송기는 src/pbtk/utils/transports.py에 정의됩니다. 다음과 같이 데코레이터가 앞에 붙은 클래스로 정의됩니다:
@register_transport(
name = 'my_transport',
desc = 'Protobuf as raw POST data',
ui_data_form = 'hex strings'
)
class MyTransport():
def __init__(self, pb_param, url):
self.url = url
def serialize_sample(self, sample):
# We got a sample of input data from the user.
# Verify that it is valid in the form described through "ui_data_form" parameter, fail with an exception or return False otherwise.
# Optionally modify this data prior to returning it.
bytes.fromhex(sample)
return sample
def load_sample(self, sample, pb_msg):
# Parse input data into the provided Protobuf object.
pb_msg.ParseFromString(bytes.fromhex(sample))
def perform_request(self, pb_data, tab_data):
# Perform a request using the provided URL and Protobuf object, and optionally other transport-specific side data.
return post(url, pb_data.SerializeToString(), headers=USER_AGENT)
향후 개선 사항
다음 기능이 향후 릴리스에 추가될 수 있습니다:
- 자동 퍼징 부분 완성.
- Java 코드에서 확장 추출 지원.
- JSPB(주 JavaScript) 런타임 지원.
- 지원을 원하는 다른 플랫폼이 있으면 이슈를 남겨주시면 검토하겠습니다.
대부분의 모듈에 대해 철저히 읽기 쉽고 주석이 잘 달린 코드를 작성하려고 노력했습니다(GUI 신호 연결과 같이 대부분 자명한 부분은 제외). 기여해 주세요.
라이선스
pbtk는 GNU GPL 라이선스로 배포됩니다(여기에서, 등등).
프로젝트 이름의 대소문자에 대한 공식적인 규칙은 없습니다. 규칙은 단지 여러분의 마음을 따르는 것입니다 ❤