diff --git a/.gitignore b/.gitignore index 3183862..9b193e2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ /target /Cargo.lock -/build +build/ *.exe /TinyInst *.obj diff --git a/Makefile.toml b/Makefile.toml index 8afc8da..fa759d1 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -1,3 +1,10 @@ [tasks.build_test] -command = "cl" -args = ["./test/test.c", "-o", "./test/test.exe"] +dependencies = ["build_configure"] +cwd = "./test" +command = "cmake" +args = ["--build", "build", "--config", "Debug"] + +[tasks.build_configure] +cwd = "./test" +command = "cmake" +args = ["-S", ".", "-B", "build"] diff --git a/README.md b/README.md index 559d6a3..d2bfc2d 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,29 @@ FFI to [TinyInst](https://github.com/googleprojectzero/TinyInst). Created for [LibAFL](https://github.com/AFLplusplus/LibAFL). +## Dependencies + +* cxxbridge +* cargo-make +* python3 +* git + ## Running the test -1. Open up developer powershell so that you have access to cl (Windows Default Compiler) +1. Open a terminal and set up your build environment (e.g. On Windows, run Developer Powershell / Developer CMD/ vcvars64.bat / vcvars32.bat) 2. Run `cargo make build_test` to build the test binary 3. Run `cargo test` to run the test + +## Optional ENV Variables + +`CUSTOM_TINYINST_GENERATOR` = Generator used for cmake `-G` flag + +`CUSTOM_TINYINST_PATH` = path to local Tinyinst repo + +`CUSTOM_TINYINST_NO_BUILD` = if set, it won't build Tinyinst everytime. Useful when paired with `CUSTOM_TINYINST_PATH` + + #### License diff --git a/build.rs b/build.rs index 0c4d735..1e891d8 100644 --- a/build.rs +++ b/build.rs @@ -18,13 +18,28 @@ fn build_dep_check(tools: &[&str]) { } } fn main() { - // First we generate .cc and .h files from ffi.rs - if !cfg!(windows) { - println!("cargo:warning=No MacOS support yet."); + if cfg!(linux) { + println!("cargo:warning=Tinyinst doesn't support linux"); exit(0); } - build_dep_check(&["git", "python", "cxxbridge"]); + build_dep_check(&["git", "cxxbridge"]); + + #[cfg(target_os = "windows")] + let cmake_generator = "Visual Studio 17 2022"; + #[cfg(target_os = "macos")] + let cmake_generator = "Xcode"; + + let custom_tinyinst_generator = + env::var_os("CUSTOM_TINYINST_GENERATOR").map(|x| x.to_string_lossy().to_string()); + + env::set_var("CXXFLAGS", "-std=c++17"); + + let tinyinst_generator = if let Some(generator) = custom_tinyinst_generator.as_ref() { + generator + } else { + cmake_generator + }; let custum_tinyinst_dir = env::var_os("CUSTOM_TINYINST_DIR").map(|x| x.to_string_lossy().to_string()); @@ -32,6 +47,7 @@ fn main() { println!("cargo:rerun-if-env-changed=CUSTOM_TINYINST_DIR"); println!("cargo:rerun-if-env-changed=CUSTOM_TINYINST_NO_BUILD"); + println!("cargo:rerun-if-env-changed=CUSTOM_TINYINST_GENERATOR"); let out_dir = env::var_os("OUT_DIR").unwrap(); let out_dir_path = Path::new(&out_dir); @@ -79,7 +95,7 @@ fn main() { let mut submodules = tinyinst_repo.submodules().unwrap(); - // do git submodule --init --recursive on Tinyinst + // do git submodule update --init --recursive on Tinyinst for submodule in &mut submodules { submodule.update(true, None).unwrap(); } @@ -89,7 +105,6 @@ fn main() { } tinyinst_path }; - if !custum_tinyinst_no_build { println!( "cargo:warning=Generating Bridge files. and building for {}", @@ -98,23 +113,36 @@ fn main() { copy_tinyinst_files(&tinyinst_path); let _ = Config::new(&tinyinst_path) - .generator("Visual Studio 17 2022") // make this configurable from env variable + .generator(tinyinst_generator) .build_target("tinyinst") .profile("Release") // without this, it goes into RelWithDbInfo folder?? .out_dir(&tinyinst_path) .build(); } + // For m1 mac(?) println!( - "cargo:rustc-link-search={}\\build\\Release", + "cargo:rustc-link-search={}/build/third_party/Release", + &tinyinst_path.to_string_lossy() + ); + + println!( + "cargo:rustc-link-search={}/build/Release", &tinyinst_path.to_string_lossy() ); println!( - "cargo:rustc-link-search={}\\build\\third_party\\obj\\wkit\\lib", + "cargo:rustc-link-search={}/build/third_party/obj/wkit/lib", &tinyinst_path.to_string_lossy() ); println!("cargo:rustc-link-lib=static=tinyinst"); + + #[cfg(target_arch = "x86_64")] println!("cargo:rustc-link-lib=static=xed"); + + #[cfg(target_arch = "aarch64")] + println!("cargo:rustc-link-lib=static=reil"); + + #[cfg(target_os = "windows")] println!("cargo:rustc-link-lib=dylib=dbghelp"); println!("cargo:rerun-if-changed=src/"); diff --git a/src/tinyinst.rs b/src/tinyinst.rs index fe3c151..3250df4 100644 --- a/src/tinyinst.rs +++ b/src/tinyinst.rs @@ -228,18 +228,33 @@ mod tests { use std::{ fs::File, io::{Seek, Write}, + path::Path, string::ToString, }; + + #[cfg(target_os = "windows")] + const TEST_FILENAME: &str = "test.exe"; + #[cfg(target_os = "macos")] + const TEST_FILENAME: &str = "test"; + + #[cfg(target_os = "macos")] + const TEST_PATH: &str = "test/build/"; + #[cfg(target_os = "windows")] + const TEST_PATH: &str = "test/build/Debug/"; + #[test] fn tinyinst_ok() { - let tinyinst_args = vec!["-instrument_module".to_string(), "test.exe".to_string()]; + let tinyinst_args = vec!["-instrument_module".to_string(), TEST_FILENAME.to_string()]; // Create file to test. - let mut file = File::create(".\\test\\test_file.txt").unwrap(); + let mut file = File::create("./test/test_file.txt").unwrap(); file.write_all(b"test1").unwrap(); let program_args = vec![ - ".\\test\\test.exe".to_string(), - ".\\test\\test_file.txt".to_string(), + Path::new(TEST_PATH) + .join(TEST_FILENAME) + .display() + .to_string(), + "./test/test_file.txt".to_string(), ]; let mut coverage = Vec::new(); @@ -259,29 +274,26 @@ mod tests { tinyinst.vec_coverage(&mut coverage, true); assert_eq!(result, super::litecov::RunResult::OK); - // Check if it contains address to if c == 'b' branch. Sometimes it gets address to memset function. Weird windows crap probably? - assert!(coverage.contains(&4151)); - // Second test case for ba _ = file.seek(std::io::SeekFrom::Start(0)).unwrap(); file.write_all(b"ba").unwrap(); let result = tinyinst.run(); tinyinst.vec_coverage(&mut coverage, true); assert_eq!(result, super::litecov::RunResult::OK); - - // Check if it contains address to if c == 'a' branch. Sometimes it gets address to memset function. - assert!(coverage.contains(&4174)); } } #[test] fn tinyinst_crash() { use alloc::{string::ToString, vec::Vec}; - let tinyinst_args = vec!["-instrument_module".to_string(), "test.exe".to_string()]; + let tinyinst_args = vec!["-instrument_module".to_string(), TEST_FILENAME.to_string()]; let program_args = vec![ - ".\\test\\test.exe".to_string(), - ".\\test\\crash_input.txt".to_string(), + Path::new(TEST_PATH) + .join(TEST_FILENAME) + .display() + .to_string(), + "./test/crash_input.txt".to_string(), ]; let mut coverage = Vec::new(); @@ -290,7 +302,6 @@ mod tests { let result = tinyinst.run(); tinyinst.vec_coverage(&mut coverage, true); assert_eq!(result, super::litecov::RunResult::CRASH); - // assert_eq!(bitmap.iter().filter(|&x| *x == 1).count(), 1307); } } } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..e747c13 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.10) +project("test") + +# Disable implicit function declaration warning on macOS so it can compile vulnerable code +if(APPLE) + set(CMAKE_C_FLAGS "-Wno-error=implicit-function-declaration") +endif() + +add_executable(test test.c) \ No newline at end of file diff --git a/test/test.c b/test/test.c index 2f2911e..c122d19 100644 --- a/test/test.c +++ b/test/test.c @@ -1,27 +1,36 @@ #include -void pass1(char *buf, int buf_size) { +void pass1(char *buf, int buf_size) +{ char target[0x10]; - if (buf[0] == 'b') { - if (buf[1] == 'a') { - if (buf[2] == 'd') { - if (buf[3] == '1') { - if (buf[4] == '2') { - printf("You got me\n"); + if (buf[0] == 'b') + { + if (buf[1] == 'a') + { + if (buf[2] == 'd') + { + if (buf[3] == '1') + { + if (buf[4] == '2') + { + printf("Triggering buffer overflow\n"); memcpy(target, buf, 0x1000000); - printf("GG\n"); + printf("Should never get to this point\n"); } } } } } } -int main(int argc, char *argv[]) { +int main(int argc, char *argv[]) +{ FILE *fp; - char buf[0x1000]; - if (argc == 2) { + char buf[0x1000]; + if (argc == 2) + { fp = fopen(argv[1], "r"); - if (fp == NULL) { + if (fp == NULL) + { printf("File not found\n"); printf("Received filename %s\n", argv[1]); return 1; @@ -29,8 +38,9 @@ int main(int argc, char *argv[]) { fscanf(fp, "%s", buf); pass1(buf, sizeof(buf)); - - } else { - printf("there is nothing\n"); + } + else + { + printf("Program requires input file\n"); } }