Repository: h311d1n3r/Cerberus
Branch: main
Commit: c31cdc500321
Files: 76
Total size: 126.2 KB
Directory structure:
gitextract_wdal68gi/
├── .dockerignore
├── .github/
│ └── workflows/
│ └── main.yml
├── .gitignore
├── .gitmodules
├── CMakeLists.txt
├── LICENSE
├── README.md
├── docker/
│ ├── debian/
│ │ └── Dockerfile-10
│ ├── fedora/
│ │ └── Dockerfile-37
│ └── ubuntu/
│ ├── Dockerfile-20.04
│ └── Dockerfile-22.04
├── src/
│ ├── algorithm/
│ │ ├── algorithm.h
│ │ ├── part_hash_algorithm.cpp
│ │ └── part_hash_algorithm.h
│ ├── binaries/
│ │ ├── bin_extractor.h
│ │ ├── bin_handler.cpp
│ │ ├── bin_handler.h
│ │ ├── bin_identifier.cpp
│ │ ├── bin_identifier.h
│ │ ├── bin_types.h
│ │ ├── extractors/
│ │ │ ├── go_extractor.cpp
│ │ │ ├── go_extractor.h
│ │ │ ├── libelf_extractor.cpp
│ │ │ ├── libelf_extractor.h
│ │ │ ├── lief_extractor.cpp
│ │ │ ├── lief_extractor.h
│ │ │ ├── radare_extractor.cpp
│ │ │ └── radare_extractor.h
│ │ ├── handlers/
│ │ │ ├── elf_handler.cpp
│ │ │ ├── elf_handler.h
│ │ │ ├── pe_handler.cpp
│ │ │ └── pe_handler.h
│ │ ├── lib/
│ │ │ ├── install/
│ │ │ │ ├── go_lib_installer.cpp
│ │ │ │ ├── go_lib_installer.h
│ │ │ │ ├── lib_installer.h
│ │ │ │ ├── rust_lib_installer.cpp
│ │ │ │ └── rust_lib_installer.h
│ │ │ ├── lib_manager.cpp
│ │ │ └── lib_manager.h
│ │ └── pe_types.h
│ ├── command/
│ │ ├── command_executor.cpp
│ │ └── command_executor.h
│ ├── global_defs.h
│ ├── langs/
│ │ ├── lang_manager.cpp
│ │ ├── lang_manager.h
│ │ ├── lang_types.h
│ │ ├── lib_regex.cpp
│ │ └── lib_regex.h
│ ├── main.cpp
│ ├── types/
│ │ └── value_ordered_map.h
│ ├── user/
│ │ ├── dependencies/
│ │ │ ├── dependency_manager.cpp
│ │ │ └── dependency_manager.h
│ │ ├── local_config.cpp
│ │ ├── local_config.h
│ │ ├── user_prompt.cpp
│ │ └── user_prompt.h
│ └── utils/
│ ├── arg_parser.cpp
│ ├── arg_parser.h
│ ├── config.h
│ ├── convert.cpp
│ ├── convert.h
│ ├── file_downloader.cpp
│ ├── file_downloader.h
│ ├── file_operations.cpp
│ ├── file_operations.h
│ ├── logger.cpp
│ ├── logger.h
│ ├── search.cpp
│ └── search.h
└── test/
├── Go/
│ └── test_1/
│ ├── result.txt
│ └── src/
│ ├── go.mod
│ ├── go.sum
│ └── test_1.go
└── Rust/
└── test_1/
├── Cargo.toml
├── result.txt
└── src/
└── main.rs
================================================
FILE CONTENTS
================================================
================================================
FILE: .dockerignore
================================================
cmake-build*/
.cerberus*/
build/
.idea/
radare2/
Goliath/
================================================
FILE: .github/workflows/main.yml
================================================
name: main
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
workflow_dispatch:
jobs:
check_app:
runs-on: ubuntu-22.04
steps:
- name: clone_project
uses: actions/checkout@v3
- name: init_submodules
run: git submodule update --init --recursive
- name: apt_dependencies
run: sudo apt update && sudo apt upgrade && sudo apt -y install libarchive-dev libcurl4-openssl-dev zlib1g-dev libelf-dev gcc-multilib g++-multilib make cmake
- name: setup_radare2
run: |
git clone https://github.com/radare/radare2.git
cd radare2
./sys/install.sh
- name: setup_rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: setup_go
uses: actions/setup-go@v4
with:
go-version: '>=1.15.0'
- name: setup_python
uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: compile
run: mkdir build && cd build && cmake .. && make
- name: append_path
run: echo "`pwd`/build" >> $GITHUB_PATH
- name: compile_rust_tests
run: |
echo "Installing Rust 32-bit architecture"
rustup target install i686-unknown-linux-gnu
echo "Compiling Rust tests"
for i in $(seq 1 1 `ls ./test/Rust | wc -l`)
do
echo "Compiling Rust test n°$i"
cd test/Rust/test_$i
cargo build --release
cargo build --release --target=i686-unknown-linux-gnu
cd ../../..
done
- name: run_rust_tests_32
run: |
echo "Running Rust 32bit tests"
for i in $(seq 1 1 `ls ./test/Rust | wc -l`)
do
echo "Starting Rust test n°$i"
cd test/Rust/test_$i/target/i686-unknown-linux-gnu/release
cerberus ./test_$i --no-prompt -output ./test_$i-syms
result=$(nm test_$i-syms)
cd ../../..
expected_result=$(cat 'result.txt')
IFS='\n' read -ra expected_result_arr <<< $expected_result
for expected_result_line in ${expected_result_arr[@]};
do
if [[ $result != *$expected_result_line* ]]
then
echo "Failure !"
echo "Content of result :"
echo $result
exit 1
fi
done
echo "Success !"
cd ../../../
done
- name: run_rust_tests_64
run: |
echo "Running Rust 64bit tests"
for i in $(seq 1 1 `ls ./test/Rust | wc -l`)
do
echo "Starting Rust test n°$i"
cd test/Rust/test_$i/target/release
cerberus ./test_$i --no-prompt -output ./test_$i-syms
result=$(nm test_$i-syms)
cd ../..
expected_result=$(cat 'result.txt')
IFS='\n' read -ra expected_result_arr <<< $expected_result
for expected_result_line in ${expected_result_arr[@]};
do
if [[ $result != *$expected_result_line* ]]
then
echo "Failure !"
echo "Content of result :"
echo $result
exit 1
fi
done
echo "Success !"
cd ../../../
done
- name: compile_go_tests
run: |
for i in $(seq 1 1 `ls ./test/Go | wc -l`)
do
echo "Compiling Go test n°$i"
cd test/Go/test_$i/src
go get ./...
go build -ldflags="-s -w" -o ../test_1 test_1.go
cd ../../../..
done
- name: run_go_tests
run: |
echo "Running Go tests"
for i in $(seq 1 1 `ls ./test/Go | wc -l`)
do
echo "Starting Go test n°$i"
cd test/Go/test_1
cerberus ./test_$i --no-prompt -output ./test_$i-syms
result=$(nm test_$i-syms)
expected_result=$(cat 'result.txt')
IFS='\n' read -ra expected_result_arr <<< $expected_result
for expected_result_line in ${expected_result_arr[@]};
do
if [[ $result != *$expected_result_line* ]]
then
echo "Failure !"
echo "Content of result :"
echo $result
exit 1
fi
done
echo "Success !"
cd ../../../
done
================================================
FILE: .gitignore
================================================
cmake-build*/
.cerberus*/
build/
.idea/
radare2/
Goliath/
lab/
================================================
FILE: .gitmodules
================================================
[submodule "lib/Goliath"]
path = lib/Goliath
url = https://github.com/h311d1n3r/Goliath
[submodule "lib/argparse"]
path = lib/argparse
url = https://github.com/p-ranav/argparse
[submodule "lib/lief"]
path = lib/lief
url = https://github.com/lief-project/LIEF
[submodule "lib/gzip-hpp"]
path = lib/gzip-hpp
url = https://github.com/mapbox/gzip-hpp
================================================
FILE: CMakeLists.txt
================================================
cmake_minimum_required(VERSION 3.22)
project(Cerberus)
set(CMAKE_CXX_STANDARD 17)
find_path(libelf.h NAMES LIBELF)
# will be included statically
add_subdirectory(lib/lief)
add_subdirectory(lib/argparse)
# will be included dynamically
find_package(CURL REQUIRED)
find_package(ZLIB REQUIRED)
find_package(LibArchive REQUIRED)
include_directories(lib/argparse/include lib/lief/include lib/gzip-hpp/include ${LIBELF} src)
add_executable(Cerberus src/main.cpp src/utils/logger.h src/utils/logger.cpp src/utils/arg_parser.h src/utils/config.h src/utils/arg_parser.cpp src/global_defs.h src/langs/lang_manager.h src/langs/lang_manager.cpp src/types/value_ordered_map.h src/binaries/bin_identifier.cpp src/user/user_prompt.cpp src/utils/convert.h src/binaries/bin_handler.h src/binaries/handlers/elf_handler.h src/binaries/handlers/elf_handler.cpp src/binaries/bin_extractor.h src/binaries/bin_types.h src/binaries/extractors/lief_extractor.h src/binaries/extractors/lief_extractor.cpp src/binaries/extractors/radare_extractor.h src/binaries/extractors/radare_extractor.cpp src/binaries/handlers/pe_handler.h src/binaries/handlers/pe_handler.cpp src/binaries/bin_handler.cpp src/langs/lib_regex.h src/utils/search.h src/utils/search.cpp src/langs/lang_types.h src/langs/lib_regex.cpp src/utils/convert.cpp src/binaries/lib/lib_manager.h src/binaries/lib/lib_manager.cpp src/binaries/lib/install/lib_installer.h src/binaries/lib/install/rust_lib_installer.h src/binaries/lib/install/go_lib_installer.h src/binaries/lib/install/rust_lib_installer.cpp src/binaries/lib/install/go_lib_installer.cpp src/utils/file_downloader.h src/utils/file_downloader.cpp src/utils/file_operations.h src/utils/file_operations.cpp src/user/dependencies/dependency_manager.h src/command/command_executor.h src/command/command_executor.cpp src/user/local_config.h src/user/local_config.cpp src/user/dependencies/dependency_manager.cpp src/algorithm/part_hash_algorithm.h src/algorithm/part_hash_algorithm.cpp src/algorithm/algorithm.h src/binaries/extractors/libelf_extractor.h src/binaries/extractors/libelf_extractor.cpp src/binaries/pe_types.h src/binaries/extractors/go_extractor.h src/binaries/extractors/go_extractor.cpp)
target_link_libraries(Cerberus PRIVATE argparse PRIVATE LIEF::LIEF PRIVATE CURL::libcurl PRIVATE ZLIB::ZLIB PRIVATE LibArchive::LibArchive PRIVATE uuid PRIVATE elf PRIVATE stdc++fs)
set_target_properties(Cerberus PROPERTIES OUTPUT_NAME cerberus)
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2021 Aurélien Tournebise
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# Cerberus
## Description
### A C++ tool to unstrip Rust and Go binaries (ELF and PE)
**Cerberus** is the tool you want to use to make RUST and GO static analysis a lot easier.
Based on hashing and scoring systems, it can retrieve lots of symbol names.
## How does it work ?
After analyzing your ELF/PE binary to find the used libraries, **Cerberus** will download and build them.
Then the tool will hash (in various ways) the functions in your file and in the libraries to make matches.
## Table of contents
[Installation](#install)
[Download a release](#install_release)
[Build the tool with Docker](#install_build_docker)
[Build the tool on host](#install_build_host)
[How to use ?](#how)
[Syntax](#how_syntax)
[Parameters](#how_params)
[Flags](#how_flags)
[Example](#how_example)
[Warning](#warning)
## Installation
### Download a release
Check the [Releases](https://github.com/h311d1n3r/Cerberus/releases/) tab on the Github project and download the latest one.
### Build the tool with Docker
1. Clone the repository `git clone https://github.com/h311d1n3r/Cerberus && cd Cerberus`.
2. Initialize git dependencies : `git submodule update --init`
3. Check the available Dockerfiles under `Cerberus/docker/{OS}`.
4. Build the docker image of your choice `docker build -f ./docker/{OS}/Dockerfile-{version} .`.
5. You can run **Cerberus** from inside the docker or extract the binary on your host. This second choice needs to install the libraries listed in [this section](#install_build_host).
### Build the tool on host
1. You need to have **libarchive**, **libcurl4-openssl**, **zlib1g**, **libelf** and the **uuid-dev** libraries installed on your system.
With APT just do `apt -y install libarchive-dev libcurl4-openssl-dev zlib1g-dev libelf-dev`
2. Clone the repository `git clone https://github.com/h311d1n3r/Cerberus && cd Cerberus`.
3. Initialize git dependencies : `git submodule update --init`
4. Create the build directory `mkdir build && cd build`.
5. Run CMake to configure the project `cmake ..`.
6. Run make to compile the project `make`.
## How to use ?
### Syntax
`cerberus binary [-param value] [--flag]`
### Parameters
`output` -> Specifies the path for the resulting ELF file.
`part_hash_len` -> Specifies the length of a `part hash`. The `part hash` of a function is just a reduction of the function with a linear pace.
This technique is used to prevent fixed addresses from corrupting a standard hash. Default value : 20
`part_hash_trust` -> Specifies minimum ratio of similarity between the two hashed functions to compare. The kept function will be the one with the most matches anyway.
Increasing this value will reduce the number of matched functions but speed up execution time. Default value : 0.6
`min_func_size` -> The minimum length a function must be to get analyzed. Decreasing this value will increase matches but also false positives. Default value : 10
### Flags
`help` -> Displays a help message.
`debug` -> Displays outputs of commands.
`no-prompt` -> Automatically skips user prompts.
### Example
#### Command
The following command will try to unstrip the file ./rust_example into a new ELF called ./rust_example_syms.
`cerberus ./rust_example -output ./rust_example_syms`
#### Result
Here is a comparison of the main function in the two files using Binary Ninja :
## Warning
**This software must only be used to carry out lawful experiments and I am not responsible for any breach of this rule !**
================================================
FILE: docker/debian/Dockerfile-10
================================================
FROM debian:10
WORKDIR /root
RUN apt -y update
RUN apt -y upgrade
RUN apt -y install g++ gcc make tar wget
RUN apt -y install libarchive-dev libcurl4-openssl-dev libssl-dev zlib1g-dev libelf-dev uuid-dev
RUN wget https://github.com/Kitware/CMake/releases/download/v3.27.5/cmake-3.27.5.tar.gz
RUN tar -xzf cmake-3.27.5.tar.gz
WORKDIR cmake-3.27.5
RUN ./bootstrap
RUN make
RUN make install
WORKDIR ..
RUN mkdir -p Cerberus
WORKDIR Cerberus
ADD ./ ./
RUN mkdir -p build
WORKDIR build
RUN cmake ..
RUN make
================================================
FILE: docker/fedora/Dockerfile-37
================================================
FROM fedora:37
WORKDIR /root
RUN dnf -y update
RUN dnf -y upgrade
RUN dnf -y install g++ gcc make cmake
RUN dnf -y install libarchive-devel libcurl-devel zlib-devel elfutils-libelf-devel libuuid-devel
RUN mkdir -p Cerberus
WORKDIR Cerberus
ADD ./ ./
RUN mkdir -p build
WORKDIR build
RUN cmake ..
RUN make
================================================
FILE: docker/ubuntu/Dockerfile-20.04
================================================
FROM ubuntu:20.04
WORKDIR /root
RUN apt -y update
RUN apt -y upgrade
RUN apt -y install g++ gcc make tar wget
RUN apt -y install libarchive-dev libcurl4-openssl-dev libssl-dev zlib1g-dev libelf-dev uuid-dev
RUN wget https://github.com/Kitware/CMake/releases/download/v3.27.5/cmake-3.27.5.tar.gz
RUN tar -xzf cmake-3.27.5.tar.gz
WORKDIR cmake-3.27.5
RUN ./bootstrap
RUN make
RUN make install
WORKDIR ..
RUN mkdir -p Cerberus
WORKDIR Cerberus
ADD ./ ./
RUN mkdir -p build
WORKDIR build
RUN cmake ..
RUN make
================================================
FILE: docker/ubuntu/Dockerfile-22.04
================================================
FROM ubuntu:22.04
WORKDIR /root
RUN apt -y update
RUN apt -y upgrade
RUN apt -y install g++ gcc make cmake
RUN apt -y install libarchive-dev libcurl4-openssl-dev zlib1g-dev libelf-dev uuid-dev
RUN mkdir -p Cerberus
WORKDIR Cerberus
ADD ./ ./
RUN mkdir -p build
WORKDIR build
RUN cmake ..
RUN make
================================================
FILE: src/algorithm/algorithm.h
================================================
#ifndef CERBERUS_ALGORITHM_H
#define CERBERUS_ALGORITHM_H
#include
#include
#include
#include
#include
class Algorithm {
protected:
std::ifstream* bin_file;
CONFIG* config;
public:
Algorithm(CONFIG* config) : config(config) {
bin_file = new std::ifstream(config->binary_path, std::ios::binary);
}
~Algorithm() {
bin_file->close();
}
virtual void process_binary(std::vector>* bin_funcs) = 0;
virtual void process_lib(std::string lib_path, std::vector>* lib_funcs) = 0;
virtual void post_process(std::vector>* bin_funcs) = 0;
};
#endif //CERBERUS_ALGORITHM_H
================================================
FILE: src/algorithm/part_hash_algorithm.cpp
================================================
#include
#include
using namespace std;
void PartHashAlgorithm::compute_part_hash(unique_ptr& func, ifstream* file) {
char data[func->end - func->start + 1];
file->seekg(func->start);
file->read(data, sizeof(data));
float pace = sizeof(data) / (float)config->part_hash_len;
if(pace == 0) pace = 1;
func->hash = "";
for(float i = 0; i < sizeof(data); i+=pace) {
func->hash += data[(uint32_t)i];
}
for(uint8_t i = func->hash.size(); i < config->part_hash_len; i++) func->hash+='\x00';
func->hash = func->hash.substr(0, config->part_hash_len);
}
float PartHashAlgorithm::compare_part_hashes(string hash1, string hash2) {
uint8_t score = 0;
for(uint8_t i = 0; i < hash1.size(); i++) {
if(hash1.at(i) == hash2.at(i)) score++;
}
return score / (float) config->part_hash_len;
}
void PartHashAlgorithm::process_binary(vector>* bin_funcs) {
for(unique_ptr& func : *bin_funcs) {
func->name = "";
if(func->end - func->start + 1 >= config->min_func_size) this->compute_part_hash(func, bin_file);
funcs_by_sz[func->end - func->start + 1].push_back(move(func));
}
}
void PartHashAlgorithm::process_lib(string lib_path, vector>* lib_funcs) {
ifstream lib_file(lib_path, ios::binary);
for (unique_ptr& lib_func : *lib_funcs) {
if(!lib_func->name.size()) continue;
size_t lib_func_sz = lib_func->end - lib_func->start + 1;
if(lib_func_sz < config->min_func_size) continue;
for(unique_ptr& func : funcs_by_sz[lib_func_sz]) {
this->compute_part_hash(lib_func, &lib_file);
float score = compare_part_hashes(lib_func->hash, func->hash);
if (score >= config->part_hash_trust) {
if(func->score < score) {
func->name = lib_func->name;
func->score = score;
}
}
}
}
lib_file.close();
}
void PartHashAlgorithm::post_process(vector>* bin_funcs) {
bin_funcs->clear();
for(auto& f_pair : funcs_by_sz) {
for(unique_ptr& f : f_pair.second) bin_funcs->push_back(move(f));
}
}
================================================
FILE: src/algorithm/part_hash_algorithm.h
================================================
#ifndef CERBERUS_PART_HASH_ALGORITHM_H
#define CERBERUS_PART_HASH_ALGORITHM_H
#include
#include