Skip to content

Commit

Permalink
Add testing example for AbstractType derive macro
Browse files Browse the repository at this point in the history
  • Loading branch information
mkrasnitski committed Jun 11, 2024
1 parent d98f561 commit d1205c9
Show file tree
Hide file tree
Showing 5 changed files with 380 additions and 0 deletions.
7 changes: 7 additions & 0 deletions rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
7 changes: 7 additions & 0 deletions rust/examples/abstract-type/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "abstract-type"
version = "0.1.0"
edition = "2021"

[dependencies]
binaryninja = { path="../../", features = ["derive"] }
68 changes: 68 additions & 0 deletions rust/examples/abstract-type/build.rs
Original file line number Diff line number Diff line change
@@ -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());
}
}
297 changes: 297 additions & 0 deletions rust/examples/abstract-type/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,297 @@
use binaryninja::rc::Ref;
use binaryninja::types::{AbstractType, EnumerationBuilder, StructureBuilder, StructureType, Type};

fn create_struct<F>(f: F) -> Ref<Type>
where
F: FnOnce(&StructureBuilder) -> &StructureBuilder,
{
Type::structure(&f(&StructureBuilder::new()).finalize())
}

fn create_enum<F>(width: usize, signed: bool, f: F) -> Ref<Type>
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();
}

0 comments on commit d1205c9

Please sign in to comment.