initial commit

This commit is contained in:
Rairosu
2024-01-24 13:07:27 +01:00
commit 06c785c352
115 changed files with 33162 additions and 0 deletions

389
src/function.rs Normal file
View File

@@ -0,0 +1,389 @@
// Copyright 2021-2024 Vector 35 Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use binaryninjacore_sys::*;
use crate::rc::*;
use crate::string::*;
use crate::types::Variable;
use crate::{
architecture::CoreArchitecture,
basicblock::{BasicBlock, BlockContext},
binaryview::{BinaryView, BinaryViewExt},
llil, mlil,
platform::Platform,
symbol::Symbol,
types::{Conf, NamedTypedVariable, Type},
};
use std::{fmt, mem};
pub struct Location {
pub arch: Option<CoreArchitecture>,
pub addr: u64,
}
impl From<u64> for Location {
fn from(addr: u64) -> Self {
Location { arch: None, addr }
}
}
impl From<(CoreArchitecture, u64)> for Location {
fn from(loc: (CoreArchitecture, u64)) -> Self {
Location {
arch: Some(loc.0),
addr: loc.1,
}
}
}
pub struct NativeBlockIter {
arch: CoreArchitecture,
bv: Ref<BinaryView>,
cur: u64,
end: u64,
}
impl Iterator for NativeBlockIter {
type Item = u64;
fn next(&mut self) -> Option<u64> {
let res = self.cur;
if res >= self.end {
None
} else {
self.bv
.instruction_len(&self.arch, res)
.map(|x| {
self.cur += x as u64;
res
})
.or_else(|| {
self.cur = self.end;
None
})
}
}
}
#[derive(Clone)]
pub struct NativeBlock {
_priv: (),
}
impl NativeBlock {
pub(crate) fn new() -> Self {
NativeBlock { _priv: () }
}
}
impl BlockContext for NativeBlock {
type Iter = NativeBlockIter;
type Instruction = u64;
fn start(&self, block: &BasicBlock<Self>) -> u64 {
block.raw_start()
}
fn iter(&self, block: &BasicBlock<Self>) -> NativeBlockIter {
NativeBlockIter {
arch: block.arch(),
bv: block.function().view(),
cur: block.raw_start(),
end: block.raw_end(),
}
}
}
#[derive(PartialEq, Eq, Hash)]
pub struct Function {
pub(crate) handle: *mut BNFunction,
}
unsafe impl Send for Function {}
unsafe impl Sync for Function {}
impl Function {
pub(crate) unsafe fn from_raw(handle: *mut BNFunction) -> Ref<Self> {
Ref::new(Self { handle })
}
pub fn arch(&self) -> CoreArchitecture {
unsafe {
let arch = BNGetFunctionArchitecture(self.handle);
CoreArchitecture::from_raw(arch)
}
}
pub fn platform(&self) -> Ref<Platform> {
unsafe {
let plat = BNGetFunctionPlatform(self.handle);
Platform::ref_from_raw(plat)
}
}
pub fn view(&self) -> Ref<BinaryView> {
unsafe {
let view = BNGetFunctionData(self.handle);
BinaryView::from_raw(view)
}
}
pub fn symbol(&self) -> Ref<Symbol> {
unsafe {
let sym = BNGetFunctionSymbol(self.handle);
Symbol::ref_from_raw(sym)
}
}
pub fn start(&self) -> u64 {
unsafe { BNGetFunctionStart(self.handle) }
}
pub fn highest_address(&self) -> u64 {
unsafe { BNGetFunctionHighestAddress(self.handle) }
}
pub fn address_ranges(&self) -> Array<AddressRange> {
unsafe {
let mut count = 0;
let addresses = BNGetFunctionAddressRanges(self.handle, &mut count);
Array::new(addresses, count, ())
}
}
pub fn comment(&self) -> BnString {
unsafe { BnString::from_raw(BNGetFunctionComment(self.handle)) }
}
pub fn set_comment<S: BnStrCompatible>(&self, comment: S) {
let raw = comment.into_bytes_with_nul();
unsafe {
BNSetFunctionComment(self.handle, raw.as_ref().as_ptr() as *mut _);
}
}
pub fn comment_at(&self, addr: u64) -> BnString {
unsafe { BnString::from_raw(BNGetCommentForAddress(self.handle, addr)) }
}
pub fn set_comment_at<S: BnStrCompatible>(&self, addr: u64, comment: S) {
let raw = comment.into_bytes_with_nul();
unsafe {
BNSetCommentForAddress(self.handle, addr, raw.as_ref().as_ptr() as *mut _);
}
}
pub fn basic_blocks(&self) -> Array<BasicBlock<NativeBlock>> {
unsafe {
let mut count = 0;
let blocks = BNGetFunctionBasicBlockList(self.handle, &mut count);
let context = NativeBlock { _priv: () };
Array::new(blocks, count, context)
}
}
pub fn basic_block_containing(
&self,
arch: &CoreArchitecture,
addr: u64,
) -> Option<Ref<BasicBlock<NativeBlock>>> {
unsafe {
let block = BNGetFunctionBasicBlockAtAddress(self.handle, arch.0, addr);
let context = NativeBlock { _priv: () };
if block.is_null() {
return None;
}
Some(Ref::new(BasicBlock::from_raw(block, context)))
}
}
pub fn get_variable_name(&self, var: &Variable) -> BnString {
unsafe {
let raw_var = var.raw();
let raw_name = BNGetVariableName(self.handle, &raw_var);
BnString::from_raw(raw_name)
}
}
pub fn medium_level_il(&self) -> Result<Ref<mlil::MediumLevelILFunction>, ()> {
unsafe {
let mlil = BNGetFunctionMediumLevelIL(self.handle);
if mlil.is_null() {
return Err(());
}
Ok(Ref::new(mlil::MediumLevelILFunction::from_raw(mlil)))
}
}
pub fn low_level_il(&self) -> Result<Ref<llil::RegularFunction<CoreArchitecture>>, ()> {
unsafe {
let llil = BNGetFunctionLowLevelIL(self.handle);
if llil.is_null() {
return Err(());
}
Ok(Ref::new(llil::RegularFunction::from_raw(self.arch(), llil)))
}
}
pub fn lifted_il(&self) -> Result<Ref<llil::LiftedFunction<CoreArchitecture>>, ()> {
unsafe {
let llil = BNGetFunctionLiftedIL(self.handle);
if llil.is_null() {
return Err(());
}
Ok(Ref::new(llil::LiftedFunction::from_raw(self.arch(), llil)))
}
}
pub fn return_type(&self) -> Conf<Ref<Type>> {
let result = unsafe { BNGetFunctionReturnType(self.handle) };
Conf::new(
unsafe { Type::ref_from_raw(result.type_) },
result.confidence,
)
}
pub fn function_type(&self) -> Ref<Type> {
unsafe { Type::ref_from_raw(BNGetFunctionType(self.handle)) }
}
pub fn set_user_type(&self, t: Type) {
unsafe {
BNSetFunctionUserType(self.handle, t.handle);
}
}
pub fn stack_layout(&self) -> Array<NamedTypedVariable> {
let mut count = 0;
unsafe {
let variables = BNGetStackLayout(self.handle, &mut count);
Array::new(variables, count, ())
}
}
pub fn apply_imported_types(&self, sym: &Symbol, t: Option<&Type>) {
unsafe {
BNApplyImportedTypes(
self.handle,
sym.handle,
if let Some(t) = t {
t.handle
} else {
core::ptr::null_mut()
},
);
}
}
}
impl fmt::Debug for Function {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"<func '{}' ({}) {:x}>",
self.symbol().full_name(),
self.platform().name(),
self.start()
)
}
}
impl ToOwned for Function {
type Owned = Ref<Self>;
fn to_owned(&self) -> Self::Owned {
unsafe { RefCountable::inc_ref(self) }
}
}
unsafe impl RefCountable for Function {
unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
Ref::new(Self {
handle: BNNewFunctionReference(handle.handle),
})
}
unsafe fn dec_ref(handle: &Self) {
BNFreeFunction(handle.handle);
}
}
impl CoreArrayProvider for Function {
type Raw = *mut BNFunction;
type Context = ();
}
unsafe impl CoreOwnedArrayProvider for Function {
unsafe fn free(raw: *mut *mut BNFunction, count: usize, _context: &()) {
BNFreeFunctionList(raw, count);
}
}
unsafe impl<'a> CoreArrayWrapper<'a> for Function {
type Wrapped = Guard<'a, Function>;
unsafe fn wrap_raw(raw: &'a *mut BNFunction, context: &'a ()) -> Guard<'a, Function> {
Guard::new(Function { handle: *raw }, context)
}
}
/////////////////
// AddressRange
#[repr(transparent)]
pub struct AddressRange(pub(crate) BNAddressRange);
impl AddressRange {
pub fn start(&self) -> u64 {
self.0.start
}
pub fn end(&self) -> u64 {
self.0.end
}
}
impl CoreArrayProvider for AddressRange {
type Raw = BNAddressRange;
type Context = ();
}
unsafe impl CoreOwnedArrayProvider for AddressRange {
unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
BNFreeAddressRanges(raw);
}
}
unsafe impl<'a> CoreArrayWrapper<'a> for AddressRange {
type Wrapped = &'a AddressRange;
unsafe fn wrap_raw(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped {
mem::transmute(raw)
}
}