Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Unicorn engine #1054

Merged
merged 20 commits into from
Feb 15, 2025
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion .github/workflows/build_and_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ jobs:
- ./fuzzers/full_system/nyx_launcher
- ./fuzzers/full_system/nyx_libxml2_standalone
- ./fuzzers/full_system/nyx_libxml2_parallel

# Structure-aware
- ./fuzzers/structure_aware/nautilus_sync
- ./fuzzers/structure_aware/baby_fuzzer_grimoire
Expand Down Expand Up @@ -344,6 +344,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
14 changes: 8 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 @@ -149,6 +149,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
27 changes: 27 additions & 0 deletions fuzzers/full_system/unicorn/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[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 = []


# Panic configuration needed so that the InProcessForkExecutor still detect the crash when the forked process crashed
[profile.dev]
panic = "abort"

[profile.release]
panic = "abort"

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

unicorn-engine = "2.0.1"
iced-x86 = "1.18.0"
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
{{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}}"

timeout 30s {{FUZZER}} {{arch}} | 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
21 changes: 21 additions & 0 deletions fuzzers/full_system/unicorn/bin/foo.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
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;
// Simple constraint on b to allow faster resolution for the test CI
return 0x6;
}

return 0x1;
}
Loading
Loading