{"id":13632266,"url":"https://github.com/FuzzAnything/Hopper","last_synced_at":"2025-04-18T02:32:21.797Z","repository":{"id":206168770,"uuid":"710269044","full_name":"FuzzAnything/Hopper","owner":"FuzzAnything","description":"Hopper is a tool for generating fuzzing test cases for libraries automatically using interpretative fuzzing.","archived":false,"fork":false,"pushed_at":"2024-09-07T10:01:22.000Z","size":455,"stargazers_count":228,"open_issues_count":3,"forks_count":29,"subscribers_count":5,"default_branch":"main","last_synced_at":"2024-09-07T11:22:41.674Z","etag":null,"topics":["afl","api-testing","binary","fuzz-driver","fuzzer","fuzzing","fuzzing-framework","interpreter","library-testing","rust","security","testing"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/FuzzAnything.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-10-26T11:06:39.000Z","updated_at":"2024-09-07T10:01:26.000Z","dependencies_parsed_at":"2023-12-05T09:29:16.667Z","dependency_job_id":"3c69d7d4-b010-40e5-886e-0748096b32c4","html_url":"https://github.com/FuzzAnything/Hopper","commit_stats":null,"previous_names":["fuzzanything/hopper"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FuzzAnything%2FHopper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FuzzAnything%2FHopper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FuzzAnything%2FHopper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FuzzAnything%2FHopper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/FuzzAnything","download_url":"https://codeload.github.com/FuzzAnything/Hopper/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223772147,"owners_count":17199968,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["afl","api-testing","binary","fuzz-driver","fuzzer","fuzzing","fuzzing-framework","interpreter","library-testing","rust","security","testing"],"created_at":"2024-08-01T22:02:58.174Z","updated_at":"2024-11-09T00:30:53.405Z","avatar_url":"https://github.com/FuzzAnything.png","language":"Rust","readme":"# Hopper\n\nHopper is a tool for generating fuzzing test cases for libraries automatically using **interpretative fuzzing**. It transforms the problem of library fuzzing into the problem of interpreter fuzzing, enabling exploration of a vast range of API usages for library fuzzing out of the box.\nSome key features of Hopper include:\n- Interpretative API invoking without any fuzz driver. \n- Type-aware mutation for arguments.\n- Automatic intra- and inter-API constraints learning.\n- Binary instrumentation support.\n\nTo learn more about Hopper, check out our [paper](https://arxiv.org/pdf/2309.03496) at CCS '23.\n\n## Build Hopper\n### Build Requirements\n- Linux-amd64 (Tested on Ubuntu 20.04 and Debian Buster)\n- Rust stable (\u003e= 1.60), can be obtained using [rustup](https://rustup.rs/)\n- Clang (\u003e= 5.0, [Install Clang](https://rust-lang.github.io/rust-bindgen/requirements.html)), [rust-bindgen](https://rust-lang.github.io/rust-bindgen/) leverages libclang to preprocess, parse, and type check C and C++ header files.\n\n### Build Hopper itself\n```sh\n./build.sh\n```\n\nThe script will create a `install` directory in hopper's root directory, then you can use `hopper`.\nTo use the command anywhere, you can set the project directory in your PATH variable.\n\n### Using Docker\nYou can choose to use the Dockerfile, which build the requirements and Hopper.\n```\ndocker build -t hopper ./\ndocker run --name hopper_dev --privileged -v /path-to-lib:/fuzz -it --rm hopper /bin/bash\n```\n\n## Compile library with Hopper\nTake `csjon` for example ([More examples](./examples/)).\n```sh\nhopper compile --header ./cJSON.h --library ./libcjson.so --output output\n```\n\nUse `hopper compile --help` to see detailed usage. If the compiling reports errors about header file, refer to the usage of [rust-bindgen](https://rust-lang.github.io/rust-bindgen/), which we used for parsing header file.\nYou may wrap the header file with the missing definitions.\nHopper uses [E9Patch](https://github.com/GJDuck/e9patch) to instrument binaries by default. Optionally, you can use [LLVM](./hopper-instrument/llvm-mode/) for source code instrumentation.\n\nAfter running `compile`, you will find that it generates the following files in the output directory:\n- `bin/hopper-fuzzer`:  generates inputs, maintains states, and uses `harness` to execute the inputs.\n- `bin/hopper-harness`:  executes the inputs.\n- `bin/hopper-translate`:  translates inputs to C source code.\n- `bin/hopper-generator`: replays the generate process.\n- `bin/hopper-sanitizer`: sanitize and minimize crashes.\n\n#### Header files\n- If there are multiple header files, you can create a new header file, and *include* all of them.\n- If header files are compiled depending on specific environment variables. You can set it by : `BINDGEN_EXTRA_CLANG_ARGS`.\n- If the header file includes API functions that you do not want to test, use `--func-pattern` to filter them while running the fuzzer.\n\n#### Environment variable for compiling\n- `HOPPER_MAP_SIZE_POW2`: controls the size of coverage path. The default value is 16, and it should be in the range of [16, 20]. e.g. `HOPPER_MAP_SIZE_POW2=18`.\n- `HOPPER_INST_RATIO`: controls how likely a block will be chosen for instrumentation. The default value is 100, and it should be in the range of (0, 100]. e.g. `HOPPER_INST_RATIO=75`.\n- `HOPPER_INCLUDE_SEARCH_PATH`: includes the search path of file in header files. e.g. `HOPPER_INCLUDE_SEARCH_PATH=../`.\n- `HOPPER_FUNC_BLACKLIST`: includes function blacklists that hopper won't compile. `bindgen` will not generate code for the functions. e.g. `HOPPER_FUNC_BLACKLIST=f1,f2`.\n- `HOPPER_TYPE_BLACKLIST`: includes type blacklists that hopper won't compile. `bindgen` will not generate code for the types. e.g. `HOPPER_TYPE_BLACKLIST=type1,type2`.\n- `HOPPER_ITEM_BLACKLIST`: includes item(constants/variables) blacklists that hopper won't compile. `bindgen` will not generate code for the items. e.g. `HOPPER_ITEM_BLACKLIST=IPPORT_RESERVED`\n- `HOPPER_CUSTOM_OPAQUE_LIST`: includes custom opaque types we defined. e.g. `HOPPER_CUSTOM_OPAQUE_LIST=type1`.\n- `HOPPER_FUZZ_INLINE_FUNCTION`: includes inline function as our targets, see [FAQ](https://rust-lang.github.io/rust-bindgen/faq.html#why-isnt-bindgen-generating-bindings-to-inline-functions) in bindgen.\n\n#### Tips\n- You can set the arguments and environment variables for compiling and running in a configuration file named `hopper.config`, see `examples/*` for details.\n\n- Reduce density: If density is larger than 20%, the IDs of edges are likely to have hash-collisions. We can a) increase  `HOPPER_MAP_SIZE_POW2` or b) reduce `HOPPER_INST_RATIO`.\n\n- Multiple libraries: (1) merge the archives into one shared library, e.g. `gcc -shared -o c.so -Wl,--whole-archive a.a b.a -Wl,--no-whole-archive`; (2) pass all of them into hopper compiler by `--library a.so b.so`.\n\n## Fuzz Library with Hopper\n\n```\nhopper fuzz output --func-pattern cJSON_*\n```\n\nUse `hopper fuzz output --help` to see detailed usage.\n\nAfter running `fuzz`, it will generate following directories.\n- `queue`: generated normal inputs.\n- `hangs`: generated timeout inputs.\n- `crashes`: generated crash inputs.\n- `misc`: store some temporal files or stats.\n\n#### Environment variable for running\n- `DISABLE_CALL_DET`: disables call's deterministic mutating.\n- `DISABLE_GEN_FAIL`: disables generating programs for functions that have been failed to invoke.\n- `HOPPER_SEED_DIR`: provides seeds for byte-like arguments (default: output/seeds if t exists).\n- `HOPPER_DICT`: provides dictionary for byte-like arguments. The grammar is the same as AFL's.\n- `HOPPER_API_INSENSITIVE_COV`: disables API-sensitive branch counting.\n- `HOPPER_FAST_EXECUTE_LOOP`:  number of programs executed (in a loop) for each fork, set as 0 or 1 to break the loop. e.g. `HOPPER_FAST_EXECUTE_LOOP=10`.\n\n#### System configuration\nSet system core dumps as AFL (on the host if you execute Hopper in a Docker container).\n```\necho core | sudo tee /proc/sys/kernel/core_pattern\n```\n\n### Function pattern \nHopper generates inputs for all functions that appear in both headers and libraries by default. However, there are two ways to filter functions in Hopper: excluding functions or including functions. This way, it can be focus on interesting functions.\n\n#### `--func-pattern`\n```\nhopper fuzz output --func-pattern @cJSON_parse,!cJSON_InitHook,cJSON_*\n```\n  - The pattern can be a function name, e.g. `cJSON_parse`, or a simple pattern, e.g. `cJSON_*`. \n  - If you have multiple patterns, use `,` to join them, e.g `cJSON_*,HTTP_*`. \n  - You can use `@` prefix to limit the fuzzer to only fuzz specific function, while the others can be candidates that provide values for fields or arguments, e.g. `@cJSON_parse,cJSON_*`.\n  - `!` is used as prefix for excluding some specific functions, e.g `!cJSON_InitHook,cJSON_*`.\n\n#### `--custom-rules`\nThe patterns can be defined in the file passed by `--custom-rules`.\n\n```rust\n// hopper fuzz output --custom-rules path-to-file\nfunc_target cJSON_parse\nfunc_exclude cJSON_InitHook\nfunc_include cJSON_*,HTTP_*\n```\n\n### Constraints\nHopper infers both intra- and inter-API constraints to invoking the APIs correctly.  \nThe constraints are written in `output/misc/constraint.config`. You can remove the file to reset the constraints.\nAdditionally, users can define a file that describes custom constraints for API invocations, which is passed by `--custom-rules`. The constraints will override the inferred ones.\n```java\n// hopper fuzz output --custom-rules path-to-file\n// Grammar: \n// func, type : prefix for adding a rule for function or type\n// $[0-9]+    : function's i-th argument, or index in array\n// [a-zA-Z_]+ : object field\n// 0, 128 ..  : integer constants\n// \"xxxx\"     : string constants\n// methods    : $len, $range, $null, $non_null, $need_init, $read_file, $write_file, $ret_from, $cast_from, $use, $arr_len, $opaque, $len_factors\n// others     :  pointer(\u0026) , option(?), e.g \u0026.$0.len,  `len` field in the pointer's first element\n//\n// Set one argument in a function to be specific constant\nfunc test_add[$0] = 128\n// One argument must be the length of another one\nfunc test_arr[$1] = $len($0)\n// Or one field must be the length of another field\nfunc test_arr[$0][len] = $len([$0][name])\n// One argument must be in a certain range\nfunc test_arr[$1] = $range(0, $len($0))\n// Argument should be non-null\nfunc test_non_null[$0] = $non_null\n// Argument should be null\nfunc test_null[$0] = $null\n// Argument should be specific string\nfunc test_magic[$0] = \"magic\"\n// Argument should be a file and the file will be read\nfunc test_path[$0] = $read_file\n// Argument should be use the value of specific function's return\nfunc test_use[$0] = $ret_from(test_create)\n// Argument should be specific type for void pointer. The type should start with *mut or *const.\nfunc test_void[$0] = $cast_from(*mut u8)\n// The array suppose has a minimal array length\nfunc test_void[$0][\u0026] = $arr_len(256)\n// The array's length is formed by the factors\nfunc fread[$0][\u0026] = $len_factors(1, $2)\n// Or\nfunc gzfread[$0][\u0026] = $len_factors($1, $2)\n// Field in argument should be specific constant\nfunc test_field[$0][len] = 128\n// Deeper fields\nfunc test_field[$0][\u0026.elements.$0] = 128\n\n// One field `len` in a type must be the length of another field `p`\ntype ArrayWrap[len] = $len(p)\n// One nested union `inner_union` in a type must be set to `member2` \ntype ComplicatedStruct[inner_union] = $use(member2)\n// Type is opaque that used as an opaque pointer\ntype Partial = $opaque\n// A type should be init with specific function\ntype Partial = $init_with(test_init, 0)\n\n// ctx: set context for specific function\n// Add a context for function\nctx test_use[$0] \u003c- test_init\n// Add implicit context\nctx test_use[*] \u003c- test_init\n// Add optional context that preferred to use\nctx test_use[$0] \u003c- test_init ?\n// Add forbidden context\nctx test_use[$0] \u003c- ! test_init\n\n// alias: alias types across different function\nalias handleA \u003c- useA($0),createA($ret),freeA($0)\n\n// assert: adding specific assertions for calls\nassert test_one == 1\nassert test_non_zero != 0\n\n```\n\n### Seeds for bytes arguments\nIf there is a `seeds` directory (Set by `HOPPER_SEED_DIR`), Hopper will try to read files inside it and uses them as the seeds for bytes arguments (e.g. char*). Also, you can indicate the seeds for specific argument via its parameter names, e.g make the subdirectory as `@buf` for parameter whose name is `buf`.\n\n### Logging\nHopper uses Rust's log crate to print log information. The default log level is `INFO`. If you want to print all logging information (`DEBUG` and `TRACE`), you can set the environment `LOG_TYPE` during running Hopper, e.g. `LOG_TYPE=trace ./hopper`.\nThe detailed logging will be written at `output/fuzzer_r*.log` and `output/harness_r*.log`.\n\n### Reproduce execution\nHopper can reproduce the execution of programs at output directories.\n\n- `hopper-harness` can parse and explain the inputs by Hopper's runtime. It will print the internal states during execution in detail.\n```\n./bin/hopper-harness ./queue/id_000000\n```\n\n- `hopper-translate` can translate the input to C source code. The C files can be a witness for reporting issues.\n```\n./bin/hopper-translate --input ./queue/id_000000  --header path-to/xx.h --output test.c\n# then compile it with specific library\ngcc -I/path-to-head -L/path-to-lib -l:libcjson.so test.c -o test\n```\n\n- `hopper-generator` is able to replay input generation except execution. You can use it to analyse how the input was generated or mutated.\n```\n./bin/hopper-generator ./queue/id_000000\n```\n\n- `hopper-sanitizer` can minimize and verify the crashes generated by Hopper. It excludes crashes that violate constraints and de-duplicate crashes according to call stacks.\n```\n./bin/hopper-sanitizer\n```\n\n## Test\n### Test rust code\n- Run all testcases\n```\nRUST_BACKTRACE=1 cargo test -- --nocapture\n```\n\n### Testsuite (test libraries)\n- [How to run and write testuite](./testsuite/README.md)\n\n### Real world examples\n- [Examples](./examples/)\n\n## Evaluating results via source-based code coverage\n- Compile the libraries' source code with [LLVM source-based code sanitizer](https://clang.llvm.org/docs/SourceBasedCodeCoverage.html). You should set the compiling flags, e.g. \n\n```\nexport CFLAGS=\"${CFLAGS:-} -fprofile-instr-generate -fcoverage-mapping -gline-tables-only -g\"\nmake\n```\n\n- Compile the libraries with `cov` instrumentation mode. e.g.\n```\nhopper compile --instrument cov --header ./cJSON.h --library ./libcjson_cov.so --output output_cov\n```\n\n- Run the interpreter with all generated seed inputs (SEED_DIR).\n``` \n# run hopper and use llvm-cov to compute the coverage.\nSEED_DIR=./output/queue hopper cov output_cov\n```\n\n## Contributing guidelines\nWe have listed some tasks in [Roadmap](https://github.com/FuzzAnything/hopper/discussions/2).\nIf you are interested, please feel free to discuss with us and contribute your code.\n\n### Coding\n- *Zero* `cargo check` warning\n- *Zero* `cargo clippy` warning\n- *Zero* `FAILED` in `cargo test`\n- *Try* to write tests for your code\n\n### Profiling\n- [Profiling Rust Applications](https://gist.github.com/KodrAus/97c92c07a90b1fdd6853654357fd557a)\n- [Inferno](https://github.com/jonhoo/inferno)\n\n```bash\nperf record --call-graph=dwarf ./bin/hopper-fuzzer\n# use flamegraph directly\nperf script | stackcollapse-perf.pl | rust-unmangle | flamegraph.pl \u003e flame.svg\n# use inferno\nperf script | inferno-collapse-perf | inferno-flamegraph \u003e flamegraph.svg\n```\n\nperf will produce huge intermediate data for analysis, so *do not* run fuzzer more than 2 minutes.\n","funding_links":[],"categories":["Rust"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FFuzzAnything%2FHopper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FFuzzAnything%2FHopper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FFuzzAnything%2FHopper/lists"}