diff options
Diffstat (limited to 'plugins/warp/src/plugin/ffi')
| -rw-r--r-- | plugins/warp/src/plugin/ffi/container.rs | 412 | ||||
| -rw-r--r-- | plugins/warp/src/plugin/ffi/function.rs | 228 |
2 files changed, 640 insertions, 0 deletions
diff --git a/plugins/warp/src/plugin/ffi/container.rs b/plugins/warp/src/plugin/ffi/container.rs new file mode 100644 index 00000000..21ad4dc0 --- /dev/null +++ b/plugins/warp/src/plugin/ffi/container.rs @@ -0,0 +1,412 @@ +use crate::cache::container::cached_containers; +use crate::container::SourcePath; +use crate::convert::{from_bn_type, to_bn_type}; +use crate::plugin::ffi::{ + BNWARPContainer, BNWARPFunction, BNWARPFunctionGUID, BNWARPSource, BNWARPTarget, BNWARPTypeGUID, +}; +use binaryninja::architecture::CoreArchitecture; +use binaryninja::binary_view::BinaryView; +use binaryninja::rc::Ref; +use binaryninja::string::BnString; +use binaryninja::types::Type; +use binaryninjacore_sys::{BNArchitecture, BNBinaryView, BNType}; +use std::ffi::{c_char, CStr}; +use std::mem::ManuallyDrop; +use std::sync::Arc; + +#[no_mangle] +pub unsafe extern "C" fn BNWARPGetContainers(count: *mut usize) -> *mut *mut BNWARPContainer { + // NOTE: Leak the arc pointers to be freed by BNWARPFreeContainerList + let boxed_raw_containers: Box<[_]> = + cached_containers().into_iter().map(Arc::into_raw).collect(); + *count = boxed_raw_containers.len(); + let leaked_raw_containers = Box::into_raw(boxed_raw_containers); + leaked_raw_containers as *mut *mut BNWARPContainer +} + +#[no_mangle] +pub unsafe extern "C" fn BNWARPContainerGetName(container: *mut BNWARPContainer) -> *const c_char { + let arc_container = ManuallyDrop::new(Arc::from_raw(container)); + let Ok(container) = arc_container.read() else { + return std::ptr::null(); + }; + let name = container.to_string(); + // NOTE: Leak the container name to be freed by BNFreeString + BnString::into_raw(name.into()) +} + +#[no_mangle] +pub unsafe extern "C" fn BNWARPContainerGetSources( + container: *mut BNWARPContainer, + count: *mut usize, +) -> *mut BNWARPSource { + let arc_container = ManuallyDrop::new(Arc::from_raw(container)); + let Ok(container) = arc_container.write() else { + return std::ptr::null_mut(); + }; + + // NOTE: Leak the sources to be freed by BNWARPFreeSourceList + let boxed_sources: Box<[_]> = container.sources().unwrap_or_default().into_boxed_slice(); + *count = boxed_sources.len(); + Box::into_raw(boxed_sources) as *mut BNWARPSource +} + +#[no_mangle] +pub unsafe extern "C" fn BNWARPContainerAddSource( + container: *mut BNWARPContainer, + source_path: *const c_char, + result: *mut BNWARPSource, +) -> bool { + let arc_container = ManuallyDrop::new(Arc::from_raw(container)); + let Ok(mut container) = arc_container.write() else { + return false; + }; + + let source_path_cstr = unsafe { CStr::from_ptr(source_path) }; + let source_path_str = source_path_cstr.to_str().unwrap(); + let source_path = SourcePath::new_with_str(source_path_str); + + match container.add_source(source_path) { + Ok(source) => { + // NOTE: Leak the source to be freed by BNFreeString + *result = source; + true + } + Err(_) => false, + } +} + +#[no_mangle] +pub unsafe extern "C" fn BNWARPContainerCommitSource( + container: *mut BNWARPContainer, + source: *const BNWARPSource, +) -> bool { + let arc_container = ManuallyDrop::new(Arc::from_raw(container)); + let Ok(mut container) = arc_container.write() else { + return false; + }; + + let source = unsafe { *source }; + + container + .commit_source(&source) + .is_ok_and(|committed| committed) +} + +#[no_mangle] +pub unsafe extern "C" fn BNWARPContainerIsSourceUncommitted( + container: *mut BNWARPContainer, + source: *const BNWARPSource, +) -> bool { + let arc_container = ManuallyDrop::new(Arc::from_raw(container)); + let Ok(container) = arc_container.read() else { + return false; + }; + + let source = unsafe { *source }; + + container + .is_source_uncommitted(&source) + .is_ok_and(|uncommitted| uncommitted) +} + +#[no_mangle] +pub unsafe extern "C" fn BNWARPContainerIsSourceWritable( + container: *mut BNWARPContainer, + source: *const BNWARPSource, +) -> bool { + let arc_container = ManuallyDrop::new(Arc::from_raw(container)); + let Ok(container) = arc_container.read() else { + return false; + }; + + let source = unsafe { *source }; + + container + .is_source_writable(&source) + .is_ok_and(|writable| writable) +} + +#[no_mangle] +pub unsafe extern "C" fn BNWARPContainerGetSourcePath( + container: *mut BNWARPContainer, + source: *const BNWARPSource, +) -> *const c_char { + let arc_container = ManuallyDrop::new(Arc::from_raw(container)); + let Ok(container) = arc_container.read() else { + return std::ptr::null(); + }; + + let source = unsafe { *source }; + + match container.source_path(&source) { + Ok(path) => { + let path = path.to_string(); + // NOTE: Leak the source path to be freed by BNFreeString + BnString::into_raw(path.into()) + } + Err(_) => std::ptr::null(), + } +} + +#[no_mangle] +pub unsafe extern "C" fn BNWARPContainerAddFunctions( + container: *mut BNWARPContainer, + target: *mut BNWARPTarget, + source: *const BNWARPSource, + functions: *mut *mut BNWARPFunction, + count: usize, +) -> bool { + let arc_container = ManuallyDrop::new(Arc::from_raw(container)); + let Ok(mut container) = arc_container.write() else { + return false; + }; + + let target = unsafe { ManuallyDrop::new(Arc::from_raw(target)) }; + + let source = unsafe { *source }; + + let functions_ptr = std::slice::from_raw_parts(functions, count); + // TODO: We have to clone the objects here to make the type checker happy. + // TODO: See about avoiding this later. + let functions: Vec<_> = functions_ptr + .iter() + .map(|&f| unsafe { ManuallyDrop::new(Arc::from_raw(f)).as_ref().clone() }) + .collect(); + container + .add_functions(&target, &source, &functions) + .is_ok() +} + +#[no_mangle] +pub unsafe extern "C" fn BNWARPContainerAddTypes( + view: *mut BNBinaryView, + container: *mut BNWARPContainer, + source: *const BNWARPSource, + types: *mut *mut BNType, + count: usize, +) -> bool { + let view = unsafe { BinaryView::from_raw(view) }; + + let arc_container = ManuallyDrop::new(Arc::from_raw(container)); + let Ok(mut container) = arc_container.write() else { + return false; + }; + + let source = unsafe { *source }; + + let types_ptr = std::slice::from_raw_parts(types, count); + let types: Vec<_> = types_ptr + .iter() + .map(|&t| Type::from_raw(t)) + .map(|ty| from_bn_type(&view, &ty, 255)) + .collect(); + container.add_types(&source, &types).is_ok() +} + +#[no_mangle] +pub unsafe extern "C" fn BNWARPContainerRemoveFunctions( + container: *mut BNWARPContainer, + target: *mut BNWARPTarget, + source: *const BNWARPSource, + functions: *mut *mut BNWARPFunction, + count: usize, +) -> bool { + let arc_container = ManuallyDrop::new(Arc::from_raw(container)); + let Ok(mut container) = arc_container.write() else { + return false; + }; + + let target = unsafe { ManuallyDrop::new(Arc::from_raw(target)) }; + + let source = unsafe { *source }; + + let functions_ptr = std::slice::from_raw_parts(functions, count); + // TODO: We have to clone the objects here to make the type checker happy. + // TODO: See about avoiding this later. + let functions: Vec<_> = functions_ptr + .iter() + .map(|&f| unsafe { ManuallyDrop::new(Arc::from_raw(f)).as_ref().clone() }) + .collect(); + container + .remove_functions(&target, &source, &functions) + .is_ok() +} + +#[no_mangle] +pub unsafe extern "C" fn BNWARPContainerRemoveTypes( + container: *mut BNWARPContainer, + source: *const BNWARPSource, + guids: *mut BNWARPTypeGUID, + count: usize, +) -> bool { + let arc_container = ManuallyDrop::new(Arc::from_raw(container)); + let Ok(mut container) = arc_container.write() else { + return false; + }; + + let source = unsafe { *source }; + + let guids = std::slice::from_raw_parts(guids, count); + container.remove_types(&source, &guids).is_ok() +} + +#[no_mangle] +pub unsafe extern "C" fn BNWARPContainerGetSourcesWithFunctionGUID( + container: *mut BNWARPContainer, + target: *mut BNWARPTarget, + guid: *const BNWARPFunctionGUID, + count: *mut usize, +) -> *mut BNWARPSource { + let arc_container = ManuallyDrop::new(Arc::from_raw(container)); + let Ok(container) = arc_container.read() else { + return std::ptr::null_mut(); + }; + + let target = unsafe { ManuallyDrop::new(Arc::from_raw(target)) }; + + let guid = unsafe { *guid }; + + // NOTE: Leak the sources to be freed by BNWARPFreeSourceList + let boxed_sources: Box<[_]> = container + .sources_with_function_guid(&target, &guid) + .unwrap_or_default() + .into_boxed_slice(); + *count = boxed_sources.len(); + Box::into_raw(boxed_sources) as *mut BNWARPSource +} + +#[no_mangle] +pub unsafe extern "C" fn BNWARPContainerGetSourcesWithTypeGUID( + container: *mut BNWARPContainer, + guid: *const BNWARPTypeGUID, + count: *mut usize, +) -> *mut BNWARPSource { + let arc_container = ManuallyDrop::new(Arc::from_raw(container)); + let Ok(container) = arc_container.read() else { + return std::ptr::null_mut(); + }; + + let guid = unsafe { *guid }; + + // NOTE: Leak the sources to be freed by BNWARPFreeSourceList + let boxed_sources: Box<[_]> = container + .sources_with_type_guid(&guid) + .unwrap_or_default() + .into_boxed_slice(); + *count = boxed_sources.len(); + Box::into_raw(boxed_sources) as *mut BNWARPSource +} + +#[no_mangle] +pub unsafe extern "C" fn BNWARPContainerGetFunctionsWithGUID( + container: *mut BNWARPContainer, + target: *mut BNWARPTarget, + source: *const BNWARPSource, + guid: *const BNWARPFunctionGUID, + count: *mut usize, +) -> *mut *mut BNWARPFunction { + let arc_container = ManuallyDrop::new(Arc::from_raw(container)); + let Ok(container) = arc_container.read() else { + return std::ptr::null_mut(); + }; + + let source = unsafe { *source }; + + let target = unsafe { ManuallyDrop::new(Arc::from_raw(target)) }; + + let guid = unsafe { *guid }; + + // NOTE: Leak the functions to be freed by BNWARPFreeFunctionList + let raw_boxed_functions: Box<[_]> = container + .functions_with_guid(&target, &source, &guid) + .unwrap_or_default() + .into_iter() + .map(Arc::new) + .map(Arc::into_raw) + .collect(); + *count = raw_boxed_functions.len(); + Box::into_raw(raw_boxed_functions) as *mut *mut BNWARPFunction +} + +// TODO: Swap arch to Target? +#[no_mangle] +pub unsafe extern "C" fn BNWARPContainerGetTypeWithGUID( + arch: *mut BNArchitecture, + container: *mut BNWARPContainer, + source: *const BNWARPSource, + guid: *const BNWARPTypeGUID, +) -> *mut BNType { + let arc_container = ManuallyDrop::new(Arc::from_raw(container)); + let Ok(container) = arc_container.read() else { + return std::ptr::null_mut(); + }; + + // NOTE: to convert the type, we must have an architecture. + let arch = CoreArchitecture::from_raw(arch); + + let source = unsafe { *source }; + + let guid = unsafe { *guid }; + + let Some(ty) = container.type_with_guid(&source, &guid).unwrap_or_default() else { + return std::ptr::null_mut(); + }; + let function_type = to_bn_type(&arch, &ty); + // NOTE: The type ref has been pre-incremented for the caller. + unsafe { Ref::into_raw(function_type) }.handle +} + +#[no_mangle] +pub unsafe extern "C" fn BNWARPContainerGetTypeGUIDsWithName( + container: *mut BNWARPContainer, + source: *const BNWARPSource, + name: *const c_char, + count: *mut usize, +) -> *mut BNWARPTypeGUID { + let arc_container = ManuallyDrop::new(Arc::from_raw(container)); + let Ok(container) = arc_container.read() else { + return std::ptr::null_mut(); + }; + + let source = unsafe { *source }; + + let name_cstr = unsafe { CStr::from_ptr(name) }; + let name = name_cstr.to_str().unwrap(); + + // NOTE: Leak the guids to be freed by BNWARPFreeTypeGUIDList + let boxed_guids = container + .type_guids_with_name(&source, name) + .unwrap_or_default() + .into_boxed_slice(); + *count = boxed_guids.len(); + Box::into_raw(boxed_guids) as *mut BNWARPTypeGUID +} + +#[no_mangle] +pub unsafe extern "C" fn BNWARPNewContainerReference( + container: *mut BNWARPContainer, +) -> *mut BNWARPContainer { + Arc::increment_strong_count(container); + container +} + +#[no_mangle] +pub unsafe extern "C" fn BNWARPFreeContainerReference(container: *mut BNWARPContainer) { + if container.is_null() { + return; + } + Arc::decrement_strong_count(container); +} + +#[no_mangle] +pub unsafe extern "C" fn BNWARPFreeContainerList( + containers: *mut *mut BNWARPContainer, + count: usize, +) { + let containers_ptr = std::ptr::slice_from_raw_parts_mut(containers, count); + let containers = unsafe { Box::from_raw(containers_ptr) }; + for container in containers { + BNWARPFreeContainerReference(container); + } +} diff --git a/plugins/warp/src/plugin/ffi/function.rs b/plugins/warp/src/plugin/ffi/function.rs new file mode 100644 index 00000000..3db8f307 --- /dev/null +++ b/plugins/warp/src/plugin/ffi/function.rs @@ -0,0 +1,228 @@ +use crate::build_function; +use crate::cache::{insert_cached_function_match, try_cached_function_match}; +use crate::convert::{to_bn_symbol_at_address, to_bn_type}; +use crate::plugin::ffi::{BNWARPConstraint, BNWARPFunction, BNWARPFunctionGUID}; +use binaryninja::function::Function; +use binaryninja::rc::Ref; +use binaryninja::string::BnString; +use binaryninjacore_sys::{BNFunction, BNSymbol, BNType}; +use std::ffi::c_char; +use std::mem::ManuallyDrop; +use std::sync::Arc; +use warp::signature::comment::FunctionComment; + +#[repr(C)] +pub struct BNWarpFunctionComment { + pub text: *mut c_char, + pub offset: i64, +} + +impl BNWarpFunctionComment { + /// Leaks the text string to be freed with BNWARPFreeFunctionComment + pub fn from_owned(value: &FunctionComment) -> Self { + let text = BnString::into_raw(BnString::new(&value.text)); + Self { + text, + offset: value.offset, + } + } + + pub unsafe fn free_raw(value: &Self) { + unsafe { BnString::free_raw(value.text) } + } +} + +#[no_mangle] +pub unsafe extern "C" fn BNWARPGetFunction( + analysis_function: *mut BNFunction, +) -> *mut BNWARPFunction { + let function = Function::from_raw(analysis_function); + let Ok(lifted_il) = function.lifted_il() else { + return std::ptr::null_mut(); + }; + let function = build_function(&function, &lifted_il); + Arc::into_raw(Arc::new(function)) as *mut BNWARPFunction +} + +#[no_mangle] +pub unsafe extern "C" fn BNWARPGetMatchedFunction( + analysis_function: *mut BNFunction, +) -> *mut BNWARPFunction { + let function = Function::from_raw(analysis_function); + match try_cached_function_match(&function) { + Some(matched_function) => { + let arc_matched_function = Arc::new(matched_function); + // NOTE: Freed by BNWARPFreeFunctionReference + Arc::into_raw(arc_matched_function) as *mut BNWARPFunction + } + None => std::ptr::null_mut(), + } +} + +#[no_mangle] +pub unsafe extern "C" fn BNWARPFunctionApply( + function: *mut BNWARPFunction, + analysis_function: *mut BNFunction, +) { + let analysis_function = Function::from_raw(analysis_function); + match function.is_null() { + false => { + // Set the matched function to `function` and return previous. + let matched_function = ManuallyDrop::new(Arc::from_raw(function)); + insert_cached_function_match( + &analysis_function, + Some(matched_function.as_ref().clone()), + ) + } + true => { + // We are removing the previous match and returning it. + insert_cached_function_match(&analysis_function, None) + } + }; +} + +#[no_mangle] +pub unsafe extern "C" fn BNWARPFunctionGetGUID( + function: *mut BNWARPFunction, +) -> BNWARPFunctionGUID { + // We do not own function so we should not drop. + let function = ManuallyDrop::new(Arc::from_raw(function)); + function.guid +} + +#[no_mangle] +pub unsafe extern "C" fn BNWARPFunctionGetSymbol( + function: *mut BNWARPFunction, + analysis_function: *mut BNFunction, +) -> *mut BNSymbol { + let analysis_function = Function::from_raw(analysis_function); + // We do not own function so we should not drop. + let function = ManuallyDrop::new(Arc::from_raw(function)); + let view = analysis_function.view(); + let address = analysis_function.symbol().address(); + let function_symbol = to_bn_symbol_at_address(&view, &function.symbol, address); + // NOTE: The symbol ref has been pre-incremented for the caller. + Ref::into_raw(function_symbol).handle +} + +#[no_mangle] +pub unsafe extern "C" fn BNWARPFunctionGetSymbolName(function: *mut BNWARPFunction) -> *mut c_char { + // We do not own function so we should not drop. + let function = ManuallyDrop::new(Arc::from_raw(function)); + let bn_name = BnString::new(&function.symbol.name); + // NOTE: The symbol name string to be freed by BNFreeString + BnString::into_raw(bn_name) +} + +#[no_mangle] +pub unsafe extern "C" fn BNWARPFunctionGetType( + function: *mut BNWARPFunction, + analysis_function: *mut BNFunction, +) -> *mut BNType { + let analysis_function = Function::from_raw(analysis_function); + // We do not own function so we should not drop. + let function = ManuallyDrop::new(Arc::from_raw(function)); + match &function.ty { + Some(func_ty) => { + let arch = analysis_function.arch(); + let function_type = to_bn_type(&arch, func_ty); + // NOTE: The type ref has been pre-incremented for the caller. + unsafe { Ref::into_raw(function_type) }.handle + } + None => std::ptr::null_mut(), + } +} + +#[no_mangle] +pub unsafe extern "C" fn BNWARPFunctionGetConstraints( + function: *mut BNWARPFunction, + count: *mut usize, +) -> *mut BNWARPConstraint { + // We do not own function so we should not drop. + let function = ManuallyDrop::new(Arc::from_raw(function)); + let raw_constraints: Box<[BNWARPConstraint]> = function + .constraints + .clone() + .into_iter() + .map(Into::into) + .collect(); + *count = raw_constraints.len(); + let raw_constraints_ptr = Box::into_raw(raw_constraints); + raw_constraints_ptr as *mut BNWARPConstraint +} + +#[no_mangle] +pub unsafe extern "C" fn BNWARPFunctionGetComments( + function: *mut BNWARPFunction, + count: *mut usize, +) -> *mut BNWarpFunctionComment { + // We do not own function so we should not drop. + let function = ManuallyDrop::new(Arc::from_raw(function)); + let raw_comments: Box<[_]> = function + .comments + .iter() + .map(BNWarpFunctionComment::from_owned) + .collect(); + *count = raw_comments.len(); + let raw_comments_ptr = Box::into_raw(raw_comments); + raw_comments_ptr as *mut BNWarpFunctionComment +} + +#[no_mangle] +pub unsafe extern "C" fn BNWARPFunctionsEqual( + function_a: *mut BNWARPFunction, + function_b: *mut BNWARPFunction, +) -> bool { + // We do not own function so we should not drop. + let function_a = ManuallyDrop::new(Arc::from_raw(function_a)); + // We do not own function so we should not drop. + let function_b = ManuallyDrop::new(Arc::from_raw(function_b)); + function_a.eq(&function_b) +} + +#[no_mangle] +pub unsafe extern "C" fn BNWARPNewFunctionReference( + function: *mut BNWARPFunction, +) -> *mut BNWARPFunction { + Arc::increment_strong_count(function); + function +} + +#[no_mangle] +pub unsafe extern "C" fn BNWARPFreeFunctionReference(function: *mut BNWARPFunction) { + if function.is_null() { + return; + } + Arc::decrement_strong_count(function); +} + +#[no_mangle] +pub unsafe extern "C" fn BNWARPFreeFunctionList(functions: *mut *mut BNWARPFunction, count: usize) { + let functions_ptr = std::ptr::slice_from_raw_parts_mut(functions, count); + let functions = Box::from_raw(functions_ptr); + for function in functions { + // NOTE: The functions themselves should also be arc. + BNWARPFreeFunctionReference(function); + } +} + +#[no_mangle] +pub unsafe extern "C" fn BNWARPFreeFunctionCommentList( + comments: *mut BNWarpFunctionComment, + count: usize, +) { + let comments_ptr = std::ptr::slice_from_raw_parts_mut(comments, count); + let comments = Box::from_raw(comments_ptr); + for comment in &comments { + BNWarpFunctionComment::free_raw(comment) + } +} + +#[no_mangle] +pub unsafe extern "C" fn BNWARPFreeConstraintList( + constraints: *mut BNWARPConstraint, + count: usize, +) { + let constraints_ptr = std::ptr::slice_from_raw_parts_mut(constraints, count); + let _constraints = unsafe { Box::from_raw(constraints_ptr) }; +} |
