summaryrefslogtreecommitdiff
path: root/plugins/workflow_objc/src/activities/alloc_init.rs
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/workflow_objc/src/activities/alloc_init.rs')
-rw-r--r--plugins/workflow_objc/src/activities/alloc_init.rs73
1 files changed, 73 insertions, 0 deletions
diff --git a/plugins/workflow_objc/src/activities/alloc_init.rs b/plugins/workflow_objc/src/activities/alloc_init.rs
new file mode 100644
index 00000000..5c8bf064
--- /dev/null
+++ b/plugins/workflow_objc/src/activities/alloc_init.rs
@@ -0,0 +1,73 @@
+use binaryninja::{
+ binary_view::{BinaryView, BinaryViewExt as _},
+ medium_level_il::MediumLevelILLiftedInstruction,
+ rc::Ref,
+ types::Type,
+ workflow::AnalysisContext,
+};
+use bstr::ByteSlice;
+
+use super::util;
+use crate::{error::ILLevel, metadata::GlobalState, workflow::Confidence, Error};
+
+// j_ prefixes are for stub functions in the dyld shared cache.
+// The prefix is added by Binary Ninja's shared cache workflow.
+const ALLOC_INIT_FUNCTIONS: &[&[u8]] = &[
+ b"_objc_alloc_init",
+ b"_objc_alloc_initWithZone",
+ b"_objc_alloc",
+ b"_objc_allocWithZone",
+ b"_objc_opt_new",
+ b"j__objc_alloc_init",
+ b"j__objc_alloc_initWithZone",
+ b"j__objc_alloc",
+ b"j__objc_allocWithZone",
+ b"j__objc_opt_new",
+];
+
+fn return_type_for_alloc_call(call: &util::Call<'_>, view: &BinaryView) -> Option<Ref<Type>> {
+ if call.call.params.is_empty() {
+ return None;
+ }
+
+ let class_addr =
+ util::match_constant_pointer_or_load_of_constant_pointer(&call.call.params[0])?;
+ let class_symbol_name = view.symbol_by_address(class_addr)?.full_name();
+ let class_name = util::class_name_from_symbol_name(class_symbol_name.to_bytes().as_bstr())?;
+
+ let class_type = view.type_by_name(class_name.to_str_lossy())?;
+ Some(Type::pointer(&call.target.arch(), &class_type))
+}
+
+fn process_instruction(instr: &MediumLevelILLiftedInstruction, view: &BinaryView) -> Option<()> {
+ let call = util::match_call_to_function_named(instr, view, ALLOC_INIT_FUNCTIONS)?;
+
+ util::adjust_return_type_of_call(
+ &call,
+ return_type_for_alloc_call(&call, view)?.as_ref(),
+ Confidence::AllocInit as u8,
+ );
+
+ Some(())
+}
+
+pub fn process(ac: &AnalysisContext) -> Result<(), Error> {
+ let bv = ac.view();
+ if GlobalState::should_ignore_view(&bv) {
+ return Ok(());
+ }
+
+ let mlil = ac.mlil_function().ok_or(Error::MissingIL {
+ level: ILLevel::Medium,
+ func_start: ac.function().start(),
+ })?;
+ let mlil_ssa = mlil.ssa_form();
+
+ for block in &mlil_ssa.basic_blocks() {
+ for instr in block.iter() {
+ process_instruction(&instr.lift(), &bv);
+ }
+ }
+
+ Ok(())
+}