Skip to content

Commit

Permalink
Add support for Unicorn engine (#1054)
Browse files Browse the repository at this point in the history
* feat: unicorn support

* feat: update

* fix: remove unused files

* fix: clean

* fix: remove undeeded parameters

* fix: typo

* moved to justfile

* use log::debug!

* fix cargo and created justfile

* feat: add CI

* add runs on

* fix: CI

* fix: CI

* fix: don't use fork executor

* not needed anymore

* fix: CI

* fix: CI

* remove extra space
  • Loading branch information
henri2h authored Feb 15, 2025
1 parent b3fe744 commit 0aba2c4
Show file tree
Hide file tree
Showing 13 changed files with 700 additions and 6 deletions.
21 changes: 21 additions & 0 deletions .github/workflows/build_and_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,27 @@ jobs:
- 'libafl_targets/**'
- 'libafl_qemu/**'
- 'fuzzers/**/*qemu*/**'
fuzzer-unicorn:
runs-on: ubuntu-24.04
needs:
- fuzzers-preflight
strategy:
fail-fast: false
matrix:
os: [ ubuntu-24.04 ]
fuzzer:
- ./fuzzers/full_system/unicorn
steps:
- uses: actions/checkout@v4
- uses: ./.github/workflows/fuzzer-tester-prepare
- name: "Install dependencies"
if: runner.os == 'Linux'
shell: bash
run: sudo apt-get update && sudo apt-get install gcc gcc-arm-linux-gnueabihf gcc-aarch64-linux-gnu
- name: Build and run example fuzzers (Linux)
if: runner.os == 'Linux'
shell: bash
run: RUN_ON_CI=1 LLVM_CONFIG=llvm-config-${{env.MAIN_LLVM_VERSION}} ./scripts/test_fuzzer.sh ${{ matrix.fuzzer }}

fuzzers-qemu:
needs:
Expand Down
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ members = [
"libafl_intelpt",
"libafl_libfuzzer",
"libafl_nyx",
"libafl_unicorn",
"libafl_targets",
"libafl_tinyinst",
"libafl_qemu",
Expand Down Expand Up @@ -88,6 +89,7 @@ bindgen = "0.71.1"
# 2024-12-16: bitbybit 1.3.3 is leading CI to fail due to missing docs.
# fixme: Change this to 1.3.3 when the issue https://github.com/danlehmann/bitfield/issues/66 is resolved.
bitbybit = "=1.3.2" # bitfields, use this for bit fields and bit enums
capstone = "0.13.0" # Disassembler used in libafl_unicorn to provide disassembly on crash
clap = "4.5.18"
cc = "1.1.21"
cmake = "0.1.51"
Expand Down Expand Up @@ -121,6 +123,7 @@ strum_macros = "0.27.0"
toml = "0.8.19" # For parsing the injections toml file
typed-builder = "0.20.0" # Implement the builder pattern at compiletime
typeid = "1.0.0" # Safe type_eq that doesn't rely on std specialization
unicorn-engine = "2.0.1" # Used in libafl_unicorn
uuid = { version = "1.10.0", features = ["serde", "v4"] }
which = "6.0.3"
windows = "0.59.0"
Expand Down
17 changes: 11 additions & 6 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ ENV SCCACHE_DIR=$HOME/.cache/sccache
ENV RUSTC_WRAPPER="/usr/local/cargo/bin/sccache"
ENV IS_DOCKER="1"
RUN sh -c 'echo set encoding=utf-8 > /root/.vimrc' \
echo "export PS1='"'[LibAFL \h] \w$(__git_ps1) \$ '"'" >> ~/.bashrc && \
mkdir ~/.cargo && \
echo "[build]\nrustc-wrapper = \"${RUSTC_WRAPPER}\"" >> ~/.cargo/config
echo "export PS1='"'[LibAFL \h] \w$(__git_ps1) \$ '"'" >> ~/.bashrc && \
mkdir ~/.cargo && \
echo "[build]\nrustc-wrapper = \"${RUSTC_WRAPPER}\"" >> ~/.cargo/config

RUN rustup default nightly
RUN rustup component add rustfmt clippy
Expand All @@ -25,9 +25,9 @@ RUN rustup component add rustfmt clippy
ENV LLVM_VERSION=18
RUN apt update && apt install -y build-essential gdb git wget python3-venv ninja-build lsb-release software-properties-common gnupg cmake
RUN set -ex &&\
wget https://apt.llvm.org/llvm.sh &&\
chmod +x llvm.sh &&\
./llvm.sh ${LLVM_VERSION}
wget https://apt.llvm.org/llvm.sh &&\
chmod +x llvm.sh &&\
./llvm.sh ${LLVM_VERSION}


# Copy a dummy.rs and Cargo.toml first, so that dependencies are cached
Expand Down Expand Up @@ -55,6 +55,9 @@ COPY libafl_frida/src/gettls.c libafl_frida/src/gettls.c
COPY libafl_intelpt/Cargo.toml libafl_intelpt/README.md libafl_intelpt/
COPY scripts/dummy.rs libafl_intelpt/src/lib.rs

COPY libafl_unicorn/Cargo.toml libafl_unicorn/
COPY scripts/dummy.rs libafl_unicorn/src/lib.rs

COPY libafl_qemu/Cargo.toml libafl_qemu/build.rs libafl_qemu/build_linux.rs libafl_qemu/
COPY scripts/dummy.rs libafl_qemu/src/lib.rs

Expand Down Expand Up @@ -149,6 +152,8 @@ COPY libafl_libfuzzer/build.rs libafl_libfuzzer/build.rs
RUN touch libafl_libfuzzer/src/lib.rs
COPY libafl_intelpt/src libafl_intelpt/src
RUN touch libafl_intelpt/src/lib.rs
COPY libafl_unicorn/src libafl_unicorn/src
RUN touch libafl_unicorn/src/lib.rs
RUN cargo build && cargo build --release

# Copy fuzzers over
Expand Down
20 changes: 20 additions & 0 deletions fuzzers/full_system/unicorn/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[package]
name = "unicorn"
version = "0.1.0"
edition = "2021"

[features]
# Enable a code hook which log the program counter at each executed instruction
default = []
code_hook = []
mem_hook = []

[dependencies]
libafl = { path = "../../../libafl/" }
libafl_bolts = { path = "../../../libafl_bolts/" }
libafl_targets = { path = "../../../libafl_targets" }
libafl_unicorn = { path = "../../../libafl_unicorn/" }

unicorn-engine = "2.1.2"
log = "0.4.25"
env_logger = "0.11.6"
43 changes: 43 additions & 0 deletions fuzzers/full_system/unicorn/Justfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
FUZZER_NAME := 'unicorn'
PROJECT_DIR := absolute_path(".")
PROFILE := 'release'
PROFILE_DIR := 'release'
CARGO_TARGET_DIR := env("CARGO_TARGET_DIR", "target")
FUZZER := CARGO_TARGET_DIR / PROFILE_DIR / FUZZER_NAME


alias build := fuzzer

fuzzer:
cargo build --profile={{PROFILE}}

run: fuzzer
RUST_LOG="debug" {{FUZZER}} arm

build_bin:
cd bin && just all


[linux]
[macos]
test: fuzzer build_bin (test_single "arm") (test_single "arm64") (test_single "x86")
echo "Done"

test_single arch="arm":
#!/bin/bash
echo "Testing {{arch}}"

RUST_LOG="debug" timeout 10s {{FUZZER}} {{arch}} 2>&1 | tee fuzz_stdout.log || true
if grep -qa "objectives: 1" fuzz_stdout.log; then
echo "Fuzzer is working"
else
echo "Fuzzer does not generate any testcases or any crashes"
exit 1
fi

[windows]
test: fuzzer
echo "Unsupported on this platform"

clean:
cargo clean
36 changes: 36 additions & 0 deletions fuzzers/full_system/unicorn/bin/Justfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
arm64 := "aarch64-linux-gnu"
arm := "arm-linux-gnueabihf"
x64 := "x86_64-linux-gnu"

assembly_arm64:
{{arm64}}-gcc -O2 -S -c foo.c -o foo_arm64.s

binary_arm64:
{{arm64}}-as foo_arm64.s -o foo_arm64.elf
{{arm64}}-objcopy -O binary -j .text.startup foo_arm64.elf foo_arm64.bin

assembly_arm:
{{arm}}-gcc -O2 -S -c foo.c -o foo_arm.s

binary_arm:
{{arm}}-as foo_arm.s -o foo_arm.elf
{{arm}}-objcopy -O binary foo_arm.elf foo_arm.bin

assembly_x86:
{{x64}}-gcc -O2 -S -c foo.c -o foo_x86.s

binary_x86:
{{x64}}-as foo_x86.s -o foo_x86.elf
# Extract the .text.startup section
{{x64}}-objcopy -O binary -j .text.startup foo_x86.elf foo_x86.bin

build_arm: assembly_arm binary_arm
build_arm64: assembly_arm64 binary_arm64
build_x86: assembly_x86 binary_x86

clean:
rm foo_*


all: build_arm build_arm64 build_x86
# sudo apt install gcc-arm-linux-gnueabihf gcc-aarch64-linux-gnu
22 changes: 22 additions & 0 deletions fuzzers/full_system/unicorn/bin/foo.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
int main() {
char *data = (char *)0x8000;
// Extract the input from the memory at 0x8000
unsigned char a = data[0];
unsigned char b = data[1];

if (a > b) {
if (a < 0x30) return 0x2;
if (a > 0x80) return 0x3;
if (a > 0x60) return 0x4;
if (a != 0x50) return 0x5;

if (b < 0x20) return 0x7;
if (b > 0x60) return 0x8;
if (b > 0x30) return 0x9;
if (b == 0x24) return 0x6; // Success

return 0x5;
}

return 0x1;
}
Loading

0 comments on commit 0aba2c4

Please sign in to comment.