├── .github └── workflows │ └── build_and_test.yml ├── .gitignore ├── Cargo.toml ├── LICENSE-APACHE.txt ├── LICENSE-MIT.txt ├── Makefile.toml ├── README.md ├── build.rs ├── src ├── CMakeLists.txt ├── aflcov.cpp ├── aflcov.h ├── instrumentation.cpp ├── instrumentation.h ├── lib.rs ├── runresult.h ├── shim.cc ├── shim.h ├── tinyinst.rs ├── tinyinstinstrumentation.cpp └── tinyinstinstrumentation.h └── test ├── CMakeLists.txt ├── crash_input.txt ├── ok_input.txt └── test.c /.github/workflows/build_and_test.yml: -------------------------------------------------------------------------------- 1 | name: build and test 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | windows: 14 | runs-on: windows-latest 15 | steps: 16 | - uses: actions/checkout@v3 17 | - uses: ilammy/msvc-dev-cmd@v1 18 | - name: install cxxbridge 19 | run: cargo install cxxbridge-cmd 20 | - name: install cargo-make 21 | run: cargo install cargo-make 22 | - name: Compile test 23 | run: cargo make build_test 24 | - name: Build 25 | run: cargo build --verbose 26 | - name: Run tests 27 | run: cargo test --verbose 28 | macos: 29 | runs-on: macOS-latest 30 | steps: 31 | - uses: actions/checkout@v3 32 | - name: install cxxbridge 33 | run: cargo install cxxbridge-cmd 34 | - name: install cargo-make 35 | run: cargo install cargo-make 36 | - name: Compile test 37 | run: cargo make build_test 38 | - name: Build 39 | run: cargo build --verbose 40 | # - name: Run tests 41 | # run: cargo test --verbose 42 | linux: 43 | runs-on: ubuntu-latest 44 | steps: 45 | - uses: actions/checkout@v3 46 | - name: install cxxbridge 47 | run: cargo install cxxbridge-cmd 48 | - name: install cargo-make 49 | run: cargo install cargo-make 50 | - name: Compile test 51 | run: cargo make build_test 52 | - name: Build 53 | run: cargo build --verbose 54 | - name: Run tests 55 | run: cargo test --verbose 56 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /Cargo.lock 3 | build/ 4 | *.exe 5 | /TinyInst 6 | *.obj 7 | test_file.txt -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tinyinst" 3 | authors = ["biazo ", "Dongjia Zhang ", "Dominik Maier "] 4 | description = "Rust bindings for googleprojectzero/TinyInst" 5 | repository = "https://github.com/AFLplusplus/tinyinst-rs/" 6 | readme = "./README.md" 7 | license = "MIT OR Apache-2.0" 8 | keywords = ["bindings", "testing", "security"] 9 | version = "0.1.0" 10 | edition = "2021" 11 | categories = ["development-tools::testing", "os", "no-std"] 12 | 13 | [dependencies] 14 | cxx = { version = "1.0", default-features = false, features = ["alloc"] } 15 | 16 | [build-dependencies] 17 | cmake = "0.1.54" 18 | git2 = "0.20.0" 19 | which = "7.0.2" 20 | -------------------------------------------------------------------------------- /LICENSE-APACHE.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. -------------------------------------------------------------------------------- /LICENSE-MIT.txt: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any 2 | person obtaining a copy of this software and associated 3 | documentation files (the "Software"), to deal in the 4 | Software without restriction, including without 5 | limitation the rights to use, copy, modify, merge, 6 | publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software 8 | is furnished to do so, subject to the following 9 | conditions: 10 | 11 | The above copyright notice and this permission notice 12 | shall be included in all copies or substantial portions 13 | of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 18 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 19 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 22 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /Makefile.toml: -------------------------------------------------------------------------------- 1 | [tasks.build_test] 2 | dependencies = ["build_configure"] 3 | cwd = "./test" 4 | command = "cmake" 5 | args = ["--build", "build", "--config", "Debug"] 6 | 7 | [tasks.build_configure] 8 | cwd = "./test" 9 | command = "cmake" 10 | args = ["-S", ".", "-B", "build"] 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tinyinst-rs 2 | 3 | FFI to [TinyInst](https://github.com/googleprojectzero/TinyInst). Created for [LibAFL](https://github.com/AFLplusplus/LibAFL). 4 | 5 | ## Dependencies 6 | 7 | * Visual Studio 2022 8 | * cxxbridge 9 | * cargo-make 10 | * python3 11 | * git 12 | 13 | ## Running the test 14 | 15 | 1. Open a terminal and set up your build environment (e.g. On Windows, run Developer Powershell / Developer CMD/ vcvars64.bat / vcvars32.bat) 16 | 2. Run `cargo make build_test` to build the test binary 17 | 3. Run `cargo test` to run the test 18 | 19 | 20 | ## Optional ENV Variables 21 | 22 | `CUSTOM_TINYINST_GENERATOR` = Generator used for cmake `-G` flag 23 | 24 | `CUSTOM_TINYINST_DIR` = path to local Tinyinst repo 25 | 26 | `CUSTOM_TINYINST_NO_BUILD` = if set, it won't build Tinyinst everytime. Useful when paired with `CUSTOM_TINYINST_DIR` 27 | 28 | 29 | #### License 30 | 31 | 32 | Licensed under either of Apache License, Version 33 | 2.0 or MIT license at your option. 34 | 35 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | use std::{env, fs, path::Path, process::Command}; 2 | 3 | use cmake::Config; 4 | use git2::{Oid, Repository}; 5 | use which::which; 6 | 7 | const TINYINST_URL: &str = "https://github.com/googleprojectzero/TinyInst.git"; 8 | const TINYINST_DIRNAME: &str = "Tinyinst"; 9 | const TINYINST_REVISION: &str = "69ae1ff55eac8cb5d2e9a257c5650486ffe2af04"; 10 | 11 | fn build_dep_check(tools: &[&str]) -> bool { 12 | for tool in tools { 13 | let found = which(tool); 14 | if found.is_err() { 15 | println!("cargo:warning={tool} not found! Couldn't build tinyinst_rs"); 16 | return false; 17 | } 18 | } 19 | return true; 20 | } 21 | 22 | fn main() { 23 | if !build_dep_check(&["git", "cxxbridge", "cmake"]) { 24 | return; 25 | } 26 | 27 | #[cfg(target_os = "windows")] 28 | let cmake_generator = "Visual Studio 17 2022"; 29 | #[cfg(target_vendor = "apple")] 30 | let cmake_generator = "Xcode"; 31 | #[cfg(target_os = "linux")] 32 | let cmake_generator = "Unix Makefiles"; 33 | 34 | let custom_tinyinst_generator = 35 | env::var_os("CUSTOM_TINYINST_GENERATOR").map(|x| x.to_string_lossy().to_string()); 36 | 37 | env::set_var("CXXFLAGS", "-std=c++17"); 38 | 39 | let tinyinst_generator = if let Some(generator) = custom_tinyinst_generator.as_ref() { 40 | generator 41 | } else { 42 | cmake_generator 43 | }; 44 | 45 | let custum_tinyinst_dir = 46 | env::var_os("CUSTOM_TINYINST_DIR").map(|x| x.to_string_lossy().to_string()); 47 | let custum_tinyinst_no_build = env::var("CUSTOM_TINYINST_NO_BUILD").is_ok(); 48 | 49 | println!("cargo:rerun-if-env-changed=CUSTOM_TINYINST_DIR"); 50 | println!("cargo:rerun-if-env-changed=CUSTOM_TINYINST_NO_BUILD"); 51 | println!("cargo:rerun-if-env-changed=CUSTOM_TINYINST_GENERATOR"); 52 | 53 | let out_dir = env::var_os("OUT_DIR").unwrap(); 54 | let out_dir_path = Path::new(&out_dir); 55 | let mut target_dir = out_dir_path.to_path_buf(); 56 | target_dir.pop(); 57 | target_dir.pop(); 58 | target_dir.pop(); 59 | 60 | let tinyinst_path = if let Some(tinyinst_dir) = custum_tinyinst_dir.as_ref() { 61 | Path::new(&tinyinst_dir).to_path_buf() 62 | } else { 63 | let tinyinst_path = out_dir_path.join(TINYINST_DIRNAME); 64 | let tinyinst_rev = target_dir.join("TINYINST_REVISION"); 65 | // if revision exists and its different, remove Tinyinst dir 66 | if tinyinst_rev.exists() 67 | && fs::read_to_string(&tinyinst_rev).expect("Failed to read TINYINST_REVISION") 68 | != TINYINST_REVISION 69 | { 70 | println!("cargo:warning=Removing Tinyinst dir. Revision changed"); 71 | let _ = fs::remove_dir_all(&tinyinst_path); 72 | } 73 | 74 | // Check if directory doesn't exist, clone 75 | if !tinyinst_path.is_dir() { 76 | println!("cargo:warning=Pulling TinyInst from github"); 77 | let tinyinst_repo = match Repository::clone(TINYINST_URL, &tinyinst_path) { 78 | Ok(repo) => repo, 79 | _ => Repository::open(&tinyinst_path).expect("Failed to open repository"), 80 | }; 81 | 82 | // checkout correct commit 83 | let oid = Oid::from_str(TINYINST_REVISION).unwrap(); 84 | let commit = tinyinst_repo.find_commit(oid).unwrap(); 85 | 86 | let _ = tinyinst_repo.branch(TINYINST_REVISION, &commit, false); 87 | let obj = tinyinst_repo 88 | .revparse_single(&("refs/heads/".to_owned() + TINYINST_REVISION)) 89 | .unwrap(); 90 | 91 | tinyinst_repo.checkout_tree(&obj, None).unwrap(); 92 | 93 | tinyinst_repo 94 | .set_head(&("refs/heads/".to_owned() + TINYINST_REVISION)) 95 | .unwrap(); 96 | 97 | let mut submodules = tinyinst_repo.submodules().unwrap(); 98 | 99 | // do git submodule update --init --recursive on Tinyinst 100 | for submodule in &mut submodules { 101 | submodule.update(true, None).unwrap(); 102 | } 103 | 104 | // write the revision to target dir 105 | fs::write(&tinyinst_rev, TINYINST_REVISION).unwrap(); 106 | } 107 | tinyinst_path 108 | }; 109 | if !custum_tinyinst_no_build { 110 | println!( 111 | "cargo:warning=Generating Bridge files. and building for {}", 112 | &tinyinst_path.to_string_lossy() 113 | ); 114 | copy_tinyinst_files(&tinyinst_path); 115 | 116 | let _ = Config::new(&tinyinst_path) 117 | .generator(tinyinst_generator) 118 | .build_target("tinyinst") 119 | .profile("Release") // without this, it goes into RelWithDbInfo folder?? 120 | .out_dir(&tinyinst_path) 121 | .define("CMAKE_POLICY_VERSION_MINIMUM", "3.5") 122 | .build(); 123 | } 124 | 125 | // For m1 mac(?) 126 | println!( 127 | "cargo:rustc-link-search={}/build/third_party/Release", 128 | &tinyinst_path.to_string_lossy() 129 | ); 130 | 131 | #[cfg(not(target_os = "linux"))] 132 | println!( 133 | "cargo:rustc-link-search={}/build/Release", 134 | &tinyinst_path.to_string_lossy() 135 | ); 136 | 137 | #[cfg(target_os = "linux")] 138 | println!( 139 | "cargo:rustc-link-search={}/build", 140 | &tinyinst_path.to_string_lossy() 141 | ); 142 | println!( 143 | "cargo:rustc-link-search={}/build/third_party/obj/wkit/lib", 144 | &tinyinst_path.to_string_lossy() 145 | ); 146 | println!("cargo:rustc-link-lib=static=tinyinst"); 147 | 148 | #[cfg(target_arch = "x86_64")] 149 | println!("cargo:rustc-link-lib=static=xed"); 150 | 151 | #[cfg(target_arch = "aarch64")] 152 | println!("cargo:rustc-link-lib=static=reil"); 153 | 154 | #[cfg(target_os = "windows")] 155 | println!("cargo:rustc-link-lib=dylib=dbghelp"); 156 | 157 | println!("cargo:rerun-if-changed=src/"); 158 | println!("cargo:rerun-if-changed=src/tinyinst.rs"); 159 | println!("cargo:rerun-if-changed=build.rs"); 160 | println!("cargo:rerun-if-changed=Tinyinst/litecov.cpp"); 161 | } 162 | 163 | // #[cfg(not(target_os = "linux"))] 164 | fn copy_tinyinst_files(tinyinst_path: &Path) { 165 | // source 166 | Command::new("cxxbridge") 167 | .args(["src/tinyinst.rs", "-o"]) 168 | .arg(format!("{}/bridge.cc", tinyinst_path.to_string_lossy())) 169 | .status() 170 | .unwrap(); 171 | 172 | // header 173 | Command::new("cxxbridge") 174 | .args(["src/tinyinst.rs", "--header", "-o"]) 175 | .arg(format!("{}/bridge.h", tinyinst_path.to_string_lossy())) 176 | .status() 177 | .unwrap(); 178 | 179 | // cxx 180 | Command::new("cxxbridge") 181 | .args(["--header", "-o"]) 182 | .arg(format!("{}/cxx.h", tinyinst_path.to_string_lossy())) 183 | .status() 184 | .unwrap(); 185 | 186 | // shim 187 | std::fs::copy("./src/shim.cc", tinyinst_path.join("shim.cc")).unwrap(); 188 | std::fs::copy("./src/shim.h", tinyinst_path.join("shim.h")).unwrap(); 189 | 190 | // runresult 191 | std::fs::copy("./src/runresult.h", tinyinst_path.join("runresult.h")).unwrap(); 192 | 193 | // instrumentation 194 | std::fs::copy( 195 | "./src/instrumentation.cpp", 196 | tinyinst_path.join("instrumentation.cpp"), 197 | ) 198 | .unwrap(); 199 | std::fs::copy( 200 | "./src/instrumentation.h", 201 | tinyinst_path.join("instrumentation.h"), 202 | ) 203 | .unwrap(); 204 | 205 | // tinyinstinstrumentation 206 | std::fs::copy( 207 | "./src/tinyinstinstrumentation.cpp", 208 | tinyinst_path.join("tinyinstinstrumentation.cpp"), 209 | ) 210 | .unwrap(); 211 | std::fs::copy( 212 | "./src/tinyinstinstrumentation.h", 213 | tinyinst_path.join("tinyinstinstrumentation.h"), 214 | ) 215 | .unwrap(); 216 | 217 | // aflcov 218 | std::fs::copy("./src/aflcov.cpp", tinyinst_path.join("aflcov.cpp")).unwrap(); 219 | std::fs::copy("./src/aflcov.h", tinyinst_path.join("aflcov.h")).unwrap(); 220 | 221 | // cmake file 222 | std::fs::copy("./src/CMakeLists.txt", tinyinst_path.join("CMakeLists.txt")).unwrap(); 223 | } 224 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | cmake_minimum_required(VERSION "3.1") 16 | set (CMAKE_CXX_STANDARD 17) 17 | 18 | # Determine whether TinyInst should be build for arm64 or x86 19 | if(APPLE AND NOT DEFINED ${ARCHITECTURE}) 20 | EXECUTE_PROCESS(COMMAND uname -m COMMAND tr -d '\n' OUTPUT_VARIABLE ARCHITECTURE) 21 | if(${ARCHITECTURE} MATCHES arm64) 22 | add_definitions(-DARM64) 23 | endif() 24 | endif() 25 | 26 | add_subdirectory(third_party) 27 | 28 | project("tinyinst") 29 | 30 | include_directories(${CMAKE_CURRENT_BINARY_DIR}/third_party/obj/wkit/include) 31 | 32 | if(${ARCHITECTURE} MATCHES arm64) 33 | set (arch_specific_files 34 | arch/arm64/reg.h 35 | arch/arm64/arm64_helpers.h 36 | arch/arm64/arm64_helpers.cpp 37 | arch/arm64/arm64_assembler.h 38 | arch/arm64/arm64_assembler.cpp 39 | arch/arm64/arm64_litecov.cpp 40 | ) 41 | else() 42 | set (arch_specific_files 43 | arch/x86/reg.h 44 | arch/x86/x86_helpers.h 45 | arch/x86/x86_helpers.cpp 46 | arch/x86/x86_assembler.h 47 | arch/x86/x86_assembler.cpp 48 | arch/x86/x86_litecov.cpp 49 | ) 50 | endif() 51 | 52 | set (cross_platform_files 53 | common.h 54 | common.cpp 55 | assembler.h 56 | instruction.h 57 | tinyinst.h 58 | tinyinst.cpp 59 | coverage.h 60 | coverage.cpp 61 | litecov.h 62 | litecov.cpp 63 | unwind.h 64 | bridge.cc 65 | bridge.h 66 | shim.cc 67 | shim.h 68 | runresult.h 69 | instrumentation.cpp 70 | instrumentation.h 71 | tinyinstinstrumentation.cpp 72 | tinyinstinstrumentation.h 73 | aflcov.cpp 74 | aflcov.h 75 | ) 76 | 77 | if (WIN32) 78 | set (platform_specific_files 79 | Windows/debugger.h 80 | Windows/debugger.cpp 81 | Windows/winunwind.cpp 82 | Windows/winunwind.h 83 | ) 84 | elseif (APPLE) 85 | if (${ARCHITECTURE} MATCHES arm64) 86 | set(CMAKE_REQUIRED_LINK_OPTIONS "-arch;arm64") 87 | endif() 88 | 89 | add_custom_command( 90 | OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/macOS/mig_client.c 91 | ${CMAKE_CURRENT_SOURCE_DIR}/macOS/mig_server.c 92 | ${CMAKE_CURRENT_SOURCE_DIR}/macOS/mig_client.h 93 | ${CMAKE_CURRENT_SOURCE_DIR}/macOS/mig_server.h 94 | COMMAND mig -user ${CMAKE_CURRENT_SOURCE_DIR}/macOS/mig_client.c 95 | -server ${CMAKE_CURRENT_SOURCE_DIR}/macOS/mig_server.c 96 | -header ${CMAKE_CURRENT_SOURCE_DIR}/macOS/mig_client.h 97 | -sheader ${CMAKE_CURRENT_SOURCE_DIR}/macOS/mig_server.h 98 | ${CMAKE_CURRENT_SOURCE_DIR}/macOS/mig.defs 99 | COMMENT "Generating Mig files" 100 | ) 101 | 102 | set (platform_specific_files 103 | macOS/debugger.h 104 | macOS/debugger.cpp 105 | macOS/machtarget.h 106 | macOS/machtarget.cpp 107 | macOS/mig_client.h 108 | macOS/mig_client.c 109 | macOS/mig_server.h 110 | macOS/mig_server.c 111 | macOS/unwindmacos.cpp 112 | macOS/unwindmacos.h 113 | macOS/dyld_cache_map_parser.cpp 114 | macOS/dyld_cache_map_parser.h 115 | ) 116 | elseif (UNIX) 117 | set (platform_specific_files 118 | Linux/debugger.h 119 | Linux/debugger.cpp 120 | Linux/elffile.h 121 | Linux/elffile.cpp 122 | Linux/procmaps.h 123 | Linux/procmaps.cpp 124 | Linux/syscallhook.h 125 | Linux/syscallhook.cpp 126 | ) 127 | endif() 128 | 129 | add_library(tinyinst STATIC 130 | ${arch_specific_files} 131 | ${arch_specific_files} 132 | ${platform_specific_files} 133 | ${cross_platform_files} 134 | ) 135 | 136 | target_include_directories(tinyinst PUBLIC 137 | ${CMAKE_CURRENT_SOURCE_DIR} 138 | ${CMAKE_CURRENT_BINARY_DIR}/third_party/obj/wkit/include 139 | ) 140 | 141 | if((${ARCHITECTURE} MATCHES arm64) AND APPLE) 142 | add_dependencies(tinyinst reil) 143 | target_link_libraries(tinyinst reil) 144 | else() 145 | add_dependencies(tinyinst xed) 146 | if (WIN32) 147 | target_link_libraries(tinyinst 148 | ${CMAKE_CURRENT_BINARY_DIR}/third_party/obj/wkit/lib/xed.lib 149 | Dbghelp.lib 150 | ) 151 | else () 152 | target_link_libraries(tinyinst 153 | ${CMAKE_CURRENT_BINARY_DIR}/third_party/obj/wkit/lib/libxed.a 154 | ) 155 | endif() 156 | endif() 157 | 158 | project("litecov") 159 | 160 | add_executable(litecov 161 | tinyinst-coverage.cpp 162 | ) 163 | 164 | target_link_libraries(litecov tinyinst) 165 | -------------------------------------------------------------------------------- /src/aflcov.cpp: -------------------------------------------------------------------------------- 1 | #include "aflcov.h" 2 | #include 3 | void AFLCov::GetCoverage(Coverage &coverage, rust::Vec &afl_coverage, bool clear_coverage) 4 | { 5 | CollectCoverage(); 6 | for (ModuleInfo *module : instrumented_modules) 7 | { 8 | ModuleCovData *data = (ModuleCovData *)module->client_data; 9 | 10 | if (data->collected_coverage.empty()) 11 | continue; 12 | 13 | // check if that module is already in the coverage list 14 | // (if the client calls with non-empty initial coverage) 15 | ModuleCoverage *module_coverage = 16 | GetModuleCoverage(coverage, module->module_name); 17 | if (module_coverage) 18 | { 19 | module_coverage->offsets.insert(data->collected_coverage.begin(), 20 | data->collected_coverage.end()); 21 | 22 | // Copy the coverage to afl_coverage 23 | std::copy(data->collected_coverage.begin(), data->collected_coverage.end(), std::back_inserter(afl_coverage)); 24 | } 25 | else 26 | { 27 | coverage.push_back({module->module_name, data->collected_coverage}); 28 | // Copy the coverage to afl_coverage 29 | std::copy(data->collected_coverage.begin(), data->collected_coverage.end(), std::back_inserter(afl_coverage)); 30 | } 31 | } 32 | 33 | if (clear_coverage) 34 | ClearCoverage(); 35 | } 36 | -------------------------------------------------------------------------------- /src/aflcov.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "litecov.h" 3 | #include "coverage.h" 4 | #include 5 | #include "cxx.h" 6 | class AFLCov : public LiteCov 7 | { 8 | public: 9 | void GetCoverage(Coverage &coverage, rust::Vec &afl_coverage, bool clear_coverage); 10 | }; 11 | -------------------------------------------------------------------------------- /src/instrumentation.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 Google LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | https://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #define _CRT_SECURE_NO_WARNINGS 18 | 19 | #include "string.h" 20 | #include "common.h" 21 | #include "instrumentation.h" 22 | 23 | #include 24 | 25 | std::string Instrumentation::AnonymizeAddress(void *addr) 26 | { 27 | char buf[20]; 28 | sprintf(buf, "%p", addr); 29 | int len = (int)strlen(buf); 30 | int firstnonzero = len; 31 | for (int i = 0; i < len; i++) 32 | { 33 | if (buf[i] != '0') 34 | { 35 | firstnonzero = i; 36 | break; 37 | } 38 | } 39 | for (int i = firstnonzero; i < len - 3; i++) 40 | { 41 | buf[i] = 'x'; 42 | } 43 | return std::string(buf); 44 | } 45 | -------------------------------------------------------------------------------- /src/instrumentation.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 Google LLC. Modified by biazo 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | https://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include "aflcov.h" 22 | #include "runresult.h" 23 | #include "cxx.h" 24 | 25 | class Instrumentation 26 | { 27 | public: 28 | virtual ~Instrumentation() {} 29 | 30 | virtual void Init(int argc, char **argv) = 0; 31 | virtual RunResult Run(int argc, char **argv, uint32_t init_timeout, uint32_t timeout) = 0; 32 | 33 | virtual RunResult RunWithCrashAnalysis(int argc, char **argv, uint32_t init_timeout, uint32_t timeout) 34 | { 35 | return Run(argc, argv, init_timeout, timeout); 36 | } 37 | 38 | virtual void CleanTarget() = 0; 39 | 40 | virtual bool HasNewCoverage() = 0; 41 | virtual void GetCoverage(Coverage &coverage, rust::Vec &afl_coverage, bool clear_coverage) = 0; 42 | virtual void ClearCoverage() = 0; 43 | virtual void IgnoreCoverage(Coverage &coverage) = 0; 44 | 45 | virtual std::string GetCrashName() { return "crash"; }; 46 | 47 | virtual uint64_t GetReturnValue() { return 0; } 48 | 49 | std::string AnonymizeAddress(void *addr); 50 | }; 51 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | * Rust bindings for [`TinyInst`](https://github.com/googleprojectzero/TinyInst) 3 | */ 4 | 5 | #![allow(incomplete_features)] 6 | #![no_std] 7 | #![warn(clippy::cargo)] 8 | #![deny(clippy::cargo_common_metadata)] 9 | #![deny(rustdoc::broken_intra_doc_links)] 10 | #![deny(clippy::all)] 11 | #![deny(clippy::pedantic)] 12 | #![allow(clippy::missing_safety_doc, clippy::missing_panics_doc)] 13 | #![cfg_attr( 14 | not(test), 15 | warn( 16 | missing_debug_implementations, 17 | trivial_casts, 18 | trivial_numeric_casts, 19 | unused_extern_crates, 20 | unused_import_braces, 21 | unused_qualifications, 22 | unused_results 23 | ) 24 | )] 25 | #![cfg_attr( 26 | test, 27 | deny( 28 | missing_debug_implementations, 29 | trivial_casts, 30 | trivial_numeric_casts, 31 | unused_extern_crates, 32 | unused_import_braces, 33 | unused_qualifications, 34 | unused_results 35 | ) 36 | )] 37 | #![cfg_attr( 38 | test, 39 | deny( 40 | bad_style, 41 | dead_code, 42 | improper_ctypes, 43 | non_shorthand_field_patterns, 44 | no_mangle_generic_items, 45 | overflowing_literals, 46 | path_statements, 47 | patterns_in_fns_without_body, 48 | private_in_public, 49 | unconditional_recursion, 50 | unused, 51 | unused_allocation, 52 | unused_comparisons, 53 | unused_parens, 54 | while_true 55 | ) 56 | )] 57 | 58 | #[cfg(test)] 59 | #[macro_use] 60 | extern crate std; 61 | pub extern crate alloc; 62 | 63 | pub mod tinyinst; 64 | -------------------------------------------------------------------------------- /src/runresult.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 Google LLC 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | https://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software 8 | distributed under the License is distributed on an "AS IS" BASIS, 9 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | See the License for the specific language governing permissions and 11 | limitations under the License. 12 | */ 13 | 14 | #pragma once 15 | 16 | enum RunResult { 17 | OK, 18 | CRASH, 19 | HANG, 20 | OTHER_ERROR, 21 | }; -------------------------------------------------------------------------------- /src/shim.cc: -------------------------------------------------------------------------------- 1 | #include "shim.h" 2 | 3 | std::unique_ptr coverage_new() 4 | { 5 | return std::make_unique(); 6 | } 7 | 8 | void get_coverage_map(uint8_t *bitmap, size_t map_size, Coverage &newcoverage) 9 | { 10 | for (auto iter = newcoverage.begin(); iter != newcoverage.end(); iter++) 11 | { 12 | for (auto &offset : iter->offsets) 13 | { 14 | if (offset < map_size) 15 | { 16 | bitmap[offset] = 1; 17 | } 18 | } 19 | } 20 | } 21 | 22 | // tinyinstinstrumentation 23 | std::unique_ptr tinyinstinstrumentation_new() 24 | { 25 | return std::make_unique(); 26 | } 27 | -------------------------------------------------------------------------------- /src/shim.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "litecov.h" 5 | #include "coverage.h" 6 | #include "tinyinstinstrumentation.h" 7 | #include "aflcov.h" 8 | 9 | // litecov 10 | std::unique_ptr coverage_new(); 11 | void get_coverage_map(uint8_t *bitmap, size_t map_size, Coverage &newcoverage); 12 | 13 | // tinyinstinstrumentation 14 | std::unique_ptr tinyinstinstrumentation_new(); -------------------------------------------------------------------------------- /src/tinyinst.rs: -------------------------------------------------------------------------------- 1 | use alloc::{ffi::CString, string::String, vec::Vec}; 2 | use core::{ 3 | ffi::c_char, 4 | fmt::{self, Debug, Formatter}, 5 | }; 6 | #[cxx::bridge] 7 | pub mod common { 8 | // C++ types and signatures exposed to Rust. 9 | unsafe extern "C++" { 10 | include!("common.h"); 11 | #[must_use] 12 | fn GetCurTime() -> u64; 13 | } 14 | } 15 | 16 | #[allow(clippy::expl_impl_clone_on_copy)] 17 | #[cxx::bridge] 18 | pub mod litecov { 19 | #[derive(Debug, Copy, Clone)] 20 | #[repr(u32)] 21 | enum RunResult { 22 | OK, 23 | CRASH, 24 | HANG, 25 | OTHER_ERROR, 26 | } 27 | 28 | #[allow(missing_debug_implementations)] 29 | unsafe extern "C++" { 30 | // for constructors. 31 | include!("shim.h"); 32 | include!("tinyinstinstrumentation.h"); 33 | include!("aflcov.h"); 34 | 35 | type ModuleCovData; 36 | pub fn ClearInstrumentationData(self: Pin<&mut ModuleCovData>); 37 | pub fn ClearCmpCoverageData(self: Pin<&mut ModuleCovData>); 38 | 39 | type Coverage; 40 | type ModuleCoverage; 41 | 42 | #[must_use] 43 | pub fn coverage_new() -> UniquePtr; 44 | 45 | pub unsafe fn get_coverage_map( 46 | bitmap: *mut u8, 47 | map_size: usize, 48 | coverage: Pin<&mut Coverage>, 49 | ); 50 | 51 | // TinyinstInstrumentation 52 | type TinyInstInstrumentation; 53 | #[must_use] 54 | pub fn tinyinstinstrumentation_new() -> UniquePtr; 55 | 56 | type RunResult; 57 | // type Coverage; 58 | #[allow(clippy::similar_names)] 59 | pub unsafe fn Init( 60 | self: Pin<&mut TinyInstInstrumentation>, 61 | argc: i32, 62 | argv: *mut *mut c_char, 63 | ); 64 | #[allow(clippy::similar_names)] 65 | pub unsafe fn Run( 66 | self: Pin<&mut TinyInstInstrumentation>, 67 | argc: i32, 68 | argv: *mut *mut c_char, 69 | init_timeout: u32, 70 | timeout: u32, 71 | ) -> RunResult; 72 | 73 | #[allow(clippy::similar_names)] 74 | pub unsafe fn RunWithCrashAnalysis( 75 | self: Pin<&mut TinyInstInstrumentation>, 76 | argc: i32, 77 | argv: *mut *mut c_char, 78 | init_timeout: u32, 79 | timeout: u32, 80 | ) -> RunResult; 81 | 82 | pub fn CleanTarget(self: Pin<&mut TinyInstInstrumentation>); 83 | #[must_use] 84 | pub fn HasNewCoverage(self: Pin<&mut TinyInstInstrumentation>) -> bool; 85 | 86 | pub fn GetCoverage( 87 | self: Pin<&mut TinyInstInstrumentation>, 88 | coverage: Pin<&mut Coverage>, 89 | afl_coverage: &mut Vec, 90 | clear_coverage: bool, 91 | ); 92 | pub fn ClearCoverage(self: Pin<&mut TinyInstInstrumentation>); 93 | pub fn IgnoreCoverage( 94 | self: Pin<&mut TinyInstInstrumentation>, 95 | coverage: Pin<&mut Coverage>, 96 | ); 97 | 98 | // Testing AFLCOV 99 | // type AFLCov; 100 | // pub unsafe fn aflcov_new(coverage: *mut u8, capacity: usize) -> UniquePtr; 101 | // pub fn add_coverage(self: Pin<&mut AFLCov>, addr: u8); 102 | } 103 | } 104 | 105 | use cxx::UniquePtr; 106 | impl litecov::TinyInstInstrumentation { 107 | #[must_use] 108 | pub fn new() -> UniquePtr { 109 | litecov::tinyinstinstrumentation_new() 110 | } 111 | } 112 | 113 | impl litecov::Coverage { 114 | #[must_use] 115 | pub fn new() -> UniquePtr { 116 | litecov::coverage_new() 117 | } 118 | } 119 | 120 | pub struct TinyInst { 121 | tinyinst_ptr: UniquePtr, 122 | program_args_cstr: Vec, 123 | program_args_ptr: Vec<*mut c_char>, 124 | coverage_ptr: UniquePtr, 125 | timeout: u32, 126 | } 127 | 128 | impl Debug for TinyInst { 129 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 130 | f.debug_struct("TinyInst") 131 | .field("program_args_cstr", &self.program_args_cstr) 132 | .field("timeout", &self.timeout) 133 | .finish_non_exhaustive() 134 | } 135 | } 136 | 137 | impl TinyInst { 138 | #[must_use] 139 | pub unsafe fn new(tinyinst_args: &[String], program_args: &[String], timeout: u32) -> TinyInst { 140 | // commented out by domenukk: 141 | // a) would require call to a libc, c++ or rust std fn 142 | // b) The program could actually be in the PATH, so, not accessible as file. 143 | /* 144 | if !Path::new(format!("{}", program_args[0]).as_str()).exists() { 145 | panic!("{} does not exist", program_args[0]); 146 | }*/ 147 | let mut tinyinst_ptr = litecov::TinyInstInstrumentation::new(); 148 | 149 | let tinyinst_args_cstr: Vec = tinyinst_args 150 | .iter() 151 | .map(|arg| CString::new(arg.as_str()).unwrap()) 152 | .collect(); 153 | 154 | let mut tinyinst_args_ptr: Vec<*mut c_char> = tinyinst_args_cstr 155 | .iter() 156 | .map(|arg| arg.as_ptr() as *mut c_char) 157 | .collect(); 158 | tinyinst_args_ptr.push(core::ptr::null_mut()); 159 | 160 | // Init TinyInst with Tinyinst arguments. 161 | tinyinst_ptr.pin_mut().Init( 162 | i32::try_from(tinyinst_args.len()).unwrap(), 163 | tinyinst_args_ptr.as_mut_ptr(), 164 | ); 165 | 166 | let program_args_cstr: Vec = program_args 167 | .iter() 168 | .map(|arg| CString::new(arg.as_str()).unwrap()) 169 | .collect(); 170 | 171 | let mut program_args_ptr: Vec<*mut c_char> = program_args_cstr 172 | .iter() 173 | .map(|arg| arg.as_ptr() as *mut c_char) 174 | .collect(); 175 | program_args_ptr.push(core::ptr::null_mut()); 176 | 177 | TinyInst { 178 | tinyinst_ptr, 179 | program_args_cstr, 180 | program_args_ptr, 181 | timeout, 182 | coverage_ptr: litecov::Coverage::new(), 183 | } 184 | } 185 | 186 | pub unsafe fn run(&mut self) -> litecov::RunResult { 187 | self.tinyinst_ptr.pin_mut().Run( 188 | i32::try_from(self.program_args_cstr.len()).unwrap(), 189 | self.program_args_ptr.as_mut_ptr(), 190 | self.timeout, 191 | self.timeout, 192 | ) 193 | } 194 | 195 | // pub unsafe fn bitmap_coverage( 196 | // &mut self, 197 | // bitmap: *mut u8, 198 | // map_size: usize, 199 | // clear_coverage: bool, 200 | // ) { 201 | // self.tinyinst_ptr 202 | // .pin_mut() 203 | // .GetCoverage(self.coverage_ptr.pin_mut(), clear_coverage); 204 | // litecov::get_coverage_map(bitmap, map_size, self.coverage_ptr.pin_mut()); 205 | // } 206 | 207 | pub fn vec_coverage(&mut self, afl_coverage: &mut Vec, clear_coverage: bool) { 208 | // Clear coverage if there was previous coverage 209 | afl_coverage.clear(); 210 | self.tinyinst_ptr.pin_mut().GetCoverage( 211 | self.coverage_ptr.pin_mut(), 212 | afl_coverage, 213 | clear_coverage, 214 | ); 215 | // This will mark coverage we have seen as already seen coverage and won't report it again. 216 | self.ignore_coverage(); 217 | } 218 | fn ignore_coverage(&mut self) { 219 | self.tinyinst_ptr 220 | .pin_mut() 221 | .IgnoreCoverage(self.coverage_ptr.pin_mut()); 222 | } 223 | } 224 | 225 | #[cfg(test)] 226 | mod tests { 227 | use alloc::vec::Vec; 228 | use std::{ 229 | fs::File, 230 | io::{Seek, Write}, 231 | path::Path, 232 | string::ToString, 233 | }; 234 | 235 | #[cfg(target_os = "windows")] 236 | const TEST_FILENAME: &str = "test.exe"; 237 | #[cfg(any(target_vendor = "apple", target_os = "linux"))] 238 | const TEST_FILENAME: &str = "test"; 239 | 240 | #[cfg(any(target_vendor = "apple", target_os = "linux"))] 241 | const TEST_PATH: &str = "test/build/"; 242 | #[cfg(target_os = "windows")] 243 | const TEST_PATH: &str = "test/build/Debug/"; 244 | 245 | #[test] 246 | fn tinyinst_ok() { 247 | let tinyinst_args = vec!["-instrument_module".to_string(), TEST_FILENAME.to_string()]; 248 | // Create file to test. 249 | let mut file = File::create("./test/test_file.txt").unwrap(); 250 | file.write_all(b"test1").unwrap(); 251 | 252 | let program_args = vec![ 253 | Path::new(TEST_PATH) 254 | .join(TEST_FILENAME) 255 | .display() 256 | .to_string(), 257 | "./test/test_file.txt".to_string(), 258 | ]; 259 | let mut coverage = Vec::new(); 260 | 261 | unsafe { 262 | let mut tinyinst = super::TinyInst::new(&tinyinst_args, &program_args, 5000); 263 | 264 | // First test case 265 | let result = tinyinst.run(); 266 | tinyinst.vec_coverage(&mut coverage, true); 267 | assert_eq!(result, super::litecov::RunResult::OK); 268 | assert!(coverage.len() <= 1412); 269 | 270 | // Second test case for b 271 | _ = file.seek(std::io::SeekFrom::Start(0)).unwrap(); 272 | file.write_all(b"b").unwrap(); 273 | let result = tinyinst.run(); 274 | tinyinst.vec_coverage(&mut coverage, true); 275 | assert_eq!(result, super::litecov::RunResult::OK); 276 | 277 | // Second test case for ba 278 | _ = file.seek(std::io::SeekFrom::Start(0)).unwrap(); 279 | file.write_all(b"ba").unwrap(); 280 | let result = tinyinst.run(); 281 | tinyinst.vec_coverage(&mut coverage, true); 282 | assert_eq!(result, super::litecov::RunResult::OK); 283 | } 284 | } 285 | #[test] 286 | fn tinyinst_crash() { 287 | use alloc::{string::ToString, vec::Vec}; 288 | 289 | let tinyinst_args = vec!["-instrument_module".to_string(), TEST_FILENAME.to_string()]; 290 | 291 | let program_args = vec![ 292 | Path::new(TEST_PATH) 293 | .join(TEST_FILENAME) 294 | .display() 295 | .to_string(), 296 | "./test/crash_input.txt".to_string(), 297 | ]; 298 | let mut coverage = Vec::new(); 299 | 300 | unsafe { 301 | let mut tinyinst = super::TinyInst::new(&tinyinst_args, &program_args, 5000); 302 | let result = tinyinst.run(); 303 | tinyinst.vec_coverage(&mut coverage, true); 304 | assert_eq!(result, super::litecov::RunResult::CRASH); 305 | } 306 | } 307 | } 308 | -------------------------------------------------------------------------------- /src/tinyinstinstrumentation.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 Google LLC. Modified by biazo 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | https://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #define _CRT_SECURE_NO_WARNINGS 18 | 19 | #include "common.h" 20 | #include "tinyinstinstrumentation.h" 21 | 22 | #include 23 | 24 | void TinyInstInstrumentation::Init(int argc, char **argv) 25 | { 26 | instrumentation = new AFLCov(); 27 | instrumentation->Init(argc, argv); 28 | 29 | persist = GetBinaryOption("-persist", argc, argv, false); 30 | num_iterations = GetIntOption("-iterations", argc, argv, 1); 31 | } 32 | 33 | RunResult TinyInstInstrumentation::Run(int argc, char **argv, 34 | uint32_t init_timeout, 35 | uint32_t timeout) 36 | { 37 | DebuggerStatus status; 38 | RunResult ret = OTHER_ERROR; 39 | 40 | if (instrumentation->IsTargetFunctionDefined()) 41 | { 42 | if (cur_iteration == num_iterations) 43 | { 44 | instrumentation->Kill(); 45 | cur_iteration = 0; 46 | } 47 | } 48 | 49 | // else clear only when the target function is reached 50 | if (!instrumentation->IsTargetFunctionDefined()) 51 | { 52 | instrumentation->ClearCoverage(); 53 | } 54 | 55 | uint32_t timeout1 = timeout; 56 | if (instrumentation->IsTargetFunctionDefined()) 57 | { 58 | timeout1 = init_timeout; 59 | } 60 | 61 | if (instrumentation->IsTargetAlive() && persist) 62 | { 63 | status = instrumentation->Continue(timeout1); 64 | } 65 | else 66 | { 67 | instrumentation->Kill(); 68 | cur_iteration = 0; 69 | status = instrumentation->Run(argc, argv, timeout1); 70 | } 71 | 72 | // if target function is defined, 73 | // we should wait until it is hit 74 | if (instrumentation->IsTargetFunctionDefined()) 75 | { 76 | if (status != DEBUGGER_TARGET_START) 77 | { 78 | // try again with a clean process 79 | WARN("Target function not reached, retrying with a clean process\n"); 80 | instrumentation->Kill(); 81 | cur_iteration = 0; 82 | status = instrumentation->Run(argc, argv, init_timeout); 83 | } 84 | 85 | if (status != DEBUGGER_TARGET_START) 86 | { 87 | switch (status) 88 | { 89 | case DEBUGGER_CRASHED: 90 | FATAL("Process crashed before reaching the target method\n"); 91 | break; 92 | case DEBUGGER_HANGED: 93 | FATAL("Process hanged before reaching the target method\n"); 94 | break; 95 | case DEBUGGER_PROCESS_EXIT: 96 | FATAL("Process exited before reaching the target method\n"); 97 | break; 98 | default: 99 | FATAL( 100 | "An unknown problem occured before reaching the target method\n"); 101 | break; 102 | } 103 | } 104 | 105 | instrumentation->ClearCoverage(); 106 | 107 | status = instrumentation->Continue(timeout); 108 | } 109 | 110 | switch (status) 111 | { 112 | case DEBUGGER_CRASHED: 113 | ret = CRASH; 114 | instrumentation->Kill(); 115 | break; 116 | case DEBUGGER_HANGED: 117 | ret = HANG; 118 | instrumentation->Kill(); 119 | break; 120 | case DEBUGGER_PROCESS_EXIT: 121 | ret = OK; 122 | if (instrumentation->IsTargetFunctionDefined()) 123 | { 124 | WARN("Process exit during target function\n"); 125 | ret = HANG; 126 | } 127 | break; 128 | case DEBUGGER_TARGET_END: 129 | if (instrumentation->IsTargetFunctionDefined()) 130 | { 131 | ret = OK; 132 | cur_iteration++; 133 | } 134 | else 135 | { 136 | FATAL("Unexpected status received from the debugger\n"); 137 | } 138 | break; 139 | default: 140 | FATAL("Unexpected status received from the debugger\n"); 141 | break; 142 | } 143 | 144 | return ret; 145 | } 146 | 147 | RunResult TinyInstInstrumentation::RunWithCrashAnalysis(int argc, char **argv, 148 | uint32_t init_timeout, 149 | uint32_t timeout) 150 | { 151 | // clean process when reproducing crashes 152 | instrumentation->Kill(); 153 | // disable instrumentation when reproducing crashes 154 | instrumentation->DisableInstrumentation(); 155 | RunResult ret = Run(argc, argv, init_timeout, timeout); 156 | instrumentation->Kill(); 157 | instrumentation->EnableInstrumentation(); 158 | return ret; 159 | } 160 | 161 | void TinyInstInstrumentation::CleanTarget() 162 | { 163 | instrumentation->Kill(); 164 | } 165 | 166 | bool TinyInstInstrumentation::HasNewCoverage() 167 | { 168 | return instrumentation->HasNewCoverage(); 169 | } 170 | 171 | void TinyInstInstrumentation::GetCoverage(Coverage &coverage, rust::Vec &afl_coverage, bool clear_coverage) 172 | { 173 | instrumentation->GetCoverage(coverage, afl_coverage, clear_coverage); 174 | } 175 | 176 | void TinyInstInstrumentation::ClearCoverage() 177 | { 178 | instrumentation->ClearCoverage(); 179 | } 180 | 181 | void TinyInstInstrumentation::IgnoreCoverage(Coverage &coverage) 182 | { 183 | instrumentation->IgnoreCoverage(coverage); 184 | } 185 | 186 | TinyInstInstrumentation::~TinyInstInstrumentation() 187 | { 188 | instrumentation->Kill(); 189 | delete instrumentation; 190 | } 191 | 192 | std::string TinyInstInstrumentation::GetCrashName() 193 | { 194 | LiteCov::Exception exception = instrumentation->GetLastException(); 195 | std::stringstream stream; 196 | switch (exception.type) 197 | { 198 | case LiteCov::ExceptionType::ACCESS_VIOLATION: 199 | stream << "access_violation"; 200 | break; 201 | case LiteCov::ExceptionType::ILLEGAL_INSTRUCTION: 202 | stream << "illegal_instruction"; 203 | break; 204 | case LiteCov::ExceptionType::STACK_OVERFLOW: 205 | stream << "stack_overflow"; 206 | break; 207 | default: 208 | stream << "other"; 209 | break; 210 | } 211 | stream << "_"; 212 | stream << AnonymizeAddress(exception.ip); 213 | stream << "_"; 214 | stream << AnonymizeAddress(exception.access_address); 215 | return stream.str(); 216 | } 217 | 218 | uint64_t TinyInstInstrumentation::GetReturnValue() 219 | { 220 | return instrumentation->GetTargetReturnValue(); 221 | } 222 | -------------------------------------------------------------------------------- /src/tinyinstinstrumentation.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2020 Google LLC. Modified by biazo 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | https://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include "instrumentation.h" 22 | #include "cxx.h" 23 | 24 | class TinyInstInstrumentation : public Instrumentation 25 | { 26 | public: 27 | ~TinyInstInstrumentation(); 28 | 29 | void Init(int argc, char **argv) override; 30 | 31 | RunResult Run(int argc, char **argv, uint32_t init_timeout, 32 | uint32_t timeout) override; 33 | RunResult RunWithCrashAnalysis(int argc, char **argv, uint32_t init_timeout, 34 | uint32_t timeout) override; 35 | 36 | void CleanTarget() override; 37 | 38 | bool HasNewCoverage() override; 39 | void GetCoverage(Coverage &coverage, rust::Vec &afl_coverage, bool clear_coverage) override; 40 | void ClearCoverage() override; 41 | void IgnoreCoverage(Coverage &coverage) override; 42 | 43 | uint64_t GetReturnValue() override; 44 | 45 | std::string GetCrashName() override; 46 | 47 | protected: 48 | AFLCov *instrumentation; 49 | bool persist; 50 | int num_iterations; 51 | int cur_iteration; 52 | }; 53 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | project("test") 3 | 4 | # Disable implicit function declaration warning on macOS so it can compile vulnerable code 5 | if(APPLE) 6 | set(CMAKE_C_FLAGS "-Wno-error=implicit-function-declaration") 7 | endif() 8 | 9 | add_executable(test test.c) -------------------------------------------------------------------------------- /test/crash_input.txt: -------------------------------------------------------------------------------- 1 | bad12 -------------------------------------------------------------------------------- /test/ok_input.txt: -------------------------------------------------------------------------------- 1 | ok -------------------------------------------------------------------------------- /test/test.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void pass1(char *buf, int buf_size) 4 | { 5 | char target[0x10]; 6 | if (buf[0] == 'b') 7 | { 8 | if (buf[1] == 'a') 9 | { 10 | if (buf[2] == 'd') 11 | { 12 | if (buf[3] == '1') 13 | { 14 | if (buf[4] == '2') 15 | { 16 | printf("Triggering buffer overflow\n"); 17 | memcpy(target, buf, 0x1000000); 18 | printf("Should never get to this point\n"); 19 | } 20 | } 21 | } 22 | } 23 | } 24 | } 25 | int main(int argc, char *argv[]) 26 | { 27 | FILE *fp; 28 | char buf[0x1000]; 29 | if (argc == 2) 30 | { 31 | fp = fopen(argv[1], "r"); 32 | if (fp == NULL) 33 | { 34 | printf("File not found\n"); 35 | printf("Received filename %s\n", argv[1]); 36 | return 1; 37 | } 38 | fscanf(fp, "%s", buf); 39 | 40 | pass1(buf, sizeof(buf)); 41 | } 42 | else 43 | { 44 | printf("Program requires input file\n"); 45 | } 46 | } 47 | --------------------------------------------------------------------------------