Rellic es una implementación del algoritmo de estructuración independiente del patrón para producir una salida C sin GOTO a partir del código de bits LLVM.
La filosofía de diseño detrás del proyecto es proporcionar una base de código relativamente pequeña y fácilmente pirateable con una gran interoperabilidad con otros proyectos LLVM y Remill.
| Programa original | Compilado con -emit-llvm -O0 y descompilado |
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 sus estructuras de datos con rellic-headergen
Descompilación interactiva con rellic-xref
Magnificador: un experimento con descompilación interactiva
| maestro | |
|---|---|
| Linux |
Si está experimentando problemas indocumentados con Rellic, solicite ayuda en el canal #binary-lifting de Empire Hacking Slack.
Rellic es compatible con las plataformas Linux y se ha probado en Ubuntu 22.04.
La mayoría de las dependencias de Rellic pueden ser proporcionadas por el repositorio de CXX-Common. Trail of Bits alberga versiones descargables de CXX-Common, lo que hace que sea sustancialmente más fácil ponerse en funcionamiento con Rellic. No obstante, la siguiente tabla representa la mayoría de las dependencias de Rellic.
| Nombre | Versión |
|---|---|
| Git | El último |
| CMake | 3.21+ |
| Banderas de Google | El último |
| Registro de Google | El último |
| LLVM | 16 |
| Sonido metálico | 16 |
| Z3 | 4.7.1+ |
Las imágenes de Docker pre-construidas están disponibles en Docker Hub y el Registro de paquetes GitHub.
Primero, actualice la aptitud y obtenga instalar las dependencias de línea de base.
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-devSi la distribución en la que se encuentra no incluye una versión reciente de CMake (3.21 o posterior), deberá instalarla. Para Ubuntu, vea aquí https://apt.kitware.com/.
El siguiente paso es clonar el repositorio rélico.
git clone --recurse-submodules https://github.com/lifting-bits/rellic.git Finalmente, construimos y empaquetamos Rellic. Este script creará otro directorio, rellic-build , en el directorio de trabajo actual. Todas las dependencias restantes necesarias por Rellic se descargarán y se colocarán en el directorio principal junto con el pago de repo en lifting-bits-downloads (consulte la opción de script -h para obtener más detalles). Este script también crea paquetes de DEB, RPM y TGZ instalables.
cd rellic
./scripts/build.sh --llvm-version 16
# to install the deb package, then do:
sudo dpkg -i rellic-build/ * .debPara probar Rellic, puede hacer lo siguiente, dado un archivo de código de bits LLVM de su elección.
# 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/stdoutAsegúrese de tener el último lanzamiento de CXX-Common para LLVM 16. Luego, construya con
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 -j8La imagen Docker debe proporcionar un entorno que pueda configurar, construir y ejecutar Rellic. Las imágenes de Docker son parametrizadas por Ubuntu Verison, versión LLVM y arquitectura.
Para construir la imagen Docker usando LLVM 16 para Ubuntu 22.04, puede ejecutar el siguiente comando:
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}Para ejecutar el descompilador, el punto de entrada ya se ha establecido, pero asegúrese de que el código de bits que está descompilando sea la misma versión LLVM que el descompilador, y ejecute:
# 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/stdoutPara explicar más el comando anterior:
# Mount current directory and change working directory
-v $( pwd ) :/test -w /testy
# Set the user to current user to ensure correct permissions
-u $( id -u ) : $( id -g ) Utilizamos varias pruebas de integración y unidad para probar Rellic.
Las pruebas de ida y vuelta tomarán el código C, lo construirán para LLVM IR y luego traducirán esa IR de regreso a C. La prueba luego ve si la C resultante se puede construir y si el código traducido hace (aproximadamente) lo mismo que el original. Para ejecutarlos, use:
cd rellic-build # or your rellic build directory
CTEST_OUTPUT_ON_FAILURE=1 cmake --build . --verbose --target test Anghabench 1000 es una muestra de 1000 archivos (arquitecturas x 4, por lo que un total de 4000 pruebas) de los millones completos de programas que vienen con Anghabench. Esta prueba solo verifica si el código de bits para estos programas se traduce en C, no en la belleza o la funcionalidad de la traducción resultante. Para ejecutar esta prueba, primero instale las dependencias de Python requeridas que se encuentran en scripts/requirements.txt y luego ejecute:
scripts/test-angha-1k.sh --rellic-cmd < path_to_rellic_decompiler_exe > Utilice el siguiente fragmento de bibtex para citar rellic:
@online{rellic,
title={Rellic},
author={Surovič, Marek and Bertolaccini, Francesco},
organization={Trail of Bits},
url={https://github.com/lifting-bits/rellic}
}