Rellic은 LLVM 비트 코드로부터 고토가없는 C 출력을 생성하기 위해 패턴 독립적 구조화 알고리즘의 구현이다.
이 프로젝트의 배후에있는 설계 철학은 다른 LLVM과 상호 운용성이 큰 비교적 작고 쉽게 해킹 가능한 코드베이스를 제공하는 것입니다.
| 원래 프로그램 | -emit-llvm -O0 으로 컴파일하고 컴파일된다 |
int main () {
for ( int i = 0 ; i < 30 ; ++ i ) {
if ( i % 3 == 0 && i % 5 == 0 ) {
printf ( "fizzbuzzn" );
} else if ( i % 3 == 0 ) {
printf ( "fizzn" );
} else if ( i % 5 == 0 ) {
printf ( "buzzn" );
} else {
printf ( "%dn" , i );
}
}
} | int main () {
unsigned int var0 ;
unsigned int i ;
var0 = 0U ;
i = 0U ;
while (( int ) i < 30 ) {
if (( int ) i % 3 != 0U || !(( int ) i % 5 == 0U || ( int ) i % 3 != 0U )) {
if (( int ) i % 3 != 0U ) {
if (( int ) i % 5 != 0U ) {
printf ( "%dn" , i );
} else {
printf ( "buzzn" );
}
} else {
printf ( "fizzn" );
}
} else {
printf ( "fizzbuzzn" );
}
i = i + 1U ;
}
return var0 ;
} |
int main () {
int i = 0 ;
start:
i ++ ;
switch ( i ) {
case 1 : printf ( "%dn" , i ); goto start; break ;
case 2 : printf ( "%dn" , i ); goto start; break ;
case 3 : printf ( "%dn" , i ); break ;
}
} | int main () {
unsigned int var0 ;
unsigned int i ;
var0 = 0U ;
i = 0U ;
do {
i = i + 1U ;
if (!( i != 3U && i != 2U && i != 1U ))
if ( i == 3U ) {
printf ( "%dn" , i );
break ;
} else if ( i == 2U ) {
printf ( "%dn" , i );
} else {
printf ( "%dn" , i );
}
} while (!( i != 3U && i != 2U && i != 1U ));
return var0 ;
} |
int main () {
int x = atoi ( "5" );
if ( x > 10 ) {
while ( x < 20 ) {
x = x + 1 ;
printf ( "loop1 x: %dn" , x );
}
}
while ( x < 20 ) {
x = x + 1 ;
printf ( "loop2 x: %dn" , x );
}
} | int main () {
unsigned int var0 ;
unsigned int x ;
unsigned int call2 ;
var0 = 0U ;
call2 = atoi ( "5" );
x = call2 ;
if (( int ) x > 10 ) {
while (( int ) x < 20 ) {
x = x + 1U ;
printf ( "loop1 x: %dn" , x );
}
}
if (( int ) x <= 10 || ( int ) x >= 20 ) {
while (( int ) x < 20 ) {
x = x + 1U ;
printf ( "loop2 x: %dn" , x );
}
}
if (( int ) x >= 20 && (( int ) x <= 10 || ( int ) x >= 20 )) {
return var0 ;
}
} |
c rellic-headergen 사용한 데이터 구조
rellic-xref 사용한 대화식 디 컴파일
돋보기 : 대화식 소환 실험
| 주인 | |
|---|---|
| 리눅스 |
Rellic과 함께 서류 미비 문제가 발생하면 Empire Hacking Slack의 #binary-lifting 채널에 도움을 요청하십시오.
Rellic은 Linux 플랫폼에서 지원되며 Ubuntu 22.04에서 테스트되었습니다.
Rellic의 종속성의 대부분은 CXX-Common 저장소에서 제공 할 수 있습니다. Trail of Bits는 CXX-Common의 다운로드 가능한 사전 구축 된 버전을 호스트하므로 Rellic과 함께 일어나고 실행하기가 쉽습니다. 그럼에도 불구하고, 다음 표는 대부분의 렐릭의 종속성을 나타냅니다.
| 이름 | 버전 |
|---|---|
| git | 최신 |
| cmake | 3.21+ |
| Google 플래그 | 최신 |
| Google 로그 | 최신 |
| llvm | 16 |
| 그 소리 | 16 |
| Z3 | 4.7.1+ |
사전 구축 된 Docker 이미지는 Docker Hub 및 Github 패키지 레지스트리에서 사용할 수 있습니다.
먼저, 적성을 업데이트하고 기준 종속성을 설치하십시오.
sudo apt update
sudo apt upgrade
sudo apt install
git
python3
wget
unzip
pixz
xz-utils
cmake
curl
build-essential
lsb-release
zlib1g-dev
libomp-dev
doctest-dev귀하가있는 분포에 CMAKE (3.21 이상)의 최근 릴리스가 포함되지 않으면 설치해야합니다. Ubuntu의 경우 여기 https://apt.kitware.com/을 참조하십시오.
다음 단계는 렐릭 저장소를 복제하는 것입니다.
git clone --recurse-submodules https://github.com/lifting-bits/rellic.git 마지막으로, 우리는 Rellic을 만들고 포장합니다. 이 스크립트는 현재 작업 디렉토리에 다른 디렉토리 인 rellic-build 생성합니다. Rellic이 필요로하는 모든 나머지 의존성은 lifting-bits-downloads 에서 Repo Checkout과 함께 학부모 디렉토리에 다운로드하여 배치됩니다 (자세한 내용은 스크립트의 -h 옵션 참조). 이 스크립트는 설치 가능한 Deb, RPM 및 TGZ 패키지를 만듭니다.
cd rellic
./scripts/build.sh --llvm-version 16
# to install the deb package, then do:
sudo dpkg -i rellic-build/ * .debRellic을 시험해 보려면 선택한 LLVM 비트 코드 파일이 주어지면 다음을 수행 할 수 있습니다.
# Create some sample bitcode or your own
clang-16 -emit-llvm -c ./tests/tools/decomp/issue_4.c -o ./tests/tools/decomp/issue_4.bc
./rellic-build/tools/rellic-decomp --input ./tests/tools/decomp/issue_4.bc --output /dev/stdoutLLVM 16 용 CXX-Common의 최신 릴리스를 확인하십시오.
cmake
-DCMAKE_BUILD_TYPE=RelWithDebInfo
-DCMAKE_TOOLCHAIN_FILE=/path/to/vcpkg/scripts/buildsystems/vcpkg.cmake
-DVCPKG_TARGET_TRIPLET=x64-osx-rel
-DRELLIC_ENABLE_TESTING=OFF
-DCMAKE_C_COMPILER= ` which clang `
-DCMAKE_CXX_COMPILER= ` which clang++ `
/path/to/rellic
make -j8Docker 이미지는 Rellic을 설정, 빌드 및 실행할 수있는 환경을 제공해야합니다. Docker 이미지는 Ubuntu Verison, LLVM 버전 및 아키텍처에 의해 매개 변수화됩니다.
Ubuntu 22.04 용 LLVM 16을 사용하여 Docker 이미지를 작성하려면 다음 명령을 실행할 수 있습니다.
UBUNTU=22.04 ; LLVM=16 ; docker build .
-t rellic:llvm ${LLVM} -ubuntu ${UBUNTU}
-f Dockerfile
--build-arg UBUNTU_VERSION= ${UBUNTU}
--build-arg LLVM_VERSION= ${LLVM}디 컴파일러를 실행하려면 EntryPoint가 이미 설정되었지만 디 컴파일하는 비트 코드가 디 컴파일러와 동일한 LLVM 버전인지 확인하고 실행하십시오.
# Get the bc file
clang-16 -emit-llvm -c ./tests/tools/decomp/issue_4.c -o ./tests/tools/decomp/issue_4.bc
# Decompile
docker run --rm -t -i
-v $( pwd ) :/test -w /test
-u $( id -u ) : $( id -g )
rellic:llvm16-ubuntu22.04 --input ./tests/tools/decomp/issue_4.bc --output /dev/stdout위의 명령을 더 설명하려면 :
# Mount current directory and change working directory
-v $( pwd ) :/test -w /test그리고
# Set the user to current user to ensure correct permissions
-u $( id -u ) : $( id -g ) 우리는 여러 통합 및 단위 테스트를 사용하여 Rellic을 테스트합니다.
라운드 트립 테스트는 C 코드를 사용하여 LLVM IR로 빌드 한 다음 해당 IR을 C로 다시 변환합니다. 테스트는 결과 C를 빌드 할 수 있는지 여부와 번역 된 코드가 원본과 동일한 일을하는지 확인합니다. 이것들을 실행하려면 사용하십시오.
cd rellic-build # or your rellic build directory
CTEST_OUTPUT_ON_FAILURE=1 cmake --build . --verbose --target test Anghabench 1000은 Anghabench와 함께 제공되는 전체 백만 개의 프로그램에서 1000 개의 파일 (x 4 아키텍처, 총 4000 개의 테스트)의 샘플입니다. 이 테스트는 이러한 프로그램의 비트 코드가 결과 번역의 예쁘게 또는 기능이 아니라 C로 변환되는지 여부 만 확인합니다. 이 테스트를 실행하려면 먼저 scripts/requirements.txt 에 필요한 필수 파이썬 종속성을 설치 한 다음 실행하십시오.
scripts/test-angha-1k.sh --rellic-cmd < path_to_rellic_decompiler_exe > 다음 Bibtex 스 니펫을 사용하여 Rellic을 인용하십시오.
@online{rellic,
title={Rellic},
author={Surovič, Marek and Bertolaccini, Francesco},
organization={Trail of Bits},
url={https://github.com/lifting-bits/rellic}
}