diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 9da1cd0e0..e28155d28 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -2,6 +2,13 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "abstract-type" +version = "0.1.0" +dependencies = [ + "binaryninja", +] + [[package]] name = "adler" version = "1.0.2" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 681c85a94..e8c350ef2 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -24,6 +24,7 @@ pdb = { path = "./examples/pdb-ng/pdb-0.8.0-patched" } [workspace] members = [ + "examples/abstract-type", "examples/basic_script", "examples/decompile", "examples/dwarf/dwarf_export", diff --git a/rust/examples/abstract-type/Cargo.toml b/rust/examples/abstract-type/Cargo.toml new file mode 100644 index 000000000..bab72cea3 --- /dev/null +++ b/rust/examples/abstract-type/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "abstract-type" +version = "0.1.0" +edition = "2021" + +[dependencies] +binaryninja = { path="../../", features = ["derive"] } diff --git a/rust/examples/abstract-type/build.rs b/rust/examples/abstract-type/build.rs new file mode 100644 index 000000000..5ba9bcde4 --- /dev/null +++ b/rust/examples/abstract-type/build.rs @@ -0,0 +1,68 @@ +use std::env; +use std::fs::File; +use std::io::BufReader; +use std::path::PathBuf; + +#[cfg(target_os = "macos")] +static LASTRUN_PATH: (&str, &str) = ("HOME", "Library/Application Support/Binary Ninja/lastrun"); + +#[cfg(target_os = "linux")] +static LASTRUN_PATH: (&str, &str) = ("HOME", ".binaryninja/lastrun"); + +#[cfg(windows)] +static LASTRUN_PATH: (&str, &str) = ("APPDATA", "Binary Ninja\\lastrun"); + +// Check last run location for path to BinaryNinja; Otherwise check the default install locations +fn link_path() -> PathBuf { + use std::io::prelude::*; + + let home = PathBuf::from(env::var(LASTRUN_PATH.0).unwrap()); + let lastrun = PathBuf::from(&home).join(LASTRUN_PATH.1); + + File::open(lastrun) + .and_then(|f| { + let mut binja_path = String::new(); + let mut reader = BufReader::new(f); + + reader.read_line(&mut binja_path)?; + Ok(PathBuf::from(binja_path.trim())) + }) + .unwrap_or_else(|_| { + #[cfg(target_os = "macos")] + return PathBuf::from("/Applications/Binary Ninja.app/Contents/MacOS"); + + #[cfg(target_os = "linux")] + return home.join("binaryninja"); + + #[cfg(windows)] + return PathBuf::from(env::var("PROGRAMFILES").unwrap()) + .join("Vector35\\BinaryNinja\\"); + }) +} + +fn main() { + // Use BINARYNINJADIR first for custom BN builds/configurations (BN devs/build server), fallback on defaults + let install_path = env::var("BINARYNINJADIR") + .map(PathBuf::from) + .unwrap_or_else(|_| link_path()); + + #[cfg(target_os = "linux")] + println!( + "cargo:rustc-link-arg=-Wl,-rpath,{},-L{},-l:libbinaryninjacore.so.1", + install_path.to_str().unwrap(), + install_path.to_str().unwrap(), + ); + + #[cfg(target_os = "macos")] + println!( + "cargo:rustc-link-arg=-Wl,-rpath,{},-L{},-lbinaryninjacore", + install_path.to_str().unwrap(), + install_path.to_str().unwrap(), + ); + + #[cfg(target_os = "windows")] + { + println!("cargo:rustc-link-lib=binaryninjacore"); + println!("cargo:rustc-link-search={}", install_path.to_str().unwrap()); + } +} diff --git a/rust/examples/abstract-type/src/main.rs b/rust/examples/abstract-type/src/main.rs new file mode 100644 index 000000000..e8df03159 --- /dev/null +++ b/rust/examples/abstract-type/src/main.rs @@ -0,0 +1,297 @@ +use binaryninja::rc::Ref; +use binaryninja::types::{AbstractType, EnumerationBuilder, StructureBuilder, StructureType, Type}; + +fn create_struct(f: F) -> Ref +where + F: FnOnce(&StructureBuilder) -> &StructureBuilder, +{ + Type::structure(&f(&StructureBuilder::new()).finalize()) +} + +fn create_enum(width: usize, signed: bool, f: F) -> Ref +where + F: FnOnce(&EnumerationBuilder) -> &EnumerationBuilder, +{ + Type::enumeration(&f(&EnumerationBuilder::new()).finalize(), width, signed) +} + +fn primitive() { + assert_eq!(u8::resolve_type(), Type::int(1, false)); + assert_eq!(u16::resolve_type(), Type::int(2, false)); + assert_eq!(u32::resolve_type(), Type::int(4, false)); + assert_eq!(u64::resolve_type(), Type::int(8, false)); + assert_eq!(u128::resolve_type(), Type::int(16, false)); + + assert_eq!(i8::resolve_type(), Type::int(1, true)); + assert_eq!(i16::resolve_type(), Type::int(2, true)); + assert_eq!(i32::resolve_type(), Type::int(4, true)); + assert_eq!(i64::resolve_type(), Type::int(8, true)); + assert_eq!(i128::resolve_type(), Type::int(16, true)); + + assert_eq!(f32::resolve_type(), Type::float(4)); + assert_eq!(f64::resolve_type(), Type::float(8)); +} + +fn basic_struct() { + #[derive(AbstractType)] + #[repr(C)] + struct A { + first: u8, + second: u32, + third: u16, + } + + assert_eq!( + A::resolve_type(), + create_struct(|s| { + s.with_members([ + (&Type::int(1, false), "first"), + (&Type::int(4, false), "second"), + (&Type::int(2, false), "third"), + ]) + }) + ); +} + +fn packed_struct() { + #[derive(AbstractType)] + #[repr(C, packed)] + struct A { + first: u8, + second: u32, + third: u16, + } + + assert_eq!( + A::resolve_type(), + create_struct(|s| { + s.set_packed(true).with_members([ + (&Type::int(1, false), "first"), + (&Type::int(4, false), "second"), + (&Type::int(2, false), "third"), + ]) + }) + ); +} + +fn custom_alignment() { + #[derive(AbstractType)] + #[repr(C, align(16))] + struct A { + first: u8, + second: u32, + third: u16, + } + + assert_eq!( + A::resolve_type(), + create_struct(|s| { + s.set_alignment(16).with_members([ + (&Type::int(1, false), "first"), + (&Type::int(4, false), "second"), + (&Type::int(2, false), "third"), + ]) + }) + ); +} + +fn named_field() { + #[derive(AbstractType)] + #[repr(C)] + struct A { + first: u8, + #[binja(named)] + second: B, + } + + #[derive(AbstractType)] + #[repr(C)] + struct B { + third: u16, + } + + assert_eq!( + A::resolve_type(), + create_struct(|s| { + s.with_members([ + (&Type::int(1, false), "first"), + ( + &Type::named_type_from_type("B", &B::resolve_type()), + "second", + ), + ]) + }) + ); + assert_eq!( + B::resolve_type(), + create_struct(|s| { s.with_members([(&Type::int(2, false), "third")]) }) + ); +} + +fn pointer_field() { + #[derive(AbstractType)] + #[repr(C)] + #[binja(pointer_width = 4)] + struct A { + first: u8, + second: *const u32, + } + + assert_eq!( + A::resolve_type(), + create_struct(|s| { + s.with_members([ + (&Type::int(1, false), "first"), + ( + &Type::pointer_of_width(&Type::int(4, false), 4, false, false, None), + "second", + ), + ]) + }) + ); +} + +fn nested_pointer_field() { + #[derive(AbstractType)] + #[repr(C)] + struct A { + first: u8, + #[binja(named)] + second: B, + } + + #[derive(AbstractType)] + #[repr(C)] + #[binja(pointer_width = 4)] + struct B { + third: u32, + fourth: *const u16, + } + + assert_eq!( + A::resolve_type(), + create_struct(|s| { + s.with_members([ + (&Type::int(1, false), "first"), + ( + &Type::named_type_from_type("B", &B::resolve_type()), + "second", + ), + ]) + }) + ); + assert_eq!( + B::resolve_type(), + create_struct(|s| { + s.with_members([ + (&Type::int(4, false), "third"), + ( + &Type::pointer_of_width(&Type::int(2, false), 4, false, false, None), + "fourth", + ), + ]) + }) + ); +} + +fn named_pointer_field() { + #[derive(AbstractType)] + #[repr(C)] + #[binja(pointer_width = 4)] + struct A { + first: u8, + #[binja(named)] + second: *const B, + } + + #[derive(AbstractType)] + #[repr(C)] + struct B { + third: u32, + fourth: u16, + } + + assert_eq!( + A::resolve_type(), + create_struct(|s| { + s.with_members([ + (&Type::int(1, false), "first"), + ( + &Type::pointer_of_width( + &Type::named_type_from_type("B", &B::resolve_type()), + 4, + false, + false, + None, + ), + "second", + ), + ]) + }) + ); + assert_eq!( + B::resolve_type(), + create_struct(|s| { + s.with_members([ + (&Type::int(4, false), "third"), + (&Type::int(2, false), "fourth"), + ]) + }) + ) +} + +fn union() { + #[derive(AbstractType)] + #[repr(C)] + union A { + first: u32, + second: [u16; 2], + third: [u8; 4], + } + + assert_eq!( + A::resolve_type(), + create_struct(|s| { + s.set_structure_type(StructureType::UnionStructureType) + .with_members([ + (&Type::int(4, false), "first"), + (&Type::array(&Type::int(2, false), 2), "second"), + (&Type::array(&Type::int(1, false), 4), "third"), + ]) + }) + ); +} + +fn enumeration() { + #[derive(AbstractType)] + #[repr(u32)] + #[allow(dead_code)] + enum Color { + Red = 0xff0000, + Green = 0x00ff00, + Blue = 0x0000ff, + } + + assert_eq!( + Color::resolve_type(), + create_enum(4, false, |e| { + e.insert("Red", 0xff0000) + .insert("Green", 0x00ff00) + .insert("Blue", 0x0000ff) + }) + ); +} + +fn main() { + let _ = binaryninja::headless::Session::new(); + primitive(); + basic_struct(); + packed_struct(); + custom_alignment(); + named_field(); + pointer_field(); + nested_pointer_field(); + named_pointer_field(); + union(); + enumeration(); +}