Q : 또 다른 디컴파일러, 특히 손상된 디컴파일러가 필요한 이유는 무엇입니까?
A : 슬픈 사실은 시중에 나와 있는 대부분의 디컴파일러가 제대로 작동하지 않는다는 것입니다. 많은 사람들은 사소한 구조를 디컴파일할 수 없고, 다른 사람들은 더 고급 구조를 디컴파일할 수 없으며, 겉보기에 이를 처리할 수 있는 것처럼 보이는 것들은 지루한 아키텍처와 OS만 지원하므로 불구가 됩니다. 그리고 거의 모든 내용을 수정하거나 새 아키텍처를 추가하는 방식으로 작성하는 것은 복잡합니다. 디컴파일러는 리버스 엔지니어링을 위한 도구이지만, 아이러니하게도 일반적인 디컴파일러를 생산적으로 사용하거나 필요에 맞게 만들려면 먼저 디컴파일러 자체를 리버스 엔지니어링해야 하며 이는 쉽게 몇 달(또는 몇 년)이 걸릴 수 있습니다. .
디컴파일러(및 모든 프로그램 변환 프레임워크)의 핵심 부분은 중간 표현(IR)입니다. 디컴파일러는 IR에서 작동해야 하며 이를 입력으로 받아들여야 하며, 특정 아키텍처의 어셈블러를 이 IR로 변환하는 것은 디컴파일러에서 잘 분리되어야 합니다. 그렇지 않으면 다른 아키텍처에 대한 지원을 추가하는 데 엄청난 노력이 필요합니다(결과적으로 제한됨). 디컴파일러의 사용자 기반).
디컴파일은 복잡한 작업이므로 디컴파일 프로세스를 쉽게 이해할 수 있어야 합니다. 이는 디컴파일러에서 사용하는 IR이 인간 친화적이어야 함을 의미합니다. 예를 들어 프로그래머에게 친숙한 구문을 사용하고 가능한 한 일반적인 기계 어셈블러에 직접 매핑해야 합니다.
위의 요구 사항은 그 자체로 매우 명확해야 합니다. 그렇지 않은 경우 해당 문제에 관한 책에서 배울 수 있습니다. 예:
"컴파일러 작성자에게는 인간이 IR 프로그램을 쉽고 직접적으로 검사할 수 있게 해주는 메커니즘도 필요합니다. 사리사욕을 고려하여 컴파일러 작성자는 이 마지막 사항에 주의를 기울여야 합니다."
(Keith Cooper, Linda Torczon, "컴파일러 엔지니어링")
그러나 OpenSource 프로젝트를 포함한 디컴파일러 프로젝트는 일상적으로 이러한 요구 사항을 위반합니다. 특정 시스템 아키텍처와 긴밀하게 연결되어 있고 IR 공급을 허용하지 않으며 사용자에게 전혀 노출하거나 문서화하지 않는 경우가 많습니다.
ScratchABlock은 이러한 관행에 "아니오"라고 말하고 위의 요구 사항을 기반으로 디컴파일 프레임워크를 개발하려는 시도입니다. ScratchABlock은 학습/연구 프로젝트로 간주될 수 있으며, 다른 프로젝트에 대한 좋은 의도와 비판을 넘어 현재 또는 전혀 일반 사용자에게 너무 많은 것을 제공하지 않을 수 있습니다. 물론 여러 측면에서 비판을 받을 수도 있다.
ScratchABlock은 GNU General Public License v3(GPLv3)의 조건에 따라 출시됩니다.
ScratchABlock은 Python3 언어로 작성되었으며 버전 3.3 이상에서 테스트되었지만 3.2 이하에서도 작동할 수 있습니다(레거시 Python2 버전에서는 작동하지 않음). 몇 가지 종속성이 있습니다.
Debian/Ubuntu Linux에서는 sudo apt-get install python3-yaml python3-nose
사용하여 설치할 수 있습니다. 또는 Python의 자체 pip
패키지 관리자(모든 OS에서 작동함)를 통해 이를 설치할 수 있습니다: pip3 install -r requirements.txt
.
ScratchABlock은 PseudoC 어셈블러를 IR로 사용합니다. 익숙한 C언어 문법을 최대한 활용하여 표현한 어셈블러 언어입니다. C 프로그래머라면 누구나 직관적으로 이해할 수 있을 것이라는 생각이지만(예제), PseudoC를 보다 공식적으로 문서화하려는 지속적인 노력이 있습니다.
문서의 이전 섹션에 설명된 요구 사항을 기반으로 하고 잘 알려진 "Unix 패러다임"에 따라 ScratchABlock은 "한 가지", 즉 PseudoC 프로그램에 대한 분석 및 변환을 수행하며 특정 아키텍처의 기계 명령어 변환과 명시적으로 관련되지 않습니다 . PseudoC로 변환합니다(적어도 지금은). 이는 ScratchABlock이 특정 변환기/리프터를 사용하도록 강요하지 않는다는 것을 의미합니다. 원하는 것을 사용할 수 있습니다. 주의 사항: 사용하려면 하나가 필요합니다. 이에 관한 몇 가지 힌트는 문서의 끝부분을 참조하세요.
소스 코드와 인터페이스 스크립트는 저장소의 루트에 있습니다. 가장 중요한 스크립트는 다음과 같습니다.
apply_xform.py
- 중앙 드라이버로 단일 파일이나 파일 디렉터리("프로젝트 디렉터리")에 일련의 변환(또는 일반적으로 고급 분석/변환 스크립트)을 적용할 수 있습니다.
inter_dataflow.py
- 프로시저 간(글로벌) 데이터 흐름 분석 드라이버(WIP)입니다.
script_*.py
- apply_xform.py
에 대한 상위 수준 분석/변환 스크립트( --script
스위치).
script_i_*.py
- inter_dataflow.py
에 대한 분석 스크립트입니다.
run_tests
- 회귀 테스트 스위트 실행기입니다. 대부분의 테스트 모음은 파일에 대해 서로 다른 패스를 사용하여 apply_xform.py를 실행하고 예상 결과를 확인하는 상위 수준입니다.
저장소의 다른 하위 디렉터리:
tests_unit
- Python으로 작성된 Python 모듈에 대한 고전적인 단위 테스트입니다.
tests
- 주요 테스트 모음입니다. 본질적으로 통합적이지만 일반적으로 하나의 간단한 파일에 대해 하나의 패스를 테스트하므로 단위 테스트 철학을 따릅니다. 테스트는 PseudoC 입력 파일로 표시되는 반면 예상 결과는 기본 블록 주석이 있는 PseudoC 및 (해당되는 경우) .dot 형식의 CFG로 표시됩니다. 이러한 테스트 사례를 보고 수정해 보고 결과를 확인하는 것이 ScratchABlock의 작동 방식을 배우는 가장 좋은 방법입니다.
docs
- 점점 늘어나는 문서 모음입니다. 예를 들어 ScratchABlock의 중간 표현(IR) 역할을 하는 PseudoC 어셈블러 언어 사양과 다른 기존 IR이 선택되지 않은 이유에 대한 설문 조사가 있습니다.
ScratchABlock의 현재 접근 방식은 프로그램 분석 및 변환을 위해 상대적으로 느슨하게 결합된 알고리즘("패스") 컬렉션을 확장하고 테스트를 통해 사용자가 쉽게 액세스할 수 있도록 하는 것입니다. 디컴파일의 마법은 이러한 알고리즘을 올바른 순서와 올바른 횟수로 적용하는 것으로 구성됩니다. 그런 다음 디컴파일 성능을 향상시키기 위해 이러한 패스에는 일반적으로 더 긴밀한 결합이 필요합니다. 위에서 설명한 대로 패스 인벤토리를 구현한 후 이러한 방향을 탐색하는 것이 다음 우선순위입니다.
ScratchABlock으로 구현된 알고리즘 및 변환:
그래프 알고리즘:
정적 단일 할당 양식(SSA):
데이터 흐름 분석:
번식:
데드 코드 제거(DCE)
재작성:
제어 흐름 구조화:
출력 형식:
ScratchABlock의 파트너 도구는 ScratchABit입니다. 이는 데이터에서 코드 분리 및 기능 경계 식별과 같은 디컴파일 프로세스의 가장 낮은 수준 작업을 수행하기 위한 대화형 역어셈블러입니다. ScratchABit은 일반적으로 기본 아키텍처 어셈블러 구문으로 작동하지만 일부 아키텍처(일반적으로 충실한 RISC)의 경우 적합한 플러그인을 사용할 수 있는 경우 ScratchABlock에 대한 입력 역할을 할 수 있는 PseudoC 구문을 출력할 수 있습니다.