Full Code of h311d1n3r/Cerberus for AI

main c31cdc500321 cached
76 files
126.2 KB
34.9k tokens
88 symbols
1 requests
Download .txt
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)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[Download a release](#install_release)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[Build the tool with Docker](#install_build_docker)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[Build the tool on host](#install_build_host)  
[How to use ?](#how)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[Syntax](#how_syntax)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[Parameters](#how_params)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[Flags](#how_flags)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[Example](#how_example)  
[Warning](#warning)  

<a name="install"/>

## Installation

<a name="install_release"/>

### Download a release
Check the [Releases](https://github.com/h311d1n3r/Cerberus/releases/) tab on the Github project and download the latest one.  

<a name="install_build_docker"/>

### 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).  

<a name="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`.  

<a name="how"/>

## How to use ?

<a name="how_syntax"/>

### Syntax
`cerberus binary [-param value] [--flag]`

<a name="how_params"/>

### 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  

<a name="how_flags"/>

### Flags
`help` -> Displays a help message.  
`debug` -> Displays outputs of commands.  
`no-prompt` -> Automatically skips user prompts.  

<a name="how_example"/>

### 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 :  

<p align="center">
  <img src="https://i.imgur.com/uvpC63E.png" alt="before.png"/>
</p>

<p align="center">
  <img src="https://i.imgur.com/Sp3ct49.png" alt="after.png"/>
</p>

<a name="warning"/>

## 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 <vector>
#include <fstream>
#include <binaries/bin_types.h>
#include <utils/config.h>
#include <memory>

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<std::unique_ptr<FUNCTION>>* bin_funcs) = 0;
    virtual void process_lib(std::string lib_path, std::vector<std::unique_ptr<FUNCTION>>* lib_funcs) = 0;
    virtual void post_process(std::vector<std::unique_ptr<FUNCTION>>* bin_funcs) = 0;
};

#endif //CERBERUS_ALGORITHM_H


================================================
FILE: src/algorithm/part_hash_algorithm.cpp
================================================
#include <algorithm/part_hash_algorithm.h>
#include <utils/convert.h>

using namespace std;

void PartHashAlgorithm::compute_part_hash(unique_ptr<FUNCTION>& 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<unique_ptr<FUNCTION>>* bin_funcs) {
    for(unique_ptr<FUNCTION>& 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<unique_ptr<FUNCTION>>* lib_funcs) {
    ifstream lib_file(lib_path, ios::binary);
    for (unique_ptr<FUNCTION>& 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<FUNCTION>& 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<unique_ptr<FUNCTION>>* bin_funcs) {
    bin_funcs->clear();
    for(auto& f_pair : funcs_by_sz) {
        for(unique_ptr<FUNCTION>& 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 <algorithm/algorithm.h>
#include <map>
#include <memory>

class PartHashAlgorithm : public Algorithm {
private:
    std::map<size_t, std::vector<std::unique_ptr<FUNCTION>>> funcs_by_sz;
    void compute_part_hash(std::unique_ptr<FUNCTION>& func, std::ifstream* file);
    float compare_part_hashes(std::string hash1, std::string hash2);
public:
    PartHashAlgorithm(CONFIG* config) : Algorithm(config) {}
    void process_binary(std::vector<std::unique_ptr<FUNCTION>>* bin_funcs) override;
    void process_lib(std::string lib_path, std::vector<std::unique_ptr<FUNCTION>>* lib_funcs) override;
    void post_process(std::vector<std::unique_ptr<FUNCTION>>* bin_funcs) override;
};

#endif //CERBERUS_PART_HASH_ALGORITHM_H


================================================
FILE: src/binaries/bin_extractor.h
================================================
#ifndef CERBERUS_BIN_EXTRACTOR_H
#define CERBERUS_BIN_EXTRACTOR_H

#include <string>
#include <vector>
#include <binaries/bin_types.h>
#include <memory>

class BinaryExtractor {
protected:
    std::string bin_path;
    BIN_TYPE type;
public:
    BinaryExtractor(std::string bin_path, BIN_TYPE type) : bin_path(bin_path), type(type) {};
    virtual BIN_ARCH extract_arch() = 0;
    virtual std::vector<std::unique_ptr<FUNCTION>> extract_functions(BIN_ARCH arch, size_t image_base) = 0;
    virtual std::vector<std::unique_ptr<SECTION>> extract_sections() = 0;
};

#endif //CERBERUS_BIN_EXTRACTOR_H


================================================
FILE: src/binaries/bin_handler.cpp
================================================
#include <binaries/bin_handler.h>
#include <binaries/lib/install/lib_installer.h>
#include <binaries/lib/install/rust_lib_installer.h>
#include <binaries/lib/install/go_lib_installer.h>
#include <langs/lib_regex.h>
#include <utils/search.h>
#include <utils/convert.h>
#include <utils/logger.h>

using namespace std;

BIN_ARCH BinaryHandler::extract_architecture() {
    this->arch = lief_extractor->extract_arch();
    return this->arch;
}

void BinaryHandler::extract_image_base() {
    this->image_base = lief_extractor->extract_image_base();
}

size_t BinaryHandler::libs_extraction() {
    vector<string> lib_regex;
    switch(lang) {
        case LANG::RUST:
            lib_regex = rust_lib_regex;
            break;
        case LANG::GO:
            lib_regex = go_lib_regex;
            break;
        default:
            return 0;
    }
    ifstream bin_file(this->bin_path, ios::binary);
    bin_file.seekg(0, ios::end);
    size_t bin_file_sz = bin_file.tellg();
    bin_file.seekg(0);
    size_t bin_file_off = 0;
    char data[2048];
    while(bin_file_off < bin_file_sz) {
        bin_file.seekg(bin_file_off);
        bin_file.read(data, sizeof(data));
        for (string reg: lib_regex) {
            vector<string> matches = search_regex(data, sizeof(data), reg, 256);
            for (string match: matches) {
                unique_ptr<LIBRARY> lib = lib_extract_callbacks[lang](match);
                if (lib) {
                    bool exists = false;
                    for (unique_ptr<LIBRARY> &lib2: this->libs) {
                        if (lib->name == lib2->name && lib->version == lib2->version) {
                            exists = true;
                            break;
                        }
                    }
                    if (!exists) this->libs.push_back(move(lib));
                }
            }
        }
        bin_file_off += 1024;
    }
    sort(this->libs.begin(), this->libs.end(), [](const unique_ptr<LIBRARY>& a, const unique_ptr<LIBRARY>& b) {
        return a->name < b->name;
    });
    bin_file.close();
    return this->libs.size();
}

size_t BinaryHandler::libs_installation() {
    unique_ptr<LibInstaller> installer;
    switch(lang) {
        case RUST:
            installer = make_unique<RustLibInstaller>(this->work_dir, this->arch, this->type);
            break;
        case GO:
            installer = make_unique<GoLibInstaller>(this->work_dir, this->arch, this->type);
            break;
        default:
            return 0;
    }
    if(!installer->pre_install_hook(this->libs)) return 0;
    size_t success_ctr = 0;
    for(std::unique_ptr<LIBRARY>& lib : this->libs) {
        fcout << "$(info)Installing $(bright_magenta:b)" << lib->name << "$$(red):$$(magenta:b)" << lib->version << "$..." << endl;
        if(installer->install_lib(*lib.get())) {
            success_ctr++;
            fcout << "$(success)Success !" << endl;
        } else fcout << "$(error)Failure..." << endl;
    }
    if(!installer->post_install_hook()) return 0;
    return success_ctr;
}

size_t BinaryHandler::get_matches_sz() {
    for(unique_ptr<FUNCTION>& func : this->functions) if(func->name.size()) matches_sz++;
    return matches_sz;
}

void BinaryHandler::demangle_functions() {
    for(unique_ptr<FUNCTION>& func : this->functions) {
        if(func->name.size()) func->name = demangle_function_name(func->name);
    }
}

================================================
FILE: src/binaries/bin_handler.h
================================================
#ifndef CERBERUS_BIN_HANDLER_H
#define CERBERUS_BIN_HANDLER_H

#include <string>
#include <vector>
#include <binaries/bin_types.h>
#include <binaries/extractors/lief_extractor.h>
#include <binaries/extractors/radare_extractor.h>
#include <langs/lang_types.h>
#include <user/dependencies/dependency_manager.h>
#include <algorithm/algorithm.h>
#include <binaries/extractors/libelf_extractor.h>

class BinaryHandler {
protected:
    std::string bin_path;
    std::string work_dir;
    LANG lang;
    Algorithm* algorithm;
    BIN_ARCH arch;
    BIN_TYPE type;
    size_t image_base;
    bool stripped;
    std::vector<std::unique_ptr<LIBRARY>> libs;
    std::vector<std::unique_ptr<FUNCTION>> functions;
    size_t matches_sz = 0;
    LiefExtractor* lief_extractor;
    RadareExtractor* radare_extractor;
public:
    BinaryHandler(std::string bin_path, std::string work_dir, LANG lang, Algorithm* algorithm, BIN_TYPE type) : bin_path(bin_path), work_dir(work_dir), lang(lang), algorithm(algorithm), type(type) {
        this->lief_extractor = new LiefExtractor(bin_path, type);
        this->radare_extractor = new RadareExtractor(bin_path, type, *this->lief_extractor);
    }
    BIN_ARCH extract_architecture();
    void extract_image_base();
    virtual void strip_analysis() = 0;
    size_t libs_extraction();
    size_t libs_installation();
    virtual size_t functions_analysis() = 0;
    virtual void functions_matching(std::string lib_path) = 0;
    virtual void post_matching() = 0;
    size_t get_matches_sz();
    void demangle_functions();
    virtual bool write_output(std::string output_path) = 0;
    bool is_stripped() {
        return this->stripped;
    }
    std::vector<std::unique_ptr<LIBRARY>>& get_libs() {
        return this->libs;
    }
    std::vector<std::unique_ptr<FUNCTION>>& get_functions() {
        return this->functions;
    }
};

#endif //CERBERUS_BIN_HANDLER_H


================================================
FILE: src/binaries/bin_identifier.cpp
================================================
#include <binaries/bin_identifier.h>
#include <fstream>
#include <cstring>

using namespace std;

map<BIN_TYPE, string> bin_type_names {
    {UNKNOWN_TYPE, "Unknown"},
    {ELF, "UNIX - Executable and Linkable Format (ELF)"},
    {PE, "WINDOWS - Portable Executable (PE)"}
};

map<string, BIN_TYPE> bin_type_from_magic = {
    {std::string("\x7f")+"ELF", BIN_TYPE::ELF},
    {"MZ", BIN_TYPE::PE}
};

BIN_TYPE identify_binary(string input_path) {
    ifstream input_file(input_path, ios::binary);
    input_file.seekg(0, ios::end);
    size_t input_sz = input_file.tellg();
    for (const pair<string, BIN_TYPE> p : bin_type_from_magic) {
        input_file.seekg(0);
        uint8_t magic_length = p.first.length();
        if(input_sz >= magic_length) {
            char magic_buffer[magic_length];
            input_file.read(magic_buffer, magic_length);
            if(!strncmp(p.first.c_str(), magic_buffer, magic_length)) {
                input_file.close();
                return p.second;
            }
        }
    }
    input_file.close();
    return UNKNOWN_TYPE;
}

================================================
FILE: src/binaries/bin_identifier.h
================================================
#ifndef CERBERUS_BIN_IDENTIFIER_H
#define CERBERUS_BIN_IDENTIFIER_H

#include <map>
#include <string>
#include <binaries/bin_types.h>

extern std::map<BIN_TYPE, std::string> bin_type_names;

extern std::map<std::string, BIN_TYPE> bin_type_from_magic;

BIN_TYPE identify_binary(std::string input_path);

#endif //CERBERUS_BIN_IDENTIFIER_H


================================================
FILE: src/binaries/bin_types.h
================================================
#ifndef CERBERUS_BIN_TYPES_H
#define CERBERUS_BIN_TYPES_H

#include <cstdint>
#include <string>

struct FUNCTION {
    uint64_t start;
    uint64_t end;
    std::string name;
    std::string hash;
    uint8_t score = 0;
    size_t ordinal = 0;
};

struct SECTION {
    uint64_t start;
    uint64_t end;
    std::string name;
};

struct LIBRARY {
    std::string name;
    std::string version;
};

enum BIN_TYPE {
    UNKNOWN_TYPE,
    ELF,
    PE,
};

enum BIN_ARCH {
    UNKNOWN_ARCH,
    X86_64,
    X86
};

#endif //CERBERUS_BIN_TYPES_H


================================================
FILE: src/binaries/extractors/go_extractor.cpp
================================================
#include <binaries/extractors/go_extractor.h>
#include <utils/convert.h>
#include <fstream>

using namespace std;

BIN_ARCH GoExtractor::extract_arch() {

}

vector<unique_ptr<FUNCTION>> GoExtractor::extract_functions(BIN_ARCH arch, size_t image_base) {
    ifstream bin_file(this->bin_path, ios::binary);
    LIEF::PE::Section* text_sec;
    if(type == BIN_TYPE::PE) text_sec = this->lief_extractor.extract_text_section();
    vector<unique_ptr<FUNCTION>> funcs;
    COMMAND_RESULT res;
    executor.execute_command("go tool nm -size "+this->bin_path, &res);
    if(res.code) return funcs;
    vector<string> lines = split_string(res.response, '\n');
    for(string line : lines) {
        vector<string> vals = split_string(line, ' ');
        vals = filter_empty_strings(vals);
        if(vals.size() < 4 || !isdigit(vals.at(0).at(0))) continue;
        unique_ptr<FUNCTION> func = make_unique<FUNCTION>();
        switch(type) {
            case BIN_TYPE::ELF:
                func->start = stoull(vals.at(0), nullptr, 16) - image_base;
                break;
            case BIN_TYPE::PE:
                func->start = stoull(vals.at(0), nullptr, 16) - image_base - text_sec->virtual_address() + text_sec->offset();
                break;
        }
        func->end = func->start + stoull(vals.at(1)) - 1;
        unsigned char b;
        bin_file.seekg(func->end);
        bin_file.read((char*)&b, 1);
        bool found_cc = false;
        if(b == 0xCC) found_cc = true;
        while(b == 0xCC) {
            bin_file.seekg(func->end--);
            bin_file.read((char*)&b, 1);
        }
        if(found_cc) func->end++;
        func->name = vals.at(3);
        if(!func->name.find("$f64") || !func->name.find("$f32")) func->name = "";
        funcs.push_back(move(func));
    }
    return funcs;
}

vector<unique_ptr<SECTION>> GoExtractor::extract_sections() {

}

================================================
FILE: src/binaries/extractors/go_extractor.h
================================================
#ifndef CERBERUS_GO_EXTRACTOR_H
#define CERBERUS_GO_EXTRACTOR_H

#include <binaries/bin_extractor.h>
#include <command/command_executor.h>
#include <binaries/extractors/lief_extractor.h>

class GoExtractor : public BinaryExtractor {
private:
    LiefExtractor& lief_extractor;
    CommandExecutor executor;
public:
    GoExtractor(std::string bin_path, BIN_TYPE type, LiefExtractor& lief_extractor) : BinaryExtractor(bin_path, type), lief_extractor(lief_extractor), executor("./") {}
    BIN_ARCH extract_arch() override;
    std::vector<std::unique_ptr<FUNCTION>> extract_functions(BIN_ARCH arch, size_t image_base) override;
    std::vector<std::unique_ptr<SECTION>> extract_sections() override;
};


#endif //CERBERUS_GO_EXTRACTOR_H


================================================
FILE: src/binaries/extractors/libelf_extractor.cpp
================================================
#include <binaries/extractors/libelf_extractor.h>
#include <fcntl.h>
#include <unistd.h>

using namespace std;

LibelfExtractor::LibelfExtractor(std::string bin_path, BIN_TYPE type) : BinaryExtractor(bin_path, type) {
    this->fd = open(bin_path.c_str(), O_RDONLY, 0);
    this->fp = fdopen(fd, "r");
    this->bin = elf_begin(fd, ELF_C_READ, NULL);
}

LibelfExtractor::~LibelfExtractor() {
    elf_end(this->bin);
    close(fd);
}

BIN_ARCH LibelfExtractor::extract_arch() {

}

vector<unique_ptr<FUNCTION>> LibelfExtractor::extract_functions_32(size_t image_base) {
    vector<unique_ptr<FUNCTION>> funcs;
    Elf_Scn *scn = nullptr;
    Elf_Scn *sym_scn = nullptr;
    uint64_t str_scn_start = 0;
    while ((scn = elf_nextscn(this->bin, scn)) != nullptr) {
        Elf32_Shdr *shdr = elf32_getshdr(scn);
        if(!sym_scn) {
            if(shdr->sh_type == SHT_SYMTAB || shdr->sh_type == SHT_DYNSYM) {
                sym_scn = scn;
                if(str_scn_start) break;
            }
        }
        if(!str_scn_start) {
            if(shdr->sh_type == SHT_STRTAB) {
                str_scn_start = shdr->sh_addr;
                if(sym_scn) break;
            }
        }
    }
    if(sym_scn) {
        Elf_Data *data = nullptr;
        data = elf_getdata(sym_scn, data);
        Elf32_Sym *symtab = (Elf32_Sym*) data->d_buf;
        size_t sym_count = data->d_size / sizeof(Elf32_Sym);
        for (size_t i = 0; i < sym_count; i++) {
            if(ELF32_ST_TYPE(symtab[i].st_info) != STT_FUNC || !symtab[i].st_size) continue;
            unique_ptr<FUNCTION> func = make_unique<FUNCTION>();
            func->start = symtab[i].st_value - image_base;
            func->end = func->start + symtab[i].st_size - 1;
            if(!str_scn_start || !symtab[i].st_value) {
                funcs.push_back(move(func));
                continue;
            }
            char buf[1024];
            fseek(this->fp, symtab[i].st_name-image_base+str_scn_start, SEEK_SET);
            fread(buf, 1024, 1, this->fp);
            func->name = string(buf);
            funcs.push_back(move(func));
        }
    }
    return funcs;
}

vector<unique_ptr<FUNCTION>> LibelfExtractor::extract_functions_64(size_t image_base) {
    vector<unique_ptr<FUNCTION>> funcs;
    Elf_Scn *scn = nullptr;
    Elf_Scn *sym_scn = nullptr;
    uint64_t str_scn_start = 0;
    while ((scn = elf_nextscn(this->bin, scn)) != nullptr) {
        Elf64_Shdr *shdr = elf64_getshdr(scn);
        if(!sym_scn) {
            if(shdr->sh_type == SHT_SYMTAB || shdr->sh_type == SHT_DYNSYM) {
                sym_scn = scn;
                if(str_scn_start) break;
            }
        }
        if(!str_scn_start) {
            if(shdr->sh_type == SHT_STRTAB) {
                str_scn_start = shdr->sh_addr;
                if(sym_scn) break;
            }
        }
    }
    if(sym_scn) {
        Elf_Data *data = nullptr;
        data = elf_getdata(sym_scn, data);
        Elf64_Sym *symtab = (Elf64_Sym*) data->d_buf;
        size_t sym_count = data->d_size / sizeof(Elf64_Sym);
        for (size_t i = 0; i < sym_count; i++) {
            if(ELF64_ST_TYPE(symtab[i].st_info) != STT_FUNC || !symtab[i].st_size) continue;
            unique_ptr<FUNCTION> func = make_unique<FUNCTION>();
            func->start = symtab[i].st_value - image_base;
            func->end = func->start + symtab[i].st_size - 1;
            if(!str_scn_start || !symtab[i].st_value) {
                funcs.push_back(move(func));
                continue;
            }
            char buf[1024];
            fseek(this->fp, symtab[i].st_name-image_base+str_scn_start, SEEK_SET);
            fread(buf, 1024, 1, this->fp);
            func->name = string(buf);
            funcs.push_back(move(func));
        }
    }
    return funcs;
}

vector<unique_ptr<FUNCTION>> LibelfExtractor::extract_functions(BIN_ARCH arch, size_t image_base) {
    if(type==BIN_TYPE::PE) image_base = 0;
    vector<unique_ptr<FUNCTION>> funcs;
    switch(arch) {
        case BIN_ARCH::X86_64:
            funcs = extract_functions_64(image_base);
            break;
        case BIN_ARCH::X86:
            funcs = extract_functions_32(image_base);
            break;
    }
    return funcs;
}

vector<unique_ptr<SECTION>> LibelfExtractor::extract_sections() {

}


================================================
FILE: src/binaries/extractors/libelf_extractor.h
================================================
#ifndef CERBERUS_LIBELF_EXTRACTOR_H
#define CERBERUS_LIBELF_EXTRACTOR_H

#include <binaries/bin_extractor.h>
#include <libelf.h>

class LibelfExtractor : public BinaryExtractor {
private:
    Elf* bin;
    int32_t fd;
    FILE* fp;
public:
    LibelfExtractor(std::string bin_path, BIN_TYPE type);
    ~LibelfExtractor();
    BIN_ARCH extract_arch() override;
    std::vector<std::unique_ptr<FUNCTION>> extract_functions_32(size_t image_base);
    std::vector<std::unique_ptr<FUNCTION>> extract_functions_64(size_t image_base);
    std::vector<std::unique_ptr<FUNCTION>> extract_functions(BIN_ARCH arch, size_t image_base) override;
    std::vector<std::unique_ptr<SECTION>> extract_sections() override;
};

#endif //CERBERUS_LIBELF_EXTRACTOR_H


================================================
FILE: src/binaries/extractors/lief_extractor.cpp
================================================
#include <binaries/extractors/lief_extractor.h>
#include <utils/convert.h>
#include <binaries/pe_types.h>
#include <fstream>
#include <filesystem>

using namespace std;

LiefExtractor::LiefExtractor(std::string bin_path, BIN_TYPE type) : BinaryExtractor(bin_path, type) {
    this->bin = LIEF::Parser::parse(bin_path);
    switch(type) {
        case BIN_TYPE::ELF:
            this->elf_bin = LIEF::ELF::Parser::parse(bin_path);
            break;
        case BIN_TYPE::PE:
            this->pe_bin = LIEF::PE::Parser::parse(bin_path);
            break;
    }
}

BIN_ARCH LiefExtractor::extract_arch() {
    switch(this->bin->header().architecture()) {
        case LIEF::ARCH_X86:
            if(this->bin->header().is_32()) return BIN_ARCH::X86;
            return BIN_ARCH::X86_64;
    }
    return BIN_ARCH::UNKNOWN_ARCH;
}

size_t LiefExtractor::extract_image_base() {
    return this->bin->imagebase();
}

size_t LiefExtractor::resolve_pe_rva(size_t rva) {
    return this->pe_bin->rva_to_offset(rva);
}

LIEF::PE::Section* LiefExtractor::extract_text_section() {
    return this->pe_bin->get_section(".text");
}

vector<unique_ptr<FUNCTION>> LiefExtractor::extract_functions(BIN_ARCH arch, size_t image_base) {
    if(type == BIN_TYPE::PE) image_base = 0;
    vector<unique_ptr<FUNCTION>> funcs;
    vector<LIEF::Function> lief_funcs;
    switch(type) {
        case BIN_TYPE::ELF:
            lief_funcs = this->elf_bin->functions();
            break;
        case BIN_TYPE::PE:
            lief_funcs = this->pe_bin->functions();
            break;
    }
    size_t ordinal = 0;
    for(LIEF::Function lief_func : lief_funcs) {
        if(!lief_func.size()) continue;
        unique_ptr<FUNCTION> func = make_unique<FUNCTION>();
        switch(type) {
            case BIN_TYPE::ELF:
                func->start = lief_func.address() - image_base;
                break;
            case BIN_TYPE::PE:
                func->start = resolve_pe_rva(lief_func.address());
                break;
        }
        func->end = func->start + lief_func.size() - 1;
        func->name = lief_func.name();
        func->ordinal = ordinal;
        funcs.push_back(move(func));
        ordinal++;
    }
    return funcs;
}

vector<unique_ptr<SECTION>> LiefExtractor::extract_sections() {
    vector<unique_ptr<SECTION>> sections;
    for(LIEF::Section lief_section : this->bin->sections()) {
        unique_ptr<SECTION> section = make_unique<SECTION>();
        section->start = lief_section.offset();
        section->end = lief_section.offset() + lief_section.size();
        section->name = lief_section.name();
        sections.push_back(move(section));
    }
    return sections;
}

bool LiefExtractor::write_elf_output(string output_path, size_t image_base, vector<unique_ptr<FUNCTION>>& funcs, bool stripped) {
    if(!this->elf_bin->has_section(".symtab")) {
        LIEF::ELF::Section symtab_sec = LIEF::ELF::Section();
        symtab_sec.name(".symtab");
        symtab_sec.type(LIEF::ELF::ELF_SECTION_TYPES::SHT_SYMTAB);
        symtab_sec.entry_size(0x18);
        symtab_sec.alignment(8);
        symtab_sec.link(this->elf_bin->header().numberof_sections()+1);
        vector<uint8_t> content(100, 0);
        symtab_sec.content(content);
        *this->elf_bin->add(symtab_sec, false);
    }
    if(!this->elf_bin->has_section(".strtab")) {
        LIEF::ELF::Section strtab_sec = LIEF::ELF::Section();
        strtab_sec.name(".strtab");
        strtab_sec.type(LIEF::ELF::ELF_SECTION_TYPES::SHT_STRTAB);
        strtab_sec.entry_size(1);
        strtab_sec.alignment(1);
        vector<uint8_t> content(100, 0);
        strtab_sec.content(content);
        *this->elf_bin->add(strtab_sec, false);
    }
    vector<uint64_t> sym_addresses;
    if(stripped) {
        LIEF::ELF::Symbol symbol = LIEF::ELF::Symbol();
        symbol.name("");
        symbol.type(LIEF::ELF::ELF_SYMBOL_TYPES::STT_NOTYPE);
        symbol.value(0);
        symbol.binding(LIEF::ELF::SYMBOL_BINDINGS::STB_LOCAL);
        symbol.size(0);
        symbol.shndx(0);
        this->elf_bin->add_static_symbol(symbol);
    } else {
        for(auto& symbol : this->elf_bin->symbols()) {
            uint64_t sym_addr = symbol.value();
            if(find(sym_addresses.begin(), sym_addresses.end(), sym_addr) == sym_addresses.end()) sym_addresses.push_back(sym_addr);
        }
    }
    for(unique_ptr<FUNCTION>& func : funcs) {
        if(stripped || std::find(sym_addresses.begin(), sym_addresses.end(), func->start) == sym_addresses.end()) {
            LIEF::ELF::Symbol symbol = LIEF::ELF::Symbol();
            symbol.name(func->name);
            symbol.type(LIEF::ELF::ELF_SYMBOL_TYPES::STT_FUNC);
            symbol.value(func->start+image_base);
            symbol.binding(LIEF::ELF::SYMBOL_BINDINGS::STB_LOCAL);
            symbol.shndx(14);
            this->elf_bin->add_static_symbol(symbol);
        }
    }
    this->elf_bin->write(output_path);
    return true;
}

bool LiefExtractor::write_pe_output(string output_path, size_t image_base, size_t matches_sz, vector<unique_ptr<FUNCTION>>& funcs) {
    vector<uint8_t> edata_content;
    EXPORT_DIRECTORY_TABLE edt;
    for(size_t i = 0; i < sizeof(edt) + matches_sz * 8; i++) edata_content.push_back(0);
    for(uint16_t i = 0; i < matches_sz; i++) {
        edata_content.push_back(i & 0xff);
        edata_content.push_back(i >> 8);
    }
    for(unique_ptr<FUNCTION>& func : funcs) {
        if(!func->name.size()) continue;
        for(char c : func->name) edata_content.push_back(c);
        edata_content.push_back(0);
    }
    LIEF::PE::Section edata_section;
    edata_section.name(".edata");
    edata_section.content(edata_content);
    edata_section.characteristics((uint32_t)(
            LIEF::PE::SECTION_CHARACTERISTICS::IMAGE_SCN_CNT_INITIALIZED_DATA |
            LIEF::PE::SECTION_CHARACTERISTICS::IMAGE_SCN_MEM_READ
        ) | 0x300000);
    edata_section = *this->pe_bin->add_section(edata_section);
    this->pe_bin->header().numberof_sections(this->pe_bin->header().numberof_sections() + 1);
    this->pe_bin->write(output_path);
    ifstream bin_file(output_path, ios::binary);
    bin_file.seekg(0, ios::end);
    size_t bin_file_sz = bin_file.tellg();
    ofstream new_bin_file(output_path+".tmp", ios::binary);
    size_t edata_start = edata_section.virtual_address();
    edt.name_rva = edata_start + matches_sz * 10;
    uint32_t edata_content_sz = edata_content.size();
    edt.address_table_entries = matches_sz;
    edt.number_of_name_pointers = matches_sz;
    edt.export_address_table_rva = edata_start + sizeof(edt);
    edt.name_pointer_rva = edata_start + sizeof(edt) + 4 * matches_sz;
    edt.ordinal_table_rva = edata_start + sizeof(edt) + 8 * matches_sz;
    for(uint8_t i = 0; i < sizeof(edt); i++) edata_content[i] = (((char*)&edt)[i]);
    size_t func_i = 0;
    size_t name_pos = 0;
    for(unique_ptr<FUNCTION>& func : funcs) {
        if(!func->name.size()) continue;
        uint32_t func_vaddr = this->pe_bin->offset_to_virtual_address(func->start).value();
        memcpy((char*)(edata_content.data()+sizeof(edt)+func_i*4), &func_vaddr, sizeof(uint32_t));
        uint32_t name_vaddr = edata_start + sizeof(edt) + matches_sz * 10 + name_pos;
        memcpy((char*)(edata_content.data()+sizeof(edt)+matches_sz*4+func_i*4), &name_vaddr, sizeof(uint32_t));
        func_i++;
        name_pos += func->name.size()+1;
    }
    char buffer[1024];
    uint32_t pe_start;
    bin_file.seekg(0x3c);
    bin_file.read((char*)&pe_start, sizeof(pe_start));
    size_t edt_data_dir = pe_start + 0x88;
    bin_file.seekg(0, ios::beg);
    bin_file.read(buffer, edt_data_dir);
    new_bin_file.write(buffer, edt_data_dir);
    new_bin_file.write((char*)&edata_start, 4);
    new_bin_file.write((char*)&edata_content_sz, 4);
    bin_file.seekg((size_t)bin_file.tellg()+8);
    size_t off = edt_data_dir+0x8;
    while(off < edata_section.offset() - sizeof(buffer)) {
        bin_file.read(buffer, sizeof(buffer));
        new_bin_file.write(buffer, sizeof(buffer));
        off+=sizeof(buffer);
    }
    bin_file.read(buffer, edata_section.offset() - off);
    new_bin_file.write(buffer, edata_section.offset() - off);
    new_bin_file.write((char*)edata_content.data(), edata_content.size());
    bin_file.seekg((size_t)bin_file.tellg()+edata_content.size());
    off = edata_section.offset() + edata_content.size();
    while(off < bin_file_sz - sizeof(buffer)) {
        bin_file.read(buffer, sizeof(buffer));
        new_bin_file.write(buffer, sizeof(buffer));
        off+=sizeof(buffer);
    }
    new_bin_file.write(buffer, bin_file_sz - off);
    bin_file.close();
    new_bin_file.close();
    filesystem::rename(output_path+".tmp", output_path);
    return true;
}

================================================
FILE: src/binaries/extractors/lief_extractor.h
================================================
#ifndef CERBERUS_LIEF_EXTRACTOR_H
#define CERBERUS_LIEF_EXTRACTOR_H

#include <binaries/bin_extractor.h>
#include <LIEF/LIEF.hpp>

class LiefExtractor : public BinaryExtractor {
private:
    std::unique_ptr<LIEF::Binary> bin;
    std::unique_ptr<LIEF::ELF::Binary> elf_bin;
    std::unique_ptr<LIEF::PE::Binary> pe_bin;
public:
    LiefExtractor(std::string bin_path, BIN_TYPE type);
    BIN_ARCH extract_arch() override;
    size_t extract_image_base();
    size_t resolve_pe_rva(size_t rva);
    LIEF::PE::Section* extract_text_section();
    std::vector<std::unique_ptr<FUNCTION>> extract_functions(BIN_ARCH arch, size_t image_base) override;
    std::vector<std::unique_ptr<SECTION>> extract_sections() override;
    bool write_elf_output(std::string output_path, size_t image_base, std::vector<std::unique_ptr<FUNCTION>>& funcs, bool stripped);
    bool write_pe_output(std::string output_path, size_t image_base, size_t matches_sz, std::vector<std::unique_ptr<FUNCTION>>& funcs);
};

#endif //CERBERUS_LIEF_EXTRACTOR_H


================================================
FILE: src/binaries/extractors/radare_extractor.cpp
================================================
#include <binaries/extractors/radare_extractor.h>
#include <utils/convert.h>

using namespace std;

BIN_ARCH RadareExtractor::extract_arch() {

}

vector<unique_ptr<FUNCTION>> RadareExtractor::extract_functions(BIN_ARCH arch, size_t image_base) {
    LIEF::PE::Section* text_sec;
    if(type == BIN_TYPE::PE) text_sec = this->lief_extractor.extract_text_section();
    vector<unique_ptr<FUNCTION>> funcs;
    COMMAND_RESULT res;
    executor.execute_command(string("radare2 -q -c aaa -c afl \"") + bin_path + string("\""), &res);
    if (!res.code) {
        vector<string> lines = split_string(res.response, '\n');
        for(string& line : lines) {
            if(line.length() < 2 || line.substr(0, 2) != "0x") continue;
            vector<string> vals = split_string(line, ' ');
            vals = filter_empty_strings(vals);
            unique_ptr<FUNCTION> func = make_unique<FUNCTION>();
            switch(type) {
                case BIN_TYPE::ELF:
                    func->start = stoull(vals[0].substr(2), nullptr, 16) - image_base;
                    break;
                case BIN_TYPE::PE:
                    func->start = stoull(vals[0].substr(2), nullptr, 16) - image_base - text_sec->virtual_address() + text_sec->offset();
                    break;
            }
            func->end = func->start + stoull(vals[2]) - 1;
            if(!func->name.find("fcn.")) func->name = vals[3];
            funcs.push_back(move(func));
        }
    }
    return funcs;
}

vector<unique_ptr<SECTION>> RadareExtractor::extract_sections() {

}

================================================
FILE: src/binaries/extractors/radare_extractor.h
================================================
#ifndef CERBERUS_RADARE_EXTRACTOR_H
#define CERBERUS_RADARE_EXTRACTOR_H

#include <binaries/bin_extractor.h>
#include <command/command_executor.h>
#include <binaries/extractors/lief_extractor.h>

class RadareExtractor : public BinaryExtractor {
private:
    LiefExtractor& lief_extractor;
    CommandExecutor executor;
public:
    RadareExtractor(std::string bin_path, BIN_TYPE type, LiefExtractor& lief_extractor) : BinaryExtractor(bin_path, type), lief_extractor(lief_extractor), executor("./") {}
    BIN_ARCH extract_arch() override;
    std::vector<std::unique_ptr<FUNCTION>> extract_functions(BIN_ARCH arch, size_t image_base) override;
    std::vector<std::unique_ptr<SECTION>> extract_sections() override;
};

#endif //CERBERUS_RADARE_EXTRACTOR_H


================================================
FILE: src/binaries/handlers/elf_handler.cpp
================================================
#include <binaries/handlers/elf_handler.h>
#include <vector>
#include <binaries/extractors/libelf_extractor.h>

using namespace std;

void ElfHandler::strip_analysis() {
    this->stripped = true;
    vector<unique_ptr<SECTION>> sections = this->lief_extractor->extract_sections();
    const vector<string> debug_sections = {".symtab", ".strtab"};
    for(unique_ptr<SECTION>& section : sections) {
        if(find(debug_sections.begin(), debug_sections.end(), section->name) != debug_sections.end()) {
            this->stripped = false;
            return;
        }
    }
}

size_t ElfHandler::functions_analysis() {
    vector<unique_ptr<FUNCTION>> funcs = this->lief_extractor->extract_functions(this->arch, this->image_base);
    if(!funcs.size()) funcs = this->radare_extractor->extract_functions(this->arch, this->image_base);
    if(!funcs.size()) funcs = this->libelf_extractor->extract_functions(this->arch, this->image_base);
    algorithm->process_binary(&funcs);
    this->functions = move(funcs);
    return this->functions.size();
}

void ElfHandler::functions_matching(string lib_path) {
    LiefExtractor lib_lief_extractor(lib_path, type);
    LibelfExtractor lib_libelf_extractor(lib_path, type);
    RadareExtractor lib_radare_extractor(lib_path, type, lib_lief_extractor);
    size_t lib_image_base = lib_lief_extractor.extract_image_base();
    vector<unique_ptr<FUNCTION>> funcs = lib_lief_extractor.extract_functions(this->arch, lib_image_base);
    if(!funcs.size()) funcs = lib_libelf_extractor.extract_functions(this->arch, lib_image_base);
    if(!funcs.size()) funcs = lib_radare_extractor.extract_functions(this->arch, lib_image_base);
    algorithm->process_lib(lib_path, &funcs);
}

void ElfHandler::post_matching() {
    algorithm->post_process(&functions);
}

bool ElfHandler::write_output(string output_path) {
    return this->lief_extractor->write_elf_output(output_path, this->image_base, this->functions, this->stripped);
}

================================================
FILE: src/binaries/handlers/elf_handler.h
================================================
#ifndef CERBERUS_ELF_HANDLER_H
#define CERBERUS_ELF_HANDLER_H

#include <binaries/bin_handler.h>

class ElfHandler : public BinaryHandler {
private:
    LibelfExtractor* libelf_extractor;
public:
    ElfHandler(std::string bin_path, std::string work_dir, LANG lang, Algorithm* algorithm) : BinaryHandler(bin_path, work_dir, lang, algorithm, BIN_TYPE::ELF) {
        this->libelf_extractor = new LibelfExtractor(bin_path, type);
    }
    void strip_analysis() override;
    size_t functions_analysis() override;
    void functions_matching(std::string lib_path) override;
    void post_matching() override;
    bool write_output(std::string output_path) override;
};

#endif //CERBERUS_ELF_HANDLER_H


================================================
FILE: src/binaries/handlers/pe_handler.cpp
================================================
#include <binaries/handlers/pe_handler.h>
#include <binaries/extractors/go_extractor.h>

using namespace std;

void PeHandler::strip_analysis() {
    this->stripped = !this->extract_section_header_start(".edata", this->bin_path) &&
            !this->extract_section_header_start(".zdebug_info", this->bin_path);
}

size_t PeHandler::functions_analysis() {
    vector<unique_ptr<FUNCTION>> funcs = this->lief_extractor->extract_functions(this->arch, this->image_base);
    if(!funcs.size()) funcs = this->radare_extractor->extract_functions(this->arch, this->image_base);
    algorithm->process_binary(&funcs);
    this->functions = move(funcs);
    return this->functions.size();
}

size_t PeHandler::extract_section_header_start(std::string section_name, std::string path) {
    ifstream bin_file(path);
    uint32_t pe_start;
    bin_file.seekg(0x3c);
    bin_file.read((char*)&pe_start, sizeof(pe_start));
    uint16_t number_of_sections;
    bin_file.seekg(pe_start+0x6);
    bin_file.read((char*)&number_of_sections, sizeof(number_of_sections));
    uint16_t size_of_opt_header;
    bin_file.seekg(pe_start+0x14);
    bin_file.read((char*)&size_of_opt_header, sizeof(size_of_opt_header));
    for(uint16_t sec_i = 0; sec_i < number_of_sections; sec_i++) {
        size_t sec_start = pe_start + 0x18 + size_of_opt_header + sec_i * 0x28;
        bin_file.seekg(sec_start);
        char sec_name[8];
        bin_file.read(sec_name, sizeof(sec_name));
        if(!strcmp(sec_name, section_name.c_str())) {
            bin_file.close();
            return sec_start;
        }
    }
    bin_file.close();
    return 0;
}

void PeHandler::fix_functions_names(vector<unique_ptr<FUNCTION>>& funcs, std::string path, LiefExtractor& extractor) {
    size_t edata_header_start = this->extract_section_header_start(".edata", path);
    if(!edata_header_start) return;
    ifstream bin_file(path);
    uint32_t edata_start;
    bin_file.seekg(edata_header_start+0xc);
    bin_file.read((char*)&edata_start, sizeof(edata_start));
    edata_start = extractor.resolve_pe_rva(edata_start);
    uint32_t pointers_sz;
    bin_file.seekg(edata_start+0x18);
    bin_file.read((char*)&pointers_sz, sizeof(pointers_sz));
    uint32_t eat_start;
    bin_file.seekg(edata_start+0x1c);
    bin_file.read((char*)&eat_start, sizeof(eat_start));
    eat_start = extractor.resolve_pe_rva(eat_start);
    uint32_t name_table_start;
    bin_file.seekg(edata_start+0x20);
    bin_file.read((char*)&name_table_start, sizeof(name_table_start));
    name_table_start = extractor.resolve_pe_rva(name_table_start);
    map<size_t, string> eat;
    for(size_t entry_i = 0; entry_i < pointers_sz; entry_i++) {
        size_t eat_entry = eat_start + entry_i * sizeof(uint32_t);
        uint32_t func_addr;
        bin_file.seekg(eat_entry);
        bin_file.read((char*)&func_addr, sizeof(func_addr));
        func_addr = extractor.resolve_pe_rva(func_addr);
        size_t name_entry = name_table_start + entry_i * sizeof(uint32_t);
        uint32_t name_addr;
        bin_file.seekg(name_entry);
        bin_file.read((char*)&name_addr, sizeof(name_addr));
        name_addr = extractor.resolve_pe_rva(name_addr);
        char name[1024];
        bin_file.seekg(name_addr);
        bin_file.read(name, sizeof(name));
        eat[func_addr] = string(name);
    }
    for(unique_ptr<FUNCTION>& func : funcs) {
        if(func->name.length()) continue;
        if(eat.find(func->start) != eat.end()) {
            func->name = eat[func->start];
        }
    }
    bin_file.close();
}

void PeHandler::functions_matching(string lib_path) {
    LiefExtractor lib_lief_extractor(lib_path, type);
    GoExtractor lib_go_extractor(lib_path, type, lib_lief_extractor);
    RadareExtractor lib_radare_extractor(lib_path, type, lib_lief_extractor);
    size_t lib_image_base = lib_lief_extractor.extract_image_base();
    vector<unique_ptr<FUNCTION>> funcs = lib_lief_extractor.extract_functions(this->arch, lib_image_base);
    if(!funcs.size()) funcs = lib_go_extractor.extract_functions(this->arch, lib_image_base);
    if(!funcs.size()) funcs = lib_radare_extractor.extract_functions(this->arch, lib_image_base);
    this->fix_functions_names(funcs, lib_path, lib_lief_extractor);
    algorithm->process_lib(lib_path, &funcs);
}

void PeHandler::post_matching() {
    algorithm->post_process(&functions);
}

bool PeHandler::write_output(string output_path) {
    return this->lief_extractor->write_pe_output(output_path, this->image_base, this->matches_sz, this->functions);
}

================================================
FILE: src/binaries/handlers/pe_handler.h
================================================
#ifndef CERBERUS_PE_HANDLER_H
#define CERBERUS_PE_HANDLER_H

#include <binaries/bin_handler.h>

class PeHandler : public BinaryHandler {
private:
    size_t extract_section_header_start(std::string section_name, std::string path);
    void fix_functions_names(std::vector<std::unique_ptr<FUNCTION>>& funcs, std::string path, LiefExtractor& extractor);
public:
    PeHandler(std::string bin_path, std::string work_dir, LANG lang, Algorithm* algorithm) : BinaryHandler(bin_path, work_dir, lang, algorithm, BIN_TYPE::PE) {}
    void strip_analysis() override;
    size_t functions_analysis() override;
    void functions_matching(std::string lib_path) override;
    void post_matching() override;
    bool write_output(std::string output_path) override;
};

#endif //CERBERUS_PE_HANDLER_H


================================================
FILE: src/binaries/lib/install/go_lib_installer.cpp
================================================
#include <binaries/lib/install/go_lib_installer.h>
#include <command/command_executor.h>
#include <utils/logger.h>
#include <algorithm>
#include <fstream>

using namespace std;

bool GoLibInstaller::pre_install_hook(vector<std::unique_ptr<LIBRARY>>& libs) {
    filesystem::create_directory(this->work_dir+"/standalone");
    auto go_lib_it = find_if(libs.begin(), libs.end(), [](const unique_ptr<LIBRARY>& item) {
        return item->name == "go";
    });
    if(go_lib_it == libs.end()) return false;
    LIBRARY* go_lib = go_lib_it->get();
    libs.erase(go_lib_it);
    if(!this->install_go_version(go_lib->version)) return false;
    CommandExecutor executor(this->work_dir+"/standalone");
    COMMAND_RESULT res;
    executor.execute_command("../go mod init build_mod", &res);
    if(res.code || res.response.find("creating new go.mod") == string::npos) return false;
    ofstream build_mod_file(this->work_dir+"/standalone/build_mod.go");
    build_mod_file << "package main" << endl << endl;
    build_mod_file << "import (" << endl;
    for(std::unique_ptr<LIBRARY>& lib : libs) {
        string lib_name = lib->name;
        if(!lib_name.find("std::")) lib_name = lib_name.substr(string("std::").length());
        build_mod_file << "\t_ \"" << lib_name << "\"" << endl;
    }
    build_mod_file << ")" << endl << endl;
    build_mod_file << "func main() {}";
    build_mod_file.close();
    return true;
}

bool GoLibInstaller::install_go_version(std::string version) {
    fcout << "$(info)Installing $(bright_magenta:b)go$$(red):$$(magenta:b)" << version << "$..." << endl;
    CommandExecutor executor(work_dir);
    COMMAND_RESULT res;
    executor.execute_command("goliath "+version, &res);
    bool success = !res.code;
    this->goliath_output_dir = this->work_dir+"/go-"+version;
    if(success) {
        filesystem::rename(goliath_output_dir+"/go/bin/go", this->work_dir+"/go");
        fcout << "$(success)Success !" << endl;
    } else fcout << "$(error)Failure..." << endl;
    return success;
}

bool GoLibInstaller::install_lib(LIBRARY lib) {
    CommandExecutor executor(this->work_dir+"/standalone");
    COMMAND_RESULT res;
    string lib_name = lib.name;
    if(!lib_name.find("std::")) lib_name = lib_name.substr(string("std::").length());
    if(lib.version != "unk") lib_name += "@v"+lib.version;
    executor.execute_command("../go get "+lib_name, &res);
    return !res.code;
}

bool GoLibInstaller::post_install_hook() {
    fcout << "$(info)Building standalone library..." << endl;
    string goos, goarch;
    string lib_extension;
    switch(type) {
        case BIN_TYPE::ELF:
            goos = "linux";
            lib_extension = ".so";
            break;
        case BIN_TYPE::PE:
            goos = "windows";
            lib_extension = ".dll";
            break;
    }
    switch(arch) {
        case BIN_ARCH::X86_64:
            goarch = "amd64";
            break;
        case BIN_ARCH::X86:
            goarch = "386";
            break;
    }
    CommandExecutor executor(this->work_dir+"/standalone");
    COMMAND_RESULT res;
    executor.execute_command("GOOS="+goos+" GOARCH="+goarch+" ../go build -o ./standalone"+lib_extension+" build_mod.go", &res);
    bool success = !res.code;
    if(success) {
        filesystem::rename(this->work_dir+"/standalone/standalone"+lib_extension, this->work_dir+"/standalone"+lib_extension);
        fcout << "$(success)Success !" << endl;
    }
    else fcout << "$(error)Failure..." << endl;
    filesystem::remove(this->work_dir+"/go");
    filesystem::remove_all(this->goliath_output_dir);
    filesystem::remove_all(this->work_dir+"/standalone");
    return success;
}

================================================
FILE: src/binaries/lib/install/go_lib_installer.h
================================================
#ifndef CERBERUS_GO_LIB_INSTALLER_H
#define CERBERUS_GO_LIB_INSTALLER_H

#include <binaries/lib/install/lib_installer.h>
#include <memory>

class GoLibInstaller : public LibInstaller {
private:
    bool install_go_version(std::string version);
    std::string goliath_output_dir;
public:
    GoLibInstaller(std::string work_dir, BIN_ARCH arch, BIN_TYPE type) : LibInstaller(work_dir, arch, type) {}
    bool install_lib(LIBRARY lib) override;
    bool pre_install_hook(std::vector<std::unique_ptr<LIBRARY>>& libs) override;
    bool post_install_hook() override;
};

#endif //CERBERUS_GO_LIB_INSTALLER_H


================================================
FILE: src/binaries/lib/install/lib_installer.h
================================================
#ifndef CERBERUS_LIB_INSTALLER_H
#define CERBERUS_LIB_INSTALLER_H

#include <string>
#include <binaries/bin_types.h>
#include <memory>
#include <vector>

class LibInstaller {
protected:
    std::string work_dir;
    BIN_ARCH arch;
    BIN_TYPE type;
public:
    LibInstaller(std::string work_dir, BIN_ARCH arch, BIN_TYPE type) : work_dir(work_dir), arch(arch), type(type) {}
    virtual bool install_lib(LIBRARY lib) = 0;
    virtual bool pre_install_hook(std::vector<std::unique_ptr<LIBRARY>>& libs) = 0;
    virtual bool post_install_hook() = 0;};

#endif //CERBERUS_LIB_INSTALLER_H


================================================
FILE: src/binaries/lib/install/rust_lib_installer.cpp
================================================
#include <binaries/lib/install/rust_lib_installer.h>
#include <utils/file_operations.h>
#include <utils/convert.h>
#include <filesystem>
#include <fstream>
#include <vector>
#include <string>
#include <map>
#include <command/command_executor.h>
#include <utils/logger.h>
#include <user/user_prompt.h>

namespace fs = std::filesystem;
using namespace std;

const string RBF_PREFIX = "$(bright_blue:b)[$(blue:b)RBF$]$ ";

void newer_edition_patch(string crate_path) {
    if(fs::exists(crate_path+"/Cargo.toml")) {
        ifstream cargo_input_file(crate_path + "/Cargo.toml");
        string line;
        vector<string> lines;
        while(getline(cargo_input_file, line)) {
            line = strip(line);
            if(line.find("[package]") != string::npos) {
                lines.push_back("[package]");
                lines.push_back("edition = \"2021\"");
            } else if(line.find("edition ") == string::npos && line.find("edition=") == string::npos) {
                lines.push_back(line);
            }
        }
        cargo_input_file.close();
        ofstream cargo_output_file(crate_path+"/Cargo.toml");
        for(string l : lines) {
            cargo_output_file.write((l + string("\n")).c_str(), l.size() + 1);
        }
        cargo_output_file.close();
    }
}

PATCH NEWER_EDITION_PATCH{
    "EDITION 2021",
    newer_edition_patch
};

void std_redefinition_patch(string crate_path) {
    if(fs::exists(crate_path+"/src/lib.rs")) {
        ifstream lib_input_file(crate_path+"/src/lib.rs");
        string line;
        vector<string> lines;
        while(getline(lib_input_file, line)) {
            if(line.find("no_std") == string::npos && line.find("as std;") == string::npos) lines.push_back(line);
        }
        lib_input_file.close();
        ofstream lib_output_file(crate_path+"/src/lib.rs");
        for(string l : lines) {
            lib_output_file.write((l + string("\n")).c_str(), l.size() + 1);
        }
        lib_output_file.close();
    }
}

PATCH STD_REDEFINITION_PATCH {
    "STD REDEFINITION",
    std_redefinition_patch
};

void add_workspace_patch(string crate_path) {
    if(fs::exists(crate_path+"/Cargo.toml")) {
        ifstream cargo_input_file(crate_path+"/Cargo.toml");
        vector<string> lines;
        string line;
        while(getline(cargo_input_file, line)) {
            lines.push_back(line);
        }
        lines.push_back("[workspace]");
        cargo_input_file.close();
        ofstream cargo_output_file(crate_path+"/Cargo.toml");
        for(string l : lines) {
            cargo_output_file.write((l + string("\n")).c_str(), l.size() + 1);
        }
        cargo_output_file.close();
    }
}

PATCH ADD_WORKSPACE_PATCH {
    "ADD WORKSPACE",
    add_workspace_patch
};

map<string, PATCH> patches = {
    {"maybe a missing crate `core`?", NEWER_EDITION_PATCH},
    {"the name `std` is defined multiple times", STD_REDEFINITION_PATCH},
    {"language item required, but not found: `eh_personality`", STD_REDEFINITION_PATCH},
    {"current package believes it's in a workspace when it's not", ADD_WORKSPACE_PATCH}
};

bool RustBuildFixer::process_error(string command, string error) {
    for(pair<string, PATCH> patch_pair : patches) {
        if(error.find(patch_pair.first) != string::npos) {
            PATCH patch = patch_pair.second;
            if(last_patch && patch.patch_func == last_patch->patch_func) return false;
            last_patch = &patch;
            fcout << "$(info)" << RBF_PREFIX << "Applying patch $(red:b)" << patch.name << "$..." << endl;
            patch.patch_func(crate_path);
            COMMAND_RESULT res;
            executor.execute_command(command, &res);
            if(!res.code) return true;
            return process_error(command, res.response);
        }
    }
    return false;
}

void RustLibInstaller::check_and_install_arch(string arch_name) {
    CommandExecutor executor("./");
    COMMAND_RESULT res;
    executor.execute_command("rustup target list", &res);
    if(res.code) return;
    vector<string> lines = split_string(res.response, '\n');
    for(string& line : lines) {
        if(line.find(arch_name) != string::npos) {
            if(line.find("installed") == string::npos) {
                fcout << "$(info)You need to install the toolchain for $(info:b)" << arch_name << "$ architecture." << endl;
                bool agree_install = ask_yes_no("Proceed to installation ?", true);
                if(agree_install) {
                    COMMAND_RESULT res;
                    string install_cmd = "rustup target install " + arch_name;
                    executor.execute_command(install_cmd, &res);
                    if(res.code) fcout << "$(error)An error occurred during installation... Run $(error:b)" << install_cmd << "$ for more information." << endl;
                    else fcout << "$(success)Done !" << endl;
                    return;
                } else return;
            } else {
                fcout << "$(info)Requested architecture is already installed." << endl;
                return;
            }
        }
    }
}

RustLibInstaller::RustLibInstaller(string work_dir, BIN_ARCH arch, BIN_TYPE type) : LibInstaller(work_dir, arch, type), downloader() {
    if(arch == BIN_ARCH::X86) check_and_install_arch("i686-unknown-linux-gnu");
}

bool RustLibInstaller::install_lib(LIBRARY lib) {
    string output_dir_name = this->work_dir+"/"+lib.name+"-"+lib.version;
    string zip_file_name = output_dir_name+".crate";
    string tar_file_name = output_dir_name+".tar";
    if(!this->downloader.download_file("https://crates.io/api/v1/crates/"+lib.name+"/"+lib.version+"/download", zip_file_name)) return false;
    if(!decompress_gzip_file(zip_file_name, tar_file_name)) return false;
    fs::remove(zip_file_name);
    if(!decompress_tar_file(tar_file_name, output_dir_name)) return false;
    fs::remove(tar_file_name);
    ifstream cargo_toml_input(output_dir_name+"/Cargo.toml");
    if(!cargo_toml_input.is_open()) return false;
    vector<string> cargo_toml_lines;
    string line;
    bool found_lib = false;
    while(getline(cargo_toml_input, line)) {
        strip(line);
        if(line.find("[lib]") != string::npos) {
            found_lib = true;
            cargo_toml_lines.push_back("[lib]");
            cargo_toml_lines.push_back("crate-type = [\"dylib\"]");
        } else if(line.find("crate-type ") && line.find("crate-type=")) cargo_toml_lines.push_back(line);
    }
    cargo_toml_input.close();
    if(!found_lib) {
        cargo_toml_lines.push_back("[lib]");
        cargo_toml_lines.push_back("crate-type = [\"dylib\"]");
    }
    if(!fs::exists(output_dir_name+"/Cargo.toml")) return false;
    ofstream cargo_toml_output(output_dir_name+"/Cargo.toml");
    for(string line : cargo_toml_lines) cargo_toml_output.write((line+string("\n")).c_str(), line.size()+1);
    cargo_toml_output.close();
    CommandExecutor executor(output_dir_name);
    COMMAND_RESULT res;
    string command;
    switch(type) {
        case BIN_TYPE::ELF:
            command = "cargo build --release";
            if(arch == BIN_ARCH::X86) command += " --target=i686-unknown-linux-gnu";
            break;
        case BIN_TYPE::PE:
            if(arch == BIN_ARCH::X86_64) command = "cross build --target x86_64-pc-windows-gnu --release";
            else if(arch == BIN_ARCH::X86) command = "cross build --target i686-pc-windows-gnu --release";
            break;
    }
    executor.execute_command(command, &res);
    bool success = res.code == 0;
    if(!success) {
        fcout << "$(warning)An error occurred during build, delegating to $(warning:b)RBF$ (Rust Build Fixer)..." << endl;
        success = RustBuildFixer(output_dir_name, type).process_error(command, res.response);
    }
    if(!success) return false;
    string release_dir;
    switch(type) {
        case BIN_TYPE::ELF:
            release_dir = output_dir_name+string("/target/release");
            break;
        case BIN_TYPE::PE:
            if(arch == BIN_ARCH::X86_64) release_dir = output_dir_name+string("/target/x86_64-pc-windows-gnu/release");
            else if(arch == BIN_ARCH::X86) release_dir = output_dir_name+string("/target/i686-pc-windows-gnu/release");
            break;
    }
    string lib_extension;
    switch(type) {
        case BIN_TYPE::ELF:
            lib_extension = ".so";
            break;
        case BIN_TYPE::PE:
            lib_extension = ".dll";
            break;
    }
    if(fs::exists(release_dir)) {
        for (const auto& entry : fs::directory_iterator(release_dir)) {
            if (fs::is_regular_file(entry)) {
                fs::path file_path = entry.path();
                string file_name = file_path.filename();
                if(ends_with(file_name, lib_extension)) {
                    fs::rename(file_path, this->work_dir+"/"+file_name);
                }
            }
        }
    }
    fs::remove_all(output_dir_name);
    return true;
}

================================================
FILE: src/binaries/lib/install/rust_lib_installer.h
================================================
#ifndef CERBERUS_RUST_LIB_INSTALLER_H
#define CERBERUS_RUST_LIB_INSTALLER_H

#include <binaries/lib/install/lib_installer.h>
#include <utils/file_downloader.h>
#include <command/command_executor.h>

struct PATCH {
    std::string name;
    void (*patch_func)(std::string crate_path);
};

class RustBuildFixer {
private:
    std::string crate_path;
    BIN_TYPE type;
    PATCH* last_patch = nullptr;
    CommandExecutor executor;
public:
    RustBuildFixer(std::string crate_path, BIN_TYPE type) : crate_path(crate_path), type(type), executor(crate_path) {}
    bool process_error(std::string command, std::string error);
};

class RustLibInstaller : public LibInstaller {
private:
    FileDownloader downloader;
    void check_and_install_arch(std::string arch_name);
public:
    RustLibInstaller(std::string work_dir, BIN_ARCH arch, BIN_TYPE type);
    bool install_lib(LIBRARY lib) override;
    bool pre_install_hook(std::vector<std::unique_ptr<LIBRARY>>& libs) override {return true;}
    bool post_install_hook() override {return true;}
};

#endif //CERBERUS_RUST_LIB_INSTALLER_H


================================================
FILE: src/binaries/lib/lib_manager.cpp
================================================
#include <binaries/lib/lib_manager.h>
#include <utils/logger.h>
#include <user/user_prompt.h>
#include <iostream>

using namespace std;

void LibManager::main_menu() {
    fcout << "$(info)Here is the current list of libraries :\n";
    fcout << "$(red:b)-------------------------------$\n";
    uint8_t lib_i = 1;
    for(std::unique_ptr<LIBRARY>& lib : this->libs) {
        fcout << to_string(lib_i) << ". $(bright_magenta:b)" << lib->name << "$$(red):$$(magenta:b)" << lib->version << "$\n";
        lib_i++;
    }
    fcout << "$(red:b)-------------------------------$\n";
    fcout << "$(info)$(info:b)1$. Validate $(info:b)2$. Add library $(info:b)3$. Change library version $(info:b)4$. Remove library" << endl;
}

void LibManager::add_lib_menu() {
    std::unique_ptr<LIBRARY> lib = make_unique<LIBRARY>();
    lib->name = "";
    lib->version = "";
    fcout << "$(info)Name:$ ";
    while(!lib->name.size()) getline(cin, lib->name);
    fcout << "$(info)Version:$ ";
    while(!lib->version.size()) getline(cin, lib->version);
    this->libs.push_back(move(lib));
}

void LibManager::change_version_menu() {
    if(!this->libs.size()) {
        fcout << "$(warning)No libraries remaining." << endl;
        return;
    }
    size_t index = ask_n("Index:", 1, this->libs.size());
    std::unique_ptr<LIBRARY>& lib = this->libs.at(index - 1);
    lib->version = "";
    fcout << "$(info)Version:$ ";
    while(!lib->version.size()) getline(cin, lib->version);
}

void LibManager::remove_lib_menu() {
    if(!this->libs.size()) {
        fcout << "$(warning)No libraries remaining." << endl;
        return;
    }
    size_t index = ask_n("Index:", 1, this->libs.size());
    this->libs.erase(this->libs.begin() + index - 1);
}

void LibManager::manage() {
    USER_CHOICE choice = USER_CHOICE::NO_CHOICE;
    do {
        main_menu();
        choice = (USER_CHOICE) ask_n("Your choice ?", 1, 4);
        switch(choice) {
            case ADD_LIB:
                this->add_lib_menu();
                break;
            case CHANGE_VERSION:
                this->change_version_menu();
                break;
            case REMOVE_LIB:
                this->remove_lib_menu();
                break;
        }
    } while(choice != USER_CHOICE::VALIDATE);
}

================================================
FILE: src/binaries/lib/lib_manager.h
================================================
#ifndef CERBERUS_LIB_MANAGER_H
#define CERBERUS_LIB_MANAGER_H

#include <vector>
#include <binaries/bin_types.h>
#include <string>
#include <memory>

enum USER_CHOICE {
    NO_CHOICE = 0,
    VALIDATE = 1,
    ADD_LIB = 2,
    CHANGE_VERSION = 3,
    REMOVE_LIB = 4
};

class LibManager {
private:
    std::vector<std::unique_ptr<LIBRARY>>& libs;
    void main_menu();
    void add_lib_menu();
    void change_version_menu();
    void remove_lib_menu();
public:
    LibManager(std::vector<std::unique_ptr<LIBRARY>>& libs) : libs(libs) {}
    void manage();
};

#endif //CERBERUS_LIB_MANAGER_H


================================================
FILE: src/binaries/pe_types.h
================================================
#ifndef CERBERUS_PE_TYPES_H
#define CERBERUS_PE_TYPES_H

#include <cstdint>

struct EXPORT_DIRECTORY_TABLE {
    uint32_t export_flags = 0;
    uint32_t time_date_stamp = 0;
    uint16_t major_version = 0;
    uint16_t minor_version = 0;
    uint32_t name_rva;
    uint32_t ordinal_base = 1;
    uint32_t address_table_entries;
    uint32_t number_of_name_pointers;
    uint32_t export_address_table_rva;
    uint32_t name_pointer_rva;
    uint32_t ordinal_table_rva;
};

#endif //CERBERUS_PE_TYPES_H


================================================
FILE: src/command/command_executor.cpp
================================================
#include <command/command_executor.h>
#include <unistd.h>
#include <cstring>
#include <utils/logger.h>

using namespace std;

bool COMMANDS_DEBUG_MODE = false;

bool CommandExecutor::test_password(std::string password) {
    COMMAND_RESULT res;
    this->execute_command("echo "+password+" | sudo -Sk echo test", &res);
    return !res.code;
}

void CommandExecutor::execute_command(string command, COMMAND_RESULT* result) {
    char current_dir[1024];
    getcwd(current_dir, sizeof(current_dir));
    if (chdir(this->env_dir.c_str()) != 0) {
        result->code = -1;
        result->response = "";
        return;
    }
    FILE* pipe = popen((command+string(" 2>&1")).c_str(), "r");
    if (!pipe) {
        result->code = -1;
        result->response = "";
        chdir(current_dir);
        return;
    }
    stringstream ss;
    char buffer[128];
    if(COMMANDS_DEBUG_MODE) fcout << "$(debug)------ COMMAND OUTPUT ------" << endl;
    while (fgets(buffer, sizeof(buffer), pipe) != nullptr) {
        if(COMMANDS_DEBUG_MODE) fcout << "$(debug)" << buffer << "$";
        ss << string(buffer, strlen(buffer));
    }
    if(COMMANDS_DEBUG_MODE) fcout << "$(debug)----------------------------" << endl;
    result->code = pclose(pipe);
    result->response = ss.str();
    chdir(current_dir);
}

================================================
FILE: src/command/command_executor.h
================================================
#ifndef CERBERUS_COMMAND_EXECUTOR_H
#define CERBERUS_COMMAND_EXECUTOR_H

#include <cstdint>
#include <string>
#include <filesystem>

extern bool COMMANDS_DEBUG_MODE;

struct COMMAND_RESULT {
    int32_t code;
    std::string response;
};

class CommandExecutor {
private:
    std::string env_dir;
public:
    CommandExecutor(std::string env_dir) : env_dir(std::filesystem::absolute(env_dir)) {};
    bool test_password(std::string password);
    void execute_command(std::string command, COMMAND_RESULT* result);
};

#endif //CERBERUS_COMMAND_EXECUTOR_H


================================================
FILE: src/global_defs.h
================================================
#ifndef CERBERUS_GLOBAL_DEFS_H
#define CERBERUS_GLOBAL_DEFS_H

#include <string>

const std::string TOOL_ART = "   ___         _       \n"
                    "  / __|___ _ _| |__  ___ _ _ _  _ ___\n"
                    " | (__/ -_) '_| '_ \\/ -_) '_| || (_-<\n"
                    "  \\___\\___|_| |_.__/\\___|_|  \\_,_/__/\n";
const std::string TOOL_NAME = "Cerberus";
const std::string TOOL_VERSION = "2.0";
const std::string TOOL_AUTHOR = "h311d1n3r";
const std::string install_dir = "~/.local/bin";

#endif //CERBERUS_GLOBAL_DEFS_H

================================================
FILE: src/langs/lang_manager.cpp
================================================
#include <langs/lang_manager.h>
#include <utils/logger.h>
#include <fstream>
#include <cstring>
#include <algorithm>

using namespace std;

map<LANG, string> name_from_lang = {
    {LANG::UNKNOWN_LANG, "Unknown"},
    {LANG::RUST, "Rust"},
    {LANG::GO, "Go"}
};

vector<pair<string, LANG>> LANG_PATTERNS = {
    std::pair("/rustc-", LANG::RUST),
    std::pair("/.cargo/", LANG::RUST),
    std::pair("\\rustc-", LANG::RUST),
    std::pair("\\.cargo\\", LANG::RUST),
    std::pair("/go-", LANG::GO),
    std::pair("\\go-", LANG::GO),
    std::pair("runtime.go", LANG::GO)
};

LangIdentifier::LangIdentifier(string input_path) {
    this->input_path = input_path;
}

value_ordered_map<LANG, size_t> LangIdentifier::identify() {
    value_ordered_map<LANG, size_t> matches;
    for(uint32_t i = 1; i < name_from_lang.size(); i++) matches[(LANG)i] = 0;
    ifstream input_file(this->input_path);
    if (!input_file.is_open()) {
        fcout << "$(critical)File $(critical:u)" << input_path << "$ can't be opened !" << endl;
        exit(1);
    }
    input_file.seekg(0, ios::end);
    size_t input_sz = input_file.tellg();
    input_file.seekg(0);
    char input_data[2048];
    size_t input_off = 0;
    while(input_off < input_sz) {
        input_file.seekg(input_off);
        input_file.read(input_data, sizeof(input_data));
        for(pair<string, LANG> lang_pattern : LANG_PATTERNS) {
            char* current_pos = input_data;
            char* occurrence;
            while(current_pos-input_data < sizeof(input_data)) {
                if ((occurrence = strstr(current_pos, lang_pattern.first.c_str())) != nullptr) {
                    current_pos = occurrence + lang_pattern.first.length();
                    matches[lang_pattern.second]++;
                } else current_pos++;
            }
        }
        input_off += 1024;
    }
    input_file.close();
    matches.invert_sort();
    return matches;
}

================================================
FILE: src/langs/lang_manager.h
================================================
#ifndef CERBERUS_LANG_MANAGER_H
#define CERBERUS_LANG_MANAGER_H

#include <string>
#include <map>
#include <vector>
#include <types/value_ordered_map.h>
#include <langs/lang_types.h>

extern std::map<LANG, std::string> name_from_lang;

extern std::vector<std::pair<std::string, LANG>> LANG_PATTERNS;

class LangIdentifier {
private:
    std::string input_path;
public:
    LangIdentifier(std::string input_path);
    value_ordered_map<LANG, size_t> identify();
};

#endif //CERBERUS_LANG_MANAGER_H


================================================
FILE: src/langs/lang_types.h
================================================
#ifndef CERBERUS_LANG_TYPES_H
#define CERBERUS_LANG_TYPES_H

enum LANG {
    UNKNOWN_LANG,
    RUST,
    GO
};

#endif //CERBERUS_LANG_TYPES_H


================================================
FILE: src/langs/lib_regex.cpp
================================================
#include <langs/lib_regex.h>
#include <utils/convert.h>

using namespace std;

std::vector<std::string> rust_lib_regex = {
    "/.cargo/(.+?)\\.rs",
    "/cargo/(.+?)\\.rs",
    "index\\.crates\\.io-(.+?)\\\\(.+?)\\\\",
    "\\\\.cargo\\\\(.+?)\\.rs",
    "\\\\cargo\\\\(.+?)\\.rs",
    "index\\.crates\\.io-(.+?)/(.+?)/",
};

std::vector<std::string> go_lib_regex = {
    "go(.*?)/pkg/mod/(.+?)\\.(s|go)",
    "go(.*?)/src/(.+?)\\.(s|go)",
    "go(.*?)\\\\pkg\\\\mod/(.+?)\\.(s|go)",
    "go(.*?)\\\\src\\\\(.+?)\\.(s|go)",
    "go\\d+\\.\\d+\\.\\d+\\x00",
    "go\\d+\\.\\d+\\x00"
};

unique_ptr<LIBRARY> rust_extract_callback(string match) {
    size_t null_term_index;
    if((null_term_index = match.find('\x00')) != string::npos) {
        match = match.substr(0, null_term_index);
    }
    string lib_and_version = "";
    if(match.find("index.crates.io-") != string::npos) {
        size_t delim_index = match.find("/");
        if(delim_index == string::npos) delim_index = match.find("\\");
        if(delim_index == string::npos) return nullptr;
        vector<string> match_parts = split_string(match, match.at(delim_index));
        if(match_parts.size() < 2) return nullptr;
        lib_and_version = match_parts.at(1);
    } else {
        vector<string> match_parts = split_string(match, match.at(0));
        if(match_parts.size() < 6) return nullptr;
        lib_and_version = match_parts.at(5);
    }
    size_t delim_index;
    if((delim_index = lib_and_version.rfind('-')) == string::npos) return nullptr;
    unique_ptr<LIBRARY> lib = make_unique<LIBRARY>();
    lib->name = lib_and_version.substr(0, delim_index);
    lib->version = lib_and_version.substr(delim_index+1);
    return lib;
}

unique_ptr<LIBRARY> go_extract_callback(string match) {
    size_t null_term_index;
    if((null_term_index = match.find('\x00')) != string::npos) {
        match = match.substr(0, null_term_index);
    }
    uint8_t mode = 0;
    if(match.find("/") != string::npos) mode = 1;
    else if(match.find("\\") != string::npos) mode = 2;
    if(mode == 0 && match.length() > 2 && isdigit(match.at(2))) {
        unique_ptr<LIBRARY> lib = make_unique<LIBRARY>();
        lib->name = "go";
        lib->version = match.substr(2);
        return lib;
    }
    size_t pkg_index, src_index;
    if((pkg_index = (mode == 1 ? match.find("/pkg/mod/") : match.find("\\pkg\\mod\\"))) != string::npos) {
        size_t version_index = match.find("@");
        if(match.find("golang.org") == string::npos && version_index != string::npos) {
            unique_ptr<LIBRARY> lib = make_unique<LIBRARY>();
            size_t name_start_index = pkg_index+string("/pkg/mod/").length();
            lib->name = match.substr(name_start_index, version_index-name_start_index);
            lib->version = match.substr(version_index+2);
            lib->version = lib->version.substr(0, lib->version.find('/'));
            return lib;
        }
    } else if((src_index = (mode == 1 ? match.find("/src/") : match.find("\\src\\"))) != string::npos) {
        const string forbidden_list[] = {"internal","runtime","github.com","golang.org"};
        for(string forbidden : forbidden_list) if(match.find(forbidden) != string::npos) return nullptr;
        match = match.substr(src_index+string("/src/").length());
        match = match.substr(0, match.find_last_of(mode == 1 ? '/' : '\\'));
        unique_ptr<LIBRARY> lib = make_unique<LIBRARY>();
        lib->name = "std::" + match;
        lib->version = "unk";
        return lib;
    }
    return nullptr;
}

map<LANG, LibExtractCallback> lib_extract_callbacks = {
    {LANG::RUST, rust_extract_callback},
    {LANG::GO, go_extract_callback}
};


================================================
FILE: src/langs/lib_regex.h
================================================
#ifndef CERBERUS_LIB_REGEX_H
#define CERBERUS_LIB_REGEX_H

#include <vector>
#include <string>
#include <map>
#include <langs/lang_types.h>
#include <binaries/bin_types.h>
#include <functional>
#include <memory>

extern std::vector<std::string> rust_lib_regex;

extern std::vector<std::string> go_lib_regex;

using LibExtractCallback = std::function<std::unique_ptr<LIBRARY>(std::string)>;

std::unique_ptr<LIBRARY> rust_extract_callback(std::string match);
std::unique_ptr<LIBRARY> go_extract_callback(std::string match);

extern std::map<LANG, LibExtractCallback> lib_extract_callbacks;

#endif //CERBERUS_LIB_REGEX_H


================================================
FILE: src/main.cpp
================================================
#include <utils/arg_parser.h>
#include <utils/config.h>
#include <langs/lang_manager.h>
#include <binaries/bin_identifier.h>
#include <utils/logger.h>
#include <global_defs.h>
#include <user/user_prompt.h>
#include <binaries/handlers/elf_handler.h>
#include <binaries/handlers/pe_handler.h>
#include <binaries/lib/lib_manager.h>
#include <user/local_config.h>
#include <filesystem>
#include <uuid/uuid.h>
#include <curl/curl.h>
#include <algorithm/part_hash_algorithm.h>
#include <utils/convert.h>

namespace fs = std::filesystem;
using namespace std;

std::string work_dir;
CONFIG* config;
LANG selected_lang = LANG::UNKNOWN_LANG;
BIN_TYPE type;
LOCAL_CONFIG* usr_config;

vector<PACKAGE*> packages = {
    new OS_PACKAGE{"git", "git"},
    new OS_PACKAGE{"cargo", "cargo"},
    new OS_PACKAGE{"golang", "go"},
    new OS_PACKAGE{"binutils", "c++filt"},
    new OS_PACKAGE{"python3", "python3"},
    new OS_PACKAGE{"python3-pip", "pip3"},
    new OS_PACKAGE{"patch", "patch"},
    new PIP3_PACKAGE{"pyinstaller", "pyinstaller"},
    new GIT_PACKAGE{"radare2", "radare2", "https://github.com/radareorg/radare2", 0, "cd .. ; mv radare2 ../ ; ../radare2/sys/install.sh", false},
    new GIT_PACKAGE{"Goliath", "goliath", "https://github.com/h311d1n3r/Goliath", 0, "cd .. ; mv Goliath ../ ; cd ../Goliath ; ./build.sh; mv ./dist/goliath "+install_dir, false, false},
    new CARGO_PACKAGE{"cross", "cross"},
    new CUSTOM_PACKAGE{"rust", "rustup", "curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rust_install.sh ; sh +x rust_install.sh -y ; rm rust_install.sh"}
};

void global_init() {
    elf_version(EV_CURRENT);
    curl_global_init(CURL_GLOBAL_ALL);
    string home_dir = string(getenv("HOME"));
    replace_all((string&)install_dir, "~", home_dir);
    if(!fs::exists(install_dir)) fs::create_directories(install_dir);
    const char* current_path = getenv("PATH");
    string new_path = string(current_path)+string(":")+install_dir;
    const char* go_path = getenv("GOPATH");
    if(go_path && strlen(go_path)) new_path+=string(":")+string(go_path)+string("/bin");
    else new_path+=":"+home_dir+"/go/bin";
    setenv("PATH", new_path.c_str(), 1);
}

void global_exit() {
    curl_global_cleanup();
}

bool install_dependencies(BinaryHandler* handler) {
    DependencyManager dep_manager(usr_config, work_dir);
    std::vector<OS_PACKAGE*> os_packages;
    std::vector<GIT_PACKAGE*> git_packages;
    std::vector<PIP3_PACKAGE*> pip3_packages;
    std::vector<CARGO_PACKAGE*> cargo_packages;
    std::vector<GO_PACKAGE*> go_packages;
    std::vector<CUSTOM_PACKAGE*> custom_packages;
    for(PACKAGE* package : packages) {
        if(!dep_manager.is_package_installed(package)) {
            switch(package->package_type) {
                case 0:
                    os_packages.push_back((OS_PACKAGE*) package);
                    break;
                case 1:
                    pip3_packages.push_back((PIP3_PACKAGE*) package);
                    break;
                case 2:
                    git_packages.push_back((GIT_PACKAGE*) package);
                    break;
                case 3:
                    cargo_packages.push_back((CARGO_PACKAGE*) package);
                    break;
                case 4:
                    go_packages.push_back((GO_PACKAGE*) package);
                    break;
                case 5:
                    custom_packages.push_back((CUSTOM_PACKAGE*) package);
                    break;
            }
        }
    }
    if(!os_packages.size() && !git_packages.size() && !pip3_packages.size() && !cargo_packages.size() && !go_packages.size() && !custom_packages.size()) fcout << "$(info)No additional package is required." << endl;
    else {
        fcout << "$(info)The following packages are required :" << endl;
        if(os_packages.size()) {
            fcout << "$(bright_magenta)With $(bright_magenta:b)" << name_from_package_manager[usr_config->package_manager] << "$:" << endl;
            for (OS_PACKAGE *package : os_packages) {
                fcout << "$(magenta)- $(magenta:b)" + package->name << endl;
            }
        }
        if(pip3_packages.size()) {
            fcout << "$(bright_blue)With $(bright_blue:b)pip3$:" << endl;
            for (PIP3_PACKAGE *package : pip3_packages) {
                fcout << "$(blue)- $(blue:b)" + package->package_name << endl;
            }
        }
        if(git_packages.size()) {
            fcout << "$(bright_red)With $(bright_red:b)git$:" << endl;
            for (GIT_PACKAGE *package : git_packages) {
                fcout << "$(red)- $(red:b)" + package->repo_name << endl;
            }
        }
        if(cargo_packages.size()) {
            fcout << "$(bright_yellow)With $(bright_yellow:b)cargo$:" << endl;
            for (CARGO_PACKAGE *package : cargo_packages) {
                fcout << "$(yellow)- $(yellow:b)" + package->package_name << endl;
            }
        }
        if(go_packages.size()) {
            fcout << "$(bright_white)With $(bright_white:b)go$:" << endl;
            for (GO_PACKAGE *package : go_packages) {
                fcout << "$(white)- $(white:b)" + package->package_name << endl;
            }
        }
        if(custom_packages.size()) {
            fcout << "$(bright_green)$(bright_green:b)Custom$:" << endl;
            for (CUSTOM_PACKAGE *package : custom_packages) {
                fcout << "$(green)- $(green:b)" + package->package_name << endl;
            }
        }
        if(usr_config->is_root || usr_config->has_sudo) {
            if(usr_config->package_manager != PACKAGE_MANAGER::UNKNOWN || !os_packages.size()) {
                bool agrees_install = ask_yes_no("Proceed to installation ?", true);
                if(agrees_install) {
                    if(!usr_config->is_root) {
                        CommandExecutor executor("./");
                        string password;
                        while(true) {
                            password = ask_password("$(info)Input your password for sudo");
                            if(executor.test_password(password)) break;
                            fcout << "$(warning)Wrong password ! Try again..." << endl;
                        }
                        dep_manager.set_password(password);
                    }
                    for(OS_PACKAGE* package : os_packages) {
                        if(dep_manager.install_package(package)) fcout << "$(success)Done." << endl;
                        else {
                            fcout << "$(error)An error occurred during installation..." << endl;
                            return false;
                        }
                    }
                    for(PIP3_PACKAGE* package : pip3_packages) {
                        if(dep_manager.install_package(package)) fcout << "$(success)Done." << endl;
                        else {
                            fcout << "$(error)An error occurred during installation..." << endl;
                            return false;
                        }
                    }
                    for(GIT_PACKAGE* package : git_packages) {
                        if(dep_manager.install_package(package)) fcout << "$(success)Done." << endl;
                        else {
                            fcout << "$(error)An error occurred during installation..." << endl;
                            return false;
                        }
                    }
                    for(CARGO_PACKAGE* package : cargo_packages) {
                        if(dep_manager.install_package(package)) fcout << "$(success)Done." << endl;
                        else {
                            fcout << "$(error)An error occurred during installation..." << endl;
                            return false;
                        }
                    }
                    for(GO_PACKAGE* package : go_packages) {
                        if(dep_manager.install_package(package)) fcout << "$(success)Done." << endl;
                        else {
                            fcout << "$(error)An error occurred during installation..." << endl;
                            return false;
                        }
                    }
                    for(CUSTOM_PACKAGE* package : custom_packages) {
                        if(dep_manager.install_package(package)) fcout << "$(success)Done." << endl;
                        else {
                            fcout << "$(error)An error occurred during installation..." << endl;
                            return false;
                        }
                    }
                } else {
                    fcout << "$(error)Ending execution." << endl;
                    return false;
                }
            } else {
                fcout << "$(error)Without a known package manager, please install these packages and try again." << endl;
                return false;
            }
        } else {
            fcout << "$(error)Without being root or having sudo, please manually install these packages and try again." << endl;
            return false;
        }
    }
    return true;
}

void start_analysis() {
    BinaryHandler* handler;
    Algorithm* algorithm = new PartHashAlgorithm(config);
    switch(type) {
        case PE:
            handler = new PeHandler(config->binary_path, work_dir, selected_lang, algorithm);
            break;
        case ELF:
            handler = new ElfHandler(config->binary_path, work_dir, selected_lang, algorithm);
            break;
        default:
            return;
    }
    if(handler->extract_architecture() == BIN_ARCH::UNKNOWN_ARCH) {
        fcout << "$(error)Unsupported architecture !" << endl;
        return;
    }
    handler->extract_image_base();
    if(!install_dependencies(handler)) return;
    handler->strip_analysis();
    if(handler->is_stripped()) fcout << "$(info)File was found to be $(info:b)stripped$." << endl;
    else {
        fcout << "$(warning)File was not found to be $(warning:b)stripped$..." << endl;
        if(!ask_yes_no("Resume analysis ?", false)) return;
    }
    fcout << "$(info)Extracting libraries..." << endl;
    size_t libs_amount = handler->libs_extraction();
    if(!libs_amount) {
        fcout << "$(error)No libraries were found." << endl;
        return;
    }
    fcout << "$(success)Identified $(success:b)" << to_string(libs_amount) << "$ libraries." << endl;
    std::vector<std::unique_ptr<LIBRARY>>& libs = handler->get_libs();
    LibManager lib_manager(libs);
    lib_manager.manage();
    if(!libs.size()) {
        fcout << "$(error)No libraries remaining." << endl;
        return;
    }
    fcout << "$(info)Installing libraries..." << endl;
    size_t libs_installed = handler->libs_installation();
    if(!libs_installed) {
        fcout << "$(error)No libraries were successfully installed..." << endl;
        return;
    }
    fcout << "$(success)Installed $(success:b)" << to_string(libs_installed) << "$ libraries." << endl;
    fcout << "$(info)Analyzing target functions..." << endl;
    size_t funcs_sz = handler->functions_analysis();
    if(!funcs_sz) {
        fcout << "$(error)No functions were successfully analyzed..." << endl;
        return;
    }
    fcout << "$(success)Analyzed $(success:b)" << to_string(funcs_sz) << "$ functions." << endl;
    fcout << "$(info)Matching with functions from libraries..." << endl;
    string lib_extension;
    switch(type) {
        case BIN_TYPE::ELF:
            lib_extension = ".so";
            break;
        case BIN_TYPE::PE:
            lib_extension = ".dll";
            break;
    }
    for(const auto& entry : fs::directory_iterator(work_dir)) {
        if (fs::is_regular_file(entry)) {
            fs::path file_path = entry.path();
            if(ends_with(file_path.filename(), lib_extension)) {
                handler->functions_matching(file_path.string());
            }
        }
    }
    handler->post_matching();
    size_t matches_sz = handler->get_matches_sz();
    if(!matches_sz) {
        fcout << "$(error)No functions were successfully matched..." << endl;
        return;
    }
    fcout << "$(success)Matched $(success:b)" << to_string(matches_sz) << "$ functions. Matching rate: $(success:b)" << to_string((uint8_t)(matches_sz/(float)funcs_sz*100)) << "%" << endl;
    fcout << "$(info)Demangling function names..." << endl;
    handler->demangle_functions();
    fcout << "$(success)Done !" << endl;
    fcout << "$(info)Writing output file..." << endl;
    if(handler->write_output(config->output_path)) fcout << "$(success)Done !" << endl;
    else fcout << "$(error)An error occurred when writing to output file..." << endl;
}

std::string generate_work_dir() {
    uuid_t uuid;
    uuid_generate_random(uuid);
    char uuid_str[37];
    uuid_unparse_lower(uuid, uuid_str);
    work_dir = ".cerberus-"+string(uuid_str, 37).substr(0, 16);
    fs::create_directory(work_dir);
    return work_dir;
}

int main(int argc, char *argv[]) {
    global_init();
    ArgParser parser;
    config = parser.compute_args(argc, argv);
    COMMANDS_DEBUG_MODE = config->debug;
    NO_PROMPT = config->no_prompt;
    if(config) {
        fcout << "$(bright_red:b)---------- $(red:b)" << TOOL_NAME << " (v" << TOOL_VERSION << ")$ ----------" << endl;
        usr_config = identify_local_config();
        if(usr_config->package_manager != PACKAGE_MANAGER::UNKNOWN) fcout << "$(info)Identified package manager: $(info:b)" << name_from_package_manager[usr_config->package_manager] << endl;
        else fcout << "$(warning)Could not identify package manager..." << endl;
        if(usr_config->is_root) fcout << "$(info)Running as root." << endl;
        else if(usr_config->has_sudo) fcout << "$(info)Not running as root but sudo detected." << endl;
        else fcout << "$(warning)Not running as root and sudo couldn't be detected." << endl;
        type = identify_binary(config->binary_path);
        if(type == BIN_TYPE::UNKNOWN_TYPE) {
            fcout << "$(critical)The input file $(critical:u)" << config->binary_path << "$ couldn't be recognized..." << endl;
            return 1;
        }
        fcout << "$(info)Identified file as $(info:b)" << bin_type_names[type] << "$." << endl;
        LangIdentifier identifier(config->binary_path);
        value_ordered_map langs = identifier.identify();
        if(langs.at(0).second) {
            fcout << "$(info)Identified language : $(magenta:b)" << name_from_lang[langs.at(0).first] << endl;
            bool agree_lang = ask_yes_no("Continue analysis with this language ?", true);
            if(agree_lang) selected_lang = langs.at(0).first;
        } else fcout << "$(warning)Couldn't identify language automatically..." << endl;
        if(selected_lang == LANG::UNKNOWN_LANG) {
            fcout << "$(info)Currently supported languages :\n";
            for(size_t lang_i = 0; lang_i < langs.size(); lang_i++) {
                fcout << "$(magenta)" << to_string(lang_i+1) << ". $(magenta:b)" << name_from_lang[langs.at(lang_i).first] << endl;
            }
            uint8_t selected_lang_i = ask_n("$(info)Your choice ?", 1, langs.size());
            selected_lang = langs.at(selected_lang_i-1).first;
        }
        work_dir = generate_work_dir();
        fcout << "$(info)Using $(magenta:b)" << name_from_lang[selected_lang] << "$ for analysis." << endl;
        start_analysis();
        fs::remove_all(work_dir);
    }
    global_exit();
    return 0;
}


================================================
FILE: src/types/value_ordered_map.h
================================================
#ifndef CERBERUS_VALUE_ORDERED_MAP_H
#define CERBERUS_VALUE_ORDERED_MAP_H

#include <vector>
#include <string>
#include <algorithm>

template <typename KeyType, typename ValueType>
class value_ordered_map {
private:
    std::vector<std::pair<KeyType, ValueType>> map;
public:
    ValueType& operator[](const KeyType key) {
        for(std::pair<KeyType, ValueType>& pair : this->map) {
            if(pair.first == key) return pair.second;
        }
        std::pair<KeyType, ValueType> new_pair = std::pair<KeyType, ValueType>(key, 0);
        this->map.push_back(new_pair);
        return this->map.at(this->map.size()-1).second;
    }
    void sort() {
        std::sort(map.begin(), map.end(), [](const auto& a, const auto& b) {
            return a.second > b.second;
        });
    }
    void invert_sort() {
        std::sort(map.begin(), map.end(), [](const auto& a, const auto& b) {
            return a.second > b.second;
        });
    }
    std::pair<KeyType, ValueType> at(int64_t i) {
        return this->map[i];
    }
    size_t size() {
        return this->map.size();
    }
};

#endif //CERBERUS_VALUE_ORDERED_MAP_H


================================================
FILE: src/user/dependencies/dependency_manager.cpp
================================================
#include <user/dependencies/dependency_manager.h>
#include <utils/logger.h>

using namespace std;

map<PACKAGE_MANAGER, string> install_commands = {
    {PACKAGE_MANAGER::APT, "apt -y install %s"},
    {PACKAGE_MANAGER::APT_GET, "apt-get -y install %s"},
    {PACKAGE_MANAGER::DNF, "dnf -y install %s"},
    {PACKAGE_MANAGER::YUM, "yum -y install %s"},
    {PACKAGE_MANAGER::ZYPPER, "zypper -y install %s"},
    {PACKAGE_MANAGER::PACMAN, "pacman -y -S %s"},
    {PACKAGE_MANAGER::PORTAGE, "emerge -y %s"},
    {PACKAGE_MANAGER::SLACKPKG, "slackpkg -y install %s"},
    {PACKAGE_MANAGER::SWARET, "swaret -y --install %s"},
    {PACKAGE_MANAGER::XBPS, "xbps-install -y -S %s"},
    {PACKAGE_MANAGER::APK, "apk -y add %s"},
    {PACKAGE_MANAGER::NIX, "nix-env -y -iA nixpkgs.%s"},
    {PACKAGE_MANAGER::PETGET, "petget -y %s.pet"}
};

void DependencyManager::set_password(string password) {
    this->password = password;
}

bool DependencyManager::is_package_installed(PACKAGE* package) {
    return is_binary_on_path(package->binary);
}

bool DependencyManager::install_package(OS_PACKAGE* package) {
    fcout << "$(info)Installing $(info:b)" << package->name << "$..." << endl;
    string command = install_commands[config->package_manager];
    char formatted_cmd_buf[command.length() - 2 + package->name.length() + 1];
    snprintf(formatted_cmd_buf, sizeof(formatted_cmd_buf), command.c_str(), package->name.c_str());
    string formatted_cmd(formatted_cmd_buf);
    if(config->is_root) {
        COMMAND_RESULT res;
        executor.execute_command(formatted_cmd, &res);
        return res.code == 0;
    }
    else if(config->has_sudo) {
        COMMAND_RESULT res;
        executor.execute_command(string("echo ")+password+string(" | sudo -S ")+formatted_cmd, &res);
        return res.code == 0;
    }
    return false;
}

bool DependencyManager::install_package(PIP3_PACKAGE *package) {
    fcout << "$(info)Installing $(info:b)" << package->package_name << "$..." << endl;
    COMMAND_RESULT res;
    executor.execute_command(string("pip3 install ")+package->package_name, &res);
    return !res.code;
}

bool DependencyManager::install_package(GIT_PACKAGE* package) {
    fcout << "$(info)Installing $(info:b)" << package->repo_name << "$..." << endl;
    COMMAND_RESULT res;
    executor.execute_command(string("git clone ")+package->url, &res);
    if(res.code != 0) return false;
    string build_cmd = "mkdir build; cd build; cmake ..; make; make install";
    if(package->custom_command.size()) build_cmd = package->custom_command;
    if(!config->is_root && package->needs_root) build_cmd = string("echo ")+password+string(" | sudo -S sh -c \"unset SUDO_USER ; ") + build_cmd + string("\"");
    executor.execute_command(string("cd ")+package->repo_name+string("; ")+build_cmd, &res);
    if(package->remove_dir) filesystem::remove_all(work_dir+string("/")+package->repo_name);
    return res.code == package->success_code;
}

bool DependencyManager::install_package(CARGO_PACKAGE *package) {
    fcout << "$(info)Installing $(info:b)" << package->package_name << "$..." << endl;
    COMMAND_RESULT res;
    executor.execute_command(string("cargo install ")+package->package_name, &res);
    return !res.code;
}

bool DependencyManager::install_package(GO_PACKAGE *package) {
    fcout << "$(info)Installing $(info:b)" << package->package_name << "$..." << endl;
    COMMAND_RESULT res;
    executor.execute_command(string("go install ")+package->url+string("@latest"), &res);
    return !res.code;
}

bool DependencyManager::install_package(CUSTOM_PACKAGE *package) {
    fcout << "$(info)Installing $(info:b)" << package->package_name << "$..." << endl;
    COMMAND_RESULT res;
    executor.execute_command(string("sh -c \"") + package->command + string("\""), &res);
    return res.code == package->success_code;
}

================================================
FILE: src/user/dependencies/dependency_manager.h
================================================
#ifndef CERBERUS_DEPENDENCY_MANAGER_H
#define CERBERUS_DEPENDENCY_MANAGER_H

#include <string>
#include <map>
#include <user/local_config.h>
#include <command/command_executor.h>

struct PACKAGE {
    uint8_t package_type;
    std::string binary;
};

struct OS_PACKAGE : PACKAGE {
    std::string name;
    OS_PACKAGE(std::string name, std::string binary) {
        PACKAGE::package_type = 0;
        PACKAGE::binary = binary;
        OS_PACKAGE::name = name;
    }
};

struct PIP3_PACKAGE : PACKAGE {
    std::string package_name;
    PIP3_PACKAGE(std::string binary, std::string package_name) {
        PACKAGE::package_type = 1;
        PACKAGE::binary = binary;
        PIP3_PACKAGE::package_name = package_name;
    }
};

struct GIT_PACKAGE : PACKAGE {
    std::string repo_name;
    std::string url;
    std::string custom_command = "";
    std::int32_t success_code = 0;
    bool remove_dir = true;
    bool needs_root = true;
    GIT_PACKAGE(std::string repo_name, std::string binary, std::string url) {
        package_type = 2;
        PACKAGE::binary = binary;
        GIT_PACKAGE::repo_name = repo_name;
        GIT_PACKAGE::url = url;
    }
    GIT_PACKAGE(std::string repo_name, std::string binary, std::string url, int32_t success_code) : GIT_PACKAGE(repo_name, binary, url) {
        GIT_PACKAGE::success_code = success_code;
    }
    GIT_PACKAGE(std::string repo_name, std::string binary, std::string url, int32_t success_code, std::string custom_command) : GIT_PACKAGE(repo_name, binary, url, success_code) {
        GIT_PACKAGE::custom_command = custom_command;
    }
    GIT_PACKAGE(std::string repo_name, std::string binary, std::string url, int32_t success_code, std::string custom_command, bool remove_dir) : GIT_PACKAGE(repo_name, binary, url, success_code, custom_command) {
        GIT_PACKAGE::remove_dir = remove_dir;
    }
    GIT_PACKAGE(std::string repo_name, std::string binary, std::string url, int32_t success_code, std::string custom_command, bool remove_dir, bool needs_root) : GIT_PACKAGE(repo_name, binary, url, success_code, custom_command, remove_dir) {
        GIT_PACKAGE::needs_root = needs_root;
    }
};

struct CARGO_PACKAGE : PACKAGE {
    std::string package_name;
    CARGO_PACKAGE(std::string binary, std::string package_name) {
        PACKAGE::package_type = 3;
        PACKAGE::binary = binary;
        CARGO_PACKAGE::package_name = package_name;
    }
};

struct GO_PACKAGE : PACKAGE {
    std::string package_name;
    std::string url;
    GO_PACKAGE(std::string binary, std::string package_name, std::string url) {
        PACKAGE::package_type = 4;
        PACKAGE::binary = binary;
        GO_PACKAGE::package_name = package_name;
        GO_PACKAGE::url = url;
    }
};

struct CUSTOM_PACKAGE : PACKAGE {
    std::string package_name;
    std::string command;
    int32_t success_code = 0;
    CUSTOM_PACKAGE(std::string package_name, std::string binary, std::string command) {
        PACKAGE::package_type = 5;
        PACKAGE::binary = binary;
        CUSTOM_PACKAGE::package_name = package_name;
        CUSTOM_PACKAGE::command = command;
    }
    CUSTOM_PACKAGE(std::string package_name, std::string binary, std::string command, int32_t success_code) : CUSTOM_PACKAGE(package_name, binary, command) {
        CUSTOM_PACKAGE::success_code = success_code;
    }
};

extern std::map<PACKAGE_MANAGER, std::string> install_commands;

class DependencyManager {
private:
    LOCAL_CONFIG* config;
    std::string work_dir;
    CommandExecutor executor;
    std::string password;
public:
    DependencyManager(LOCAL_CONFIG* config, std::string work_dir) : config(config), work_dir(work_dir), executor(work_dir) {};
    void set_password(std::string password);
    bool is_package_installed(PACKAGE* package);
    bool install_package(OS_PACKAGE* package);
    bool install_package(GIT_PACKAGE* package);
    bool install_package(PIP3_PACKAGE* package);
    bool install_package(CARGO_PACKAGE* package);
    bool install_package(GO_PACKAGE* package);
    bool install_package(CUSTOM_PACKAGE* package);
};

#endif //CERBERUS_DEPENDENCY_MANAGER_H


================================================
FILE: src/user/local_config.cpp
================================================
#include <user/local_config.h>
#include <unistd.h>
#include <utils/convert.h>

using namespace std;

map<PACKAGE_MANAGER, string> name_from_package_manager = {
    {UNKNOWN, "your package manager"},
    {APT, "apt"},
    {APT_GET, "apt-get"},
    {DNF, "dnf"},
    {YUM, "yum"},
    {ZYPPER, "zypper"},
    {PACMAN, "pacman"},
    {PORTAGE, "emerge"},
    {SLACKPKG, "slackpkg"},
    {SWARET, "swaret"},
    {XBPS, "xbps-install"},
    {APK, "apk"},
    {NIX, "nix-env"},
    {PETGET, "petget"}
};

PACKAGE_MANAGER find_package_manager() {
    for(pair<PACKAGE_MANAGER, string> manager : name_from_package_manager) {
        if(is_binary_on_path(manager.second)) return manager.first;
    }
    return PACKAGE_MANAGER::UNKNOWN;
}

bool is_root() {
    return geteuid() == 0;
}

bool has_sudo() {
    return is_binary_on_path("sudo");
}

LOCAL_CONFIG* identify_local_config() {
    LOCAL_CONFIG* config = new LOCAL_CONFIG();
    config->package_manager = find_package_manager();
    config->is_root = is_root();
    config->has_sudo = has_sudo();
    return config;
}

bool is_binary_on_path(string binary) {
    const char* path_env = std::getenv("PATH");
    if (path_env == nullptr) return false;
    string path_env_str(path_env);
    vector<string> paths = split_string(path_env_str,':');
    for(string path : paths) {
        string full_path = path + '/' + binary;
        if (access(full_path.c_str(), X_OK) == 0) return true;
    }
    return false;
}

================================================
FILE: src/user/local_config.h
================================================
#ifndef CERBERUS_LOCAL_CONFIG_H
#define CERBERUS_LOCAL_CONFIG_H

#include <string>
#include <map>

enum PACKAGE_MANAGER {
    UNKNOWN,
    APT,
    APT_GET,
    DNF,
    YUM,
    ZYPPER,
    PACMAN,
    PORTAGE,
    SLACKPKG,
    SWARET,
    XBPS,
    APK,
    NIX,
    PETGET
};

struct LOCAL_CONFIG {
    PACKAGE_MANAGER package_manager;
    bool is_root;
    bool has_sudo;
};

extern std::map<PACKAGE_MANAGER, std::string> name_from_package_manager;

LOCAL_CONFIG* identify_local_config();

bool is_binary_on_path(std::string binary);

#endif //CERBERUS_LOCAL_CONFIG_H


================================================
FILE: src/user/user_prompt.cpp
================================================
#include <user/user_prompt.h>
#include <utils/logger.h>
#include <utils/convert.h>
#include <iostream>
#include <termios.h>
#include <unistd.h>

using namespace std;

bool NO_PROMPT = false;

bool ask_yes_no(string question, bool should_yes) {
    if(NO_PROMPT) return should_yes;
    fcout << "$(info)" << question << " (" << (should_yes?"Y":"y") << "/" << (should_yes?"n":"N") << ") $";
    string response;
    getline(cin, response);
    if(!response.size()) return should_yes;
    if(should_yes) {
        if(tolower(response.at(0), locale()) == 'n') return false;
        return true;
    } else {
        if(tolower(response.at(0), locale()) == 'y') return true;
        return false;
    }
}

uint8_t ask_n(string question, uint8_t min, uint8_t max) {
    if(NO_PROMPT) return min;
    fcout << "$(info)" << question << " (" << to_string(min) << "-" << to_string(max) << ") $";
    string response;
    uint8_t response_i = max + 1;
    while(response_i < min || response_i > max) {
        getline(cin, response);
        while (!string_to_int<uint8_t>(response, response_i)) {
            fcout << "$(error)Wrong value, please try again (" << to_string(min) << "-" << to_string(max) << ") $";
            getline(cin, response);
        }
        if(response_i < min || response_i > max) fcout << "$(error)Value is not in range, please try again (" << to_string(min) << "-" << to_string(max) << ") $";
    }
    return response_i;
}

string ask_password(string question) {
    termios oldt;
    tcgetattr(STDIN_FILENO, &oldt);
    termios newt = oldt;
    newt.c_lflag &= ~ECHO;
    tcsetattr(STDIN_FILENO, TCSANOW, &newt);
    fcout << "$(info)" << question << ": $";
    string password;
    getline(cin, password);
    fcout << endl;
    tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
    return password;
}

================================================
FILE: src/user/user_prompt.h
================================================
#ifndef CERBERUS_USER_PROMPT_H
#define CERBERUS_USER_PROMPT_H

#include <string>
#include <cstdint>

extern bool NO_PROMPT;

bool ask_yes_no(std::string question, bool should_yes);
uint8_t ask_n(std::string question, uint8_t min, uint8_t max);
std::string ask_password(std::string question);

#endif //CERBERUS_USER_PROMPT_H


================================================
FILE: src/utils/arg_parser.cpp
================================================
#include <utils/arg_parser.h>
#include <utils/logger.h>
#include <global_defs.h>
#include <filesystem>

namespace fs = std::filesystem;
using namespace std;

string ArgParser::format_help() {
    string res = "$(cyan)$(cyan:b)" + TOOL_ART + "$\n";
    res += " Version: $(white:b)" + TOOL_VERSION + "$\n";
    res += " Author: $(white:b)" + TOOL_AUTHOR + "$\n";
    res += "______________________________________\n\n";
    res += "$(cyan:b)Syntax: $(red:b)cerberus binary [-param value] [--flag]$$\n\n";
    res += "$(cyan:b)Parameters:$\n";
    res += "   $(red:b)output (o)$ -> Specifies the path for the resulting executable file. $(cyan:b)Default value: [input_binary]-patched$\n";
    res += "   $(red:b)part_hash_len (phl)$ -> 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. $(cyan:b)Default value: 20$\n";
    res += "   $(red:b)part_hash_trust (pht)$ -> 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. $(cyan:b)Default value: 0.6$\n";
    res += "   $(red:b)min_func_size (mfs)$ -> Specifies the minimum length a function must be to get analyzed. Decreasing this value will increase matches but also false positives. $(cyan:b)Default value : 10$\n\n";
    res += "$(cyan:b)Flags:$\n";
    res += "   $(red:b)help (h)$ -> Displays this message.\n";
    res += "   $(red:b)debug (h)$ -> Displays outputs of commands.\n";
    res += "   $(red:b)no-prompt (np)$ -> Automatically skips user prompts.";
    return res;
}

void ArgParser::prepare_args() {
    this->parser.add_argument("binary").default_value("");
    this->parser.add_argument("-output", "-o");
    this->parser.add_argument("-part_hash_len", "-phl");
    this->parser.add_argument("-part_hash_trust", "-pht");
    this->parser.add_argument("-min_func_size", "-mfs");
    this->parser.add_argument("--help", "--h").implicit_value(true);
    this->parser.add_argument("--debug", "--dbg").implicit_value(true);
    this->parser.add_argument("--no-prompt", "--np").implicit_value(true);
}

CONFIG* ArgParser::compute_args(int argc, char **argv) {
    CONFIG* config = new CONFIG;
    if(argc >= 2) {
        this->parser.parse_args(argc, argv);
        config->binary_path = this->parser.get<string>("binary");
        if(this->parser.is_used("-output")) config->output_path = this->parser.get<string>("output");
        else {
            size_t extension_idx;
            string extension = "";
            if((extension_idx = config->binary_path.find_last_of('.')) != string::npos) {
                if(config->binary_path.find_last_of('/') < extension_idx && config->binary_path.find_last_of('\\') < extension_idx) {
                    extension = config->binary_path.substr(extension_idx);
                }
            }
            config->output_path = config->binary_path + extension + "-patched";
        }
        if (this->parser.is_used("-part_hash_len")) config->part_hash_len = this->parser.get<uint16_t>("part_hash_len");
        if (this->parser.is_used("-part_hash_trust"))
            config->part_hash_trust = this->parser.get<float>("part_hash_trust");
        if (this->parser.is_used("-min_func_size")) config->min_func_size = this->parser.get<uint16_t>("min_func_size");
        if (this->parser.is_used("--debug")) config->debug = true;
        if (this->parser.is_used("--no-prompt")) config->no_prompt = true;
    }
    if(argc < 2 || this->parser.is_used("--help") || !config->binary_path.length()) {
        string help = this->format_help();
        fcout << help << endl;
        exit(0);
    }
    if(!fs::exists(config->binary_path)) {
        fcout << "$(critical)File $(critical:u)" << config->binary_path << "$ does not exist !" << endl;
        exit(1);
    }
    return config;
}

ArgParser::ArgParser() {
    this->parser = argparse::ArgumentParser("cerberus");
    this->prepare_args();
}

================================================
FILE: src/utils/arg_parser.h
================================================
#ifndef CERBERUS_ARG_PARSER_H
#define CERBERUS_ARG_PARSER_H

#include <utils/config.h>
#include <argparse/argparse.hpp>

class ArgParser {
private:
    argparse::ArgumentParser parser;
    std::string format_help();
    void prepare_args();
public:
    ArgParser();
    CONFIG* compute_args(int argc, char *argv[]);
};

#endif //CERBERUS_ARG_PARSER_H


================================================
FILE: src/utils/config.h
================================================
#ifndef CERBERUS_CONFIG_H
#define CERBERUS_CONFIG_H

#include <string>
#include <cstdint>

struct CONFIG {
    std::string binary_path;
    std::string output_path;
    uint16_t part_hash_len = 20;
    float part_hash_trust = 0.6;
    uint16_t min_func_size = 10;
    bool debug = false;
    bool no_prompt = false;
};

#endif //CERBERUS_CONFIG_H


================================================
FILE: src/utils/convert.cpp
================================================
#include <utils/convert.h>
#include <sstream>
#include <command/command_executor.h>

using namespace std;

vector<string> split_string(const string& input, char delimiter) {
    vector<std::string> tokens;
    istringstream token_stream(input);
    string token;
    while (getline(token_stream, token, delimiter)) {
        tokens.push_back(token);
    }
    return tokens;
}

vector<std::string> filter_empty_strings(const vector<std::string>& tab) {
    vector<std::string> result;
    for (const std::string& s : tab) {
        if (!s.empty()) {
            result.push_back(s);
        }
    }
    return result;
}

string strip(const string& str) {
    size_t first = str.find_first_not_of(" \t\n");
    if (string::npos == first) {
        return "";
    }
    size_t last = str.find_last_not_of(" \t\n");
    return str.substr(first, (last - first + 1));
}

bool ends_with(string const &value, string const &ending) {
    if (ending.size() > value.size()) return false;
    return equal(ending.rbegin(), ending.rend(), value.rbegin());
}

void replace_all(string& str, const string& from, const string& to) {
    if(from.empty()) return;
    size_t start_pos = 0;
    while((start_pos = str.find(from, start_pos)) != std::string::npos) {
        str.replace(start_pos, from.length(), to);
        start_pos += to.length();
    }
}

string demangle_function_name(string& mangled_name) {
    replace_all(mangled_name, string("$"), string("\\$"));
    CommandExecutor executor("./");
    COMMAND_RESULT res;
    executor.execute_command(string("c++filt \"")+mangled_name+string("\""), &res);
    if(!res.code) return res.response.substr(0, res.response.length()-1);
    return mangled_name;
}

================================================
FILE: src/utils/convert.h
================================================
#ifndef CERBERUS_CONVERT_H
#define CERBERUS_CONVERT_H

#include <string>
#include <vector>

template<typename IntType> bool string_to_int(std::string s, IntType& val) {
    try {
        if (s.size() >= 2 && s.substr(0, 2) == "0x") val = static_cast<IntType>(stoll(s.substr(2), nullptr, 16));
        else val = static_cast<IntType>(stoll(s, nullptr, 10));
        return true;
    } catch (const std::exception& e) {
        return false;
    }
}

std::vector<std::string> split_string(const std::string& input, char delimiter);

std::vector<std::string> filter_empty_strings(const std::vector<std::string>& tab);

std::string strip(const std::string& str);

bool ends_with(std::string const& value, std::string const& ending);

void replace_all(std::string& str, const std::string& from, const std::string& to);

std::string demangle_function_name(std::string& mangled_name);

#endif //CERBERUS_CONVERT_H


================================================
FILE: src/utils/file_downloader.cpp
================================================
#include <utils/file_downloader.h>

using namespace std;

FileDownloader::FileDownloader() {
    curl = curl_easy_init();
}

FileDownloader::~FileDownloader() {
    curl_easy_cleanup(curl);
}

size_t write_callback(void* contents, size_t size, size_t nmemb, FILE* file) {
    return fwrite(contents, size, nmemb, file);
}

bool FileDownloader::download_file(string url, string path) {
    FILE* file = fopen(path.c_str(), "wb");
    if (file) {
        curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
        curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, file);
        CURLcode res = curl_easy_perform(curl);
        fclose(file);
        if (res == CURLE_OK) return true;
    }
    return false;
}

================================================
FILE: src/utils/file_downloader.h
================================================
#ifndef CERBERUS_FILE_DOWNLOADER_H
#define CERBERUS_FILE_DOWNLOADER_H
#include <curl/curl.h>
#include <string>

class FileDownloader {
private:
    CURL* curl;
public:
    FileDownloader();
    ~FileDownloader();
    bool download_file(std::string url, std::string path);
};

#endif //CERBERUS_FILE_DOWNLOADER_H


================================================
FILE: src/utils/file_operations.cpp
================================================
#include <utils/file_operations.h>
#include <fstream>
#include <gzip/utils.hpp>
#include <gzip/decompress.hpp>
#include <archive.h>
#include <archive_entry.h>
#include <fcntl.h>
#include <filesystem>
#include <iostream>

using namespace std;

bool decompress_gzip_file(string input, string output) {
    ifstream input_file(input, ios::binary);
    input_file.seekg(0, ios::end);
    size_t input_file_sz = input_file.tellg();
    input_file.seekg(0);
    char* data = (char*) malloc(input_file_sz);
    if(!data) return false;
    input_file.read(data, input_file_sz);
    input_file.close();
    if(!gzip::is_compressed(data, input_file_sz)) return false;
    string decompressed = gzip::decompress(data, input_file_sz);
    ofstream output_file(output, ios::binary);
    output_file.write(decompressed.c_str(), decompressed.size());
    output_file.close();
    free(data);
    return true;
}

bool decompress_tar_file(string input, string output) {
    struct archive* a = archive_read_new();
    archive_read_support_format_all(a);
    if (archive_read_open_filename(a, input.c_str(), 10240) != ARCHIVE_OK) {
        return false;
    }
    if (!filesystem::create_directory(output)) {
        return false;
    }
    struct archive_entry* entry;
    while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
        string entry_name = string(archive_entry_pathname(entry));
        size_t first_separator_index = entry_name.find('/');
        if(first_separator_index == string::npos) continue;
        entry_name = entry_name.substr(first_separator_index+1);
        string output_file_path = string(output) + "/" + entry_name;
        size_t last_separator_index = output_file_path.rfind('/');
        if(last_separator_index != string::npos) {
            string directory_part = output_file_path.substr(0, last_separator_index);
            filesystem::create_directories(directory_part);
        }
        int outputFd = open(output_file_path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
        if (outputFd == -1) {
            continue;
        }
        const void* buffer;
        size_t size;
        int64_t offset;
        while (archive_read_data_block(a, &buffer, &size, &offset) == ARCHIVE_OK) {
            write(outputFd, buffer, size);
        }
        close(outputFd);
    }
    archive_read_close(a);
    archive_read_free(a);
    return true;
}

================================================
FILE: src/utils/file_operations.h
================================================
#ifndef CERBERUS_FILE_OPERATIONS_H
#define CERBERUS_FILE_OPERATIONS_H

#include <string>

bool decompress_gzip_file(std::string input, std::string output);
bool decompress_tar_file(std::string input, std::string output);

#endif //CERBERUS_FILE_OPERATIONS_H


================================================
FILE: src/utils/logger.cpp
================================================
#include <utils/logger.h>
#include <iostream>

using namespace std;

FCout fcout;

map<string, uint8_t> LOG_COLORS = {
    {"black", 30},
    {"red", 31},
    {"green", 32},
    {"yellow", 33},
    {"blue", 34},
    {"magenta", 35},
    {"cyan", 36},
    {"white", 37},
    {"bright_black", 90},
    {"bright_red", 91},
    {"bright_green", 92},
    {"bright_yellow", 93},
    {"bright_blue", 94},
    {"bright_magenta", 95},
    {"bright_cyan", 96},
    {"bright_white", 97}
};

map<string, pair<uint8_t, uint8_t>> LOG_LEVELS = {
    {"success", pair(32, '+')},
    {"info", pair(36, '*')},
    {"debug", pair(34, '~')},
    {"warning", pair(33, '#')},
    {"error", pair(35, '?')},
    {"critical", pair(31, '!')}
};

map<char, uint8_t> LOG_STYLES = {
    {'n', 0},
    {'b', 1},
    {'i', 3},
    {'u', 4},
    {'s', 9},
};

FCout FCout::operator<<(string s) {
    format(s);
    std::cout << s;
    fcout = *this;
    return *this;
}

FCout FCout::operator<<(std::ostream&(*pManip)(std::ostream&)) {
    cout << *pManip << "\033[0;"+to_string(LOG_COLORS["gray"])+"m";
    args_stack.clear();
    fcout = *this;
    return *this;
}

void FCout::format(std::string& s) {
   size_t index;
   string res = "";
   while((index = s.find('$')) != string::npos) {
        res += s.substr(0, index);
        if(index < s.length()-1 && s.at(index+1) == '(') {
            string arg_name = s.substr(index+2);
            arg_name = arg_name.substr(0, arg_name.find(')'));
            int index2;
            uint8_t font_mode = 0;
            bool has_font_mode = false;
            if((index2 = arg_name.find(":")) != string::npos) {
                has_font_mode = true;
                uint8_t font_mode_chr = arg_name.at(index2+1);
                if(LOG_STYLES.find(font_mode_chr) != LOG_STYLES.end()) {
                    font_mode = LOG_STYLES[font_mode_chr];
                }
                arg_name = arg_name.substr(0, arg_name.length()-2);
            }
            if(LOG_COLORS.find(arg_name) != LOG_COLORS.end()) {
                args_stack.push_back(pair(LOG_COLORS[arg_name], font_mode));
                res += "\033["+to_string(font_mode)+";"+to_string(LOG_COLORS[arg_name])+"m";
            } else if(LOG_LEVELS.find(arg_name) != LOG_LEVELS.end()) {
                pair<uint8_t, uint8_t> level = LOG_LEVELS[arg_name];
                res += "\033["+to_string(font_mode)+";"+to_string(level.first)+"m";
                if(!this->args_stack.size() || this->args_stack.at(this->args_stack.size()-1).first != level.first) res += string("[")+(char)level.second+"] ";
                args_stack.push_back(pair(level.first, font_mode));
            }
            s = s.substr(index+3+arg_name.length()+(has_font_mode?2:0));
        } else if(args_stack.size() > 0) {
            args_stack.pop_back();
            pair<uint8_t, uint8_t> arg;
            if(args_stack.size() > 0) arg = args_stack.at(args_stack.size()-1);
            else arg = pair(LOG_COLORS["gray"], 0);
            res += "\033["+to_string(arg.second)+";"+to_string(arg.first)+"m";
            s = s.substr(index+1);
        }
   }
   res += s;
   s = res;
}

================================================
FILE: src/utils/logger.h
================================================
#ifndef CERBERUS_LOGGER_H
#define CERBERUS_LOGGER_H

#include <string>
#include <map>
#include <vector>
#include <cstdint>

extern std::map<std::string, uint8_t> LOG_COLORS;
extern std::map<std::string, std::pair<uint8_t, uint8_t>> LOG_LEVELS;
extern std::map<char, uint8_t> LOG_STYLES;

class FCout {
private:
    std::vector<std::pair<uint8_t,uint8_t>> args_stack;
public:
    FCout operator<<(std::string s);
    FCout operator<<(std::ostream&(*pManip)(std::ostream&));
    void format(std::string& s);
};

extern FCout fcout;

#endif //CERBERUS_LOGGER_H


================================================
FILE: src/utils/search.cpp
================================================
#include <utils/search.h>

using namespace std;

vector<string> search_regex(char* data, size_t data_sz, string pattern, size_t match_max_sz) {
    vector<string> matches;
    regex reg(pattern);
    size_t data_i = 0;
    while(data_i < data_sz) {
        string data_str(data+data_i, 1024+match_max_sz);
        sregex_iterator it(data_str.begin(), data_str.end(), reg);
        sregex_iterator end;
        while (it != end) {
            smatch match = *it;
            matches.push_back(match.str());
            ++it;
        }
        data_i += 1024;
    }
    return matches;
}

================================================
FILE: src/utils/search.h
================================================
#ifndef CERBERUS_SEARCH_H
#define CERBERUS_SEARCH_H

#include <regex>
#include <vector>

std::vector<std::string> search_regex(char* data, size_t data_sz, std::string pattern, size_t match_max_sz);

#endif //CERBERUS_SEARCH_H


================================================
FILE: test/Go/test_1/result.txt
================================================
github.com/fatih/color.colorPrint
crypto/aes.NewCipher


================================================
FILE: test/Go/test_1/src/go.mod
================================================
module test_1

go 1.18

require (
	github.com/fatih/color v1.15.0 // indirect
	github.com/mattn/go-colorable v0.1.13 // indirect
	github.com/mattn/go-isatty v0.0.17 // indirect
	golang.org/x/sys v0.6.0 // indirect
)


================================================
FILE: test/Go/test_1/src/go.sum
================================================
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=


================================================
FILE: test/Go/test_1/src/test_1.go
================================================
package main

import (
	"github.com/fatih/color"
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/base64"
	"fmt"
	"io"
)

func main() {
	fmt.Println("Hey ! Starting the program...")

	key := []byte("The secret key !")

	plaintext := []byte("Message to encrypt")

	iv := make([]byte, aes.BlockSize)
	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
		panic(err)
	}

	block, err := aes.NewCipher(key)
	if err != nil {
		panic(err)
	}

	mode := cipher.NewCBCEncrypter(block, iv)

	plaintext = padPKCS7(plaintext, aes.BlockSize)

	ciphertext := make([]byte, len(plaintext))

	mode.CryptBlocks(ciphertext, plaintext)

	ciphertext = append(iv, ciphertext...)

	encodedText := base64.StdEncoding.EncodeToString(ciphertext)
	fmt.Println("Encrypted text (base64):", encodedText)

	decodedText, err := base64.StdEncoding.DecodeString(encodedText)
	if err != nil {
		panic(err)
	}

	iv = decodedText[:aes.BlockSize]
	ciphertext = decodedText[aes.BlockSize:]

	mode = cipher.NewCBCDecrypter(block, iv)

	decryptedText := make([]byte, len(ciphertext))

	mode.CryptBlocks(decryptedText, ciphertext)

	decryptedText = unpadPKCS7(decryptedText)

	fmt.Println("Decrypted text:", string(decryptedText))
	
	color.Cyan("Prints text in cyan.")
}

func padPKCS7(data []byte, blockSize int) []byte {
	padding := blockSize - (len(data) % blockSize)
	padText := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(data, padText...)
}

func unpadPKCS7(data []byte) []byte {
	length := len(data)
	unpadding := int(data[length-1])
	return data[:length-unpadding]
}


================================================
FILE: test/Rust/test_1/Cargo.toml
================================================
[package]
name = "test_1"
version = "0.1.0"
edition = "2021"

[dependencies]
aes = "0.8.2"

[profile.release]
strip = true


================================================
FILE: test/Rust/test_1/result.txt
================================================
aes::soft::fixslice::aes128_encrypt
<aes::ni::Aes128Enc as crypto_common::KeyInit>::new


================================================
FILE: test/Rust/test_1/src/main.rs
================================================
use aes::Aes128;
use aes::cipher::{
    BlockEncrypt, BlockDecrypt, KeyInit,
    generic_array::GenericArray,
};

fn main() {
    let key = GenericArray::from([0u8; 16]);
    let mut block = GenericArray::from([42u8; 16]);
    let cipher = Aes128::new(&key);
    let block_copy = block.clone();
    cipher.encrypt_block(&mut block);
    cipher.decrypt_block(&mut block);
    assert_eq!(block, block_copy);
    let mut blocks = [block; 100];
    cipher.encrypt_blocks(&mut blocks);
    for block in blocks.iter_mut() {
        cipher.decrypt_block(block);
        assert_eq!(block, &block_copy);
    }
    cipher.decrypt_blocks(&mut blocks);
    for block in blocks.iter_mut() {
        cipher.encrypt_block(block);
        assert_eq!(block, &block_copy);
    }
}
Download .txt
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
Download .txt
SYMBOL INDEX (88 symbols across 45 files)

FILE: src/algorithm/algorithm.h
  function class (line 10) | class Algorithm {

FILE: src/algorithm/part_hash_algorithm.h
  function class (line 8) | class PartHashAlgorithm : public Algorithm {

FILE: src/binaries/bin_extractor.h
  function class (line 9) | class BinaryExtractor {

FILE: src/binaries/bin_handler.cpp
  function BIN_ARCH (line 12) | BIN_ARCH BinaryHandler::extract_architecture() {

FILE: src/binaries/bin_handler.h
  function class (line 14) | class BinaryHandler {
  function is_stripped (line 45) | bool is_stripped() {

FILE: src/binaries/bin_identifier.cpp
  function BIN_TYPE (line 18) | BIN_TYPE identify_binary(string input_path) {

FILE: src/binaries/bin_types.h
  type FUNCTION (line 7) | struct FUNCTION {
  type SECTION (line 16) | struct SECTION {
  type LIBRARY (line 22) | struct LIBRARY {
  type BIN_TYPE (line 27) | enum BIN_TYPE {
  type BIN_ARCH (line 33) | enum BIN_ARCH {

FILE: src/binaries/extractors/go_extractor.cpp
  function BIN_ARCH (line 7) | BIN_ARCH GoExtractor::extract_arch() {

FILE: src/binaries/extractors/go_extractor.h
  function class (line 8) | class GoExtractor : public BinaryExtractor {

FILE: src/binaries/extractors/libelf_extractor.cpp
  function BIN_ARCH (line 18) | BIN_ARCH LibelfExtractor::extract_arch() {

FILE: src/binaries/extractors/libelf_extractor.h
  function class (line 7) | class LibelfExtractor : public BinaryExtractor {

FILE: src/binaries/extractors/lief_extractor.cpp
  function BIN_ARCH (line 21) | BIN_ARCH LiefExtractor::extract_arch() {

FILE: src/binaries/extractors/lief_extractor.h
  function class (line 7) | class LiefExtractor : public BinaryExtractor {

FILE: src/binaries/extractors/radare_extractor.cpp
  function BIN_ARCH (line 6) | BIN_ARCH RadareExtractor::extract_arch() {

FILE: src/binaries/extractors/radare_extractor.h
  function class (line 8) | class RadareExtractor : public BinaryExtractor {

FILE: src/binaries/handlers/elf_handler.h
  function class (line 6) | class ElfHandler : public BinaryHandler {

FILE: src/binaries/handlers/pe_handler.h
  function class (line 6) | class PeHandler : public BinaryHandler {

FILE: src/binaries/lib/install/go_lib_installer.h
  function class (line 7) | class GoLibInstaller : public LibInstaller {

FILE: src/binaries/lib/install/lib_installer.h
  function class (line 9) | class LibInstaller {

FILE: src/binaries/lib/install/rust_lib_installer.cpp
  function newer_edition_patch (line 18) | void newer_edition_patch(string crate_path) {
  function std_redefinition_patch (line 46) | void std_redefinition_patch(string crate_path) {
  function add_workspace_patch (line 68) | void add_workspace_patch(string crate_path) {

FILE: src/binaries/lib/install/rust_lib_installer.h
  type PATCH (line 8) | struct PATCH {
  function class (line 13) | class RustBuildFixer {
  function class (line 24) | class RustLibInstaller : public LibInstaller {

FILE: src/binaries/lib/lib_manager.h
  type USER_CHOICE (line 9) | enum USER_CHOICE {
  function class (line 17) | class LibManager {

FILE: src/binaries/pe_types.h
  type EXPORT_DIRECTORY_TABLE (line 6) | struct EXPORT_DIRECTORY_TABLE {

FILE: src/command/command_executor.h
  type COMMAND_RESULT (line 10) | struct COMMAND_RESULT {
  function class (line 15) | class CommandExecutor {

FILE: src/langs/lang_manager.h
  function class (line 14) | class LangIdentifier {

FILE: src/langs/lang_types.h
  type LANG (line 4) | enum LANG {

FILE: src/langs/lib_regex.cpp
  function rust_extract_callback (line 24) | unique_ptr<LIBRARY> rust_extract_callback(string match) {
  function go_extract_callback (line 50) | unique_ptr<LIBRARY> go_extract_callback(string match) {

FILE: src/main.cpp
  function global_init (line 42) | void global_init() {
  function global_exit (line 56) | void global_exit() {
  function install_dependencies (line 60) | bool install_dependencies(BinaryHandler* handler) {
  function start_analysis (line 203) | void start_analysis() {
  function generate_work_dir (line 289) | std::string generate_work_dir() {
  function main (line 299) | int main(int argc, char *argv[]) {

FILE: src/types/value_ordered_map.h
  function sort (line 21) | void sort() {
  function invert_sort (line 26) | void invert_sort() {
  function size (line 34) | size_t size() {

FILE: src/user/dependencies/dependency_manager.h
  type PACKAGE (line 9) | struct PACKAGE {
  function PACKAGE (line 14) | struct OS_PACKAGE : PACKAGE {
  function PACKAGE (line 23) | struct PIP3_PACKAGE : PACKAGE {
  function PACKAGE (line 32) | struct GIT_PACKAGE : PACKAGE {
  function PACKAGE (line 59) | struct CARGO_PACKAGE : PACKAGE {
  function PACKAGE (line 68) | struct GO_PACKAGE : PACKAGE {
  function PACKAGE (line 79) | struct CUSTOM_PACKAGE : PACKAGE {
  function class (line 96) | class DependencyManager {

FILE: src/user/local_config.cpp
  function PACKAGE_MANAGER (line 24) | PACKAGE_MANAGER find_package_manager() {
  function is_root (line 31) | bool is_root() {
  function has_sudo (line 35) | bool has_sudo() {
  function LOCAL_CONFIG (line 39) | LOCAL_CONFIG* identify_local_config() {
  function is_binary_on_path (line 47) | bool is_binary_on_path(string binary) {

FILE: src/user/local_config.h
  type PACKAGE_MANAGER (line 7) | enum PACKAGE_MANAGER {
  type LOCAL_CONFIG (line 24) | struct LOCAL_CONFIG {

FILE: src/user/user_prompt.cpp
  function ask_yes_no (line 12) | bool ask_yes_no(string question, bool should_yes) {
  function ask_n (line 27) | uint8_t ask_n(string question, uint8_t min, uint8_t max) {
  function string (line 43) | string ask_password(string question) {

FILE: src/utils/arg_parser.cpp
  function string (line 9) | string ArgParser::format_help() {
  function CONFIG (line 38) | CONFIG* ArgParser::compute_args(int argc, char **argv) {

FILE: src/utils/arg_parser.h
  function class (line 7) | class ArgParser {

FILE: src/utils/config.h
  type CONFIG (line 7) | struct CONFIG {

FILE: src/utils/convert.cpp
  function split_string (line 7) | vector<string> split_string(const string& input, char delimiter) {
  function filter_empty_strings (line 17) | vector<std::string> filter_empty_strings(const vector<std::string>& tab) {
  function string (line 27) | string strip(const string& str) {
  function ends_with (line 36) | bool ends_with(string const &value, string const &ending) {
  function replace_all (line 41) | void replace_all(string& str, const string& from, const string& to) {
  function string (line 50) | string demangle_function_name(string& mangled_name) {

FILE: src/utils/file_downloader.cpp
  function write_callback (line 13) | size_t write_callback(void* contents, size_t size, size_t nmemb, FILE* f...

FILE: src/utils/file_downloader.h
  function class (line 6) | class FileDownloader {

FILE: src/utils/file_operations.cpp
  function decompress_gzip_file (line 13) | bool decompress_gzip_file(string input, string output) {
  function decompress_tar_file (line 31) | bool decompress_tar_file(string input, string output) {

FILE: src/utils/logger.cpp
  function FCout (line 44) | FCout FCout::operator<<(string s) {
  function FCout (line 51) | FCout FCout::operator<<(std::ostream&(*pManip)(std::ostream&)) {

FILE: src/utils/logger.h
  function class (line 13) | class FCout {

FILE: src/utils/search.cpp
  function search_regex (line 5) | vector<string> search_regex(char* data, size_t data_sz, string pattern, ...

FILE: test/Go/test_1/src/test_1.go
  function main (line 14) | func main() {
  function padPKCS7 (line 65) | func padPKCS7(data []byte, blockSize int) []byte {
  function unpadPKCS7 (line 71) | func unpadPKCS7(data []byte) []byte {

FILE: test/Rust/test_1/src/main.rs
  function main (line 7) | fn main() {
Condensed preview — 76 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (139K chars).
[
  {
    "path": ".dockerignore",
    "chars": 58,
    "preview": "cmake-build*/\n.cerberus*/\nbuild/\n.idea/\nradare2/\nGoliath/\n"
  },
  {
    "path": ".github/workflows/main.yml",
    "chars": 4293,
    "preview": "name: main\n\non:\n  push:\n    branches: [ main ]\n  pull_request:\n    branches: [ main ]\n  workflow_dispatch:\n\njobs:\n  chec"
  },
  {
    "path": ".gitignore",
    "chars": 63,
    "preview": "cmake-build*/\n.cerberus*/\nbuild/\n.idea/\nradare2/\nGoliath/\nlab/\n"
  },
  {
    "path": ".gitmodules",
    "chars": 355,
    "preview": "[submodule \"lib/Goliath\"]\n\tpath = lib/Goliath\n\turl = https://github.com/h311d1n3r/Goliath\n[submodule \"lib/argparse\"]\n\tpa"
  },
  {
    "path": "CMakeLists.txt",
    "chars": 2450,
    "preview": "cmake_minimum_required(VERSION 3.22)\nproject(Cerberus)\n\nset(CMAKE_CXX_STANDARD 17)\n\nfind_path(libelf.h NAMES LIBELF)\n\n# "
  },
  {
    "path": "LICENSE",
    "chars": 1076,
    "preview": "MIT License\n\nCopyright (c) 2021 Aurélien Tournebise\n\nPermission is hereby granted, free of charge, to any person obtaini"
  },
  {
    "path": "README.md",
    "chars": 4196,
    "preview": "# Cerberus\n## Description\n### A C++ tool to unstrip Rust and Go binaries (ELF and PE) \n**Cerberus** is the tool you want"
  },
  {
    "path": "docker/debian/Dockerfile-10",
    "chars": 508,
    "preview": "FROM debian:10\n\nWORKDIR /root\n\nRUN apt -y update\nRUN apt -y upgrade\nRUN apt -y install g++ gcc make tar wget\nRUN apt -y "
  },
  {
    "path": "docker/fedora/Dockerfile-37",
    "chars": 309,
    "preview": "FROM fedora:37\n\nWORKDIR /root\n\nRUN dnf -y update\nRUN dnf -y upgrade\nRUN dnf -y install g++ gcc make cmake\nRUN dnf -y ins"
  },
  {
    "path": "docker/ubuntu/Dockerfile-20.04",
    "chars": 511,
    "preview": "FROM ubuntu:20.04\n\nWORKDIR /root\n\nRUN apt -y update\nRUN apt -y upgrade\nRUN apt -y install g++ gcc make tar wget\nRUN apt "
  },
  {
    "path": "docker/ubuntu/Dockerfile-22.04",
    "chars": 301,
    "preview": "FROM ubuntu:22.04\n\nWORKDIR /root\n\nRUN apt -y update\nRUN apt -y upgrade\nRUN apt -y install g++ gcc make cmake\nRUN apt -y "
  },
  {
    "path": "src/algorithm/algorithm.h",
    "chars": 758,
    "preview": "#ifndef CERBERUS_ALGORITHM_H\n#define CERBERUS_ALGORITHM_H\n\n#include <vector>\n#include <fstream>\n#include <binaries/bin_t"
  },
  {
    "path": "src/algorithm/part_hash_algorithm.cpp",
    "chars": 2312,
    "preview": "#include <algorithm/part_hash_algorithm.h>\n#include <utils/convert.h>\n\nusing namespace std;\n\nvoid PartHashAlgorithm::com"
  },
  {
    "path": "src/algorithm/part_hash_algorithm.h",
    "chars": 810,
    "preview": "#ifndef CERBERUS_PART_HASH_ALGORITHM_H\n#define CERBERUS_PART_HASH_ALGORITHM_H\n\n#include <algorithm/algorithm.h>\n#include"
  },
  {
    "path": "src/binaries/bin_extractor.h",
    "chars": 597,
    "preview": "#ifndef CERBERUS_BIN_EXTRACTOR_H\n#define CERBERUS_BIN_EXTRACTOR_H\n\n#include <string>\n#include <vector>\n#include <binarie"
  },
  {
    "path": "src/binaries/bin_handler.cpp",
    "chars": 3400,
    "preview": "#include <binaries/bin_handler.h>\n#include <binaries/lib/install/lib_installer.h>\n#include <binaries/lib/install/rust_li"
  },
  {
    "path": "src/binaries/bin_handler.h",
    "chars": 1896,
    "preview": "#ifndef CERBERUS_BIN_HANDLER_H\n#define CERBERUS_BIN_HANDLER_H\n\n#include <string>\n#include <vector>\n#include <binaries/bi"
  },
  {
    "path": "src/binaries/bin_identifier.cpp",
    "chars": 1078,
    "preview": "#include <binaries/bin_identifier.h>\n#include <fstream>\n#include <cstring>\n\nusing namespace std;\n\nmap<BIN_TYPE, string> "
  },
  {
    "path": "src/binaries/bin_identifier.h",
    "chars": 338,
    "preview": "#ifndef CERBERUS_BIN_IDENTIFIER_H\n#define CERBERUS_BIN_IDENTIFIER_H\n\n#include <map>\n#include <string>\n#include <binaries"
  },
  {
    "path": "src/binaries/bin_types.h",
    "chars": 540,
    "preview": "#ifndef CERBERUS_BIN_TYPES_H\n#define CERBERUS_BIN_TYPES_H\n\n#include <cstdint>\n#include <string>\n\nstruct FUNCTION {\n    u"
  },
  {
    "path": "src/binaries/extractors/go_extractor.cpp",
    "chars": 1876,
    "preview": "#include <binaries/extractors/go_extractor.h>\n#include <utils/convert.h>\n#include <fstream>\n\nusing namespace std;\n\nBIN_A"
  },
  {
    "path": "src/binaries/extractors/go_extractor.h",
    "chars": 736,
    "preview": "#ifndef CERBERUS_GO_EXTRACTOR_H\n#define CERBERUS_GO_EXTRACTOR_H\n\n#include <binaries/bin_extractor.h>\n#include <command/c"
  },
  {
    "path": "src/binaries/extractors/libelf_extractor.cpp",
    "chars": 4302,
    "preview": "#include <binaries/extractors/libelf_extractor.h>\n#include <fcntl.h>\n#include <unistd.h>\n\nusing namespace std;\n\nLibelfEx"
  },
  {
    "path": "src/binaries/extractors/libelf_extractor.h",
    "chars": 745,
    "preview": "#ifndef CERBERUS_LIBELF_EXTRACTOR_H\n#define CERBERUS_LIBELF_EXTRACTOR_H\n\n#include <binaries/bin_extractor.h>\n#include <l"
  },
  {
    "path": "src/binaries/extractors/lief_extractor.cpp",
    "chars": 8765,
    "preview": "#include <binaries/extractors/lief_extractor.h>\n#include <utils/convert.h>\n#include <binaries/pe_types.h>\n#include <fstr"
  },
  {
    "path": "src/binaries/extractors/lief_extractor.h",
    "chars": 1025,
    "preview": "#ifndef CERBERUS_LIEF_EXTRACTOR_H\n#define CERBERUS_LIEF_EXTRACTOR_H\n\n#include <binaries/bin_extractor.h>\n#include <LIEF/"
  },
  {
    "path": "src/binaries/extractors/radare_extractor.cpp",
    "chars": 1555,
    "preview": "#include <binaries/extractors/radare_extractor.h>\n#include <utils/convert.h>\n\nusing namespace std;\n\nBIN_ARCH RadareExtra"
  },
  {
    "path": "src/binaries/extractors/radare_extractor.h",
    "chars": 755,
    "preview": "#ifndef CERBERUS_RADARE_EXTRACTOR_H\n#define CERBERUS_RADARE_EXTRACTOR_H\n\n#include <binaries/bin_extractor.h>\n#include <c"
  },
  {
    "path": "src/binaries/handlers/elf_handler.cpp",
    "chars": 1963,
    "preview": "#include <binaries/handlers/elf_handler.h>\n#include <vector>\n#include <binaries/extractors/libelf_extractor.h>\n\nusing na"
  },
  {
    "path": "src/binaries/handlers/elf_handler.h",
    "chars": 700,
    "preview": "#ifndef CERBERUS_ELF_HANDLER_H\n#define CERBERUS_ELF_HANDLER_H\n\n#include <binaries/bin_handler.h>\n\nclass ElfHandler : pub"
  },
  {
    "path": "src/binaries/handlers/pe_handler.cpp",
    "chars": 4537,
    "preview": "#include <binaries/handlers/pe_handler.h>\n#include <binaries/extractors/go_extractor.h>\n\nusing namespace std;\n\nvoid PeHa"
  },
  {
    "path": "src/binaries/handlers/pe_handler.h",
    "chars": 786,
    "preview": "#ifndef CERBERUS_PE_HANDLER_H\n#define CERBERUS_PE_HANDLER_H\n\n#include <binaries/bin_handler.h>\n\nclass PeHandler : public"
  },
  {
    "path": "src/binaries/lib/install/go_lib_installer.cpp",
    "chars": 3667,
    "preview": "#include <binaries/lib/install/go_lib_installer.h>\n#include <command/command_executor.h>\n#include <utils/logger.h>\n#incl"
  },
  {
    "path": "src/binaries/lib/install/go_lib_installer.h",
    "chars": 604,
    "preview": "#ifndef CERBERUS_GO_LIB_INSTALLER_H\n#define CERBERUS_GO_LIB_INSTALLER_H\n\n#include <binaries/lib/install/lib_installer.h>"
  },
  {
    "path": "src/binaries/lib/install/lib_installer.h",
    "chars": 585,
    "preview": "#ifndef CERBERUS_LIB_INSTALLER_H\n#define CERBERUS_LIB_INSTALLER_H\n\n#include <string>\n#include <binaries/bin_types.h>\n#in"
  },
  {
    "path": "src/binaries/lib/install/rust_lib_installer.cpp",
    "chars": 8974,
    "preview": "#include <binaries/lib/install/rust_lib_installer.h>\n#include <utils/file_operations.h>\n#include <utils/convert.h>\n#incl"
  },
  {
    "path": "src/binaries/lib/install/rust_lib_installer.h",
    "chars": 1086,
    "preview": "#ifndef CERBERUS_RUST_LIB_INSTALLER_H\n#define CERBERUS_RUST_LIB_INSTALLER_H\n\n#include <binaries/lib/install/lib_installe"
  },
  {
    "path": "src/binaries/lib/lib_manager.cpp",
    "chars": 2268,
    "preview": "#include <binaries/lib/lib_manager.h>\n#include <utils/logger.h>\n#include <user/user_prompt.h>\n#include <iostream>\n\nusing"
  },
  {
    "path": "src/binaries/lib/lib_manager.h",
    "chars": 593,
    "preview": "#ifndef CERBERUS_LIB_MANAGER_H\n#define CERBERUS_LIB_MANAGER_H\n\n#include <vector>\n#include <binaries/bin_types.h>\n#includ"
  },
  {
    "path": "src/binaries/pe_types.h",
    "chars": 501,
    "preview": "#ifndef CERBERUS_PE_TYPES_H\n#define CERBERUS_PE_TYPES_H\n\n#include <cstdint>\n\nstruct EXPORT_DIRECTORY_TABLE {\n    uint32_"
  },
  {
    "path": "src/command/command_executor.cpp",
    "chars": 1300,
    "preview": "#include <command/command_executor.h>\n#include <unistd.h>\n#include <cstring>\n#include <utils/logger.h>\n\nusing namespace "
  },
  {
    "path": "src/command/command_executor.h",
    "chars": 554,
    "preview": "#ifndef CERBERUS_COMMAND_EXECUTOR_H\n#define CERBERUS_COMMAND_EXECUTOR_H\n\n#include <cstdint>\n#include <string>\n#include <"
  },
  {
    "path": "src/global_defs.h",
    "chars": 538,
    "preview": "#ifndef CERBERUS_GLOBAL_DEFS_H\n#define CERBERUS_GLOBAL_DEFS_H\n\n#include <string>\n\nconst std::string TOOL_ART = \"   ___  "
  },
  {
    "path": "src/langs/lang_manager.cpp",
    "chars": 1923,
    "preview": "#include <langs/lang_manager.h>\n#include <utils/logger.h>\n#include <fstream>\n#include <cstring>\n#include <algorithm>\n\nus"
  },
  {
    "path": "src/langs/lang_manager.h",
    "chars": 498,
    "preview": "#ifndef CERBERUS_LANG_MANAGER_H\n#define CERBERUS_LANG_MANAGER_H\n\n#include <string>\n#include <map>\n#include <vector>\n#inc"
  },
  {
    "path": "src/langs/lang_types.h",
    "chars": 143,
    "preview": "#ifndef CERBERUS_LANG_TYPES_H\n#define CERBERUS_LANG_TYPES_H\n\nenum LANG {\n    UNKNOWN_LANG,\n    RUST,\n    GO\n};\n\n#endif /"
  },
  {
    "path": "src/langs/lib_regex.cpp",
    "chars": 3688,
    "preview": "#include <langs/lib_regex.h>\n#include <utils/convert.h>\n\nusing namespace std;\n\nstd::vector<std::string> rust_lib_regex ="
  },
  {
    "path": "src/langs/lib_regex.h",
    "chars": 620,
    "preview": "#ifndef CERBERUS_LIB_REGEX_H\n#define CERBERUS_LIB_REGEX_H\n\n#include <vector>\n#include <string>\n#include <map>\n#include <"
  },
  {
    "path": "src/main.cpp",
    "chars": 15474,
    "preview": "#include <utils/arg_parser.h>\n#include <utils/config.h>\n#include <langs/lang_manager.h>\n#include <binaries/bin_identifie"
  },
  {
    "path": "src/types/value_ordered_map.h",
    "chars": 1138,
    "preview": "#ifndef CERBERUS_VALUE_ORDERED_MAP_H\n#define CERBERUS_VALUE_ORDERED_MAP_H\n\n#include <vector>\n#include <string>\n#include "
  },
  {
    "path": "src/user/dependencies/dependency_manager.cpp",
    "chars": 3834,
    "preview": "#include <user/dependencies/dependency_manager.h>\n#include <utils/logger.h>\n\nusing namespace std;\n\nmap<PACKAGE_MANAGER, "
  },
  {
    "path": "src/user/dependencies/dependency_manager.h",
    "chars": 4102,
    "preview": "#ifndef CERBERUS_DEPENDENCY_MANAGER_H\n#define CERBERUS_DEPENDENCY_MANAGER_H\n\n#include <string>\n#include <map>\n#include <"
  },
  {
    "path": "src/user/local_config.cpp",
    "chars": 1460,
    "preview": "#include <user/local_config.h>\n#include <unistd.h>\n#include <utils/convert.h>\n\nusing namespace std;\n\nmap<PACKAGE_MANAGER"
  },
  {
    "path": "src/user/local_config.h",
    "chars": 573,
    "preview": "#ifndef CERBERUS_LOCAL_CONFIG_H\n#define CERBERUS_LOCAL_CONFIG_H\n\n#include <string>\n#include <map>\n\nenum PACKAGE_MANAGER "
  },
  {
    "path": "src/user/user_prompt.cpp",
    "chars": 1814,
    "preview": "#include <user/user_prompt.h>\n#include <utils/logger.h>\n#include <utils/convert.h>\n#include <iostream>\n#include <termios"
  },
  {
    "path": "src/user/user_prompt.h",
    "chars": 325,
    "preview": "#ifndef CERBERUS_USER_PROMPT_H\n#define CERBERUS_USER_PROMPT_H\n\n#include <string>\n#include <cstdint>\n\nextern bool NO_PROM"
  },
  {
    "path": "src/utils/arg_parser.cpp",
    "chars": 4145,
    "preview": "#include <utils/arg_parser.h>\n#include <utils/logger.h>\n#include <global_defs.h>\n#include <filesystem>\n\nnamespace fs = s"
  },
  {
    "path": "src/utils/arg_parser.h",
    "chars": 351,
    "preview": "#ifndef CERBERUS_ARG_PARSER_H\n#define CERBERUS_ARG_PARSER_H\n\n#include <utils/config.h>\n#include <argparse/argparse.hpp>\n"
  },
  {
    "path": "src/utils/config.h",
    "chars": 347,
    "preview": "#ifndef CERBERUS_CONFIG_H\n#define CERBERUS_CONFIG_H\n\n#include <string>\n#include <cstdint>\n\nstruct CONFIG {\n    std::stri"
  },
  {
    "path": "src/utils/convert.cpp",
    "chars": 1697,
    "preview": "#include <utils/convert.h>\n#include <sstream>\n#include <command/command_executor.h>\n\nusing namespace std;\n\nvector<string"
  },
  {
    "path": "src/utils/convert.h",
    "chars": 907,
    "preview": "#ifndef CERBERUS_CONVERT_H\n#define CERBERUS_CONVERT_H\n\n#include <string>\n#include <vector>\n\ntemplate<typename IntType> b"
  },
  {
    "path": "src/utils/file_downloader.cpp",
    "chars": 828,
    "preview": "#include <utils/file_downloader.h>\n\nusing namespace std;\n\nFileDownloader::FileDownloader() {\n    curl = curl_easy_init()"
  },
  {
    "path": "src/utils/file_downloader.h",
    "chars": 312,
    "preview": "#ifndef CERBERUS_FILE_DOWNLOADER_H\n#define CERBERUS_FILE_DOWNLOADER_H\n#include <curl/curl.h>\n#include <string>\n\nclass Fi"
  },
  {
    "path": "src/utils/file_operations.cpp",
    "chars": 2377,
    "preview": "#include <utils/file_operations.h>\n#include <fstream>\n#include <gzip/utils.hpp>\n#include <gzip/decompress.hpp>\n#include "
  },
  {
    "path": "src/utils/file_operations.h",
    "chars": 258,
    "preview": "#ifndef CERBERUS_FILE_OPERATIONS_H\n#define CERBERUS_FILE_OPERATIONS_H\n\n#include <string>\n\nbool decompress_gzip_file(std:"
  },
  {
    "path": "src/utils/logger.cpp",
    "chars": 3140,
    "preview": "#include <utils/logger.h>\n#include <iostream>\n\nusing namespace std;\n\nFCout fcout;\n\nmap<string, uint8_t> LOG_COLORS = {\n "
  },
  {
    "path": "src/utils/logger.h",
    "chars": 558,
    "preview": "#ifndef CERBERUS_LOGGER_H\n#define CERBERUS_LOGGER_H\n\n#include <string>\n#include <map>\n#include <vector>\n#include <cstdin"
  },
  {
    "path": "src/utils/search.cpp",
    "chars": 585,
    "preview": "#include <utils/search.h>\n\nusing namespace std;\n\nvector<string> search_regex(char* data, size_t data_sz, string pattern,"
  },
  {
    "path": "src/utils/search.h",
    "chars": 226,
    "preview": "#ifndef CERBERUS_SEARCH_H\n#define CERBERUS_SEARCH_H\n\n#include <regex>\n#include <vector>\n\nstd::vector<std::string> search"
  },
  {
    "path": "test/Go/test_1/result.txt",
    "chars": 55,
    "preview": "github.com/fatih/color.colorPrint\ncrypto/aes.NewCipher\n"
  },
  {
    "path": "test/Go/test_1/src/go.mod",
    "chars": 216,
    "preview": "module test_1\n\ngo 1.18\n\nrequire (\n\tgithub.com/fatih/color v1.15.0 // indirect\n\tgithub.com/mattn/go-colorable v0.1.13 // "
  },
  {
    "path": "test/Go/test_1/src/go.sum",
    "chars": 865,
    "preview": "github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=\ngithub.com/fatih/color v1.15.0/go.mod h1:"
  },
  {
    "path": "test/Go/test_1/src/test_1.go",
    "chars": 1569,
    "preview": "package main\n\nimport (\n\t\"github.com/fatih/color\"\n\t\"bytes\"\n\t\"crypto/aes\"\n\t\"crypto/cipher\"\n\t\"crypto/rand\"\n\t\"encoding/base6"
  },
  {
    "path": "test/Rust/test_1/Cargo.toml",
    "chars": 123,
    "preview": "[package]\nname = \"test_1\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\naes = \"0.8.2\"\n\n[profile.release]\nstrip = tr"
  },
  {
    "path": "test/Rust/test_1/result.txt",
    "chars": 88,
    "preview": "aes::soft::fixslice::aes128_encrypt\n<aes::ni::Aes128Enc as crypto_common::KeyInit>::new\n"
  },
  {
    "path": "test/Rust/test_1/src/main.rs",
    "chars": 763,
    "preview": "use aes::Aes128;\nuse aes::cipher::{\n    BlockEncrypt, BlockDecrypt, KeyInit,\n    generic_array::GenericArray,\n};\n\nfn mai"
  }
]

About this extraction

This page contains the full source code of the h311d1n3r/Cerberus GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 76 files (126.2 KB), approximately 34.9k tokens, and a symbol index with 88 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!