From e7e34b0889ecd9655f5d2863006d608f6e9ef53b Mon Sep 17 00:00:00 2001 From: Mark Date: Thu, 23 May 2024 09:30:15 +0100 Subject: [PATCH 001/146] Target newer z3, fmt, clippy --- Cargo.lock | 120 ++++++++++++++++++++++++--- jingle/Cargo.toml | 2 +- jingle/src/modeling/branch.rs | 6 +- jingle/src/modeling/mod.rs | 15 ++-- jingle/src/modeling/state/mod.rs | 35 ++++---- jingle_sleigh/src/context/mod.rs | 2 +- jingle_sleigh/src/ffi/context_ffi.rs | 6 +- 7 files changed, 138 insertions(+), 48 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7aa8321..4ee9a9b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,18 +17,24 @@ dependencies = [ "memchr", ] +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + [[package]] name = "bindgen" -version = "0.66.1" +version = "0.69.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2b84e06fc203107bfbad243f4aba2af864eb7db3b1cf46ea0a023b0b433d2a7" +checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" dependencies = [ "bitflags", "cexpr", "clang-sys", + "itertools", "lazy_static", "lazycell", - "peeking_take_while", "proc-macro2", "quote", "regex", @@ -155,6 +161,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "either" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" + [[package]] name = "elf" version = "0.7.4" @@ -177,6 +189,15 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "jingle" version = "0.1.1" @@ -276,6 +297,79 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + [[package]] name = "object" version = "0.35.0" @@ -293,18 +387,18 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" -[[package]] -name = "peeking_take_while" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" - [[package]] name = "pin-project-lite" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + [[package]] name = "proc-macro2" version = "1.0.83" @@ -614,18 +708,18 @@ checksum = "791978798f0597cfc70478424c2b4fdc2b7a8024aaff78497ef00f24ef674193" [[package]] name = "z3" version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a7ff5718c079e7b813378d67a5bed32ccc2086f151d6185074a7e24f4a565e8" +source = "git+https://github.com/prove-rs/z3.rs.git?rev=1971033#19710337ae280c06bc4da912c6745291e3078109" dependencies = [ "log", + "num", "z3-sys", ] [[package]] name = "z3-sys" version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7cf70fdbc0de3f42b404f49b0d4686a82562254ea29ff0a155eef2f5430f4b0" +source = "git+https://github.com/prove-rs/z3.rs.git?rev=1971033#19710337ae280c06bc4da912c6745291e3078109" dependencies = [ "bindgen", + "pkg-config", ] diff --git a/jingle/Cargo.toml b/jingle/Cargo.toml index 751fc0c..eabe88b 100644 --- a/jingle/Cargo.toml +++ b/jingle/Cargo.toml @@ -16,7 +16,7 @@ keywords = ["ghidra", "sleigh", "pcode", "smt"] [dependencies] jingle_sleigh = { path = "../jingle_sleigh", version = "0.1.1" } -z3 = { version = "0.12.1" } +z3 = { git = "https://github.com/prove-rs/z3.rs.git", rev = "1971033" } thiserror = "1.0.58" serde = { version = "1.0.197", features = ["derive"] } tracing = "0.1.40" diff --git a/jingle/src/modeling/branch.rs b/jingle/src/modeling/branch.rs index 2b95381..5501bef 100644 --- a/jingle/src/modeling/branch.rs +++ b/jingle/src/modeling/branch.rs @@ -33,9 +33,7 @@ impl BlockEndBehavior { UnconditionalBranch(b) => { match b { // Direct branch - GeneralizedVarNode::Direct(d) => { - ctx.get_final_state().read_varnode_metadata(&d) - } + GeneralizedVarNode::Direct(d) => ctx.get_final_state().read_varnode_metadata(d), // Indirect branch, we want to only inspect the pointer GeneralizedVarNode::Indirect(i) => ctx .get_final_state() @@ -84,7 +82,7 @@ impl BranchConstraint { pub fn has_branch(&self) -> bool { match self.last { - Fallthrough(_) => self.conditional_branches.len() != 0, + Fallthrough(_) => self.conditional_branches.is_empty(), UnconditionalBranch(_) => true, } } diff --git a/jingle/src/modeling/mod.rs b/jingle/src/modeling/mod.rs index f1e119e..549f358 100644 --- a/jingle/src/modeling/mod.rs +++ b/jingle/src/modeling/mod.rs @@ -659,14 +659,15 @@ pub(crate) trait TranslationContext<'ctx>: ModelingContext<'ctx> { let output_size = output.size as u32; let size = min(input_size, output_size); let input = bv0.extract((input_low_byte + size) * 8 - 1, input_low_byte * 8); - if size < output_size { - self.write(&output.into(), input.zero_ext((output_size - size) * 8))?; - } else if output_size < size { - self.write(&output.into(), input.extract(output_size * 8 - 1, 0))?; - } else { - self.write(&output.into(), input)?; + match size.cmp(&output_size) { + Ordering::Less => { + self.write(&output.into(), input.zero_ext((output_size - size) * 8)) + } + Ordering::Greater => { + self.write(&output.into(), input.extract(output_size * 8 - 1, 0)) + } + Ordering::Equal => self.write(&output.into(), input), } - Ok(()) } PcodeOperation::CallOther { inputs, output } => { let mut hasher = DefaultHasher::new(); diff --git a/jingle/src/modeling/state/mod.rs b/jingle/src/modeling/state/mod.rs index 303f385..b20df07 100644 --- a/jingle/src/modeling/state/mod.rs +++ b/jingle/src/modeling/state/mod.rs @@ -180,26 +180,23 @@ impl<'ctx> State<'ctx> { if dest.size != val.get_size() as usize { return Err(Mismatched); } - match self.space_info[dest.space_index]._type { - // We are allowing writes to the constant space for metadata - // to allow flagging userop values for syscalls - _ => { - let space = self - .spaces - .get_mut(dest.space_index) - .ok_or(UnmodeledSpace)?; - space.write_metadata( - &val, - &BV::from_u64( - self.z3, - dest.offset, - self.space_info[dest.space_index].index_size_bytes * 8, - ), - ); - Ok(()) - } - } + // We are allowing writes to the constant space for metadata + // to allow flagging userop values for syscalls + let space = self + .spaces + .get_mut(dest.space_index) + .ok_or(UnmodeledSpace)?; + space.write_metadata( + &val, + &BV::from_u64( + self.z3, + dest.offset, + self.space_info[dest.space_index].index_size_bytes * 8, + ), + ); + Ok(()) } + /// Model a write to an [IndirectVarNode] on top of the current context. pub fn write_varnode_indirect<'a>( &'a mut self, diff --git a/jingle_sleigh/src/context/mod.rs b/jingle_sleigh/src/context/mod.rs index faf5416..41ed01a 100644 --- a/jingle_sleigh/src/context/mod.rs +++ b/jingle_sleigh/src/context/mod.rs @@ -50,7 +50,7 @@ impl SpaceManager for SleighContext { impl RegisterManager for SleighContext { fn get_register(&self, name: &str) -> Option { - self.ctx.getRegister(name).map(|f| VarNode::from(f)).ok() + self.ctx.getRegister(name).map(VarNode::from).ok() } fn get_register_name(&self, location: VarNode) -> Option<&str> { diff --git a/jingle_sleigh/src/ffi/context_ffi.rs b/jingle_sleigh/src/ffi/context_ffi.rs index e324527..4bb7210 100644 --- a/jingle_sleigh/src/ffi/context_ffi.rs +++ b/jingle_sleigh/src/ffi/context_ffi.rs @@ -3,9 +3,9 @@ use bridge::ContextFFI; use cxx::{Exception, UniquePtr}; use std::sync::Mutex; -pub(crate) static CTX_BUILD_MUTEX: Mutex< - fn(&str, bridge::Image) -> Result, Exception>, -> = Mutex::new(makeContext); +type ContextGeneratorFp = fn(&str, bridge::Image) -> Result, Exception>; + +pub(crate) static CTX_BUILD_MUTEX: Mutex = Mutex::new(makeContext); #[cxx::bridge] pub(crate) mod bridge { From bb497babb1230210653de8a26048aa4022ef7c19 Mon Sep 17 00:00:00 2001 From: Mark Date: Thu, 23 May 2024 09:33:32 +0100 Subject: [PATCH 002/146] Remove reference --- jingle/src/modeling/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jingle/src/modeling/mod.rs b/jingle/src/modeling/mod.rs index 549f358..39d0ae4 100644 --- a/jingle/src/modeling/mod.rs +++ b/jingle/src/modeling/mod.rs @@ -182,8 +182,8 @@ pub trait ModelingContext<'ctx>: SpaceManager + Debug + Sized { Ok(Some(Bool::and( self.get_z3(), &[ - &self_bv._eq(&other_bv).simplify(), - &self_bv_metadata._eq(&other_bv_metadata).simplify(), + self_bv._eq(&other_bv).simplify(), + self_bv_metadata._eq(&other_bv_metadata).simplify(), ], ))) } From 7b4272389e0215c1cfc43054ca35e9589e6be7b8 Mon Sep 17 00:00:00 2001 From: Mark Date: Thu, 23 May 2024 13:50:34 +0100 Subject: [PATCH 003/146] Add catch for sleigh size mismatch --- jingle/src/error.rs | 6 ++++-- jingle/src/modeling/state/mod.rs | 15 +++++++-------- jingle/src/modeling/state/space.rs | 27 +++++++++++++++++++++------ 3 files changed, 32 insertions(+), 16 deletions(-) diff --git a/jingle/src/error.rs b/jingle/src/error.rs index bac1e7e..56f41d2 100644 --- a/jingle/src/error.rs +++ b/jingle/src/error.rs @@ -21,8 +21,10 @@ pub enum JingleError { ConstantWrite, #[error("Attempt to read an indirect value from the constant space. While this can be modeled, it's almost definitely unintended.")] IndirectConstantRead, - #[error("Attempted to perform a write of a bitvector to a VarNode with leftover space. Sleigh guarantees this will be done with an explicit extension operation.")] - Mismatched, + #[error("Attempted to perform a write of a bitvector to a VarNode with leftover space. This is a sleigh bug.")] + MismatchedWordSize, + #[error("Attempted to perform a write to a space using the wrong size of address. This is a sleigh bug.")] + MismatchedAddressSize, #[error("Jingle does not yet model this instruction")] UnmodeledInstruction(Box), } diff --git a/jingle/src/modeling/state/mod.rs b/jingle/src/modeling/state/mod.rs index b20df07..4511221 100644 --- a/jingle/src/modeling/state/mod.rs +++ b/jingle/src/modeling/state/mod.rs @@ -2,7 +2,7 @@ mod space; use crate::error::JingleError; use crate::error::JingleError::{ - ConstantWrite, IndirectConstantRead, Mismatched, UnexpectedArraySort, UnmodeledSpace, + ConstantWrite, IndirectConstantRead, MismatchedWordSize, UnexpectedArraySort, UnmodeledSpace, ZeroSizedVarnode, }; @@ -149,8 +149,7 @@ impl<'ctx> State<'ctx> { val: BV<'b>, ) -> Result<(), JingleError> { if dest.size as u32 * 8 != val.get_size() { - dbg!(dest.size, val.get_size()); - return Err(Mismatched); + return Err(MismatchedWordSize); } match self.space_info[dest.space_index]._type { SpaceType::IPTR_CONSTANT => Err(ConstantWrite), @@ -166,7 +165,7 @@ impl<'ctx> State<'ctx> { dest.offset, self.space_info[dest.space_index].index_size_bytes * 8, ), - ); + )?; Ok(()) } } @@ -178,7 +177,7 @@ impl<'ctx> State<'ctx> { val: BV<'b>, ) -> Result<(), JingleError> { if dest.size != val.get_size() as usize { - return Err(Mismatched); + return Err(MismatchedWordSize); } // We are allowing writes to the constant space for metadata // to allow flagging userop values for syscalls @@ -193,7 +192,7 @@ impl<'ctx> State<'ctx> { dest.offset, self.space_info[dest.space_index].index_size_bytes * 8, ), - ); + )?; Ok(()) } @@ -207,7 +206,7 @@ impl<'ctx> State<'ctx> { return Err(ConstantWrite); } let ptr = self.read_varnode(&dest.pointer_location)?; - self.spaces[dest.pointer_space_index].write_data(&val, &ptr); + self.spaces[dest.pointer_space_index].write_data(&val, &ptr)?; Ok(()) } @@ -220,7 +219,7 @@ impl<'ctx> State<'ctx> { return Err(ConstantWrite); } let ptr = self.read_varnode(&dest.pointer_location)?; - self.spaces[dest.pointer_space_index].write_metadata(&val, &ptr); + self.spaces[dest.pointer_space_index].write_metadata(&val, &ptr)?; Ok(()) } diff --git a/jingle/src/modeling/state/space.rs b/jingle/src/modeling/state/space.rs index 13d43df..33ec8d4 100644 --- a/jingle/src/modeling/state/space.rs +++ b/jingle/src/modeling/state/space.rs @@ -1,5 +1,5 @@ use crate::JingleError; -use crate::JingleError::{UnexpectedArraySort, ZeroSizedVarnode}; +use crate::JingleError::{MismatchedAddressSize, UnexpectedArraySort, ZeroSizedVarnode}; use jingle_sleigh::{SleighEndianness, SpaceInfo}; use std::ops::Add; use z3::ast::{Array, BV}; @@ -18,6 +18,7 @@ pub(crate) struct ModeledSpace<'ctx> { data: Array<'ctx>, #[allow(unused)] metadata: Array<'ctx>, + space_info: SpaceInfo } impl<'ctx> ModeledSpace<'ctx> { @@ -28,7 +29,7 @@ impl<'ctx> ModeledSpace<'ctx> { Self { endianness: space_info.endianness, data: Array::fresh_const(z3, &space_info.name, &domain, &range), - metadata: Array::const_array(z3, &domain, &BV::from_u64(z3, 0, 1)), + metadata: Array::const_array(z3, &domain, &BV::from_u64(z3, 0, 1)), space_info: space_info.clone() } } @@ -43,6 +44,9 @@ impl<'ctx> ModeledSpace<'ctx> { offset: &BV<'ctx>, size_bytes: usize, ) -> Result, JingleError> { + if offset.get_size() != self.space_info.index_size_bytes * 8{ + return Err(MismatchedAddressSize) + } read_from_array(&self.data, offset, size_bytes, self.endianness) } @@ -53,17 +57,28 @@ impl<'ctx> ModeledSpace<'ctx> { offset: &BV<'ctx>, size_bytes: usize, ) -> Result, JingleError> { + if offset.get_size() != self.space_info.index_size_bytes * 8{ + return Err(MismatchedAddressSize) + } read_from_array(&self.metadata, offset, size_bytes, self.endianness) } /// Write the given bitvector of data to the given bitvector offset - pub(crate) fn write_data(&mut self, val: &BV<'ctx>, offset: &BV<'ctx>) { - self.data = write_to_array::<8>(&self.data, val, offset, self.endianness) + pub(crate) fn write_data(&mut self, val: &BV<'ctx>, offset: &BV<'ctx>) -> Result<(), JingleError> { + if offset.get_size() != self.space_info.index_size_bytes * 8{ + return Err(MismatchedAddressSize) + } + self.data = write_to_array::<8>(&self.data, val, offset, self.endianness); + Ok(()) } /// Write the given bitvector of metadata to the given bitvector offset - pub(crate) fn write_metadata(&mut self, val: &BV<'ctx>, offset: &BV<'ctx>) { - self.metadata = write_to_array::<1>(&self.metadata, val, offset, self.endianness) + pub(crate) fn write_metadata(&mut self, val: &BV<'ctx>, offset: &BV<'ctx>) -> Result<(), JingleError> { + if offset.get_size() != self.space_info.index_size_bytes * 8{ + return Err(MismatchedAddressSize) + } + self.metadata = write_to_array::<1>(&self.metadata, val, offset, self.endianness); + Ok(()) } } From f8f9b3e276d127e0218c2239f7ed55d0c3fe600e Mon Sep 17 00:00:00 2001 From: Mark Date: Sun, 26 May 2024 14:33:08 +0100 Subject: [PATCH 004/146] Fix condition --- jingle/src/modeling/branch.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jingle/src/modeling/branch.rs b/jingle/src/modeling/branch.rs index 5501bef..ddcae87 100644 --- a/jingle/src/modeling/branch.rs +++ b/jingle/src/modeling/branch.rs @@ -82,7 +82,7 @@ impl BranchConstraint { pub fn has_branch(&self) -> bool { match self.last { - Fallthrough(_) => self.conditional_branches.is_empty(), + Fallthrough(_) => !self.conditional_branches.is_empty(), UnconditionalBranch(_) => true, } } From cf92431234a5993a266cb22a16bccfe670327948 Mon Sep 17 00:00:00 2001 From: Mark Date: Sun, 26 May 2024 14:33:27 +0100 Subject: [PATCH 005/146] fmt --- jingle/src/modeling/state/space.rs | 33 +++++++++++++++++++----------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/jingle/src/modeling/state/space.rs b/jingle/src/modeling/state/space.rs index 33ec8d4..387e791 100644 --- a/jingle/src/modeling/state/space.rs +++ b/jingle/src/modeling/state/space.rs @@ -18,7 +18,7 @@ pub(crate) struct ModeledSpace<'ctx> { data: Array<'ctx>, #[allow(unused)] metadata: Array<'ctx>, - space_info: SpaceInfo + space_info: SpaceInfo, } impl<'ctx> ModeledSpace<'ctx> { @@ -29,7 +29,8 @@ impl<'ctx> ModeledSpace<'ctx> { Self { endianness: space_info.endianness, data: Array::fresh_const(z3, &space_info.name, &domain, &range), - metadata: Array::const_array(z3, &domain, &BV::from_u64(z3, 0, 1)), space_info: space_info.clone() + metadata: Array::const_array(z3, &domain, &BV::from_u64(z3, 0, 1)), + space_info: space_info.clone(), } } @@ -44,8 +45,8 @@ impl<'ctx> ModeledSpace<'ctx> { offset: &BV<'ctx>, size_bytes: usize, ) -> Result, JingleError> { - if offset.get_size() != self.space_info.index_size_bytes * 8{ - return Err(MismatchedAddressSize) + if offset.get_size() != self.space_info.index_size_bytes * 8 { + return Err(MismatchedAddressSize); } read_from_array(&self.data, offset, size_bytes, self.endianness) } @@ -57,25 +58,33 @@ impl<'ctx> ModeledSpace<'ctx> { offset: &BV<'ctx>, size_bytes: usize, ) -> Result, JingleError> { - if offset.get_size() != self.space_info.index_size_bytes * 8{ - return Err(MismatchedAddressSize) + if offset.get_size() != self.space_info.index_size_bytes * 8 { + return Err(MismatchedAddressSize); } read_from_array(&self.metadata, offset, size_bytes, self.endianness) } /// Write the given bitvector of data to the given bitvector offset - pub(crate) fn write_data(&mut self, val: &BV<'ctx>, offset: &BV<'ctx>) -> Result<(), JingleError> { - if offset.get_size() != self.space_info.index_size_bytes * 8{ - return Err(MismatchedAddressSize) + pub(crate) fn write_data( + &mut self, + val: &BV<'ctx>, + offset: &BV<'ctx>, + ) -> Result<(), JingleError> { + if offset.get_size() != self.space_info.index_size_bytes * 8 { + return Err(MismatchedAddressSize); } self.data = write_to_array::<8>(&self.data, val, offset, self.endianness); Ok(()) } /// Write the given bitvector of metadata to the given bitvector offset - pub(crate) fn write_metadata(&mut self, val: &BV<'ctx>, offset: &BV<'ctx>) -> Result<(), JingleError> { - if offset.get_size() != self.space_info.index_size_bytes * 8{ - return Err(MismatchedAddressSize) + pub(crate) fn write_metadata( + &mut self, + val: &BV<'ctx>, + offset: &BV<'ctx>, + ) -> Result<(), JingleError> { + if offset.get_size() != self.space_info.index_size_bytes * 8 { + return Err(MismatchedAddressSize); } self.metadata = write_to_array::<1>(&self.metadata, val, offset, self.endianness); Ok(()) From 0b17240556424d000b2f6868e4613e9d1e1bc989 Mon Sep 17 00:00:00 2001 From: Mark Date: Thu, 30 May 2024 15:40:18 +0100 Subject: [PATCH 006/146] Initial context work --- jingle/src/context.rs | 25 +++++++++++++++++++++++++ jingle/src/lib.rs | 1 + 2 files changed, 26 insertions(+) create mode 100644 jingle/src/context.rs diff --git a/jingle/src/context.rs b/jingle/src/context.rs new file mode 100644 index 0000000..bfe979b --- /dev/null +++ b/jingle/src/context.rs @@ -0,0 +1,25 @@ +use z3::Context; +use jingle_sleigh::SpaceInfo; +use crate::modeling::State; + +struct SleighModelInfo { + spaces: Vec, + default_code_space_index: usize +} +pub(crate) struct JingleContext<'ctx>{ + z3: &'ctx Context, + sleigh_model_info: SleighModelInfo +} + + +impl JingleContext { + pub fn fresh_state(&self) -> State{ + State::new(self.z3, &self) + } +} + +impl From<&JingleContext> for &Context{ + fn from(value: &JingleContext) -> Self { + value.z3 + } +} \ No newline at end of file diff --git a/jingle/src/lib.rs b/jingle/src/lib.rs index 9b6982f..d629eb6 100644 --- a/jingle/src/lib.rs +++ b/jingle/src/lib.rs @@ -2,6 +2,7 @@ mod error; pub mod modeling; mod translator; pub mod varnode; +mod context; pub use jingle_sleigh as sleigh; From 15a42bc7644169a545b051a5f092a15e29e0913b Mon Sep 17 00:00:00 2001 From: Mark Date: Thu, 30 May 2024 18:33:44 +0100 Subject: [PATCH 007/146] Add context; will slowly move stuff over to using this instead --- jingle/src/context.rs | 70 +++++++++++++++++++++++++----- jingle/src/lib.rs | 1 + jingle/src/modeling/state/space.rs | 6 +-- 3 files changed, 62 insertions(+), 15 deletions(-) diff --git a/jingle/src/context.rs b/jingle/src/context.rs index bfe979b..dd8d917 100644 --- a/jingle/src/context.rs +++ b/jingle/src/context.rs @@ -1,25 +1,71 @@ +use std::collections::HashMap; use z3::Context; -use jingle_sleigh::SpaceInfo; +use jingle_sleigh::{RegisterManager, SpaceInfo, SpaceManager, VarNode}; use crate::modeling::State; -struct SleighModelInfo { +pub struct JingleContext<'ctx> { + z3: &'ctx Context, spaces: Vec, - default_code_space_index: usize + default_code_space_index: usize, + varnode_name_mapping: HashMap, + name_varnode_mapping: HashMap, } -pub(crate) struct JingleContext<'ctx>{ - z3: &'ctx Context, - sleigh_model_info: SleighModelInfo + + +impl<'ctx> JingleContext<'ctx> { + pub fn new(z3: &'ctx Context, r: &R) -> Self { + let regs = r.get_registers(); + let mut varnode_name_mapping = HashMap::new(); + let mut name_varnode_mapping = HashMap::new(); + for (vn, s) in regs { + varnode_name_mapping.insert(vn.clone(), s.clone()); + name_varnode_mapping.insert(s, vn); + } + let spaces = r.get_all_space_info().to_vec(); + let default_code_space_index = r.get_code_space_idx(); + Self { + z3, + varnode_name_mapping, + name_varnode_mapping, + spaces, + default_code_space_index, + } + } + pub fn fresh_state(&self) -> State<'ctx> { + State::new(self.z3, self) + } +} + +impl<'ctx> SpaceManager for JingleContext<'ctx> { + fn get_space_info(&self, idx: usize) -> Option<&SpaceInfo> { + self.spaces.get(idx) + } + + fn get_all_space_info(&self) -> &[SpaceInfo] { + self.spaces.as_slice() + } + + fn get_code_space_idx(&self) -> usize { + self.default_code_space_index + } } +impl<'ctx> RegisterManager for JingleContext<'ctx> { + fn get_register(&self, name: &str) -> Option { + self.name_varnode_mapping.get(name).cloned() + } + + fn get_register_name(&self, location: VarNode) -> Option<&str> { + self.varnode_name_mapping.get(&location).map(|f| f.as_str()) + } -impl JingleContext { - pub fn fresh_state(&self) -> State{ - State::new(self.z3, &self) + fn get_registers(&self) -> Vec<(VarNode, String)> { + self.varnode_name_mapping.clone().into_iter().collect() } } -impl From<&JingleContext> for &Context{ - fn from(value: &JingleContext) -> Self { - value.z3 +impl<'ctx> AsRef for JingleContext<'ctx> { + fn as_ref(&self) -> &Context { + self.z3 } } \ No newline at end of file diff --git a/jingle/src/lib.rs b/jingle/src/lib.rs index d629eb6..2080f9c 100644 --- a/jingle/src/lib.rs +++ b/jingle/src/lib.rs @@ -8,3 +8,4 @@ pub use jingle_sleigh as sleigh; pub use error::JingleError; pub use translator::SleighTranslator; +pub use context::JingleContext; \ No newline at end of file diff --git a/jingle/src/modeling/state/space.rs b/jingle/src/modeling/state/space.rs index 387e791..42914ec 100644 --- a/jingle/src/modeling/state/space.rs +++ b/jingle/src/modeling/state/space.rs @@ -155,7 +155,7 @@ mod tests { space.write_data( &BV::from_u64(&z3, 0xdead_beef, 32), &BV::from_u64(&z3, 0, 32), - ); + ).unwrap(); let expected = match e { SleighEndianness::Big => [0xde, 0xad, 0xbe, 0xef], SleighEndianness::Little => [0xef, 0xbe, 0xad, 0xde], @@ -181,7 +181,7 @@ mod tests { space.write_data( &BV::from_u64(&z3, byte_layout[i as usize], 8), &BV::from_u64(&z3, i, 32), - ); + ).unwrap(); } let val = space .read_data(&BV::from_u64(&z3, 0, 32), 4) @@ -194,7 +194,7 @@ mod tests { fn test_single_write(e: SleighEndianness) { let z3 = Context::new(&Config::new()); let mut space = make_space(&z3, e); - space.write_data(&BV::from_u64(&z3, 0x42, 8), &BV::from_u64(&z3, 0, 32)); + space.write_data(&BV::from_u64(&z3, 0x42, 8), &BV::from_u64(&z3, 0, 32)).unwrap(); let expected = 0x42; let data = space .read_data(&BV::from_u64(&z3, 0, 32), 1) From b44a40b2496d6d09ba8511a6f20c3b111c1e40f1 Mon Sep 17 00:00:00 2001 From: Mark Date: Thu, 30 May 2024 18:35:04 +0100 Subject: [PATCH 008/146] Add derives --- jingle/src/context.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/jingle/src/context.rs b/jingle/src/context.rs index dd8d917..bc483ee 100644 --- a/jingle/src/context.rs +++ b/jingle/src/context.rs @@ -3,6 +3,7 @@ use z3::Context; use jingle_sleigh::{RegisterManager, SpaceInfo, SpaceManager, VarNode}; use crate::modeling::State; +#[derive(Clone, Debug)] pub struct JingleContext<'ctx> { z3: &'ctx Context, spaces: Vec, From 0fbde20bfa4fc98b68986c70afb99fd997c4a7f8 Mon Sep 17 00:00:00 2001 From: Mark Date: Thu, 30 May 2024 18:57:43 +0100 Subject: [PATCH 009/146] Pub z3 --- jingle/src/context.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/jingle/src/context.rs b/jingle/src/context.rs index bc483ee..f906872 100644 --- a/jingle/src/context.rs +++ b/jingle/src/context.rs @@ -5,7 +5,7 @@ use crate::modeling::State; #[derive(Clone, Debug)] pub struct JingleContext<'ctx> { - z3: &'ctx Context, + pub z3: &'ctx Context, spaces: Vec, default_code_space_index: usize, varnode_name_mapping: HashMap, @@ -64,9 +64,3 @@ impl<'ctx> RegisterManager for JingleContext<'ctx> { self.varnode_name_mapping.clone().into_iter().collect() } } - -impl<'ctx> AsRef for JingleContext<'ctx> { - fn as_ref(&self) -> &Context { - self.z3 - } -} \ No newline at end of file From 38e40518c03ead4d4df4b0297d564d075557e903 Mon Sep 17 00:00:00 2001 From: Mark Date: Thu, 30 May 2024 19:55:35 +0100 Subject: [PATCH 010/146] cargo fmt --- jingle/src/context.rs | 5 ++--- jingle/src/lib.rs | 4 ++-- jingle/src/modeling/state/space.rs | 28 +++++++++++++++++----------- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/jingle/src/context.rs b/jingle/src/context.rs index f906872..c6aa500 100644 --- a/jingle/src/context.rs +++ b/jingle/src/context.rs @@ -1,7 +1,7 @@ +use crate::modeling::State; +use jingle_sleigh::{RegisterManager, SpaceInfo, SpaceManager, VarNode}; use std::collections::HashMap; use z3::Context; -use jingle_sleigh::{RegisterManager, SpaceInfo, SpaceManager, VarNode}; -use crate::modeling::State; #[derive(Clone, Debug)] pub struct JingleContext<'ctx> { @@ -12,7 +12,6 @@ pub struct JingleContext<'ctx> { name_varnode_mapping: HashMap, } - impl<'ctx> JingleContext<'ctx> { pub fn new(z3: &'ctx Context, r: &R) -> Self { let regs = r.get_registers(); diff --git a/jingle/src/lib.rs b/jingle/src/lib.rs index 2080f9c..3deec73 100644 --- a/jingle/src/lib.rs +++ b/jingle/src/lib.rs @@ -1,11 +1,11 @@ +mod context; mod error; pub mod modeling; mod translator; pub mod varnode; -mod context; pub use jingle_sleigh as sleigh; +pub use context::JingleContext; pub use error::JingleError; pub use translator::SleighTranslator; -pub use context::JingleContext; \ No newline at end of file diff --git a/jingle/src/modeling/state/space.rs b/jingle/src/modeling/state/space.rs index 42914ec..2116055 100644 --- a/jingle/src/modeling/state/space.rs +++ b/jingle/src/modeling/state/space.rs @@ -10,8 +10,8 @@ use z3::{Context, Sort}; /// /// `jingle` also maintains a separate Array holding "metadata" for the space. For right now, this /// metadata has a single-bit bitvector as its word type, and it is only used for tracking whether -/// a given value originated from a CALLOTHER operation. This is necessary for distinguishing between -/// normal indirect jumps and some syscalls +/// a given value originated from a CALLOTHER operation. This is necessary for distinguishing +/// between normal indirect jumps and some syscalls #[derive(Clone, Debug)] pub(crate) struct ModeledSpace<'ctx> { endianness: SleighEndianness, @@ -152,10 +152,12 @@ mod tests { fn test_endian_write(e: SleighEndianness) { let z3 = Context::new(&Config::new()); let mut space = make_space(&z3, e); - space.write_data( - &BV::from_u64(&z3, 0xdead_beef, 32), - &BV::from_u64(&z3, 0, 32), - ).unwrap(); + space + .write_data( + &BV::from_u64(&z3, 0xdead_beef, 32), + &BV::from_u64(&z3, 0, 32), + ) + .unwrap(); let expected = match e { SleighEndianness::Big => [0xde, 0xad, 0xbe, 0xef], SleighEndianness::Little => [0xef, 0xbe, 0xad, 0xde], @@ -178,10 +180,12 @@ mod tests { SleighEndianness::Little => [0xef, 0xbe, 0xad, 0xde], }; for i in 0..4 { - space.write_data( - &BV::from_u64(&z3, byte_layout[i as usize], 8), - &BV::from_u64(&z3, i, 32), - ).unwrap(); + space + .write_data( + &BV::from_u64(&z3, byte_layout[i as usize], 8), + &BV::from_u64(&z3, i, 32), + ) + .unwrap(); } let val = space .read_data(&BV::from_u64(&z3, 0, 32), 4) @@ -194,7 +198,9 @@ mod tests { fn test_single_write(e: SleighEndianness) { let z3 = Context::new(&Config::new()); let mut space = make_space(&z3, e); - space.write_data(&BV::from_u64(&z3, 0x42, 8), &BV::from_u64(&z3, 0, 32)).unwrap(); + space + .write_data(&BV::from_u64(&z3, 0x42, 8), &BV::from_u64(&z3, 0, 32)) + .unwrap(); let expected = 0x42; let data = space .read_data(&BV::from_u64(&z3, 0, 32), 1) From 1fe4b8344177f058372c000877342431c717ef85 Mon Sep 17 00:00:00 2001 From: Mark Date: Thu, 30 May 2024 20:14:34 +0100 Subject: [PATCH 011/146] Ditch cargo lock --- Cargo.lock | 725 --------------------------------------- jingle_sleigh/Cargo.toml | 10 +- 2 files changed, 5 insertions(+), 730 deletions(-) delete mode 100644 Cargo.lock diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index 4ee9a9b..0000000 --- a/Cargo.lock +++ /dev/null @@ -1,725 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "autocfg" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" - -[[package]] -name = "bindgen" -version = "0.69.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" -dependencies = [ - "bitflags", - "cexpr", - "clang-sys", - "itertools", - "lazy_static", - "lazycell", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn 2.0.65", -] - -[[package]] -name = "bitflags" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "cc" -version = "1.0.98" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" - -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "clang-sys" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" -dependencies = [ - "glob", - "libc", - "libloading", -] - -[[package]] -name = "codespan-reporting" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" -dependencies = [ - "termcolor", - "unicode-width", -] - -[[package]] -name = "crc32fast" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "cxx" -version = "1.0.122" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb497fad022245b29c2a0351df572e2d67c1046bcef2260ebc022aec81efea82" -dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", -] - -[[package]] -name = "cxx-build" -version = "1.0.122" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9327c7f9fbd6329a200a5d4aa6f674c60ab256525ff0084b52a889d4e4c60cee" -dependencies = [ - "cc", - "codespan-reporting", - "once_cell", - "proc-macro2", - "quote", - "scratch", - "syn 2.0.65", -] - -[[package]] -name = "cxxbridge-flags" -version = "1.0.122" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688c799a4a846f1c0acb9f36bb9c6272d9b3d9457f3633c7753c6057270df13c" - -[[package]] -name = "cxxbridge-macro" -version = "1.0.122" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928bc249a7e3cd554fd2e8e08a426e9670c50bbfc9a621653cfa9accc9641783" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.65", -] - -[[package]] -name = "derive_more" -version = "0.99.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "either" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" - -[[package]] -name = "elf" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4445909572dbd556c457c849c4ca58623d84b27c8fff1e74b0b4227d8b90d17b" - -[[package]] -name = "flate2" -version = "1.0.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - -[[package]] -name = "jingle" -version = "0.1.1" -dependencies = [ - "jingle_sleigh", - "serde", - "thiserror", - "tracing", - "z3", -] - -[[package]] -name = "jingle_sleigh" -version = "0.1.1" -dependencies = [ - "cxx", - "cxx-build", - "elf", - "object", - "serde", - "serde-xml-rs", - "thiserror", - "tracing", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - -[[package]] -name = "libc" -version = "0.2.155" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" - -[[package]] -name = "libloading" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" -dependencies = [ - "cfg-if", - "windows-targets", -] - -[[package]] -name = "link-cplusplus" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d240c6f7e1ba3a28b0249f774e6a9dd0175054b52dfbb61b16eb8505c3785c9" -dependencies = [ - "cc", -] - -[[package]] -name = "log" -version = "0.4.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" - -[[package]] -name = "memchr" -version = "2.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "miniz_oxide" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" -dependencies = [ - "adler", -] - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "num" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" -dependencies = [ - "num-bigint", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] - -[[package]] -name = "num-bigint" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "num-complex" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" -dependencies = [ - "num-bigint", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "object" -version = "0.35.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8ec7ab813848ba4522158d5517a6093db1ded27575b070f4177b8d12b41db5e" -dependencies = [ - "flate2", - "memchr", - "ruzstd", -] - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "pin-project-lite" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" - -[[package]] -name = "pkg-config" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" - -[[package]] -name = "proc-macro2" -version = "1.0.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "regex" -version = "1.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "ruzstd" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5174a470eeb535a721ae9fdd6e291c2411a906b96592182d05217591d5c5cf7b" -dependencies = [ - "byteorder", - "derive_more", - "twox-hash", -] - -[[package]] -name = "scratch" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3cf7c11c38cb994f3d40e8a8cde3bbd1f72a435e4c49e85d6553d8312306152" - -[[package]] -name = "serde" -version = "1.0.202" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde-xml-rs" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb3aa78ecda1ebc9ec9847d5d3aba7d618823446a049ba2491940506da6e2782" -dependencies = [ - "log", - "serde", - "thiserror", - "xml-rs", -] - -[[package]] -name = "serde_derive" -version = "1.0.202" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.65", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.65" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2863d96a84c6439701d7a38f9de935ec562c8832cc55d1dde0f513b52fad106" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "termcolor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "thiserror" -version = "1.0.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.65", -] - -[[package]] -name = "tracing" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" -dependencies = [ - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.65", -] - -[[package]] -name = "tracing-core" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" -dependencies = [ - "once_cell", -] - -[[package]] -name = "twox-hash" -version = "1.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" -dependencies = [ - "cfg-if", - "static_assertions", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-width" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" - -[[package]] -name = "winapi-util" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" - -[[package]] -name = "xml-rs" -version = "0.8.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791978798f0597cfc70478424c2b4fdc2b7a8024aaff78497ef00f24ef674193" - -[[package]] -name = "z3" -version = "0.12.1" -source = "git+https://github.com/prove-rs/z3.rs.git?rev=1971033#19710337ae280c06bc4da912c6745291e3078109" -dependencies = [ - "log", - "num", - "z3-sys", -] - -[[package]] -name = "z3-sys" -version = "0.8.1" -source = "git+https://github.com/prove-rs/z3.rs.git?rev=1971033#19710337ae280c06bc4da912c6745291e3078109" -dependencies = [ - "bindgen", - "pkg-config", -] diff --git a/jingle_sleigh/Cargo.toml b/jingle_sleigh/Cargo.toml index 1500e81..ac68616 100644 --- a/jingle_sleigh/Cargo.toml +++ b/jingle_sleigh/Cargo.toml @@ -20,16 +20,16 @@ include = [ # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -cxx = "1.0.120" -serde = { version = "1.0.197", features = ["derive"] } +cxx = "1.0.122" +serde = { version = "1.0.203", features = ["derive"] } serde-xml-rs = "0.6.0" -thiserror = { version = "1.0.58", features = [] } +thiserror = { version = "1.0.61", features = [] } elf = { version = "0.7.4", optional = true } -object = { version = "0.35.0", optional = true } +object = { version = "0.36.0", optional = true } tracing = "0.1.40" [build-dependencies] -cxx-build = "1.0.120" +cxx-build = "1.0.122" [features] compile = [] From 721cacd28677b0085059abaeca7fd2201433bdca Mon Sep 17 00:00:00 2001 From: Mark Date: Thu, 30 May 2024 23:51:33 +0100 Subject: [PATCH 012/146] Update ci --- .github/workflows/check.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 6fadea7..2997fb3 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -10,4 +10,4 @@ jobs: - uses: actions-rs/toolchain@v1 with: toolchain: stable - - run: cargo check --all-features + - run: cargo build --all-features From fdc8b445419200d5470d03389ec72946cccd1682 Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 31 May 2024 10:17:22 +0100 Subject: [PATCH 013/146] Remove registers from context for now until link issues are fixed --- jingle/src/context.rs | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/jingle/src/context.rs b/jingle/src/context.rs index c6aa500..c384bdc 100644 --- a/jingle/src/context.rs +++ b/jingle/src/context.rs @@ -8,25 +8,14 @@ pub struct JingleContext<'ctx> { pub z3: &'ctx Context, spaces: Vec, default_code_space_index: usize, - varnode_name_mapping: HashMap, - name_varnode_mapping: HashMap, } impl<'ctx> JingleContext<'ctx> { pub fn new(z3: &'ctx Context, r: &R) -> Self { - let regs = r.get_registers(); - let mut varnode_name_mapping = HashMap::new(); - let mut name_varnode_mapping = HashMap::new(); - for (vn, s) in regs { - varnode_name_mapping.insert(vn.clone(), s.clone()); - name_varnode_mapping.insert(s, vn); - } let spaces = r.get_all_space_info().to_vec(); let default_code_space_index = r.get_code_space_idx(); Self { z3, - varnode_name_mapping, - name_varnode_mapping, spaces, default_code_space_index, } @@ -49,17 +38,3 @@ impl<'ctx> SpaceManager for JingleContext<'ctx> { self.default_code_space_index } } - -impl<'ctx> RegisterManager for JingleContext<'ctx> { - fn get_register(&self, name: &str) -> Option { - self.name_varnode_mapping.get(name).cloned() - } - - fn get_register_name(&self, location: VarNode) -> Option<&str> { - self.varnode_name_mapping.get(&location).map(|f| f.as_str()) - } - - fn get_registers(&self) -> Vec<(VarNode, String)> { - self.varnode_name_mapping.clone().into_iter().collect() - } -} From 1e143fb21ee6c6b9e5a3cd38c8c23ef2fb2951c2 Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 31 May 2024 10:22:44 +0100 Subject: [PATCH 014/146] Relax context requirement --- jingle/src/context.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/jingle/src/context.rs b/jingle/src/context.rs index c384bdc..f04aabf 100644 --- a/jingle/src/context.rs +++ b/jingle/src/context.rs @@ -1,6 +1,5 @@ use crate::modeling::State; -use jingle_sleigh::{RegisterManager, SpaceInfo, SpaceManager, VarNode}; -use std::collections::HashMap; +use jingle_sleigh::{ SpaceInfo, SpaceManager}; use z3::Context; #[derive(Clone, Debug)] @@ -11,7 +10,7 @@ pub struct JingleContext<'ctx> { } impl<'ctx> JingleContext<'ctx> { - pub fn new(z3: &'ctx Context, r: &R) -> Self { + pub fn new(z3: &'ctx Context, r: &S) -> Self { let spaces = r.get_all_space_info().to_vec(); let default_code_space_index = r.get_code_space_idx(); Self { From 3b4c06a6196dc32ed9dd5d160712468047352883 Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 31 May 2024 10:46:31 +0100 Subject: [PATCH 015/146] Add state equality helper --- jingle/src/context.rs | 2 +- jingle/src/modeling/mod.rs | 29 ++++++++--------------------- jingle/src/modeling/state/mod.rs | 18 +++++++++++++++++- 3 files changed, 26 insertions(+), 23 deletions(-) diff --git a/jingle/src/context.rs b/jingle/src/context.rs index f04aabf..b983b3f 100644 --- a/jingle/src/context.rs +++ b/jingle/src/context.rs @@ -1,5 +1,5 @@ use crate::modeling::State; -use jingle_sleigh::{ SpaceInfo, SpaceManager}; +use jingle_sleigh::{SpaceInfo, SpaceManager}; use z3::Context; #[derive(Clone, Debug)] diff --git a/jingle/src/modeling/mod.rs b/jingle/src/modeling/mod.rs index 39d0ae4..24076c0 100644 --- a/jingle/src/modeling/mod.rs +++ b/jingle/src/modeling/mod.rs @@ -52,9 +52,9 @@ pub trait ModelingContext<'ctx>: SpaceManager + Debug + Sized { /// from the [State] returned by [get_final_state], as it is guaranteed to have a handle to /// all intermediate spaces that may be referenced fn get_inputs(&self) -> HashSet>; - /// Get a hashset of the addresses written by this trace. The values returned in this hashset are - /// fully modeled: a read from a given varnode will evaluate to its value at the stage in the - /// computation that the read was performed. Because of this, these should always be read + /// Get a hashset of the addresses written by this trace. The values returned in this hashset + /// are fully modeled: a read from a given varnode will evaluate to its value at the stage in + /// the computation that the read was performed. Because of this, these should always be read /// from the [State] returned by [get_final_state], as it is guaranteed to have a handle to /// all intermediate spaces that may be referenced fn get_outputs(&self) -> HashSet>; @@ -144,24 +144,11 @@ pub trait ModelingContext<'ctx>: SpaceManager + Debug + Sized { &self, other: &T, ) -> Result, JingleError> { - let mut terms = vec![]; - for (i, _) in self - .get_final_state() - .get_all_space_info() - .iter() - .enumerate() - .filter(|(_, n)| n._type == SpaceType::IPTR_PROCESSOR) - { - let other = other.get_original_state().get_space(i)?; - let space = self.get_final_state().get_space(i)?; - terms.push(space._eq(other).simplify()) - } - let eq_terms: Vec<&Bool> = terms.iter().collect(); - Ok(Bool::and(self.get_z3(), eq_terms.as_slice())) + self.get_final_state()._eq(other.get_original_state()) } - /// Returns an assertion that [other]'s end-branch behavior is able to branch to the same destination - /// as [self], given that [self] has branching behavior + /// Returns an assertion that [other]'s end-branch behavior is able to branch to the same + /// destination as [self], given that [self] has branching behavior /// todo: should swap self and other to make this align better with [upholds_postcondition] fn branch_comparison>( &self, @@ -199,8 +186,8 @@ pub trait ModelingContext<'ctx>: SpaceManager + Debug + Sized { /// This trait is used for types that build modeling contexts. This could maybe be a single /// struct instead of a trait. -/// The helper methods in here allow for parsing pcode operations into z3 formulae, and automatically -/// tracking the inputs/outputs of each operation and traces composed thereof +/// The helper methods in here allow for parsing pcode operations into z3 formulae, and +/// automatically tracking the inputs/outputs of each operation and traces composed thereof pub(crate) trait TranslationContext<'ctx>: ModelingContext<'ctx> { /// Adds a [GeneralizedVarNode] to the "input care set" for this operation. /// This is usually used for asserting equality of all input varnodes when diff --git a/jingle/src/modeling/state/mod.rs b/jingle/src/modeling/state/mod.rs index 4511221..8d8b325 100644 --- a/jingle/src/modeling/state/mod.rs +++ b/jingle/src/modeling/state/mod.rs @@ -12,7 +12,7 @@ use jingle_sleigh::{ GeneralizedVarNode, IndirectVarNode, SpaceInfo, SpaceManager, SpaceType, VarNode, }; use std::ops::Add; -use z3::ast::{Array, Ast, BV}; +use z3::ast::{Array, Ast, Bool, BV}; use z3::Context; /// Represents the modeled combined memory state of the system. State @@ -263,4 +263,20 @@ impl<'ctx> State<'ctx> { .map(|b| b.simplify()) .unwrap() } + + pub fn _eq(&self, other: &State<'ctx>) -> Result, JingleError> { + let mut terms = vec![]; + for (i, _) in self + .get_all_space_info() + .iter() + .enumerate() + .filter(|(_, n)| n._type == SpaceType::IPTR_PROCESSOR) + { + let self_space = self.get_space(i)?; + let other_space = other.get_space(i)?; + terms.push(self_space._eq(other_space)) + } + let eq_terms: Vec<&Bool> = terms.iter().collect(); + Ok(Bool::and(self.z3, eq_terms.as_slice())) + } } From 3e46d9d007d521ab4c42c7dfbe02bc3cdf233a75 Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 25 Jun 2024 20:21:55 +0100 Subject: [PATCH 016/146] Bump z3 --- jingle/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jingle/Cargo.toml b/jingle/Cargo.toml index eabe88b..30daef2 100644 --- a/jingle/Cargo.toml +++ b/jingle/Cargo.toml @@ -16,7 +16,7 @@ keywords = ["ghidra", "sleigh", "pcode", "smt"] [dependencies] jingle_sleigh = { path = "../jingle_sleigh", version = "0.1.1" } -z3 = { git = "https://github.com/prove-rs/z3.rs.git", rev = "1971033" } +z3 = { git = "https://github.com/prove-rs/z3.rs.git", rev = "c126e07" } thiserror = "1.0.58" serde = { version = "1.0.197", features = ["derive"] } tracing = "0.1.40" From 41622bdc5e09fc78961638747246ebabab3de0c7 Mon Sep 17 00:00:00 2001 From: Mark Date: Thu, 27 Jun 2024 10:42:12 +0100 Subject: [PATCH 017/146] Store language id in sleigh context --- jingle_sleigh/src/context/builder/mod.rs | 3 +-- jingle_sleigh/src/context/mod.rs | 11 +++++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/jingle_sleigh/src/context/builder/mod.rs b/jingle_sleigh/src/context/builder/mod.rs index 6be2d01..f243295 100644 --- a/jingle_sleigh/src/context/builder/mod.rs +++ b/jingle_sleigh/src/context/builder/mod.rs @@ -31,8 +31,7 @@ impl SleighContextBuilder { pub fn build(mut self, id: &str) -> Result { let image = self.image.take().ok_or(NoImageProvided)?; let (lang, path) = self.get_language(id).ok_or(InvalidLanguageId)?; - let sla_path = path.join(&lang.sla_file); - let mut context = SleighContext::new(&sla_path, image)?; + let mut context = SleighContext::new(lang, path, image)?; event!(Level::INFO, "Created sleigh context"); let pspec_path = path.join(&lang.processor_spec); let pspec = parse_pspec(&pspec_path)?; diff --git a/jingle_sleigh/src/context/mod.rs b/jingle_sleigh/src/context/mod.rs index 41ed01a..b6f14e5 100644 --- a/jingle_sleigh/src/context/mod.rs +++ b/jingle_sleigh/src/context/mod.rs @@ -17,10 +17,12 @@ use crate::VarNode; use cxx::{SharedPtr, UniquePtr}; use std::fmt::{Debug, Formatter}; use std::path::Path; +use crate::context::builder::language_def::LanguageDefinition; pub struct SleighContext { ctx: UniquePtr, spaces: Vec, + language_id: String, pub image: Image, } @@ -74,7 +76,8 @@ impl RegisterManager for SleighContext { } impl SleighContext { - pub(crate) fn new(path: &Path, image: Image) -> Result { + pub(crate) fn new>(language_def: &LanguageDefinition, base_path: T, image: Image) -> Result { + let path = base_path.as_ref().join(&language_def.sla_file); let abs = path.canonicalize().map_err(|_| LanguageSpecRead)?; let path_str = abs.to_str().ok_or(LanguageSpecRead)?; match CTX_BUILD_MUTEX.lock() { @@ -84,7 +87,7 @@ impl SleighContext { for idx in 0..ctx.getNumSpaces() { spaces.push(SpaceInfo::from(ctx.getSpaceByIndex(idx))); } - Ok(Self { image, ctx, spaces }) + Ok(Self { image, ctx, spaces, language_id: language_def.id.clone() }) } Err(_) => Err(SleighInitError), } @@ -105,6 +108,10 @@ impl SleighContext { } spaces } + + pub fn get_language_id(&self) -> &str { + &self.language_id + } } pub struct SleighContextInstructionIterator<'a> { From f759fd9d4bc1c00c9fe651b825b93d2aecf497ad Mon Sep 17 00:00:00 2001 From: Mark Date: Thu, 27 Jun 2024 16:45:27 +0100 Subject: [PATCH 018/146] Update image section debug --- jingle/src/modeling/instruction.rs | 8 ++++++++ jingle_sleigh/src/ffi/image.rs | 17 ++++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/jingle/src/modeling/instruction.rs b/jingle/src/modeling/instruction.rs index b95b8b4..d41e48c 100644 --- a/jingle/src/modeling/instruction.rs +++ b/jingle/src/modeling/instruction.rs @@ -124,3 +124,11 @@ impl<'ctx> TranslationContext<'ctx> for ModeledInstruction<'ctx> { &mut self.branch_builder } } + +impl<'ctx> From<&[ModeledInstruction<'ctx>]> for ModeledInstruction<'ctx>{ + fn from(value: &[ModeledInstruction<'ctx>]) -> Self { + for instr in value.iter() { + instr. + } + } +} \ No newline at end of file diff --git a/jingle_sleigh/src/ffi/image.rs b/jingle_sleigh/src/ffi/image.rs index a478a92..aac0ac2 100644 --- a/jingle_sleigh/src/ffi/image.rs +++ b/jingle_sleigh/src/ffi/image.rs @@ -1,3 +1,5 @@ +use std::fmt::{Debug, Formatter}; + #[cxx::bridge] pub(crate) mod bridge { #[derive(Debug, Clone)] @@ -14,8 +16,21 @@ pub(crate) mod bridge { pub(crate) perms: Perms, } - #[derive(Debug, Clone)] + #[derive(Clone)] pub struct Image { pub sections: Vec, } } + +impl Debug for bridge::ImageSection{ + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let d = f.debug_struct("ImageSection").field("base_address", &self.base_address).field("perms", &self.perms); + if self.data.len() > 16{ + d.field("data", &format!("[ < {} bytes > ]", self.data.len())); + }else{ + d.field("data", &self.data); + } + d.finish() + } +} + From 646de6bde8dafa2f9b109942542e41bb7086beb2 Mon Sep 17 00:00:00 2001 From: Mark Date: Thu, 27 Jun 2024 16:49:01 +0100 Subject: [PATCH 019/146] Oops --- jingle_sleigh/src/ffi/image.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jingle_sleigh/src/ffi/image.rs b/jingle_sleigh/src/ffi/image.rs index aac0ac2..8d85a8a 100644 --- a/jingle_sleigh/src/ffi/image.rs +++ b/jingle_sleigh/src/ffi/image.rs @@ -9,14 +9,14 @@ pub(crate) mod bridge { pub(crate) exec: bool, } - #[derive(Debug, Clone)] + #[derive(Clone)] pub struct ImageSection { pub(crate) data: Vec, pub(crate) base_address: usize, pub(crate) perms: Perms, } - #[derive(Clone)] + #[derive(Debug, Clone)] pub struct Image { pub sections: Vec, } From ab6ff2184a8a939fcf18550c3ffd7b8b2139dd46 Mon Sep 17 00:00:00 2001 From: Mark Date: Thu, 27 Jun 2024 16:53:03 +0100 Subject: [PATCH 020/146] Actually run cargo check this time; comment out thing I didn't finish writing --- jingle/src/modeling/instruction.rs | 4 ++-- jingle_sleigh/src/ffi/image.rs | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/jingle/src/modeling/instruction.rs b/jingle/src/modeling/instruction.rs index d41e48c..26a07ea 100644 --- a/jingle/src/modeling/instruction.rs +++ b/jingle/src/modeling/instruction.rs @@ -125,10 +125,10 @@ impl<'ctx> TranslationContext<'ctx> for ModeledInstruction<'ctx> { } } -impl<'ctx> From<&[ModeledInstruction<'ctx>]> for ModeledInstruction<'ctx>{ +/*impl<'ctx> From<&[ModeledInstruction<'ctx>]> for ModeledInstruction<'ctx>{ fn from(value: &[ModeledInstruction<'ctx>]) -> Self { for instr in value.iter() { instr. } } -} \ No newline at end of file +}*/ \ No newline at end of file diff --git a/jingle_sleigh/src/ffi/image.rs b/jingle_sleigh/src/ffi/image.rs index 8d85a8a..905d936 100644 --- a/jingle_sleigh/src/ffi/image.rs +++ b/jingle_sleigh/src/ffi/image.rs @@ -24,7 +24,8 @@ pub(crate) mod bridge { impl Debug for bridge::ImageSection{ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let d = f.debug_struct("ImageSection").field("base_address", &self.base_address).field("perms", &self.perms); + let mut d = f.debug_struct("ImageSection"); + d.field("base_address", &self.base_address).field("perms", &self.perms); if self.data.len() > 16{ d.field("data", &format!("[ < {} bytes > ]", self.data.len())); }else{ From a5c585bf1d00df61001e0b7269b37b68214e89f9 Mon Sep 17 00:00:00 2001 From: Mark Date: Thu, 27 Jun 2024 17:05:12 +0100 Subject: [PATCH 021/146] Try section flags instead of segment flags --- .../src/context/builder/image/gimli.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/jingle_sleigh/src/context/builder/image/gimli.rs b/jingle_sleigh/src/context/builder/image/gimli.rs index 8597b86..e248f37 100644 --- a/jingle_sleigh/src/context/builder/image/gimli.rs +++ b/jingle_sleigh/src/context/builder/image/gimli.rs @@ -2,15 +2,15 @@ use crate::context::builder::image::Perms; use crate::context::{Image, ImageSection}; use crate::JingleSleighError; use crate::JingleSleighError::ImageLoadError; -use object::elf::{PF_R, PF_W, PF_X}; +use object::elf::{PF_R, PF_W, PF_X, SHF_EXECINSTR, SHF_WRITE}; use object::macho::{VM_PROT_EXECUTE, VM_PROT_READ, VM_PROT_WRITE}; -use object::{Architecture, Endianness, File, Object, ObjectSegment, SegmentFlags}; +use object::{Architecture, Endianness, File, Object, ObjectSection, ObjectSegment, SectionFlags, SegmentFlags}; impl<'d> TryFrom> for Image { type Error = JingleSleighError; fn try_from(value: File) -> Result { let mut img: Image = Image { sections: vec![] }; - for x in value.segments() { + for x in value.sections() { let base_address = x.address(); let data = x.data().map_err(|_| ImageLoadError)?.to_vec(); let perms = map_flags(&x.flags()); @@ -24,14 +24,14 @@ impl<'d> TryFrom> for Image { } } -fn map_flags(flags: &SegmentFlags) -> Perms { +fn map_flags(flags: &SectionFlags) -> Perms { match flags { - SegmentFlags::Elf { p_flags } => Perms { - exec: (p_flags & PF_X) == PF_X, - write: (p_flags & PF_W) == PF_W, - read: (p_flags & PF_R) == PF_R, + SectionFlags::Elf { sh_flags } => Perms { + exec: (*sh_flags as u32 & SHF_EXECINSTR) == SHF_EXECINSTR, + write: (*sh_flags as u32 & SHF_WRITE) == SHF_WRITE, + read: true, }, - SegmentFlags::MachO { flags, .. } => Perms { + SectionFlags::MachO { flags, .. } => Perms { exec: (flags & VM_PROT_EXECUTE) == VM_PROT_EXECUTE, write: (flags & VM_PROT_WRITE) == VM_PROT_WRITE, read: (flags & VM_PROT_READ) == VM_PROT_READ, From 3404a7f4796fd55e40aea100ddf60e432e05df31 Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 28 Jun 2024 16:11:19 +0100 Subject: [PATCH 022/146] Add bb-read --- jingle_sleigh/src/context/mod.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/jingle_sleigh/src/context/mod.rs b/jingle_sleigh/src/context/mod.rs index b6f14e5..0c5da9c 100644 --- a/jingle_sleigh/src/context/mod.rs +++ b/jingle_sleigh/src/context/mod.rs @@ -98,7 +98,11 @@ impl SleighContext { } pub fn read(&self, offset: u64, max_instrs: usize) -> SleighContextInstructionIterator { - SleighContextInstructionIterator::new(self, offset, max_instrs) + SleighContextInstructionIterator::new(self, offset, max_instrs, false) + } + + pub fn read_block(&self, offset: u64, max_instrs: usize) -> SleighContextInstructionIterator { + SleighContextInstructionIterator::new(self, offset, max_instrs, true) } pub fn spaces(&self) -> Vec> { @@ -118,14 +122,18 @@ pub struct SleighContextInstructionIterator<'a> { sleigh: &'a SleighContext, remaining: usize, offset: u64, + terminate_branch: bool, + already_hit_branch: bool, } impl<'a> SleighContextInstructionIterator<'a> { - pub(crate) fn new(sleigh: &'a SleighContext, offset: u64, remaining: usize) -> Self { + pub(crate) fn new(sleigh: &'a SleighContext, offset: u64, remaining: usize, terminate_branch: bool) -> Self { SleighContextInstructionIterator { sleigh, remaining, offset, + terminate_branch, + already_hit_branch: false, } } } @@ -140,12 +148,16 @@ impl<'a> Iterator for SleighContextInstructionIterator<'a> { if !self.sleigh.image.contains_address(self.offset as usize) { return None; } + if self.terminate_branch && self.already_hit_branch{ + return None; + } let instr = self .sleigh .ctx .get_one_instruction(self.offset) .map(Instruction::from) .ok()?; + self.already_hit_branch = instr.terminates_basic_block(); self.offset += instr.length as u64; self.remaining -= 1; Some(instr) From 8fcf49683e6185c0c969fa78d788cdc2c4bcbb89 Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 28 Jun 2024 17:05:12 +0100 Subject: [PATCH 023/146] Only load executable sections into ghidra for now --- jingle/src/modeling/instruction.rs | 2 +- .../src/context/builder/image/gimli.rs | 18 ++++++--- jingle_sleigh/src/context/mod.rs | 39 ++++++++++++++++--- jingle_sleigh/src/ffi/image.rs | 10 ++--- 4 files changed, 51 insertions(+), 18 deletions(-) diff --git a/jingle/src/modeling/instruction.rs b/jingle/src/modeling/instruction.rs index 26a07ea..565a7e7 100644 --- a/jingle/src/modeling/instruction.rs +++ b/jingle/src/modeling/instruction.rs @@ -131,4 +131,4 @@ impl<'ctx> TranslationContext<'ctx> for ModeledInstruction<'ctx> { instr. } } -}*/ \ No newline at end of file +}*/ diff --git a/jingle_sleigh/src/context/builder/image/gimli.rs b/jingle_sleigh/src/context/builder/image/gimli.rs index e248f37..2a98ddb 100644 --- a/jingle_sleigh/src/context/builder/image/gimli.rs +++ b/jingle_sleigh/src/context/builder/image/gimli.rs @@ -4,7 +4,10 @@ use crate::JingleSleighError; use crate::JingleSleighError::ImageLoadError; use object::elf::{PF_R, PF_W, PF_X, SHF_EXECINSTR, SHF_WRITE}; use object::macho::{VM_PROT_EXECUTE, VM_PROT_READ, VM_PROT_WRITE}; -use object::{Architecture, Endianness, File, Object, ObjectSection, ObjectSegment, SectionFlags, SegmentFlags}; +use object::{ + Architecture, Endianness, File, Object, ObjectSection, ObjectSegment, SectionFlags, + SegmentFlags, +}; impl<'d> TryFrom> for Image { type Error = JingleSleighError; @@ -14,11 +17,13 @@ impl<'d> TryFrom> for Image { let base_address = x.address(); let data = x.data().map_err(|_| ImageLoadError)?.to_vec(); let perms = map_flags(&x.flags()); - img.sections.push(ImageSection { - perms, - data, - base_address: base_address as usize, - }) + if perms.exec { + img.sections.push(ImageSection { + perms, + data, + base_address: base_address as usize, + }) + } } Ok(img) } @@ -43,6 +48,7 @@ fn map_flags(flags: &SectionFlags) -> Perms { }, } } + pub fn map_gimli_architecture(file: &File) -> Option<&'static str> { match &file.architecture() { Architecture::Unknown => None, diff --git a/jingle_sleigh/src/context/mod.rs b/jingle_sleigh/src/context/mod.rs index 0c5da9c..060560f 100644 --- a/jingle_sleigh/src/context/mod.rs +++ b/jingle_sleigh/src/context/mod.rs @@ -11,13 +11,13 @@ pub use builder::image::gimli::map_gimli_architecture; pub use builder::image::{Image, ImageSection}; pub use builder::SleighContextBuilder; +use crate::context::builder::language_def::LanguageDefinition; use crate::ffi::context_ffi::CTX_BUILD_MUTEX; use crate::ffi::instruction::bridge::VarnodeInfoFFI; use crate::VarNode; use cxx::{SharedPtr, UniquePtr}; use std::fmt::{Debug, Formatter}; use std::path::Path; -use crate::context::builder::language_def::LanguageDefinition; pub struct SleighContext { ctx: UniquePtr, @@ -76,7 +76,11 @@ impl RegisterManager for SleighContext { } impl SleighContext { - pub(crate) fn new>(language_def: &LanguageDefinition, base_path: T, image: Image) -> Result { + pub(crate) fn new>( + language_def: &LanguageDefinition, + base_path: T, + image: Image, + ) -> Result { let path = base_path.as_ref().join(&language_def.sla_file); let abs = path.canonicalize().map_err(|_| LanguageSpecRead)?; let path_str = abs.to_str().ok_or(LanguageSpecRead)?; @@ -87,7 +91,12 @@ impl SleighContext { for idx in 0..ctx.getNumSpaces() { spaces.push(SpaceInfo::from(ctx.getSpaceByIndex(idx))); } - Ok(Self { image, ctx, spaces, language_id: language_def.id.clone() }) + Ok(Self { + image, + ctx, + spaces, + language_id: language_def.id.clone(), + }) } Err(_) => Err(SleighInitError), } @@ -127,7 +136,12 @@ pub struct SleighContextInstructionIterator<'a> { } impl<'a> SleighContextInstructionIterator<'a> { - pub(crate) fn new(sleigh: &'a SleighContext, offset: u64, remaining: usize, terminate_branch: bool) -> Self { + pub(crate) fn new( + sleigh: &'a SleighContext, + offset: u64, + remaining: usize, + terminate_branch: bool, + ) -> Self { SleighContextInstructionIterator { sleigh, remaining, @@ -148,7 +162,7 @@ impl<'a> Iterator for SleighContextInstructionIterator<'a> { if !self.sleigh.image.contains_address(self.offset as usize) { return None; } - if self.terminate_branch && self.already_hit_branch{ + if self.terminate_branch && self.already_hit_branch { return None; } let instr = self @@ -169,7 +183,7 @@ mod test { use crate::context::builder::image::Image; use crate::context::builder::SleighContextBuilder; use crate::pcode::PcodeOperation; - use crate::SpaceManager; + use crate::{Instruction, SpaceManager}; use crate::tests::SLEIGH_ARCH; use crate::varnode; @@ -194,4 +208,17 @@ mod test { }; assert!(matches!(&instr.ops[0], _op)) } + + #[test] + fn stop_at_branch() { + let mov_eax_0: [u8; 4] = [0x0f, 0x05, 0x0f, 0x05]; + let ctx_builder = + SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); + let ctx = ctx_builder + .set_image(Image::from(mov_eax_0.as_slice())) + .build(SLEIGH_ARCH) + .unwrap(); + let instr: Vec = ctx.read_block(0, 2).collect(); + assert_eq!(instr.len(), 1); + } } diff --git a/jingle_sleigh/src/ffi/image.rs b/jingle_sleigh/src/ffi/image.rs index 905d936..b728d08 100644 --- a/jingle_sleigh/src/ffi/image.rs +++ b/jingle_sleigh/src/ffi/image.rs @@ -22,16 +22,16 @@ pub(crate) mod bridge { } } -impl Debug for bridge::ImageSection{ +impl Debug for bridge::ImageSection { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let mut d = f.debug_struct("ImageSection"); - d.field("base_address", &self.base_address).field("perms", &self.perms); - if self.data.len() > 16{ + d.field("base_address", &self.base_address) + .field("perms", &self.perms); + if self.data.len() > 16 { d.field("data", &format!("[ < {} bytes > ]", self.data.len())); - }else{ + } else { d.field("data", &self.data); } d.finish() } } - From 203e869d6499fc69e83b917d16c0802e57a34bf4 Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 28 Jun 2024 17:06:33 +0100 Subject: [PATCH 024/146] Only load executable sections into ghidra for now --- jingle/src/modeling/state/space.rs | 2 +- jingle_sleigh/src/context/builder/image/gimli.rs | 5 ++--- jingle_sleigh/src/ffi/mod.rs | 4 ++-- jingle_sleigh/src/varnode/mod.rs | 8 +++----- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/jingle/src/modeling/state/space.rs b/jingle/src/modeling/state/space.rs index 2116055..9969693 100644 --- a/jingle/src/modeling/state/space.rs +++ b/jingle/src/modeling/state/space.rs @@ -147,7 +147,7 @@ mod tests { index: 0, _type: SpaceType::IPTR_PROCESSOR, }; - ModeledSpace::new(&z3, &space_info) + ModeledSpace::new(z3, &space_info) } fn test_endian_write(e: SleighEndianness) { let z3 = Context::new(&Config::new()); diff --git a/jingle_sleigh/src/context/builder/image/gimli.rs b/jingle_sleigh/src/context/builder/image/gimli.rs index 2a98ddb..0c3523c 100644 --- a/jingle_sleigh/src/context/builder/image/gimli.rs +++ b/jingle_sleigh/src/context/builder/image/gimli.rs @@ -2,11 +2,10 @@ use crate::context::builder::image::Perms; use crate::context::{Image, ImageSection}; use crate::JingleSleighError; use crate::JingleSleighError::ImageLoadError; -use object::elf::{PF_R, PF_W, PF_X, SHF_EXECINSTR, SHF_WRITE}; +use object::elf::{SHF_EXECINSTR, SHF_WRITE}; use object::macho::{VM_PROT_EXECUTE, VM_PROT_READ, VM_PROT_WRITE}; use object::{ - Architecture, Endianness, File, Object, ObjectSection, ObjectSegment, SectionFlags, - SegmentFlags, + Architecture, Endianness, File, Object, ObjectSection, SectionFlags, }; impl<'d> TryFrom> for Image { diff --git a/jingle_sleigh/src/ffi/mod.rs b/jingle_sleigh/src/ffi/mod.rs index de8a0da..124d603 100644 --- a/jingle_sleigh/src/ffi/mod.rs +++ b/jingle_sleigh/src/ffi/mod.rs @@ -17,7 +17,7 @@ mod tests { SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); let bin_sleigh = builder - .set_image(Image::try_from(bytes.as_slice()).unwrap()) + .set_image(Image::from(bytes.as_slice())) .build("x86:LE:64:default") .unwrap(); let _lib = bin_sleigh.read(0, 1).next().unwrap(); @@ -29,7 +29,7 @@ mod tests { SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); let bin_sleigh = builder - .set_image(Image::try_from(bytes.as_slice()).unwrap()) + .set_image(Image::from(bytes.as_slice())) .build("x86:LE:64:default") .unwrap(); let _lib = bin_sleigh.read(0, 1).next().unwrap(); diff --git a/jingle_sleigh/src/varnode/mod.rs b/jingle_sleigh/src/varnode/mod.rs index 324853c..16b178b 100644 --- a/jingle_sleigh/src/varnode/mod.rs +++ b/jingle_sleigh/src/varnode/mod.rs @@ -182,8 +182,7 @@ mod tests { space_index: 0, size: 4, }; - let tests = vec![ - VarNode { + let tests = [VarNode { offset: 0, space_index: 0, size: 4, @@ -212,8 +211,7 @@ mod tests { offset: 2, space_index: 0, size: 1, - }, - ]; - assert!(tests.iter().all(|v| vn1.covers(&v))) + }]; + assert!(tests.iter().all(|v| vn1.covers(v))) } } From a8e43f5129002ff308c098d5bb7d5396773e9a60 Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 9 Jul 2024 10:35:10 +0100 Subject: [PATCH 025/146] Try bumping to ghidra 11.1 --- jingle_sleigh/Cargo.toml | 1 + jingle_sleigh/build.rs | 2 ++ jingle_sleigh/ghidra | 2 +- jingle_sleigh/src/ffi/mod.rs | 4 ++++ 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/jingle_sleigh/Cargo.toml b/jingle_sleigh/Cargo.toml index ac68616..20e5544 100644 --- a/jingle_sleigh/Cargo.toml +++ b/jingle_sleigh/Cargo.toml @@ -26,6 +26,7 @@ serde-xml-rs = "0.6.0" thiserror = { version = "1.0.61", features = [] } elf = { version = "0.7.4", optional = true } object = { version = "0.36.0", optional = true } +libz-sys = { version = "1.1.18", default-features = false, features = ["libc"] } tracing = "0.1.40" [build-dependencies] diff --git a/jingle_sleigh/build.rs b/jingle_sleigh/build.rs index 0efc1f5..80de9a8 100644 --- a/jingle_sleigh/build.rs +++ b/jingle_sleigh/build.rs @@ -27,6 +27,7 @@ fn main() { let mut cpp_sources = vec![ "src/ffi/cpp/sleigh/address.cc", + "src/ffi/cpp/sleigh/compression.cc", "src/ffi/cpp/sleigh/context.cc", "src/ffi/cpp/sleigh/globalcontext.cc", "src/ffi/cpp/sleigh/float.cc", @@ -34,6 +35,7 @@ fn main() { "src/ffi/cpp/sleigh/opcodes.cc", "src/ffi/cpp/sleigh/pcoderaw.cc", "src/ffi/cpp/sleigh/semantics.cc", + "src/ffi/cpp/sleigh/slaformat.cc", "src/ffi/cpp/sleigh/sleigh.cc", "src/ffi/cpp/sleigh/sleighbase.cc", "src/ffi/cpp/sleigh/slghpatexpress.cc", diff --git a/jingle_sleigh/ghidra b/jingle_sleigh/ghidra index ec868c1..febbeb4 160000 --- a/jingle_sleigh/ghidra +++ b/jingle_sleigh/ghidra @@ -1 +1 @@ -Subproject commit ec868c12b688636db73ab569fb24599a8cf9d470 +Subproject commit febbeb447af1f059d583b11d7cefc8758b99f887 diff --git a/jingle_sleigh/src/ffi/mod.rs b/jingle_sleigh/src/ffi/mod.rs index 124d603..6656638 100644 --- a/jingle_sleigh/src/ffi/mod.rs +++ b/jingle_sleigh/src/ffi/mod.rs @@ -6,6 +6,10 @@ pub(crate) mod image; pub(crate) mod instruction; pub(crate) mod opcode; +// Need to pull this in somewhere so that libz symbols are available +// for the `sleigh` CPP code at link-time. +use libz_sys; + #[cfg(test)] mod tests { use crate::context::{Image, SleighContextBuilder}; From adaa1b869507ea66d2fdfcfe573581f046fb60b5 Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 9 Jul 2024 14:36:27 +0100 Subject: [PATCH 026/146] Update how loading is done for ghidra 11.1 --- jingle_sleigh/src/ffi/cpp/context.cpp | 8 +++++++- jingle_sleigh/src/ffi/cpp/exception.h | 11 +++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/jingle_sleigh/src/ffi/cpp/context.cpp b/jingle_sleigh/src/ffi/cpp/context.cpp index abe904e..8b3f9a7 100644 --- a/jingle_sleigh/src/ffi/cpp/context.cpp +++ b/jingle_sleigh/src/ffi/cpp/context.cpp @@ -90,7 +90,13 @@ ContextFFI::ContextFFI(rust::Str slaPath, Image image) { this->img = DummyLoadImage(std::move(image)); documentStorage = ghidra::DocumentStorage(); - ghidra::Document *doc = documentStorage.openDocument(slaPath.operator std::string()); + + std::stringstream sleighfilename; + sleighfilename << ""; + sleighfilename << slaPath; + sleighfilename << ""; + + ghidra::Document *doc = documentStorage.parseDocument(sleighfilename); ghidra::Element *root = doc->getRoot(); documentStorage.registerTag(root); sleigh = std::make_unique(&img, &contextDatabase); diff --git a/jingle_sleigh/src/ffi/cpp/exception.h b/jingle_sleigh/src/ffi/cpp/exception.h index fcedb24..8151c57 100644 --- a/jingle_sleigh/src/ffi/cpp/exception.h +++ b/jingle_sleigh/src/ffi/cpp/exception.h @@ -3,17 +3,20 @@ #define JINGLE_EXCEPTION_H #include "sleigh/error.hh" +#include "sleigh/xml.hh" namespace rust { namespace behavior { - template + template static void trycatch(Try &&func, Fail &&fail) noexcept try { - func(); + func(); } catch (const ghidra::LowlevelError &e) { - fail(e.explain); + fail(e.explain); + } catch (const ghidra::DecoderError &e) { + fail(e.explain); } catch (const std::exception &e) { - fail(e.what()); + fail(e.what()); } } } From f9b622588ae1cf59a14e187655687bb7e4a5779a Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 12 Jul 2024 18:03:04 +0100 Subject: [PATCH 027/146] Fix get_registers() --- jingle_sleigh/src/context/mod.rs | 14 +++++++++++++- jingle_sleigh/src/ffi/context_ffi.rs | 1 + jingle_sleigh/src/ffi/cpp/context.cpp | 5 ++++- jingle_sleigh/src/ffi/cpp/context.h | 4 ++++ 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/jingle_sleigh/src/context/mod.rs b/jingle_sleigh/src/context/mod.rs index 060560f..a533c3e 100644 --- a/jingle_sleigh/src/context/mod.rs +++ b/jingle_sleigh/src/context/mod.rs @@ -183,7 +183,7 @@ mod test { use crate::context::builder::image::Image; use crate::context::builder::SleighContextBuilder; use crate::pcode::PcodeOperation; - use crate::{Instruction, SpaceManager}; + use crate::{Instruction, RegisterManager, SpaceManager}; use crate::tests::SLEIGH_ARCH; use crate::varnode; @@ -221,4 +221,16 @@ mod test { let instr: Vec = ctx.read_block(0, 2).collect(); assert_eq!(instr.len(), 1); } + + #[test] + fn get_regs(){ + let mov_eax_0: [u8; 6] = [0xb8, 0x00, 0x00, 0x00, 0x00, 0xc3]; + let ctx_builder = + SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); + let ctx = ctx_builder + .set_image(Image::from(mov_eax_0.as_slice())) + .build(SLEIGH_ARCH) + .unwrap(); + assert_eq!(ctx.get_registers(), vec![]); + } } diff --git a/jingle_sleigh/src/ffi/context_ffi.rs b/jingle_sleigh/src/ffi/context_ffi.rs index 4bb7210..03b09e3 100644 --- a/jingle_sleigh/src/ffi/context_ffi.rs +++ b/jingle_sleigh/src/ffi/context_ffi.rs @@ -38,4 +38,5 @@ pub(crate) mod bridge { pub(crate) fn getRegisters(&self) -> Vec; } + impl Vec {} } diff --git a/jingle_sleigh/src/ffi/cpp/context.cpp b/jingle_sleigh/src/ffi/cpp/context.cpp index 8b3f9a7..a710505 100644 --- a/jingle_sleigh/src/ffi/cpp/context.cpp +++ b/jingle_sleigh/src/ffi/cpp/context.cpp @@ -171,6 +171,9 @@ rust::Vec ContextFFI::getRegisters() const { std::map reglist; rust::Vec v; sleigh->getAllRegisters(reglist); - std::transform(reglist.begin(), reglist.end(), std::back_inserter(v), collectRegInfo); + v.reserve(reglist.size()); + for (auto const& vn : reglist){ + v.emplace_back(collectRegInfo(vn)); + } return v; } \ No newline at end of file diff --git a/jingle_sleigh/src/ffi/cpp/context.h b/jingle_sleigh/src/ffi/cpp/context.h index 4a1295d..9796919 100644 --- a/jingle_sleigh/src/ffi/cpp/context.h +++ b/jingle_sleigh/src/ffi/cpp/context.h @@ -51,6 +51,10 @@ class ContextFFI { rust::Vec getRegisters() const; }; +RegisterInfoFFI collectRegInfo(std::tuple el); + +VarnodeInfoFFI varnodeToFFI(ghidra::VarnodeData vn); + std::unique_ptr makeContext(rust::Str slaPath, Image img); #endif //JINGLE_SLEIGH_CONTEXT_H From 697be4ed468c771460c51c9296ef85b5f8cf97d6 Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 12 Jul 2024 18:06:24 +0100 Subject: [PATCH 028/146] Update test --- jingle_sleigh/src/context/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jingle_sleigh/src/context/mod.rs b/jingle_sleigh/src/context/mod.rs index a533c3e..ad493f0 100644 --- a/jingle_sleigh/src/context/mod.rs +++ b/jingle_sleigh/src/context/mod.rs @@ -231,6 +231,6 @@ mod test { .set_image(Image::from(mov_eax_0.as_slice())) .build(SLEIGH_ARCH) .unwrap(); - assert_eq!(ctx.get_registers(), vec![]); + assert_ne!(ctx.get_registers(), vec![]); } } From 9cc4bc55c1e7896cd422fa199b8b90aaf3233788 Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 16 Jul 2024 20:15:24 +0100 Subject: [PATCH 029/146] Add section parsing log --- jingle_sleigh/src/context/builder/image/gimli.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/jingle_sleigh/src/context/builder/image/gimli.rs b/jingle_sleigh/src/context/builder/image/gimli.rs index 0c3523c..78ebe33 100644 --- a/jingle_sleigh/src/context/builder/image/gimli.rs +++ b/jingle_sleigh/src/context/builder/image/gimli.rs @@ -7,9 +7,11 @@ use object::macho::{VM_PROT_EXECUTE, VM_PROT_READ, VM_PROT_WRITE}; use object::{ Architecture, Endianness, File, Object, ObjectSection, SectionFlags, }; +use tracing::{event, instrument, Level}; impl<'d> TryFrom> for Image { type Error = JingleSleighError; + #[instrument(skip_all)] fn try_from(value: File) -> Result { let mut img: Image = Image { sections: vec![] }; for x in value.sections() { @@ -17,6 +19,8 @@ impl<'d> TryFrom> for Image { let data = x.data().map_err(|_| ImageLoadError)?.to_vec(); let perms = map_flags(&x.flags()); if perms.exec { + let name = x.name().unwrap_or(""); + event!(Level::TRACE,"Selecting section {} at {:x}", name, base_address); img.sections.push(ImageSection { perms, data, From 86e4326b2bc553ec0cd31277d3cc6664fa2e4b51 Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 16 Jul 2024 20:18:16 +0100 Subject: [PATCH 030/146] Fmt --- jingle_sleigh/src/context/builder/image/gimli.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jingle_sleigh/src/context/builder/image/gimli.rs b/jingle_sleigh/src/context/builder/image/gimli.rs index 78ebe33..5b37678 100644 --- a/jingle_sleigh/src/context/builder/image/gimli.rs +++ b/jingle_sleigh/src/context/builder/image/gimli.rs @@ -20,7 +20,7 @@ impl<'d> TryFrom> for Image { let perms = map_flags(&x.flags()); if perms.exec { let name = x.name().unwrap_or(""); - event!(Level::TRACE,"Selecting section {} at {:x}", name, base_address); + event!(Level::TRACE,"Selecting section {} at {:x}", name, base_address); img.sections.push(ImageSection { perms, data, From 2aaf7e0629642443f65386315e61b8e724d53379 Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 16 Jul 2024 20:23:43 +0100 Subject: [PATCH 031/146] Show range instead --- jingle_sleigh/src/context/builder/image/gimli.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/jingle_sleigh/src/context/builder/image/gimli.rs b/jingle_sleigh/src/context/builder/image/gimli.rs index 5b37678..becc6c9 100644 --- a/jingle_sleigh/src/context/builder/image/gimli.rs +++ b/jingle_sleigh/src/context/builder/image/gimli.rs @@ -20,7 +20,9 @@ impl<'d> TryFrom> for Image { let perms = map_flags(&x.flags()); if perms.exec { let name = x.name().unwrap_or(""); - event!(Level::TRACE,"Selecting section {} at {:x}", name, base_address); + let start = base_address; + let end = base_address + data.len() as u64; + event!(Level::TRACE,"Selecting section {} ({:x}-{:x})", name, start, end); img.sections.push(ImageSection { perms, data, From 8d7853b296555c04eb948b5a0063b4d811ef87e0 Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 17 Jul 2024 14:59:21 +0100 Subject: [PATCH 032/146] Kludgy try_from impl, silencing warnings, fmt, clippy --- .../src/context/builder/image/gimli.rs | 12 ++++++--- .../src/context/builder/language_def.rs | 3 +++ .../src/context/builder/processor_spec.rs | 1 + jingle_sleigh/src/context/mod.rs | 2 +- jingle_sleigh/src/error.rs | 3 +++ jingle_sleigh/src/ffi/mod.rs | 3 ++- jingle_sleigh/src/instruction.rs | 25 +++++++++++++++++++ jingle_sleigh/src/varnode/mod.rs | 6 +++-- 8 files changed, 47 insertions(+), 8 deletions(-) diff --git a/jingle_sleigh/src/context/builder/image/gimli.rs b/jingle_sleigh/src/context/builder/image/gimli.rs index becc6c9..42ab898 100644 --- a/jingle_sleigh/src/context/builder/image/gimli.rs +++ b/jingle_sleigh/src/context/builder/image/gimli.rs @@ -4,9 +4,7 @@ use crate::JingleSleighError; use crate::JingleSleighError::ImageLoadError; use object::elf::{SHF_EXECINSTR, SHF_WRITE}; use object::macho::{VM_PROT_EXECUTE, VM_PROT_READ, VM_PROT_WRITE}; -use object::{ - Architecture, Endianness, File, Object, ObjectSection, SectionFlags, -}; +use object::{Architecture, Endianness, File, Object, ObjectSection, SectionFlags}; use tracing::{event, instrument, Level}; impl<'d> TryFrom> for Image { @@ -22,7 +20,13 @@ impl<'d> TryFrom> for Image { let name = x.name().unwrap_or(""); let start = base_address; let end = base_address + data.len() as u64; - event!(Level::TRACE,"Selecting section {} ({:x}-{:x})", name, start, end); + event!( + Level::TRACE, + "Selecting section {} ({:x}-{:x})", + name, + start, + end + ); img.sections.push(ImageSection { perms, data, diff --git a/jingle_sleigh/src/context/builder/language_def.rs b/jingle_sleigh/src/context/builder/language_def.rs index 03bcdf7..3781cce 100644 --- a/jingle_sleigh/src/context/builder/language_def.rs +++ b/jingle_sleigh/src/context/builder/language_def.rs @@ -12,6 +12,7 @@ pub enum SleighEndian { Big, } +#[allow(unused)] #[derive(Clone, Debug, Deserialize)] pub struct Compiler { pub name: String, @@ -19,12 +20,14 @@ pub struct Compiler { pub id: String, } +#[allow(unused)] #[derive(Clone, Debug, Deserialize)] pub struct ExternalName { pub tool: String, pub name: String, } +#[allow(unused)] #[derive(Clone, Debug, Deserialize)] pub struct LanguageDefinition { pub processor: String, diff --git a/jingle_sleigh/src/context/builder/processor_spec.rs b/jingle_sleigh/src/context/builder/processor_spec.rs index ebbc61f..3e58e12 100644 --- a/jingle_sleigh/src/context/builder/processor_spec.rs +++ b/jingle_sleigh/src/context/builder/processor_spec.rs @@ -11,6 +11,7 @@ pub struct ContextSet { #[serde(rename = "val")] pub value: u64, } +#[allow(unused)] #[derive(Debug, Deserialize)] #[serde(rename = "context_set")] pub struct ContextSetSpace { diff --git a/jingle_sleigh/src/context/mod.rs b/jingle_sleigh/src/context/mod.rs index ad493f0..ac3031a 100644 --- a/jingle_sleigh/src/context/mod.rs +++ b/jingle_sleigh/src/context/mod.rs @@ -223,7 +223,7 @@ mod test { } #[test] - fn get_regs(){ + fn get_regs() { let mov_eax_0: [u8; 6] = [0xb8, 0x00, 0x00, 0x00, 0x00, 0xc3]; let ctx_builder = SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); diff --git a/jingle_sleigh/src/error.rs b/jingle_sleigh/src/error.rs index 99f2daf..148e054 100644 --- a/jingle_sleigh/src/error.rs +++ b/jingle_sleigh/src/error.rs @@ -33,6 +33,9 @@ pub enum JingleSleighError { /// A [`VarNode`](crate::VarNode) was constructed referencing a non-existent space #[error("A varnode was constructed referencing a non-existent space")] InvalidSpaceName, + /// Attempted to construct an [Instruction](crate::Instruction) from an empty slice of instructions + #[error("Attempted to construct an instruction from an empty slice of instructions")] + EmptyInstruction, } impl From for std::fmt::Error { diff --git a/jingle_sleigh/src/ffi/mod.rs b/jingle_sleigh/src/ffi/mod.rs index 6656638..aa2c4bc 100644 --- a/jingle_sleigh/src/ffi/mod.rs +++ b/jingle_sleigh/src/ffi/mod.rs @@ -8,7 +8,8 @@ pub(crate) mod opcode; // Need to pull this in somewhere so that libz symbols are available // for the `sleigh` CPP code at link-time. -use libz_sys; +#[allow(unused_imports)] +use libz_sys::{inflate}; #[cfg(test)] mod tests { diff --git a/jingle_sleigh/src/instruction.rs b/jingle_sleigh/src/instruction.rs index f1763c3..d341bfd 100644 --- a/jingle_sleigh/src/instruction.rs +++ b/jingle_sleigh/src/instruction.rs @@ -4,6 +4,7 @@ use crate::ffi::instruction::bridge::InstructionFFI; use crate::pcode::display::PcodeOperationDisplay; use crate::pcode::PcodeOperation; use crate::space::SpaceManager; +use crate::JingleSleighError::EmptyInstruction; use crate::OpCode; use serde::{Deserialize, Serialize}; use std::fmt::{Display, Formatter}; @@ -82,3 +83,27 @@ impl From for Instruction { } } } + +/// todo: this is a gross placeholder until I refactor stuff into a proper +/// trace +impl TryFrom<&[Instruction]> for Instruction { + type Error = JingleSleighError; + fn try_from(value: &[Instruction]) -> Result { + if value.is_empty() { + return Err(EmptyInstruction); + } + let ops: Vec = value.iter().flat_map(|i| i.ops.iter().cloned()).collect(); + let length = value.iter().map(|i| i.length).reduce(|a, b| a + b).unwrap(); + let address = value[0].address; + let disassembly = Disassembly { + mnemonic: "".to_string(), + args: "".to_string(), + }; + Ok(Self { + ops, + length, + address, + disassembly, + }) + } +} diff --git a/jingle_sleigh/src/varnode/mod.rs b/jingle_sleigh/src/varnode/mod.rs index 16b178b..6c9ff79 100644 --- a/jingle_sleigh/src/varnode/mod.rs +++ b/jingle_sleigh/src/varnode/mod.rs @@ -182,7 +182,8 @@ mod tests { space_index: 0, size: 4, }; - let tests = [VarNode { + let tests = [ + VarNode { offset: 0, space_index: 0, size: 4, @@ -211,7 +212,8 @@ mod tests { offset: 2, space_index: 0, size: 1, - }]; + }, + ]; assert!(tests.iter().all(|v| vn1.covers(v))) } } From 73bc3bbda775d06193ce73997524ac9a4ba74180 Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 17 Jul 2024 18:50:02 +0100 Subject: [PATCH 033/146] Clone if there's only one --- jingle_sleigh/src/instruction.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/jingle_sleigh/src/instruction.rs b/jingle_sleigh/src/instruction.rs index d341bfd..30f02bf 100644 --- a/jingle_sleigh/src/instruction.rs +++ b/jingle_sleigh/src/instruction.rs @@ -92,6 +92,9 @@ impl TryFrom<&[Instruction]> for Instruction { if value.is_empty() { return Err(EmptyInstruction); } + if value.len() == 1{ + return Ok(value[0].clone()) + } let ops: Vec = value.iter().flat_map(|i| i.ops.iter().cloned()).collect(); let length = value.iter().map(|i| i.length).reduce(|a, b| a + b).unwrap(); let address = value[0].address; From cb50f741129e5974bf34493ed6a86cba7d09ed96 Mon Sep 17 00:00:00 2001 From: Mark Date: Thu, 18 Jul 2024 10:41:29 +0100 Subject: [PATCH 034/146] impl (Partial)Eq for Instruction --- jingle_sleigh/src/ffi/mod.rs | 2 +- jingle_sleigh/src/instruction.rs | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/jingle_sleigh/src/ffi/mod.rs b/jingle_sleigh/src/ffi/mod.rs index aa2c4bc..389d53b 100644 --- a/jingle_sleigh/src/ffi/mod.rs +++ b/jingle_sleigh/src/ffi/mod.rs @@ -9,7 +9,7 @@ pub(crate) mod opcode; // Need to pull this in somewhere so that libz symbols are available // for the `sleigh` CPP code at link-time. #[allow(unused_imports)] -use libz_sys::{inflate}; +use libz_sys::inflate; #[cfg(test)] mod tests { diff --git a/jingle_sleigh/src/instruction.rs b/jingle_sleigh/src/instruction.rs index 30f02bf..bdf2e87 100644 --- a/jingle_sleigh/src/instruction.rs +++ b/jingle_sleigh/src/instruction.rs @@ -22,6 +22,14 @@ pub struct Instruction { pub address: u64, } +impl PartialEq for Instruction { + fn eq(&self, other: &Self) -> bool { + self.length == other.length && self.address == other.address && self.ops == other.ops + } +} + +impl Eq for Instruction {} + /// A helper structure allowing displaying an instruction and its semantics /// without requiring lots of pcode metadata to be stored in the instruction itself pub struct InstructionDisplay<'a, T: SpaceManager> { @@ -92,8 +100,8 @@ impl TryFrom<&[Instruction]> for Instruction { if value.is_empty() { return Err(EmptyInstruction); } - if value.len() == 1{ - return Ok(value[0].clone()) + if value.len() == 1 { + return Ok(value[0].clone()); } let ops: Vec = value.iter().flat_map(|i| i.ops.iter().cloned()).collect(); let length = value.iter().map(|i| i.length).reduce(|a, b| a + b).unwrap(); From cb64e46a010bef5ac5776796ae87b4fc92b61275 Mon Sep 17 00:00:00 2001 From: Mark Date: Thu, 18 Jul 2024 10:45:02 +0100 Subject: [PATCH 035/146] Derive ParitalEq/Eq so that I can derive Hash soundly --- jingle_sleigh/src/ffi/instruction.rs | 2 +- jingle_sleigh/src/instruction.rs | 10 +--------- jingle_sleigh/src/pcode/mod.rs | 2 +- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/jingle_sleigh/src/ffi/instruction.rs b/jingle_sleigh/src/ffi/instruction.rs index 6524766..8c76ef1 100644 --- a/jingle_sleigh/src/ffi/instruction.rs +++ b/jingle_sleigh/src/ffi/instruction.rs @@ -36,7 +36,7 @@ pub(crate) mod bridge { /// A display-friendly representation of an instruction, generated by SLEIGH. Sleigh does not /// provide any tokenization of instruction operands, so they are all contained as a string /// representation in the [args](Self::args) attribute. - #[derive(Clone, Debug, Serialize, Deserialize)] + #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Disassembly { /// SLEIGH's name for an ISA instruction pub mnemonic: String, diff --git a/jingle_sleigh/src/instruction.rs b/jingle_sleigh/src/instruction.rs index bdf2e87..440f771 100644 --- a/jingle_sleigh/src/instruction.rs +++ b/jingle_sleigh/src/instruction.rs @@ -10,7 +10,7 @@ use serde::{Deserialize, Serialize}; use std::fmt::{Display, Formatter}; /// A rust representation of a SLEIGH assembly instruction -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Instruction { pub disassembly: Disassembly, /// The PCODE semantics of this instruction @@ -22,14 +22,6 @@ pub struct Instruction { pub address: u64, } -impl PartialEq for Instruction { - fn eq(&self, other: &Self) -> bool { - self.length == other.length && self.address == other.address && self.ops == other.ops - } -} - -impl Eq for Instruction {} - /// A helper structure allowing displaying an instruction and its semantics /// without requiring lots of pcode metadata to be stored in the instruction itself pub struct InstructionDisplay<'a, T: SpaceManager> { diff --git a/jingle_sleigh/src/pcode/mod.rs b/jingle_sleigh/src/pcode/mod.rs index fe13179..a3bae4c 100644 --- a/jingle_sleigh/src/pcode/mod.rs +++ b/jingle_sleigh/src/pcode/mod.rs @@ -22,7 +22,7 @@ use crate::GeneralizedVarNode; use serde::{Deserialize, Serialize}; use std::fmt::Debug; -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)] pub enum PcodeOperation { Copy { input: VarNode, From a8f7a4a65e4a4d1c167edef9077006dec73cf446 Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 6 Aug 2024 20:04:57 +0100 Subject: [PATCH 036/146] Readme tweak --- README.md | 27 +++++++++++++++++++-------- jingle.svg | 1 + 2 files changed, 20 insertions(+), 8 deletions(-) create mode 100644 jingle.svg diff --git a/README.md b/README.md index f9249cb..47c3b2c 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,30 @@ -# `jingle`: SMT Modeling for SLEIGH +
-`jingle` is a library for program analysis over traces of PCODE operations. I -am writing in the course of my PhD work and it is still very much "in flux". + + +🎶 Jingle bells, Jingle bells, Jingle all the `SLEIGH` 🎶 + +
+ +# `jingle`: SMT Modeling for `p-code` +`jingle` is a library that translates (a fragment of) Ghidra's `p-code` into SMT. It allows expressing symbolic state +of the pcode vm and the relational semantics between those states defined by `p-code` operations. + +**I am writing in the course of my PhD work and it is still very much "in flux". Breaking changes may happen at any time +and the overall design may change too.** This repository contains a [Cargo Workspace](https://doc.rust-lang.org/book/ch14-03-cargo-workspaces.html) for two related crates: * [`jingle_sleigh`](./jingle_sleigh): a Rust FFI in front of [Ghidra](https://github.com/NationalSecurityAgency/ghidra)' s - code translator: SLEIGH. Sleigh is written in C++ and can be + code translator: `SLEIGH`. `SLEIGH` is written in C++ and can be found [here](https://github.com/NationalSecurityAgency/ghidra/tree/master/Ghidra/Features/Decompiler/src/decompile/cpp). - This crate contains a private internal low-level API to SLEIGH and exposes an idiomatic high-level API to consumers. -* [`jingle`](./jingle): a set of functions built on top of `jingle_sleigh` that defines an encoding of PCODE operations - into quantifier-free SMT statements operating on objects of the `Array(BitVec, BitVec)` sort. `jingle` is currently - designed for providing formulas for use in decision procedures over program traces. A more robust analysis + This crate contains a private internal low-level API to `SLEIGH` and exposes an idiomatic high-level API to consumers. +* [`jingle`](./jingle): a set of functions built on top of `jingle_sleigh` that defines an encoding of `p-code` operations + into SMT. `jingle` is currently + designed for providing formulas for use in decision procedures over individual program traces. As such, it does not yet + expose APIs for constructing or reasoning about control-flow graphs. A more robust analysis is forthcoming, depending on my research needs. ## Usage diff --git a/jingle.svg b/jingle.svg new file mode 100644 index 0000000..1220e99 --- /dev/null +++ b/jingle.svg @@ -0,0 +1 @@ +jingle \ No newline at end of file From 1e09cf8dc2ec1d060714b4e6e561e1058769137f Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 9 Aug 2024 14:06:47 +0100 Subject: [PATCH 037/146] Remove unnecessary compile API now that Ghidraships with precompiled sla. Also added a new bin target for jingle --- jingle/Cargo.toml | 2 + jingle/src/main.rs | 1 + jingle_sleigh/Cargo.toml | 1 - jingle_sleigh/build.rs | 10 +--- jingle_sleigh/src/ffi/compile.rs | 94 -------------------------------- jingle_sleigh/src/ffi/mod.rs | 2 - 6 files changed, 5 insertions(+), 105 deletions(-) create mode 100644 jingle/src/main.rs delete mode 100644 jingle_sleigh/src/ffi/compile.rs diff --git a/jingle/Cargo.toml b/jingle/Cargo.toml index 30daef2..7aa2c67 100644 --- a/jingle/Cargo.toml +++ b/jingle/Cargo.toml @@ -20,7 +20,9 @@ z3 = { git = "https://github.com/prove-rs/z3.rs.git", rev = "c126e07" } thiserror = "1.0.58" serde = { version = "1.0.197", features = ["derive"] } tracing = "0.1.40" +clap = { version = "4.5.14" , optional = true} [features] +default = [] elf = ["jingle_sleigh/elf"] gimli = ["jingle_sleigh/gimli"] diff --git a/jingle/src/main.rs b/jingle/src/main.rs new file mode 100644 index 0000000..e71fdf5 --- /dev/null +++ b/jingle/src/main.rs @@ -0,0 +1 @@ +fn main() {} \ No newline at end of file diff --git a/jingle_sleigh/Cargo.toml b/jingle_sleigh/Cargo.toml index 20e5544..d7168ee 100644 --- a/jingle_sleigh/Cargo.toml +++ b/jingle_sleigh/Cargo.toml @@ -33,7 +33,6 @@ tracing = "0.1.40" cxx-build = "1.0.122" [features] -compile = [] elf = ["dep:elf"] gimli = ["dep:object"] default = ["elf", "gimli"] diff --git a/jingle_sleigh/build.rs b/jingle_sleigh/build.rs index 80de9a8..750df71 100644 --- a/jingle_sleigh/build.rs +++ b/jingle_sleigh/build.rs @@ -17,7 +17,7 @@ fn main() { copy_sources(); } - let mut rust_sources = vec![ + let rust_sources = vec![ "src/ffi/addrspace.rs", "src/ffi/context_ffi.rs", "src/ffi/instruction.rs", @@ -25,7 +25,7 @@ fn main() { "src/ffi/image.rs", ]; - let mut cpp_sources = vec![ + let cpp_sources = vec![ "src/ffi/cpp/sleigh/address.cc", "src/ffi/cpp/sleigh/compression.cc", "src/ffi/cpp/sleigh/context.cc", @@ -52,11 +52,6 @@ fn main() { "src/ffi/cpp/addrspace_handle.cpp", "src/ffi/cpp/addrspace_manager_handle.cpp", ]; - if cfg!(compile) { - rust_sources.push("src/ffi/compile.rs"); - cpp_sources.push("src/ffi/cpp/compile.cpp"); - cpp_sources.push("src/ffi/cpp/sleigh/slgh_compile.cc"); - } // This assumes all your C++ bindings are in lib cxx_build::bridges(rust_sources) .files(cpp_sources) @@ -73,7 +68,6 @@ fn main() { println!("cargo::rerun-if-changed=src/ffi/cpp/"); println!("cargo::rerun-if-changed=src/ffi/addrspace.rs"); - println!("cargo::rerun-if-changed=src/ffi/compile.rs"); println!("cargo::rerun-if-changed=src/ffi/context_ffi.rs"); println!("cargo::rerun-if-changed=src/ffi/instruction.rs"); println!( diff --git a/jingle_sleigh/src/ffi/compile.rs b/jingle_sleigh/src/ffi/compile.rs deleted file mode 100644 index 5c08394..0000000 --- a/jingle_sleigh/src/ffi/compile.rs +++ /dev/null @@ -1,94 +0,0 @@ -use crate::ffi::compile::bridge::{CompileDefine, CompileParams}; -use std::collections::BTreeMap; -use std::path::Path; - -pub struct SleighCompileParams { - defines: BTreeMap, - unnecessary_pcode_warning: bool, - lenient_conflict: bool, - all_collision_warning: bool, - all_nop_warning: bool, - dead_temp_warning: bool, - enforce_local_keyword: bool, - large_temporary_warning: bool, - case_sensitive_register_names: bool, -} - -pub fn compile( - in_path: impl AsRef, - out_path: impl AsRef, - params: Option, -) { - let _hi = Path::new("hi"); - if let Some(in_path) = in_path.as_ref().to_str() { - if let Some(out_path) = out_path.as_ref().to_str() { - bridge::compile(in_path, out_path, params.unwrap_or_default().into()) - } - } -} - -impl Default for SleighCompileParams { - fn default() -> Self { - Self { - defines: BTreeMap::new(), - unnecessary_pcode_warning: false, - lenient_conflict: true, - all_collision_warning: false, - all_nop_warning: false, - dead_temp_warning: false, - enforce_local_keyword: false, - large_temporary_warning: false, - case_sensitive_register_names: false, - } - } -} - -impl From for CompileParams { - fn from(value: SleighCompileParams) -> Self { - Self { - defines: value - .defines - .iter() - .map(|(name, val)| CompileDefine { - name: name.clone(), - value: val.clone(), - }) - .collect(), - unnecessary_pcode_warning: value.unnecessary_pcode_warning, - lenient_conflict: value.lenient_conflict, - all_collision_warning: value.all_collision_warning, - all_nop_warning: value.all_nop_warning, - dead_temp_warning: value.dead_temp_warning, - enforce_local_keyword: value.enforce_local_keyword, - large_temporary_warning: value.large_temporary_warning, - case_sensitive_register_names: value.case_sensitive_register_names, - } - } -} - -#[cxx::bridge] -mod bridge { - struct CompileDefine { - name: String, - value: String, - } - - struct CompileParams { - defines: Vec, - unnecessary_pcode_warning: bool, - lenient_conflict: bool, - all_collision_warning: bool, - all_nop_warning: bool, - dead_temp_warning: bool, - enforce_local_keyword: bool, - large_temporary_warning: bool, - case_sensitive_register_names: bool, - } - - unsafe extern "C++" { - include!("jingle_sleigh/src/ffi/cpp/compile.h"); - - fn compile(inFile: &str, outFile: &str, params: CompileParams); - - } -} diff --git a/jingle_sleigh/src/ffi/mod.rs b/jingle_sleigh/src/ffi/mod.rs index 389d53b..226865f 100644 --- a/jingle_sleigh/src/ffi/mod.rs +++ b/jingle_sleigh/src/ffi/mod.rs @@ -1,6 +1,4 @@ pub(crate) mod addrspace; -#[cfg(compile)] -pub(crate) mod compile; pub(crate) mod context_ffi; pub(crate) mod image; pub(crate) mod instruction; From 784af794b674a3bf3d96c711f255208766fc8876 Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 9 Aug 2024 14:55:00 +0100 Subject: [PATCH 038/146] Initial CLI --- jingle/Cargo.toml | 10 ++++- jingle/src/main.rs | 91 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 99 insertions(+), 2 deletions(-) diff --git a/jingle/Cargo.toml b/jingle/Cargo.toml index 7aa2c67..4f7a2ea 100644 --- a/jingle/Cargo.toml +++ b/jingle/Cargo.toml @@ -14,15 +14,23 @@ keywords = ["ghidra", "sleigh", "pcode", "smt"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[[bin]] +name = "jingle" + +required-features = ["clap", "confy"] + [dependencies] jingle_sleigh = { path = "../jingle_sleigh", version = "0.1.1" } z3 = { git = "https://github.com/prove-rs/z3.rs.git", rev = "c126e07" } thiserror = "1.0.58" serde = { version = "1.0.197", features = ["derive"] } tracing = "0.1.40" -clap = { version = "4.5.14" , optional = true} +clap = { version = "4.5.14", optional = true, features = ["derive"] } +confy = { version = "0.6.1" , optional = true} [features] default = [] +clap = ["dep:clap"] +confy = ["dep:confy"] elf = ["jingle_sleigh/elf"] gimli = ["jingle_sleigh/gimli"] diff --git a/jingle/src/main.rs b/jingle/src/main.rs index e71fdf5..986fc36 100644 --- a/jingle/src/main.rs +++ b/jingle/src/main.rs @@ -1 +1,90 @@ -fn main() {} \ No newline at end of file +use std::path::PathBuf; +use clap::builder::Str; +use clap::{Parser, Subcommand}; +use serde::{Deserialize, Serialize}; +use tracing::Level; +use jingle_sleigh::context::SleighContextBuilder; + +#[derive(Debug, Serialize, Deserialize)] +struct JingleConfig { + ghidra_path: PathBuf, +} + +impl Default for JingleConfig{ + fn default() -> Self { + return if cfg!(target_os = "windows") { + let path = PathBuf::from(r"C:\Program Files\ghidra"); + Self { + ghidra_path: path + } + } else if cfg!(target_os = "macos") { + let path = PathBuf::from(r"/Applications/ghidra"); + Self { + ghidra_path: path + } + } else { + let path = PathBuf::from(r"/opt/ghidra"); + Self { + ghidra_path: path + } + } + } +} + +#[derive(Debug, Parser)] +#[command(version, about, long_about = None)] +struct JingleParams { + #[command(subcommand)] + command: Commands, + ghidra_path: Option +} + +#[derive(Debug, Subcommand)] +enum Commands { + /// Adds files to myapp + Disassemble { + architecture: String, + hex_bytes: String, + }, + Lift { + architecture: String, + hex_bytes: String, + }, + Model { + architecture: String, + hex_bytes: String, + }, + Architectures +} + +fn main() { + let params: JingleParams = JingleParams::parse(); + if let Some(ghidra) = params.ghidra_path { + update_config(ghidra); + } + let config: JingleConfig = confy::load("jingle", None).unwrap(); + match params.command { + Commands::Disassemble { .. } => {} + Commands::Lift { .. } => {} + Commands::Model { .. } => {} + Commands::Architectures => list_architectures(config.ghidra_path) + } + + +fn list_architectures(ghidra: PathBuf) { + let sleigh = SleighContextBuilder::load_ghidra_installation(ghidra).unwrap(); + for language_id in sleigh.get_language_ids() { + println!("{}", language_id) + } +} +fn update_config(ghidra: String){ + let config: JingleConfig = confy::load("jingle", None).unwrap(); + let ghidra = PathBuf::from(ghidra); + if ghidra != config.ghidra_path{ + let new_config = JingleConfig{ghidra_path: ghidra}; + confy::store("jingle", None, new_config).unwrap() + } + } + + +} \ No newline at end of file From 2e329908e22c284a2ae45180ed7911c93aa18580 Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 9 Aug 2024 14:55:20 +0100 Subject: [PATCH 039/146] cargo fmt --- jingle/src/main.rs | 49 ++++++++++++++++++++-------------------------- 1 file changed, 21 insertions(+), 28 deletions(-) diff --git a/jingle/src/main.rs b/jingle/src/main.rs index 986fc36..d3ea225 100644 --- a/jingle/src/main.rs +++ b/jingle/src/main.rs @@ -1,33 +1,27 @@ -use std::path::PathBuf; use clap::builder::Str; use clap::{Parser, Subcommand}; +use jingle_sleigh::context::SleighContextBuilder; use serde::{Deserialize, Serialize}; +use std::path::PathBuf; use tracing::Level; -use jingle_sleigh::context::SleighContextBuilder; #[derive(Debug, Serialize, Deserialize)] struct JingleConfig { ghidra_path: PathBuf, } -impl Default for JingleConfig{ +impl Default for JingleConfig { fn default() -> Self { return if cfg!(target_os = "windows") { let path = PathBuf::from(r"C:\Program Files\ghidra"); - Self { - ghidra_path: path - } + Self { ghidra_path: path } } else if cfg!(target_os = "macos") { let path = PathBuf::from(r"/Applications/ghidra"); - Self { - ghidra_path: path - } + Self { ghidra_path: path } } else { let path = PathBuf::from(r"/opt/ghidra"); - Self { - ghidra_path: path - } - } + Self { ghidra_path: path } + }; } } @@ -36,7 +30,7 @@ impl Default for JingleConfig{ struct JingleParams { #[command(subcommand)] command: Commands, - ghidra_path: Option + ghidra_path: Option, } #[derive(Debug, Subcommand)] @@ -54,7 +48,7 @@ enum Commands { architecture: String, hex_bytes: String, }, - Architectures + Architectures, } fn main() { @@ -67,24 +61,23 @@ fn main() { Commands::Disassemble { .. } => {} Commands::Lift { .. } => {} Commands::Model { .. } => {} - Commands::Architectures => list_architectures(config.ghidra_path) + Commands::Architectures => list_architectures(config.ghidra_path), } - -fn list_architectures(ghidra: PathBuf) { - let sleigh = SleighContextBuilder::load_ghidra_installation(ghidra).unwrap(); - for language_id in sleigh.get_language_ids() { - println!("{}", language_id) + fn list_architectures(ghidra: PathBuf) { + let sleigh = SleighContextBuilder::load_ghidra_installation(ghidra).unwrap(); + for language_id in sleigh.get_language_ids() { + println!("{}", language_id) + } } -} -fn update_config(ghidra: String){ + fn update_config(ghidra: String) { let config: JingleConfig = confy::load("jingle", None).unwrap(); let ghidra = PathBuf::from(ghidra); - if ghidra != config.ghidra_path{ - let new_config = JingleConfig{ghidra_path: ghidra}; + if ghidra != config.ghidra_path { + let new_config = JingleConfig { + ghidra_path: ghidra, + }; confy::store("jingle", None, new_config).unwrap() } } - - -} \ No newline at end of file +} From 6dc04cacef1e794fb4f337bfa2c08e1c3a0b8d77 Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 9 Aug 2024 18:37:35 +0100 Subject: [PATCH 040/146] Basic bin functionality --- jingle/Cargo.toml | 8 +-- jingle/src/main.rs | 150 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 127 insertions(+), 31 deletions(-) diff --git a/jingle/Cargo.toml b/jingle/Cargo.toml index 4f7a2ea..9659432 100644 --- a/jingle/Cargo.toml +++ b/jingle/Cargo.toml @@ -16,8 +16,7 @@ keywords = ["ghidra", "sleigh", "pcode", "smt"] [[bin]] name = "jingle" - -required-features = ["clap", "confy"] +required-features = ["bin_features"] [dependencies] jingle_sleigh = { path = "../jingle_sleigh", version = "0.1.1" } @@ -27,10 +26,9 @@ serde = { version = "1.0.197", features = ["derive"] } tracing = "0.1.40" clap = { version = "4.5.14", optional = true, features = ["derive"] } confy = { version = "0.6.1" , optional = true} - +hex = { version = "0.4.3" , optional = true} [features] default = [] -clap = ["dep:clap"] -confy = ["dep:confy"] +bin_features = ["dep:clap", "dep:confy", "dep:hex"] elf = ["jingle_sleigh/elf"] gimli = ["jingle_sleigh/gimli"] diff --git a/jingle/src/main.rs b/jingle/src/main.rs index d3ea225..d8e717d 100644 --- a/jingle/src/main.rs +++ b/jingle/src/main.rs @@ -1,13 +1,22 @@ -use clap::builder::Str; use clap::{Parser, Subcommand}; -use jingle_sleigh::context::SleighContextBuilder; +use hex::decode; +use jingle::modeling::{ModeledBlock, ModelingContext}; +use jingle::JingleContext; +use jingle_sleigh::context::{Image, SleighContext, SleighContextBuilder}; +use jingle_sleigh::{Disassembly, Instruction, JingleSleighError, PcodeOperation, VarNode}; use serde::{Deserialize, Serialize}; use std::path::PathBuf; -use tracing::Level; +use z3::{Config, Context, Solver}; -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] struct JingleConfig { - ghidra_path: PathBuf, + pub ghidra_path: PathBuf, +} + +impl JingleConfig { + pub fn sleigh_builder(&self) -> Result { + SleighContextBuilder::load_ghidra_installation(&self.ghidra_path) + } } impl Default for JingleConfig { @@ -25,12 +34,23 @@ impl Default for JingleConfig { } } +impl From<&JingleParams> for JingleConfig { + fn from(value: &JingleParams) -> Self { + let path = value.ghidra_path.clone(); + Self { + ghidra_path: path + .map(|p| PathBuf::from(p)) + .unwrap_or(JingleConfig::default().ghidra_path), + } + } +} + #[derive(Debug, Parser)] #[command(version, about, long_about = None)] struct JingleParams { #[command(subcommand)] - command: Commands, - ghidra_path: Option, + pub command: Commands, + pub ghidra_path: Option, } #[derive(Debug, Subcommand)] @@ -53,31 +73,109 @@ enum Commands { fn main() { let params: JingleParams = JingleParams::parse(); - if let Some(ghidra) = params.ghidra_path { - update_config(ghidra); - } + update_config(¶ms); let config: JingleConfig = confy::load("jingle", None).unwrap(); match params.command { - Commands::Disassemble { .. } => {} - Commands::Lift { .. } => {} - Commands::Model { .. } => {} - Commands::Architectures => list_architectures(config.ghidra_path), + Commands::Disassemble { + architecture, + hex_bytes, + } => disassemble(&config, architecture, hex_bytes), + Commands::Lift { + architecture, + hex_bytes, + } => lift(&config, architecture, hex_bytes), + Commands::Model { + architecture, + hex_bytes, + } => model(&config, architecture, hex_bytes), + Commands::Architectures => list_architectures(&config), + } +} + +fn update_config(params: &JingleParams) { + let stored_config: JingleConfig = confy::load("jingle", None).unwrap(); + let new_config = JingleConfig::from(params); + if stored_config != new_config { + confy::store("jingle", None, new_config).unwrap() + } +} + +fn list_architectures(config: &JingleConfig) { + let sleigh = config.sleigh_builder().unwrap(); + for language_id in sleigh.get_language_ids() { + println!("{}", language_id) } +} - fn list_architectures(ghidra: PathBuf) { - let sleigh = SleighContextBuilder::load_ghidra_installation(ghidra).unwrap(); - for language_id in sleigh.get_language_ids() { - println!("{}", language_id) +fn get_instructions( + config: &JingleConfig, + architecture: String, + hex_bytes: String, +) -> (SleighContext, Vec) { + let sleigh_build = config.sleigh_builder().unwrap(); + let img = decode(hex_bytes).unwrap(); + let max_len = img.len(); + let mut offset = 0; + let sleigh = sleigh_build + .set_image(Image::from(img)) + .build(&architecture) + .unwrap(); + let mut instrs = vec![]; + while offset < max_len { + for instruction in sleigh.read(offset as u64, 1) { + offset += instruction.length; + instrs.push(instruction); } + if sleigh.read(offset as u64, 1).next().is_none() { + break; + } + } + (sleigh, instrs) +} + +fn disassemble(config: &JingleConfig, architecture: String, hex_bytes: String) { + for instr in get_instructions(config, architecture, hex_bytes).1 { + println!("{}", instr.disassembly) } - fn update_config(ghidra: String) { - let config: JingleConfig = confy::load("jingle", None).unwrap(); - let ghidra = PathBuf::from(ghidra); - if ghidra != config.ghidra_path { - let new_config = JingleConfig { - ghidra_path: ghidra, - }; - confy::store("jingle", None, new_config).unwrap() +} + +fn lift(config: &JingleConfig, architecture: String, hex_bytes: String) { + let (sleigh, instrs) = get_instructions(config, architecture, hex_bytes); + for instr in instrs { + for x in instr.ops { + let x_disp = x.display(&sleigh).unwrap(); + println!("{}", x_disp) } } } + +fn model(config: &JingleConfig, architecture: String, hex_bytes: String) { + let z3 = Context::new(&Config::new()); + let solver = Solver::new(&z3); + let (sleigh, mut instrs) = get_instructions(config, architecture, hex_bytes); + // todo: this is a disgusting hack to let us read a modeled block without requiring the user + // to enter a block-terminating instruction. Everything with reading blocks needs to be reworked + // at some point. For now, this lets me not break anything else relying on this behavior while + // still getting this to work. + instrs.push(Instruction { + address: 0, + disassembly: Disassembly { + args: "".to_string(), + mnemonic: "".to_string(), + }, + ops: vec![PcodeOperation::Branch { + input: VarNode { + space_index: 1, + offset: 0, + size: 1, + }, + }], + length: 1, + }); + + let jingle_ctx = JingleContext::new(&z3, &sleigh); + let block = ModeledBlock::read(&z3, &sleigh, instrs.into_iter()).unwrap(); + let final_state = jingle_ctx.fresh_state(); + solver.assert(&final_state._eq(block.get_final_state()).unwrap()); + println!("{}", solver.to_smt2()) +} From 5dcf4cf1870b169ca8ba791f4faf113ca7fe2446 Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 9 Aug 2024 18:48:00 +0100 Subject: [PATCH 041/146] Add readme note and two missing operations --- README.md | 3 +++ jingle/src/modeling/mod.rs | 28 ++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/README.md b/README.md index 47c3b2c..c58646a 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,9 @@ of the pcode vm and the relational semantics between those states defined by `p- **I am writing in the course of my PhD work and it is still very much "in flux". Breaking changes may happen at any time and the overall design may change too.** +The API is currently a bit of a mess because I've been trying out different approaches to figure out what I like (e.g. +traits vs context objects). I hope to clean it up at some point and expose one right way to do things. + This repository contains a [Cargo Workspace](https://doc.rust-lang.org/book/ch14-03-cargo-workspaces.html) for two related crates: diff --git a/jingle/src/modeling/mod.rs b/jingle/src/modeling/mod.rs index 24076c0..3b2d3ec 100644 --- a/jingle/src/modeling/mod.rs +++ b/jingle/src/modeling/mod.rs @@ -508,6 +508,20 @@ pub(crate) trait TranslationContext<'ctx>: ModelingContext<'ctx> { ); self.write(&output.into(), out_bv) } + PcodeOperation::IntSignedLessEqual { + input0, + input1, + output, + } => { + let in0 = self.read_and_track(input0.into())?; + let in1 = self.read_and_track(input1.into())?; + let out_bool = in0.bvsle(&in1); + let out_bv = out_bool.ite( + &BV::from_i64(self.get_z3(), 1, 8), + &BV::from_i64(self.get_z3(), 0, 8), + ); + self.write(&output.into(), out_bv) + } PcodeOperation::IntLess { input0, input1, @@ -522,6 +536,20 @@ pub(crate) trait TranslationContext<'ctx>: ModelingContext<'ctx> { ); self.write(&output.into(), out_bv) } + PcodeOperation::IntLessEqual { + input0, + input1, + output, + } => { + let in0 = self.read_and_track(input0.into())?; + let in1 = self.read_and_track(input1.into())?; + let out_bool = in0.bvule(&in1); + let out_bv = out_bool.ite( + &BV::from_i64(self.get_z3(), 1, 8), + &BV::from_i64(self.get_z3(), 0, 8), + ); + self.write(&output.into(), out_bv) + } PcodeOperation::IntEqual { input0, input1, From 97e5f79fd10b83196f9bf8c37d33e59a2d4b4864 Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 9 Aug 2024 18:55:37 +0100 Subject: [PATCH 042/146] Simplify printed model --- jingle/src/main.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/jingle/src/main.rs b/jingle/src/main.rs index d8e717d..c33ae01 100644 --- a/jingle/src/main.rs +++ b/jingle/src/main.rs @@ -7,6 +7,7 @@ use jingle_sleigh::{Disassembly, Instruction, JingleSleighError, PcodeOperation, use serde::{Deserialize, Serialize}; use std::path::PathBuf; use z3::{Config, Context, Solver}; +use z3::ast::Ast; #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] struct JingleConfig { @@ -176,6 +177,6 @@ fn model(config: &JingleConfig, architecture: String, hex_bytes: String) { let jingle_ctx = JingleContext::new(&z3, &sleigh); let block = ModeledBlock::read(&z3, &sleigh, instrs.into_iter()).unwrap(); let final_state = jingle_ctx.fresh_state(); - solver.assert(&final_state._eq(block.get_final_state()).unwrap()); + solver.assert(&final_state._eq(block.get_final_state()).unwrap().simplify()); println!("{}", solver.to_smt2()) } From 5e519766c151bbab44d7bc3a14636714f8be8926 Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 12 Aug 2024 13:00:49 +0100 Subject: [PATCH 043/146] Sleigh parsing tweaks --- jingle/src/main.rs | 2 +- .../src/context/builder/language_def.rs | 2 +- jingle_sleigh/src/context/builder/mod.rs | 20 ++++++++++++------- .../src/context/builder/processor_spec.rs | 7 ++++--- jingle_sleigh/src/context/mod.rs | 5 +++-- jingle_sleigh/src/error.rs | 4 +++- 6 files changed, 25 insertions(+), 15 deletions(-) diff --git a/jingle/src/main.rs b/jingle/src/main.rs index c33ae01..e05944d 100644 --- a/jingle/src/main.rs +++ b/jingle/src/main.rs @@ -6,8 +6,8 @@ use jingle_sleigh::context::{Image, SleighContext, SleighContextBuilder}; use jingle_sleigh::{Disassembly, Instruction, JingleSleighError, PcodeOperation, VarNode}; use serde::{Deserialize, Serialize}; use std::path::PathBuf; -use z3::{Config, Context, Solver}; use z3::ast::Ast; +use z3::{Config, Context, Solver}; #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] struct JingleConfig { diff --git a/jingle_sleigh/src/context/builder/language_def.rs b/jingle_sleigh/src/context/builder/language_def.rs index 3781cce..9582556 100644 --- a/jingle_sleigh/src/context/builder/language_def.rs +++ b/jingle_sleigh/src/context/builder/language_def.rs @@ -35,7 +35,7 @@ pub struct LanguageDefinition { pub variant: String, pub version: String, #[serde(rename = "slafile")] - pub sla_file: String, + pub sla_file: PathBuf, #[serde(rename = "processorspec")] pub processor_spec: PathBuf, #[serde(rename = "manualindexfile")] diff --git a/jingle_sleigh/src/context/builder/mod.rs b/jingle_sleigh/src/context/builder/mod.rs index f243295..517459f 100644 --- a/jingle_sleigh/src/context/builder/mod.rs +++ b/jingle_sleigh/src/context/builder/mod.rs @@ -35,10 +35,16 @@ impl SleighContextBuilder { event!(Level::INFO, "Created sleigh context"); let pspec_path = path.join(&lang.processor_spec); let pspec = parse_pspec(&pspec_path)?; - for set in pspec.context_data.context_set.sets { - context.set_initial_context(&set.name, set.value as u32) + if let Some(ctx_sets) = pspec.context_data.map(|d| d.context_set).flatten() { + for set in ctx_sets.sets { + // todo: gross hack + if set.value.starts_with("0x") { + context.set_initial_context(&set.name, u32::from_str_radix(&set.value[2..], 16).unwrap()) + } else { + context.set_initial_context(&set.name, u32::from_str_radix(&set.value, 10).unwrap()) + } + } } - Ok(context) } pub fn load_folder>(path: T) -> Result { @@ -110,7 +116,7 @@ mod tests { parse_ldef(Path::new( "ghidra/Ghidra/Processors/x86/data/languages/x86.ldefs", )) - .unwrap(); + .unwrap(); } #[test] @@ -118,7 +124,7 @@ mod tests { parse_pspec(Path::new( "ghidra/Ghidra/Processors/x86/data/languages/x86.pspec", )) - .unwrap(); + .unwrap(); } #[test] @@ -126,7 +132,7 @@ mod tests { SleighContextBuilder::load_folder(Path::new( "ghidra/Ghidra/Processors/x86/data/languages/", )) - .unwrap(); + .unwrap(); SleighContextBuilder::load_folder(Path::new("ghidra/Ghidra/Processors/x86/data/languages")) .unwrap(); } @@ -141,7 +147,7 @@ mod tests { let langs = SleighContextBuilder::load_folder(Path::new( "ghidra/Ghidra/Processors/x86/data/languages/", )) - .unwrap(); + .unwrap(); assert!(langs.get_language("sdf").is_none()); assert!(langs.get_language(SLEIGH_ARCH).is_some()); } diff --git a/jingle_sleigh/src/context/builder/processor_spec.rs b/jingle_sleigh/src/context/builder/processor_spec.rs index 3e58e12..94278c1 100644 --- a/jingle_sleigh/src/context/builder/processor_spec.rs +++ b/jingle_sleigh/src/context/builder/processor_spec.rs @@ -9,7 +9,7 @@ use std::path::Path; pub struct ContextSet { pub name: String, #[serde(rename = "val")] - pub value: u64, + pub value: String, } #[allow(unused)] #[derive(Debug, Deserialize)] @@ -22,7 +22,8 @@ pub struct ContextSetSpace { #[derive(Debug, Deserialize)] pub struct ContextData { - pub context_set: ContextSetSpace, + pub context_set: Option, + pub tracked_set: Option } #[derive(Debug, Deserialize)] @@ -30,7 +31,7 @@ pub struct ContextData { pub struct ProcessorSpec { // TODO: Properties // properties: Properties - pub context_data: ContextData, + pub context_data: Option, } pub(super) fn parse_pspec(path: &Path) -> Result { diff --git a/jingle_sleigh/src/context/mod.rs b/jingle_sleigh/src/context/mod.rs index ac3031a..bcacadf 100644 --- a/jingle_sleigh/src/context/mod.rs +++ b/jingle_sleigh/src/context/mod.rs @@ -18,6 +18,7 @@ use crate::VarNode; use cxx::{SharedPtr, UniquePtr}; use std::fmt::{Debug, Formatter}; use std::path::Path; +use crate::JingleSleighError::SleighCompilerMutexError; pub struct SleighContext { ctx: UniquePtr, @@ -86,7 +87,7 @@ impl SleighContext { let path_str = abs.to_str().ok_or(LanguageSpecRead)?; match CTX_BUILD_MUTEX.lock() { Ok(make_context) => { - let ctx = make_context(path_str, image.clone()).map_err(|_| SleighInitError)?; + let ctx = make_context(path_str, image.clone()).map_err(|e| SleighInitError(e.to_string()))?; let mut spaces: Vec = Vec::with_capacity(ctx.getNumSpaces() as usize); for idx in 0..ctx.getNumSpaces() { spaces.push(SpaceInfo::from(ctx.getSpaceByIndex(idx))); @@ -98,7 +99,7 @@ impl SleighContext { language_id: language_def.id.clone(), }) } - Err(_) => Err(SleighInitError), + Err(_) => Err(SleighCompilerMutexError), } } diff --git a/jingle_sleigh/src/error.rs b/jingle_sleigh/src/error.rs index 148e054..30977a9 100644 --- a/jingle_sleigh/src/error.rs +++ b/jingle_sleigh/src/error.rs @@ -15,7 +15,7 @@ pub enum JingleSleighError { InvalidLanguageId, /// Attempted to initialize sleigh but something went wrong #[error("Something went wrong putting bytes into sleigh")] - SleighInitError, + SleighInitError(String), /// Unable to load the provided binary image for sleigh #[error("Something went wrong putting bytes into sleigh")] ImageLoadError, @@ -36,6 +36,8 @@ pub enum JingleSleighError { /// Attempted to construct an [Instruction](crate::Instruction) from an empty slice of instructions #[error("Attempted to construct an instruction from an empty slice of instructions")] EmptyInstruction, + #[error("Failure to acquire mutex to sleigh FFI function")] + SleighCompilerMutexError } impl From for std::fmt::Error { From 9d23a2bcfc31df33df5e3fbb25cac3d52f0690bd Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 13 Aug 2024 16:22:32 +0100 Subject: [PATCH 044/146] Update logo --- jingle.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jingle.svg b/jingle.svg index 1220e99..f0783f6 100644 --- a/jingle.svg +++ b/jingle.svg @@ -1 +1 @@ -jingle \ No newline at end of file + \ No newline at end of file From dee9ff161b1fdaec1afcdcb21f371bdf808000a4 Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 26 Aug 2024 12:53:55 +0100 Subject: [PATCH 045/146] Gimli change --- .../src/context/builder/image/gimli.rs | 53 +++++++------------ .../src/context/builder/processor_spec.rs | 1 + 2 files changed, 21 insertions(+), 33 deletions(-) diff --git a/jingle_sleigh/src/context/builder/image/gimli.rs b/jingle_sleigh/src/context/builder/image/gimli.rs index 42ab898..4b37090 100644 --- a/jingle_sleigh/src/context/builder/image/gimli.rs +++ b/jingle_sleigh/src/context/builder/image/gimli.rs @@ -2,9 +2,7 @@ use crate::context::builder::image::Perms; use crate::context::{Image, ImageSection}; use crate::JingleSleighError; use crate::JingleSleighError::ImageLoadError; -use object::elf::{SHF_EXECINSTR, SHF_WRITE}; -use object::macho::{VM_PROT_EXECUTE, VM_PROT_READ, VM_PROT_WRITE}; -use object::{Architecture, Endianness, File, Object, ObjectSection, SectionFlags}; +use object::{Architecture, Endianness, File, Object, ObjectSection, SectionKind}; use tracing::{event, instrument, Level}; impl<'d> TryFrom> for Image { @@ -12,49 +10,38 @@ impl<'d> TryFrom> for Image { #[instrument(skip_all)] fn try_from(value: File) -> Result { let mut img: Image = Image { sections: vec![] }; - for x in value.sections() { + for x in value.sections().filter(|s| matches!(s.kind(), SectionKind::Text)) { let base_address = x.address(); let data = x.data().map_err(|_| ImageLoadError)?.to_vec(); - let perms = map_flags(&x.flags()); - if perms.exec { - let name = x.name().unwrap_or(""); - let start = base_address; - let end = base_address + data.len() as u64; - event!( + let perms = map_kind(&x.kind()); + let name = x.name().unwrap_or(""); + let start = base_address; + let end = base_address + data.len() as u64; + event!( Level::TRACE, "Selecting section {} ({:x}-{:x})", name, start, end ); - img.sections.push(ImageSection { - perms, - data, - base_address: base_address as usize, - }) - } + img.sections.push(ImageSection { + perms, + data, + base_address: base_address as usize, + }) + } + if img.sections.is_empty() { + event!(Level::WARN, "No executable sections loaded from file") } Ok(img) } } -fn map_flags(flags: &SectionFlags) -> Perms { - match flags { - SectionFlags::Elf { sh_flags } => Perms { - exec: (*sh_flags as u32 & SHF_EXECINSTR) == SHF_EXECINSTR, - write: (*sh_flags as u32 & SHF_WRITE) == SHF_WRITE, - read: true, - }, - SectionFlags::MachO { flags, .. } => Perms { - exec: (flags & VM_PROT_EXECUTE) == VM_PROT_EXECUTE, - write: (flags & VM_PROT_WRITE) == VM_PROT_WRITE, - read: (flags & VM_PROT_READ) == VM_PROT_READ, - }, - _ => Perms { - read: false, - write: false, - exec: false, - }, +fn map_kind(kind: &SectionKind) -> Perms { + Perms { + exec: matches!(kind, SectionKind::Text), + write: matches!(kind, SectionKind::Data) && !matches!(kind, SectionKind::ReadOnlyData | SectionKind::ReadOnlyString | SectionKind::ReadOnlyDataWithRel), + read: matches!(kind, SectionKind::Data | SectionKind::ReadOnlyData | SectionKind::ReadOnlyString | SectionKind::ReadOnlyDataWithRel), } } diff --git a/jingle_sleigh/src/context/builder/processor_spec.rs b/jingle_sleigh/src/context/builder/processor_spec.rs index 94278c1..11ab41f 100644 --- a/jingle_sleigh/src/context/builder/processor_spec.rs +++ b/jingle_sleigh/src/context/builder/processor_spec.rs @@ -23,6 +23,7 @@ pub struct ContextSetSpace { #[derive(Debug, Deserialize)] pub struct ContextData { pub context_set: Option, + #[allow(unused)] pub tracked_set: Option } From e5e1b49194049e13c512dc56c00388c478a0edd6 Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 27 Aug 2024 14:23:11 +0100 Subject: [PATCH 046/146] Block tweak --- jingle/src/modeling/block.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/jingle/src/modeling/block.rs b/jingle/src/modeling/block.rs index b1e445b..558f744 100644 --- a/jingle/src/modeling/block.rs +++ b/jingle/src/modeling/block.rs @@ -113,9 +113,14 @@ impl<'ctx> ModeledBlock<'ctx> { ModeledBlock::read(self.z3, self, self.instructions.clone().into_iter()) } - pub fn get_address(&self) -> u64 { + pub fn get_first_address(&self) -> u64 { self.instructions[0].address } + + pub fn get_last_address(&self) -> u64 { + let i =self.instructions.last().unwrap(); + i.address + i.length as u64 + } } impl<'ctx> SpaceManager for ModeledBlock<'ctx> { From 347b2997c1fa88d66a81bd9d82300f4f08066a5b Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 28 Aug 2024 19:32:40 +0100 Subject: [PATCH 047/146] Add input enumeration --- jingle_sleigh/src/pcode/mod.rs | 76 ++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/jingle_sleigh/src/pcode/mod.rs b/jingle_sleigh/src/pcode/mod.rs index a3bae4c..f112615 100644 --- a/jingle_sleigh/src/pcode/mod.rs +++ b/jingle_sleigh/src/pcode/mod.rs @@ -397,6 +397,82 @@ impl PcodeOperation { }) } + pub fn inputs(&self) -> Vec { + match self { + Copy { input, .. } => {vec![input.into()]} + Load { input, .. } => {vec![input.into()]} + Store { input, .. } => {vec![input.into()]} + Branch { input, .. } => {vec![input.into()]} + CBranch { input0, input1, .. } => {vec![input0.into(), input1.into()]} + BranchInd { input, .. } => {vec![input.into()]} + Call { input, .. } => {vec![input.into()]} + CallInd { input, .. } => {vec![input.into()]} + CallOther { inputs, .. } => {inputs.iter().map(|i|i.into()).collect()} + Return { input, .. } => {vec![input.into()]} + IntEqual { input0, input1, .. } => {vec![input0.into(), input1.into()]} + IntNotEqual { input0, input1, .. } => {vec![input0.into(), input1.into()]} + IntSignedLess { input0, input1, .. } => {vec![input0.into(), input1.into()]} + IntSignedLessEqual { input0, input1, .. } => {vec![input0.into(), input1.into()]} + IntLess { input0, input1, .. } => {vec![input0.into(), input1.into()]} + IntLessEqual { input0, input1, .. } => {vec![input0.into(), input1.into()]} + IntSExt { input, .. } => {vec![input.into()]} + IntZExt { input, .. } => {vec![input.into()]} + IntAdd { input0, input1, .. } => {vec![input0.into(), input1.into()]} + IntSub { input0, input1, .. } => {vec![input0.into(), input1.into()]} + IntCarry { input0, input1, .. } => {vec![input0.into(), input1.into()]} + IntSignedCarry { input0, input1, .. } => {vec![input0.into(), input1.into()]} + IntSignedBorrow { input0, input1, .. } => {vec![input0.into(), input1.into()]} + Int2Comp { input, .. } => {vec![input.into()]} + IntNegate { input, .. } => {vec![input.into()]} + IntXor { input0, input1, .. } => {vec![input0.into(), input1.into()]} + IntAnd { input0, input1, .. } => {vec![input0.into(), input1.into()]} + IntOr { input0, input1, .. } => {vec![input0.into(), input1.into()]} + IntLeftShift { input0, input1, .. } => {vec![input0.into(), input1.into()]} + IntRightShift { input0, input1, .. } => {vec![input0.into(), input1.into()]} + IntSignedRightShift { input0, input1, .. } => {vec![input0.into(), input1.into()]} + IntMult { input0, input1, .. } => {vec![input0.into(), input1.into()]} + IntDiv { input0, input1, .. } => {vec![input0.into(), input1.into()]} + IntSignedDiv { input0, input1, .. } => {vec![input0.into(), input1.into()]} + IntRem { input0, input1, .. } => {vec![input0.into(), input1.into()]} + IntSignedRem { input0, input1, .. } => {vec![input0.into(), input1.into()]} + BoolNegate { input, .. } => {vec![input.into()]} + BoolXor { input0, input1, .. } => {vec![input0.into(), input1.into()]} + BoolAnd { input0, input1, .. } => {vec![input0.into(), input1.into()]} + BoolOr { input0, input1, .. } => {vec![input0.into(), input1.into()]} + FloatEqual { input0, input1, .. } => {vec![input0.into(), input1.into()]} + FloatNotEqual { input0, input1, .. } => {vec![input0.into(), input1.into()]} + FloatLess { input0, input1, .. } => {vec![input0.into(), input1.into()]} + FloatLessEqual { input0, input1, .. } => {vec![input0.into(), input1.into()]} + FloatNaN { input, .. } => {vec![input.into()]} + FloatAdd { input0, input1, .. } => {vec![input0.into(), input1.into()]} + FloatDiv { input0, input1, .. } => {vec![input0.into(), input1.into()]} + FloatMult { input0, input1, .. } => {vec![input0.into(), input1.into()]} + FloatSub { input0, input1, .. } => {vec![input0.into(), input1.into()]} + FloatNeg { input, .. } => {vec![input.into()]} + FloatAbs { input, .. } => {vec![input.into()]} + FloatSqrt { input, .. } => {vec![input.into()]} + FloatIntToFloat { input, .. } => {vec![input.into()]} + FloatFloatToFloat { input, .. } => {vec![input.into()]} + FloatTrunc { input, .. } => {vec![input.into()]} + FloatCeil { input, .. } => {vec![input.into()]} + FloatFloor { input, .. } => {vec![input.into()]} + FloatRound { input, .. } => {vec![input.into()]} + MultiEqual { input0, input1, .. } => {vec![input0.into(), input1.into()]} + Indirect { input0, input1, .. } => {vec![input0.into(), input1.into()]} + Piece { input0, input1, .. } => {vec![input0.into(), input1.into()]} + SubPiece { input0, input1, .. } => {vec![input0.into(), input1.into()]} + Cast { input, .. } => {vec![input.into()]} + PtrAdd { input0, input1, .. } => {vec![input0.into(), input1.into()]} + PtrSub { input0, input1, .. } => {vec![input0.into(), input1.into()]} + SegmentOp { input0, input1, .. } => {vec![input0.into(), input1.into()]} + CPoolRef { input0, input1, .. } => {vec![input0.into(), input1.into()]} + New { input, .. } => {vec![input.into()]} + Insert { input0, input1, .. } => {vec![input0.into(), input1.into()]} + Extract { input0, .. } => {vec![input0.into()]} + PopCount { input, .. } => {vec![input.into()]} + LzCount { input, .. } => {vec![input.into()]} + } + } pub fn output(&self) -> Option { match self { Copy { output, .. } => Some(GeneralizedVarNode::from(output)), From 600e720607fa2c6dbc11161f501e0d17e53e0724 Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 28 Aug 2024 20:14:27 +0100 Subject: [PATCH 048/146] Add constraint --- jingle/src/modeling/mod.rs | 12 ++++++++++-- jingle/src/varnode/mod.rs | 1 + 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/jingle/src/modeling/mod.rs b/jingle/src/modeling/mod.rs index 3b2d3ec..3db40b3 100644 --- a/jingle/src/modeling/mod.rs +++ b/jingle/src/modeling/mod.rs @@ -130,8 +130,14 @@ pub trait ModelingContext<'ctx>: SpaceManager + Debug + Sized { .filter(|v| self.should_varnode_constrain(v)) { let ours = self.get_final_state().read_resolved(vn)?; - let other = other.get_final_state().read_resolved(vn)?; - output_terms.push(ours._eq(&other).simplify()); + let other_bv = other.get_final_state().read_resolved(vn)?; + output_terms.push(ours._eq(&other_bv).simplify()); + if let Indirect(a) = vn{ + let ours = self.get_final_state().read_varnode(&a.pointer_location)?; + let other = other.get_final_state().read_varnode(&a.pointer_location)?; + output_terms.push(ours._eq(&other).simplify()); + + } } let imp_terms: Vec<&Bool> = output_terms.iter().collect(); let outputs_pairwise_equal = Bool::and(self.get_z3(), imp_terms.as_slice()); @@ -220,6 +226,7 @@ pub(crate) trait TranslationContext<'ctx>: ModelingContext<'ctx> { .clone(); self.track_input(&Indirect(ResolvedIndirectVarNode { pointer, + pointer_location: indirect.pointer_location.clone(), access_size_bytes: indirect.access_size_bytes, pointer_space_idx: indirect.pointer_space_index, })); @@ -242,6 +249,7 @@ pub(crate) trait TranslationContext<'ctx>: ModelingContext<'ctx> { let pointer = self.read_and_track(indirect.pointer_location.clone().into())?; self.track_output(&Indirect(ResolvedIndirectVarNode { pointer, + pointer_location: indirect.pointer_location.clone(), access_size_bytes: indirect.access_size_bytes, pointer_space_idx: indirect.pointer_space_index, })); diff --git a/jingle/src/varnode/mod.rs b/jingle/src/varnode/mod.rs index adcfc6d..b255e64 100644 --- a/jingle/src/varnode/mod.rs +++ b/jingle/src/varnode/mod.rs @@ -12,6 +12,7 @@ use z3::ast::BV; pub struct ResolvedIndirectVarNode<'ctx> { pub pointer_space_idx: usize, pub pointer: BV<'ctx>, + pub pointer_location: VarNode, pub access_size_bytes: usize, } From 854dd20c6602a837b638f6c3471f17f71939b44e Mon Sep 17 00:00:00 2001 From: Mark Date: Thu, 29 Aug 2024 10:00:52 +0100 Subject: [PATCH 049/146] Explicitly add pointer dependencies to input call --- jingle_sleigh/src/pcode/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jingle_sleigh/src/pcode/mod.rs b/jingle_sleigh/src/pcode/mod.rs index f112615..1ea2b86 100644 --- a/jingle_sleigh/src/pcode/mod.rs +++ b/jingle_sleigh/src/pcode/mod.rs @@ -400,8 +400,8 @@ impl PcodeOperation { pub fn inputs(&self) -> Vec { match self { Copy { input, .. } => {vec![input.into()]} - Load { input, .. } => {vec![input.into()]} - Store { input, .. } => {vec![input.into()]} + Load { input, .. } => {vec![input.into(), input.pointer_location.clone().into()]} + Store { input, output } => {vec![input.into(), output.pointer_location.clone().into()]} Branch { input, .. } => {vec![input.into()]} CBranch { input0, input1, .. } => {vec![input0.into(), input1.into()]} BranchInd { input, .. } => {vec![input.into()]} From 500cd55decbc63ae5f050c16adae9358480deb84 Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 3 Sep 2024 16:26:44 +0100 Subject: [PATCH 050/146] Add arch and fmt --- jingle/src/modeling/block.rs | 2 +- jingle/src/modeling/mod.rs | 3 +-- jingle_sleigh/src/context/builder/image/gimli.rs | 5 ++++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/jingle/src/modeling/block.rs b/jingle/src/modeling/block.rs index 558f744..4b56f3a 100644 --- a/jingle/src/modeling/block.rs +++ b/jingle/src/modeling/block.rs @@ -118,7 +118,7 @@ impl<'ctx> ModeledBlock<'ctx> { } pub fn get_last_address(&self) -> u64 { - let i =self.instructions.last().unwrap(); + let i = self.instructions.last().unwrap(); i.address + i.length as u64 } } diff --git a/jingle/src/modeling/mod.rs b/jingle/src/modeling/mod.rs index 3db40b3..bcc0521 100644 --- a/jingle/src/modeling/mod.rs +++ b/jingle/src/modeling/mod.rs @@ -132,11 +132,10 @@ pub trait ModelingContext<'ctx>: SpaceManager + Debug + Sized { let ours = self.get_final_state().read_resolved(vn)?; let other_bv = other.get_final_state().read_resolved(vn)?; output_terms.push(ours._eq(&other_bv).simplify()); - if let Indirect(a) = vn{ + if let Indirect(a) = vn { let ours = self.get_final_state().read_varnode(&a.pointer_location)?; let other = other.get_final_state().read_varnode(&a.pointer_location)?; output_terms.push(ours._eq(&other).simplify()); - } } let imp_terms: Vec<&Bool> = output_terms.iter().collect(); diff --git a/jingle_sleigh/src/context/builder/image/gimli.rs b/jingle_sleigh/src/context/builder/image/gimli.rs index 4b37090..f84d6f5 100644 --- a/jingle_sleigh/src/context/builder/image/gimli.rs +++ b/jingle_sleigh/src/context/builder/image/gimli.rs @@ -62,7 +62,10 @@ pub fn map_gimli_architecture(file: &File) -> Option<&'static str> { }, Architecture::I386 => Some("x86:LE:32:default"), Architecture::X86_64 => Some("x86:LE:64:default"), - + Architecture::PowerPc64 => match file.endianness(){ + Endianness::Little => Some("PowerPC:LE:64:default"), + Endianness::Big => Some("PowerPC:BE:64:default") + } Architecture::Xtensa => match file.endianness() { Endianness::Little => Some("Xtensa:LE:32:default"), Endianness::Big => Some("Xtensa:BE:32:default"), From 24ad9e73097465f7eee2e137756ff1114bc88742 Mon Sep 17 00:00:00 2001 From: Mark Date: Thu, 10 Oct 2024 12:00:54 +0100 Subject: [PATCH 051/146] Initial context stuff --- jingle_sleigh/CMakeLists.txt | 5 +- jingle_sleigh/src/ffi/cpp/context.cpp | 101 +++++--------------- jingle_sleigh/src/ffi/cpp/context.h | 11 +-- jingle_sleigh/src/ffi/cpp/exception.h | 3 + jingle_sleigh/src/ffi/cpp/image_context.cpp | 88 +++++++++++++++++ jingle_sleigh/src/ffi/cpp/image_context.h | 35 +++++++ 6 files changed, 160 insertions(+), 83 deletions(-) create mode 100644 jingle_sleigh/src/ffi/cpp/image_context.cpp create mode 100644 jingle_sleigh/src/ffi/cpp/image_context.h diff --git a/jingle_sleigh/CMakeLists.txt b/jingle_sleigh/CMakeLists.txt index 5066462..e657186 100644 --- a/jingle_sleigh/CMakeLists.txt +++ b/jingle_sleigh/CMakeLists.txt @@ -30,7 +30,10 @@ add_library(jingle_sleigh_cpp src/ffi/cpp/compile.cpp src/ffi/cpp/addrspace_handle.cpp src/ffi/cpp/addrspace_manager_handle.cpp - src/ffi/cpp/context.h) + src/ffi/cpp/context.h + src/ffi/cpp/image_context.cpp + src/ffi/cpp/image_context.h + src/ffi/cpp/exception.h) add_executable(sleigh_compile src/ffi/cpp/sleigh/address.cc diff --git a/jingle_sleigh/src/ffi/cpp/context.cpp b/jingle_sleigh/src/ffi/cpp/context.cpp index a710505..7803a2d 100644 --- a/jingle_sleigh/src/ffi/cpp/context.cpp +++ b/jingle_sleigh/src/ffi/cpp/context.cpp @@ -6,52 +6,6 @@ #include "jingle_sleigh/src/ffi/instruction.rs.h" #include "sleigh/loadimage.hh" -class PcodeCacher : public ghidra::PcodeEmit { -public: - rust::Vec ops; - - PcodeCacher() = default; - - void dump(const ghidra::Address &addr, ghidra::OpCode opc, ghidra::VarnodeData *outvar, ghidra::VarnodeData *vars, - ghidra::int4 isize) override { - RawPcodeOp op; - op.op = opc; - op.has_output = false; - if (outvar != nullptr && outvar->space != nullptr) { - op.has_output = true; - op.output.offset = outvar->offset; - op.output.size = outvar->size; - op.output.space = std::make_unique(AddrSpaceHandle(outvar->space)); - outvar->space->getType(); - } - op.inputs.reserve(isize); - for (int i = 0; i < isize; i++) { - VarnodeInfoFFI info; - info.space = std::make_unique(vars[i].space); - info.size = vars[i].size; - info.offset = vars[i].offset; - op.space = std::make_unique(addr.getSpace()); - op.inputs.emplace_back(std::move(info)); - } - ops.emplace_back(op); - - } -}; - -class AssemblyCacher : public ghidra::AssemblyEmit { -public: - rust::String mnem; - rust::String body; - - AssemblyCacher() : mnem(""), body("") { - - }; - - void dump(const ghidra::Address &addr, const std::string &mnem, const std::string &body) override { - this->mnem = mnem; - this->body = body; - } -}; DummyLoadImage::DummyLoadImage() : ghidra::LoadImage("jingle") { img = Image{}; @@ -63,6 +17,7 @@ DummyLoadImage::DummyLoadImage(Image image) : ghidra::LoadImage("jingle") { void DummyLoadImage::loadFill(ghidra::uint1 *ptr, ghidra::int4 size, const ghidra::Address &addr) { size_t offset = addr.getOffset(); + size_t bytes_written = 0; for (const auto §ion: img.sections) { size_t start = section.base_address; size_t end = start + section.data.size(); @@ -71,11 +26,18 @@ void DummyLoadImage::loadFill(ghidra::uint1 *ptr, ghidra::int4 size, const ghidr size_t start_idx = offset - start; std::memcpy(ptr, §ion.data[start_idx], len); offset = offset + len; + bytes_written += len; } } for (size_t i = offset; i < size; ++i) { ptr[i] = 0; } + if (bytes_written == 0) { + ghidra::ostringstream errmsg; + errmsg << "Unable to load " << std::dec << size << " bytes at " << addr.getShortcut(); + addr.printRaw(errmsg); + throw ghidra::DataUnavailError(errmsg.str()); + } } void DummyLoadImage::adjustVma(long adjust) {} @@ -84,12 +46,12 @@ std::string DummyLoadImage::getArchType() const { return "placeholder"; } -ContextFFI::ContextFFI(rust::Str slaPath, Image image) { +ContextFFI::ContextFFI(rust::Str slaPath) { ghidra::AttributeId::initialize(); ghidra::ElementId::initialize(); - this->img = DummyLoadImage(std::move(image)); - documentStorage = ghidra::DocumentStorage(); + DummyLoadImage img = DummyLoadImage(Image()); + ghidra::DocumentStorage documentStorage = ghidra::DocumentStorage(); std::stringstream sleighfilename; sleighfilename << ""; @@ -99,44 +61,27 @@ ContextFFI::ContextFFI(rust::Str slaPath, Image image) { ghidra::Document *doc = documentStorage.parseDocument(sleighfilename); ghidra::Element *root = doc->getRoot(); documentStorage.registerTag(root); - sleigh = std::make_unique(&img, &contextDatabase); - sleigh->initialize(documentStorage); + sleigh = ghidra::Sleigh(&img, &c_db); + sleigh.initialize(documentStorage); } void ContextFFI::set_initial_context(rust::Str name, uint32_t val) { - sleigh->setContextDefault(name.operator std::string(), val); + sleigh.setContextDefault(name.operator std::string(), val); } -InstructionFFI ContextFFI::get_one_instruction(uint64_t offset) const { - PcodeCacher pcode; - AssemblyCacher assembly; - ghidra::Address a = ghidra::Address(sleigh->getDefaultCodeSpace(), offset); - sleigh->printAssembly(assembly, a); - sleigh->oneInstruction(pcode, a); - size_t length = sleigh->instructionLength(a); - InstructionFFI i; - Disassembly d; - i.ops = std::move(pcode.ops); - d.args = std::move(assembly.body); - d.mnemonic = std::move(assembly.mnem); - i.disassembly = std::move(d); - i.address = offset; - i.length = length; - return i; -} std::shared_ptr ContextFFI::getSpaceByIndex(ghidra::int4 idx) const { - return std::make_shared(sleigh->getSpace(idx)); + return std::make_shared(sleigh.getSpace(idx)); } ghidra::int4 ContextFFI::getNumSpaces() const { - return sleigh->numSpaces(); + return sleigh.numSpaces(); } VarnodeInfoFFI ContextFFI::getRegister(rust::Str name) const { - ghidra::VarnodeData vn = sleigh->getRegister(name.operator std::string()); + ghidra::VarnodeData vn = sleigh.getRegister(name.operator std::string()); VarnodeInfoFFI info; info.space = std::make_unique(vn.space); info.size = vn.size; @@ -145,7 +90,7 @@ VarnodeInfoFFI ContextFFI::getRegister(rust::Str name) const { }; rust::Str ContextFFI::getRegisterName(VarnodeInfoFFI vn) const { - std::string name = sleigh->getRegisterName(vn.space->getRaw(), vn.offset, vn.size); + std::string name = sleigh.getRegisterName(vn.space->getRaw(), vn.offset, vn.size); return {name}; } @@ -170,10 +115,14 @@ RegisterInfoFFI collectRegInfo(std::tuple el) rust::Vec ContextFFI::getRegisters() const { std::map reglist; rust::Vec v; - sleigh->getAllRegisters(reglist); + sleigh.getAllRegisters(reglist); v.reserve(reglist.size()); - for (auto const& vn : reglist){ + for (auto const &vn: reglist) { v.emplace_back(collectRegInfo(vn)); } return v; -} \ No newline at end of file +} + +std::unique_ptr ContextFFI::makeImageContext(Image img) { + return std::unique_ptr(sleigh, img); +} diff --git a/jingle_sleigh/src/ffi/cpp/context.h b/jingle_sleigh/src/ffi/cpp/context.h index 9796919..dcf39ec 100644 --- a/jingle_sleigh/src/ffi/cpp/context.h +++ b/jingle_sleigh/src/ffi/cpp/context.h @@ -9,6 +9,7 @@ #include "sleigh/sleigh.hh" #include "jingle_sleigh/src/ffi/image.rs.h" #include "sleigh/loadimage.hh" +#include "image_context.h" class DummyLoadImage : public ghidra::LoadImage { Image img; @@ -27,18 +28,16 @@ class DummyLoadImage : public ghidra::LoadImage { class ContextFFI { - DummyLoadImage img; - ghidra::DocumentStorage documentStorage; - ghidra::ContextInternal contextDatabase; - std::unique_ptr sleigh; + ghidra::Sleigh sleigh; + ghidra::ContextInternal c_db; + DummyLoadImage image; public: explicit ContextFFI(rust::Str slaPath, Image img); void set_initial_context(rust::Str name, uint32_t val); - InstructionFFI get_one_instruction(uint64_t offset) const; - + std::unique_ptr makeImageContext(Image img); [[nodiscard]] std::shared_ptr getSpaceByIndex(ghidra::int4 idx) const; diff --git a/jingle_sleigh/src/ffi/cpp/exception.h b/jingle_sleigh/src/ffi/cpp/exception.h index 8151c57..e6a5d17 100644 --- a/jingle_sleigh/src/ffi/cpp/exception.h +++ b/jingle_sleigh/src/ffi/cpp/exception.h @@ -4,6 +4,7 @@ #include "sleigh/error.hh" #include "sleigh/xml.hh" +#include "sleigh/loadimage.hh" namespace rust { namespace behavior { @@ -15,6 +16,8 @@ namespace rust { fail(e.explain); } catch (const ghidra::DecoderError &e) { fail(e.explain); + } catch (const ghidra::DataUnavailError &e){ + fail(e.explain); } catch (const std::exception &e) { fail(e.what()); } diff --git a/jingle_sleigh/src/ffi/cpp/image_context.cpp b/jingle_sleigh/src/ffi/cpp/image_context.cpp new file mode 100644 index 0000000..95a2760 --- /dev/null +++ b/jingle_sleigh/src/ffi/cpp/image_context.cpp @@ -0,0 +1,88 @@ +// +// Created by mark denhoed on 10/10/24. +// +#include "image_context.h" +#include "context.h" + +#include + +class PcodeCacher : public ghidra::PcodeEmit { +public: + rust::Vec ops; + + PcodeCacher() = default; + + void dump(const ghidra::Address &addr, ghidra::OpCode opc, ghidra::VarnodeData *outvar, ghidra::VarnodeData *vars, + ghidra::int4 isize) override { + RawPcodeOp op; + op.op = opc; + op.has_output = false; + if (outvar != nullptr && outvar->space != nullptr) { + op.has_output = true; + op.output.offset = outvar->offset; + op.output.size = outvar->size; + op.output.space = std::make_unique(AddrSpaceHandle(outvar->space)); + outvar->space->getType(); + } + op.inputs.reserve(isize); + for (int i = 0; i < isize; i++) { + VarnodeInfoFFI info; + info.space = std::make_unique(vars[i].space); + info.size = vars[i].size; + info.offset = vars[i].offset; + op.space = std::make_unique(addr.getSpace()); + op.inputs.emplace_back(std::move(info)); + } + ops.emplace_back(op); + + } +}; + +class AssemblyCacher : public ghidra::AssemblyEmit { +public: + rust::String mnem; + rust::String body; + + AssemblyCacher() : mnem(""), body("") { + + }; + + void dump(const ghidra::Address &addr, const std::string &mnem, const std::string &body) override { + this->mnem = mnem; + this->body = body; + } +}; + +SleighImage::SleighImage(Image img, ghidra::Sleigh sl) { + sl = sl; + image = DummyLoadImage(img); + sl.reset(&image, &c_db); +} + + + +std::shared_ptr ContextFFI::getSpaceByIndex(ghidra::int4 idx) const { + return std::make_shared(sleigh.getSpace(idx)); +} + +ghidra::int4 ContextFFI::getNumSpaces() const { + return sleigh.numSpaces(); +} + +VarnodeInfoFFI ContextFFI::getRegister(rust::Str name) const { + ghidra::VarnodeData vn = sleigh.getRegister(name.operator std::string()); + VarnodeInfoFFI info; + info.space = std::make_unique(vn.space); + info.size = vn.size; + info.offset = vn.offset; + return info; +}; + +rust::Str ContextFFI::getRegisterName(VarnodeInfoFFI vn) const { + std::string name = sleigh.getRegisterName(vn.space->getRaw(), vn.offset, vn.size); + return {name}; +} + +std::unique_ptr makeContext(rust::Str slaPath, Image img) { + return std::make_unique(slaPath, std::move(img)); +} \ No newline at end of file diff --git a/jingle_sleigh/src/ffi/cpp/image_context.h b/jingle_sleigh/src/ffi/cpp/image_context.h new file mode 100644 index 0000000..65a4113 --- /dev/null +++ b/jingle_sleigh/src/ffi/cpp/image_context.h @@ -0,0 +1,35 @@ +// +// Created by toolCHAINZ on 10/10/24. +// + +#ifndef JINGLE_SLEIGH_IMAGE_CONTEXT_H +#define JINGLE_SLEIGH_IMAGE_CONTEXT_H + +#include "sleigh/sleigh.hh" +#include "rust/cxx.h" +#include "jingle_sleigh/src/ffi/image.rs.h" +#include "context.h" + +class SleighImage{ + ghidra::Sleigh sl; + ghidra::ContextInternal c_db; + DummyLoadImage image; + +public: + SleighImage(ghidra::Sleigh, Image); + + InstructionFFI get_one_instruction(uint64_t offset) const; + + + [[nodiscard]] std::shared_ptr getSpaceByIndex(ghidra::int4 idx) const; + + int getNumSpaces() const; + + VarnodeInfoFFI getRegister(rust::Str name) const; + + rust::Str getRegisterName(VarnodeInfoFFI name) const; + + rust::Vec getRegisters() const; +}; + +#endif //JINGLE_SLEIGH_IMAGE_CONTEXT_H From e9417e7859c37da844a5fe3b72710dd50ac3a29e Mon Sep 17 00:00:00 2001 From: Mark Date: Thu, 10 Oct 2024 14:13:53 +0100 Subject: [PATCH 052/146] Fixed up C++ build side, now to fix FFI --- jingle_sleigh/src/ffi/context_ffi.rs | 4 +- jingle_sleigh/src/ffi/cpp/context.cpp | 52 +++---------------- jingle_sleigh/src/ffi/cpp/context.h | 21 ++------ .../src/ffi/cpp/dummy_load_image.cpp | 40 ++++++++++++++ jingle_sleigh/src/ffi/cpp/dummy_load_image.h | 25 +++++++++ jingle_sleigh/src/ffi/cpp/image_context.cpp | 26 ++++------ jingle_sleigh/src/ffi/cpp/image_context.h | 7 +-- 7 files changed, 91 insertions(+), 84 deletions(-) create mode 100644 jingle_sleigh/src/ffi/cpp/dummy_load_image.cpp create mode 100644 jingle_sleigh/src/ffi/cpp/dummy_load_image.h diff --git a/jingle_sleigh/src/ffi/context_ffi.rs b/jingle_sleigh/src/ffi/context_ffi.rs index 03b09e3..243d796 100644 --- a/jingle_sleigh/src/ffi/context_ffi.rs +++ b/jingle_sleigh/src/ffi/context_ffi.rs @@ -25,10 +25,10 @@ pub(crate) mod bridge { include!("jingle_sleigh/src/ffi/cpp/exception.h"); pub(crate) type ContextFFI; - pub(super) fn makeContext(slaPath: &str, img: Image) -> Result>; + pub(super) fn makeContext(slaPath: &str) -> Result>; pub(crate) fn set_initial_context(self: Pin<&mut ContextFFI>, name: &str, value: u32); - pub(crate) fn get_one_instruction(&self, offset: u64) -> Result; + // pub(crate) fn get_one_instruction(&self, offset: u64) -> Result; pub(crate) fn getSpaceByIndex(&self, idx: i32) -> SharedPtr; pub(crate) fn getNumSpaces(&self) -> i32; diff --git a/jingle_sleigh/src/ffi/cpp/context.cpp b/jingle_sleigh/src/ffi/cpp/context.cpp index 7803a2d..b470843 100644 --- a/jingle_sleigh/src/ffi/cpp/context.cpp +++ b/jingle_sleigh/src/ffi/cpp/context.cpp @@ -3,50 +3,12 @@ #include #include +#include "image_context.h" #include "jingle_sleigh/src/ffi/instruction.rs.h" #include "sleigh/loadimage.hh" -DummyLoadImage::DummyLoadImage() : ghidra::LoadImage("jingle") { - img = Image{}; -} - -DummyLoadImage::DummyLoadImage(Image image) : ghidra::LoadImage("jingle") { - img = std::move(image); -} - -void DummyLoadImage::loadFill(ghidra::uint1 *ptr, ghidra::int4 size, const ghidra::Address &addr) { - size_t offset = addr.getOffset(); - size_t bytes_written = 0; - for (const auto §ion: img.sections) { - size_t start = section.base_address; - size_t end = start + section.data.size(); - if (start <= offset && offset < end) { - size_t len = std::min((size_t) size, (size_t) end - (size_t) offset); - size_t start_idx = offset - start; - std::memcpy(ptr, §ion.data[start_idx], len); - offset = offset + len; - bytes_written += len; - } - } - for (size_t i = offset; i < size; ++i) { - ptr[i] = 0; - } - if (bytes_written == 0) { - ghidra::ostringstream errmsg; - errmsg << "Unable to load " << std::dec << size << " bytes at " << addr.getShortcut(); - addr.printRaw(errmsg); - throw ghidra::DataUnavailError(errmsg.str()); - } -} - -void DummyLoadImage::adjustVma(long adjust) {} - -std::string DummyLoadImage::getArchType() const { - return "placeholder"; -} - -ContextFFI::ContextFFI(rust::Str slaPath) { +ContextFFI::ContextFFI(rust::Str slaPath): sleigh(&image, &c_db) { ghidra::AttributeId::initialize(); ghidra::ElementId::initialize(); @@ -61,8 +23,8 @@ ContextFFI::ContextFFI(rust::Str slaPath) { ghidra::Document *doc = documentStorage.parseDocument(sleighfilename); ghidra::Element *root = doc->getRoot(); documentStorage.registerTag(root); - sleigh = ghidra::Sleigh(&img, &c_db); - sleigh.initialize(documentStorage); + this->sleigh = ghidra::Sleigh(&img, &c_db); + this->sleigh.initialize(documentStorage); } @@ -94,8 +56,8 @@ rust::Str ContextFFI::getRegisterName(VarnodeInfoFFI vn) const { return {name}; } -std::unique_ptr makeContext(rust::Str slaPath, Image img) { - return std::make_unique(slaPath, std::move(img)); +std::unique_ptr makeContext(rust::Str slaPath) { + return std::make_unique(slaPath); } VarnodeInfoFFI varnodeToFFI(ghidra::VarnodeData vn) { @@ -124,5 +86,5 @@ rust::Vec ContextFFI::getRegisters() const { } std::unique_ptr ContextFFI::makeImageContext(Image img) { - return std::unique_ptr(sleigh, img); + return std::unique_ptr(new SleighImage(img, sleigh)); } diff --git a/jingle_sleigh/src/ffi/cpp/context.h b/jingle_sleigh/src/ffi/cpp/context.h index dcf39ec..090af71 100644 --- a/jingle_sleigh/src/ffi/cpp/context.h +++ b/jingle_sleigh/src/ffi/cpp/context.h @@ -10,22 +10,7 @@ #include "jingle_sleigh/src/ffi/image.rs.h" #include "sleigh/loadimage.hh" #include "image_context.h" - -class DummyLoadImage : public ghidra::LoadImage { - Image img; -public: - DummyLoadImage(); - - DummyLoadImage(Image img); - - void loadFill(ghidra::uint1 *ptr, ghidra::int4 size, const ghidra::Address &addr) override; - - std::string getArchType(void) const override; - - void adjustVma(long adjust) override; - -}; - +#include "dummy_load_image.h" class ContextFFI { ghidra::Sleigh sleigh; @@ -33,7 +18,7 @@ class ContextFFI { DummyLoadImage image; public: - explicit ContextFFI(rust::Str slaPath, Image img); + explicit ContextFFI(rust::Str slaPath); void set_initial_context(rust::Str name, uint32_t val); @@ -54,6 +39,6 @@ RegisterInfoFFI collectRegInfo(std::tuple el) VarnodeInfoFFI varnodeToFFI(ghidra::VarnodeData vn); -std::unique_ptr makeContext(rust::Str slaPath, Image img); +std::unique_ptr makeContext(rust::Str slaPath); #endif //JINGLE_SLEIGH_CONTEXT_H diff --git a/jingle_sleigh/src/ffi/cpp/dummy_load_image.cpp b/jingle_sleigh/src/ffi/cpp/dummy_load_image.cpp new file mode 100644 index 0000000..dd26e49 --- /dev/null +++ b/jingle_sleigh/src/ffi/cpp/dummy_load_image.cpp @@ -0,0 +1,40 @@ +#include "dummy_load_image.h" + +DummyLoadImage::DummyLoadImage() : ghidra::LoadImage("jingle") { + img = Image{}; +} + +DummyLoadImage::DummyLoadImage(Image image) : ghidra::LoadImage("jingle") { + img = std::move(image); +} + +void DummyLoadImage::loadFill(ghidra::uint1 *ptr, ghidra::int4 size, const ghidra::Address &addr) { + size_t offset = addr.getOffset(); + size_t bytes_written = 0; + for (const auto §ion: img.sections) { + size_t start = section.base_address; + size_t end = start + section.data.size(); + if (start <= offset && offset < end) { + size_t len = std::min((size_t) size, (size_t) end - (size_t) offset); + size_t start_idx = offset - start; + std::memcpy(ptr, §ion.data[start_idx], len); + offset = offset + len; + bytes_written += len; + } + } + for (size_t i = offset; i < size; ++i) { + ptr[i] = 0; + } + if (bytes_written == 0) { + ghidra::ostringstream errmsg; + errmsg << "Unable to load " << std::dec << size << " bytes at " << addr.getShortcut(); + addr.printRaw(errmsg); + throw ghidra::DataUnavailError(errmsg.str()); + } +} + +void DummyLoadImage::adjustVma(long adjust) {} + +std::string DummyLoadImage::getArchType() const { + return "placeholder"; +} diff --git a/jingle_sleigh/src/ffi/cpp/dummy_load_image.h b/jingle_sleigh/src/ffi/cpp/dummy_load_image.h new file mode 100644 index 0000000..935aeea --- /dev/null +++ b/jingle_sleigh/src/ffi/cpp/dummy_load_image.h @@ -0,0 +1,25 @@ + +#ifndef JINGLE_SLEIGH_DUMMY_LOAD_IMAGE_H +#define JINGLE_SLEIGH_DUMMY_LOAD_IMAGE_H + + +#include "jingle_sleigh/src/ffi/image.rs.h" +#include "sleigh/loadimage.hh" + +class DummyLoadImage : public ghidra::LoadImage { + Image img; +public: + + DummyLoadImage(); + + DummyLoadImage(Image img); + + void loadFill(ghidra::uint1 *ptr, ghidra::int4 size, const ghidra::Address &addr) override; + + std::string getArchType(void) const override; + + void adjustVma(long adjust) override; + +}; + +#endif //JINGLE_SLEIGH_DUMMY_LOAD_IMAGE_H diff --git a/jingle_sleigh/src/ffi/cpp/image_context.cpp b/jingle_sleigh/src/ffi/cpp/image_context.cpp index 95a2760..60b33e0 100644 --- a/jingle_sleigh/src/ffi/cpp/image_context.cpp +++ b/jingle_sleigh/src/ffi/cpp/image_context.cpp @@ -2,7 +2,7 @@ // Created by mark denhoed on 10/10/24. // #include "image_context.h" -#include "context.h" +#include "dummy_load_image.h" #include @@ -53,24 +53,22 @@ class AssemblyCacher : public ghidra::AssemblyEmit { } }; -SleighImage::SleighImage(Image img, ghidra::Sleigh sl) { - sl = sl; - image = DummyLoadImage(img); +SleighImage::SleighImage(Image img, ghidra::Sleigh sl): sl(sl), image(DummyLoadImage(img)) { sl.reset(&image, &c_db); } -std::shared_ptr ContextFFI::getSpaceByIndex(ghidra::int4 idx) const { - return std::make_shared(sleigh.getSpace(idx)); +std::shared_ptr SleighImage::getSpaceByIndex(ghidra::int4 idx) const { + return std::make_shared(sl.getSpace(idx)); } -ghidra::int4 ContextFFI::getNumSpaces() const { - return sleigh.numSpaces(); +ghidra::int4 SleighImage::getNumSpaces() const { + return sl.numSpaces(); } -VarnodeInfoFFI ContextFFI::getRegister(rust::Str name) const { - ghidra::VarnodeData vn = sleigh.getRegister(name.operator std::string()); +VarnodeInfoFFI SleighImage::getRegister(rust::Str name) const { + ghidra::VarnodeData vn = sl.getRegister(name.operator std::string()); VarnodeInfoFFI info; info.space = std::make_unique(vn.space); info.size = vn.size; @@ -78,11 +76,7 @@ VarnodeInfoFFI ContextFFI::getRegister(rust::Str name) const { return info; }; -rust::Str ContextFFI::getRegisterName(VarnodeInfoFFI vn) const { - std::string name = sleigh.getRegisterName(vn.space->getRaw(), vn.offset, vn.size); +rust::Str SleighImage::getRegisterName(VarnodeInfoFFI vn) const { + std::string name = sl.getRegisterName(vn.space->getRaw(), vn.offset, vn.size); return {name}; } - -std::unique_ptr makeContext(rust::Str slaPath, Image img) { - return std::make_unique(slaPath, std::move(img)); -} \ No newline at end of file diff --git a/jingle_sleigh/src/ffi/cpp/image_context.h b/jingle_sleigh/src/ffi/cpp/image_context.h index 65a4113..dc587fb 100644 --- a/jingle_sleigh/src/ffi/cpp/image_context.h +++ b/jingle_sleigh/src/ffi/cpp/image_context.h @@ -5,10 +5,12 @@ #ifndef JINGLE_SLEIGH_IMAGE_CONTEXT_H #define JINGLE_SLEIGH_IMAGE_CONTEXT_H +#include "addrspace_handle.h" +#include "jingle_sleigh/src/ffi/instruction.rs.h" #include "sleigh/sleigh.hh" #include "rust/cxx.h" #include "jingle_sleigh/src/ffi/image.rs.h" -#include "context.h" +#include "dummy_load_image.h" class SleighImage{ ghidra::Sleigh sl; @@ -16,11 +18,10 @@ class SleighImage{ DummyLoadImage image; public: - SleighImage(ghidra::Sleigh, Image); + SleighImage(Image img, ghidra::Sleigh& sl); InstructionFFI get_one_instruction(uint64_t offset) const; - [[nodiscard]] std::shared_ptr getSpaceByIndex(ghidra::int4 idx) const; int getNumSpaces() const; From f2bf49953b6031819a2eb1690036ca3a77f4b21a Mon Sep 17 00:00:00 2001 From: Mark Date: Thu, 10 Oct 2024 18:57:22 +0100 Subject: [PATCH 053/146] Fix stuff and fmt. Builds, but need to make sure it actually works --- jingle_sleigh/CMakeLists.txt | 4 +- jingle_sleigh/build.rs | 3 + .../src/context/builder/image/gimli.rs | 39 ++- jingle_sleigh/src/context/builder/mod.rs | 29 +- .../src/context/builder/processor_spec.rs | 2 +- jingle_sleigh/src/context/mod.rs | 73 +---- .../sleigh_image/instruction_iterator.rs | 96 ++++++ jingle_sleigh/src/context/sleigh_image/mod.rs | 35 +++ jingle_sleigh/src/error.rs | 2 +- jingle_sleigh/src/ffi/context_ffi.rs | 6 +- jingle_sleigh/src/ffi/cpp/context.cpp | 6 +- jingle_sleigh/src/ffi/cpp/context.h | 4 +- jingle_sleigh/src/ffi/cpp/exception.h | 3 - .../{image_context.cpp => sleigh_image.cpp} | 2 +- .../cpp/{image_context.h => sleigh_image.h} | 8 +- jingle_sleigh/src/ffi/mod.rs | 1 + jingle_sleigh/src/ffi/sleigh_image.rs | 31 ++ jingle_sleigh/src/pcode/mod.rs | 286 +++++++++++++----- 18 files changed, 450 insertions(+), 180 deletions(-) create mode 100644 jingle_sleigh/src/context/sleigh_image/instruction_iterator.rs create mode 100644 jingle_sleigh/src/context/sleigh_image/mod.rs rename jingle_sleigh/src/ffi/cpp/{image_context.cpp => sleigh_image.cpp} (98%) rename jingle_sleigh/src/ffi/cpp/{image_context.h => sleigh_image.h} (81%) create mode 100644 jingle_sleigh/src/ffi/sleigh_image.rs diff --git a/jingle_sleigh/CMakeLists.txt b/jingle_sleigh/CMakeLists.txt index e657186..b553382 100644 --- a/jingle_sleigh/CMakeLists.txt +++ b/jingle_sleigh/CMakeLists.txt @@ -31,8 +31,8 @@ add_library(jingle_sleigh_cpp src/ffi/cpp/addrspace_handle.cpp src/ffi/cpp/addrspace_manager_handle.cpp src/ffi/cpp/context.h - src/ffi/cpp/image_context.cpp - src/ffi/cpp/image_context.h + src/ffi/cpp/sleigh_image.cpp + src/ffi/cpp/sleigh_image.h src/ffi/cpp/exception.h) add_executable(sleigh_compile diff --git a/jingle_sleigh/build.rs b/jingle_sleigh/build.rs index 750df71..bd20ac6 100644 --- a/jingle_sleigh/build.rs +++ b/jingle_sleigh/build.rs @@ -20,6 +20,7 @@ fn main() { let rust_sources = vec![ "src/ffi/addrspace.rs", "src/ffi/context_ffi.rs", + "src/ffi/sleigh_image.rs", "src/ffi/instruction.rs", "src/ffi/opcode.rs", "src/ffi/image.rs", @@ -49,6 +50,8 @@ fn main() { "src/ffi/cpp/sleigh/slghscan.cc", "src/ffi/cpp/sleigh/slghparse.cc", "src/ffi/cpp/context.cpp", + "src/ffi/cpp/dummy_load_image.cpp", + "src/ffi/cpp/sleigh_image.cpp", "src/ffi/cpp/addrspace_handle.cpp", "src/ffi/cpp/addrspace_manager_handle.cpp", ]; diff --git a/jingle_sleigh/src/context/builder/image/gimli.rs b/jingle_sleigh/src/context/builder/image/gimli.rs index f84d6f5..4ba9049 100644 --- a/jingle_sleigh/src/context/builder/image/gimli.rs +++ b/jingle_sleigh/src/context/builder/image/gimli.rs @@ -10,7 +10,10 @@ impl<'d> TryFrom> for Image { #[instrument(skip_all)] fn try_from(value: File) -> Result { let mut img: Image = Image { sections: vec![] }; - for x in value.sections().filter(|s| matches!(s.kind(), SectionKind::Text)) { + for x in value + .sections() + .filter(|s| matches!(s.kind(), SectionKind::Text)) + { let base_address = x.address(); let data = x.data().map_err(|_| ImageLoadError)?.to_vec(); let perms = map_kind(&x.kind()); @@ -18,12 +21,12 @@ impl<'d> TryFrom> for Image { let start = base_address; let end = base_address + data.len() as u64; event!( - Level::TRACE, - "Selecting section {} ({:x}-{:x})", - name, - start, - end - ); + Level::TRACE, + "Selecting section {} ({:x}-{:x})", + name, + start, + end + ); img.sections.push(ImageSection { perms, data, @@ -40,8 +43,20 @@ impl<'d> TryFrom> for Image { fn map_kind(kind: &SectionKind) -> Perms { Perms { exec: matches!(kind, SectionKind::Text), - write: matches!(kind, SectionKind::Data) && !matches!(kind, SectionKind::ReadOnlyData | SectionKind::ReadOnlyString | SectionKind::ReadOnlyDataWithRel), - read: matches!(kind, SectionKind::Data | SectionKind::ReadOnlyData | SectionKind::ReadOnlyString | SectionKind::ReadOnlyDataWithRel), + write: matches!(kind, SectionKind::Data) + && !matches!( + kind, + SectionKind::ReadOnlyData + | SectionKind::ReadOnlyString + | SectionKind::ReadOnlyDataWithRel + ), + read: matches!( + kind, + SectionKind::Data + | SectionKind::ReadOnlyData + | SectionKind::ReadOnlyString + | SectionKind::ReadOnlyDataWithRel + ), } } @@ -62,10 +77,10 @@ pub fn map_gimli_architecture(file: &File) -> Option<&'static str> { }, Architecture::I386 => Some("x86:LE:32:default"), Architecture::X86_64 => Some("x86:LE:64:default"), - Architecture::PowerPc64 => match file.endianness(){ + Architecture::PowerPc64 => match file.endianness() { Endianness::Little => Some("PowerPC:LE:64:default"), - Endianness::Big => Some("PowerPC:BE:64:default") - } + Endianness::Big => Some("PowerPC:BE:64:default"), + }, Architecture::Xtensa => match file.endianness() { Endianness::Little => Some("Xtensa:LE:32:default"), Endianness::Big => Some("Xtensa:BE:32:default"), diff --git a/jingle_sleigh/src/context/builder/mod.rs b/jingle_sleigh/src/context/builder/mod.rs index 517459f..4529c88 100644 --- a/jingle_sleigh/src/context/builder/mod.rs +++ b/jingle_sleigh/src/context/builder/mod.rs @@ -16,7 +16,6 @@ pub(crate) mod processor_spec; #[derive(Debug, Default, Clone)] pub struct SleighContextBuilder { defs: Vec<(LanguageDefinition, PathBuf)>, - image: Option, } impl SleighContextBuilder { @@ -29,9 +28,8 @@ impl SleighContextBuilder { } #[instrument(skip_all, fields(%id))] pub fn build(mut self, id: &str) -> Result { - let image = self.image.take().ok_or(NoImageProvided)?; let (lang, path) = self.get_language(id).ok_or(InvalidLanguageId)?; - let mut context = SleighContext::new(lang, path, image)?; + let mut context = SleighContext::new(lang, path)?; event!(Level::INFO, "Created sleigh context"); let pspec_path = path.join(&lang.processor_spec); let pspec = parse_pspec(&pspec_path)?; @@ -39,9 +37,15 @@ impl SleighContextBuilder { for set in ctx_sets.sets { // todo: gross hack if set.value.starts_with("0x") { - context.set_initial_context(&set.name, u32::from_str_radix(&set.value[2..], 16).unwrap()) + context.set_initial_context( + &set.name, + u32::from_str_radix(&set.value[2..], 16).unwrap(), + ) } else { - context.set_initial_context(&set.name, u32::from_str_radix(&set.value, 10).unwrap()) + context.set_initial_context( + &set.name, + u32::from_str_radix(&set.value, 10).unwrap(), + ) } } } @@ -51,7 +55,6 @@ impl SleighContextBuilder { let ldef = SleighContextBuilder::_load_folder(path.as_ref())?; Ok(SleighContextBuilder { defs: ldef, - image: None, }) } @@ -83,13 +86,9 @@ impl SleighContextBuilder { defs.extend(d); } } - Ok(SleighContextBuilder { defs, image: None }) + Ok(SleighContextBuilder { defs }) } - pub fn set_image(mut self, img: Image) -> Self { - self.image = Some(img); - self - } } fn find_ldef(path: &Path) -> Result { @@ -116,7 +115,7 @@ mod tests { parse_ldef(Path::new( "ghidra/Ghidra/Processors/x86/data/languages/x86.ldefs", )) - .unwrap(); + .unwrap(); } #[test] @@ -124,7 +123,7 @@ mod tests { parse_pspec(Path::new( "ghidra/Ghidra/Processors/x86/data/languages/x86.pspec", )) - .unwrap(); + .unwrap(); } #[test] @@ -132,7 +131,7 @@ mod tests { SleighContextBuilder::load_folder(Path::new( "ghidra/Ghidra/Processors/x86/data/languages/", )) - .unwrap(); + .unwrap(); SleighContextBuilder::load_folder(Path::new("ghidra/Ghidra/Processors/x86/data/languages")) .unwrap(); } @@ -147,7 +146,7 @@ mod tests { let langs = SleighContextBuilder::load_folder(Path::new( "ghidra/Ghidra/Processors/x86/data/languages/", )) - .unwrap(); + .unwrap(); assert!(langs.get_language("sdf").is_none()); assert!(langs.get_language(SLEIGH_ARCH).is_some()); } diff --git a/jingle_sleigh/src/context/builder/processor_spec.rs b/jingle_sleigh/src/context/builder/processor_spec.rs index 11ab41f..ded59a7 100644 --- a/jingle_sleigh/src/context/builder/processor_spec.rs +++ b/jingle_sleigh/src/context/builder/processor_spec.rs @@ -24,7 +24,7 @@ pub struct ContextSetSpace { pub struct ContextData { pub context_set: Option, #[allow(unused)] - pub tracked_set: Option + pub tracked_set: Option, } #[derive(Debug, Deserialize)] diff --git a/jingle_sleigh/src/context/mod.rs b/jingle_sleigh/src/context/mod.rs index bcacadf..d6fbee0 100644 --- a/jingle_sleigh/src/context/mod.rs +++ b/jingle_sleigh/src/context/mod.rs @@ -1,4 +1,5 @@ mod builder; +mod sleigh_image; use crate::error::JingleSleighError; use crate::error::JingleSleighError::{LanguageSpecRead, SleighInitError}; @@ -12,24 +13,24 @@ pub use builder::image::{Image, ImageSection}; pub use builder::SleighContextBuilder; use crate::context::builder::language_def::LanguageDefinition; +use crate::context::sleigh_image::SleighImage; use crate::ffi::context_ffi::CTX_BUILD_MUTEX; use crate::ffi::instruction::bridge::VarnodeInfoFFI; +use crate::JingleSleighError::SleighCompilerMutexError; use crate::VarNode; use cxx::{SharedPtr, UniquePtr}; use std::fmt::{Debug, Formatter}; use std::path::Path; -use crate::JingleSleighError::SleighCompilerMutexError; pub struct SleighContext { ctx: UniquePtr, spaces: Vec, language_id: String, - pub image: Image, } impl Debug for SleighContext { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "Sleigh {{image: {:?}}}", self.image) + write!(f, "Sleigh {{arch: {}}}", self.language_id) } } @@ -80,20 +81,18 @@ impl SleighContext { pub(crate) fn new>( language_def: &LanguageDefinition, base_path: T, - image: Image, ) -> Result { let path = base_path.as_ref().join(&language_def.sla_file); let abs = path.canonicalize().map_err(|_| LanguageSpecRead)?; let path_str = abs.to_str().ok_or(LanguageSpecRead)?; match CTX_BUILD_MUTEX.lock() { Ok(make_context) => { - let ctx = make_context(path_str, image.clone()).map_err(|e| SleighInitError(e.to_string()))?; + let ctx = make_context(path_str).map_err(|e| SleighInitError(e.to_string()))?; let mut spaces: Vec = Vec::with_capacity(ctx.getNumSpaces() as usize); for idx in 0..ctx.getNumSpaces() { spaces.push(SpaceInfo::from(ctx.getSpaceByIndex(idx))); } Ok(Self { - image, ctx, spaces, language_id: language_def.id.clone(), @@ -107,14 +106,6 @@ impl SleighContext { self.ctx.pin_mut().set_initial_context(name, value); } - pub fn read(&self, offset: u64, max_instrs: usize) -> SleighContextInstructionIterator { - SleighContextInstructionIterator::new(self, offset, max_instrs, false) - } - - pub fn read_block(&self, offset: u64, max_instrs: usize) -> SleighContextInstructionIterator { - SleighContextInstructionIterator::new(self, offset, max_instrs, true) - } - pub fn spaces(&self) -> Vec> { let mut spaces = Vec::with_capacity(self.ctx.getNumSpaces() as usize); for i in 0..self.ctx.getNumSpaces() { @@ -126,56 +117,12 @@ impl SleighContext { pub fn get_language_id(&self) -> &str { &self.language_id } -} - -pub struct SleighContextInstructionIterator<'a> { - sleigh: &'a SleighContext, - remaining: usize, - offset: u64, - terminate_branch: bool, - already_hit_branch: bool, -} - -impl<'a> SleighContextInstructionIterator<'a> { - pub(crate) fn new( - sleigh: &'a SleighContext, - offset: u64, - remaining: usize, - terminate_branch: bool, - ) -> Self { - SleighContextInstructionIterator { - sleigh, - remaining, - offset, - terminate_branch, - already_hit_branch: false, - } - } -} - -impl<'a> Iterator for SleighContextInstructionIterator<'a> { - type Item = Instruction; - fn next(&mut self) -> Option { - if self.remaining == 0 { - return None; - } - if !self.sleigh.image.contains_address(self.offset as usize) { - return None; - } - if self.terminate_branch && self.already_hit_branch { - return None; - } - let instr = self - .sleigh - .ctx - .get_one_instruction(self.offset) - .map(Instruction::from) - .ok()?; - self.already_hit_branch = instr.terminates_basic_block(); - self.offset += instr.length as u64; - self.remaining -= 1; - Some(instr) + pub fn load_image>(&self, img: T) -> Result { + self.ctx + .makeImageContext(img.into()) + .map(SleighImage::new) + .map_err(|e| JingleSleighError::ImageLoadError) } } diff --git a/jingle_sleigh/src/context/sleigh_image/instruction_iterator.rs b/jingle_sleigh/src/context/sleigh_image/instruction_iterator.rs new file mode 100644 index 0000000..c96cdf0 --- /dev/null +++ b/jingle_sleigh/src/context/sleigh_image/instruction_iterator.rs @@ -0,0 +1,96 @@ +use crate::context::sleigh_image::SleighImage; +use crate::context::{Image, SleighContext}; +use crate::Instruction; + +pub struct SleighContextInstructionIterator<'a> { + sleigh: &'a SleighImage, + remaining: usize, + offset: u64, + terminate_branch: bool, + already_hit_branch: bool, +} + +impl<'a> SleighContextInstructionIterator<'a> { + pub(crate) fn new( + sleigh: &'a SleighImage, + offset: u64, + remaining: usize, + terminate_branch: bool, + ) -> Self { + SleighContextInstructionIterator { + sleigh, + remaining, + offset, + terminate_branch, + already_hit_branch: false, + } + } +} + +impl<'a> Iterator for SleighContextInstructionIterator<'a> { + type Item = Instruction; + + fn next(&mut self) -> Option { + if self.remaining == 0 { + return None; + } + if self.terminate_branch && self.already_hit_branch { + return None; + } + let instr = self + .sleigh + .img_ffi + .get_one_instruction(self.offset) + .map(Instruction::from) + .ok()?; + self.already_hit_branch = instr.terminates_basic_block(); + self.offset += instr.length as u64; + self.remaining -= 1; + Some(instr) + } +} + +#[cfg(test)] +mod test { + use crate::context::builder::image::Image; + use crate::context::builder::SleighContextBuilder; + use crate::pcode::PcodeOperation; + use crate::{Instruction, RegisterManager, SpaceManager}; + + use crate::tests::SLEIGH_ARCH; + use crate::varnode; + + #[test] + fn get_one() { + let mov_eax_0: [u8; 6] = [0xb8, 0x00, 0x00, 0x00, 0x00, 0xc3]; + let ctx_builder = + SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); + let ctx = ctx_builder + .set_image(Image::from(mov_eax_0.as_slice())) + .build(SLEIGH_ARCH) + .unwrap(); + let instr = ctx.read(0, 1).last().unwrap(); + assert_eq!(instr.length, 5); + assert!(instr.disassembly.mnemonic.eq("MOV")); + assert!(!instr.ops.is_empty()); + varnode!(&ctx, #0:4).unwrap(); + let _op = PcodeOperation::Copy { + input: varnode!(&ctx, #0:4).unwrap(), + output: varnode!(&ctx, "register"[0]:4).unwrap(), + }; + assert!(matches!(&instr.ops[0], _op)) + } + + #[test] + fn stop_at_branch() { + let mov_eax_0: [u8; 4] = [0x0f, 0x05, 0x0f, 0x05]; + let ctx_builder = + SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); + let ctx = ctx_builder + .set_image(Image::from(mov_eax_0.as_slice())) + .build(SLEIGH_ARCH) + .unwrap(); + let instr: Vec = ctx.read_block(0, 2).collect(); + assert_eq!(instr.len(), 1); + } +} diff --git a/jingle_sleigh/src/context/sleigh_image/mod.rs b/jingle_sleigh/src/context/sleigh_image/mod.rs new file mode 100644 index 0000000..5314cfc --- /dev/null +++ b/jingle_sleigh/src/context/sleigh_image/mod.rs @@ -0,0 +1,35 @@ +mod instruction_iterator; + +use crate::context::sleigh_image::instruction_iterator::SleighContextInstructionIterator; +use crate::ffi::sleigh_image::bridge::SleighImage as SleighImageFFI; +use crate::Instruction; +use cxx::UniquePtr; +use std::ops::Index; + +pub struct SleighImage { + img_ffi: UniquePtr, +} + +impl SleighImage { + pub(crate) fn new(ffi: UniquePtr) -> Self { + Self { img_ffi: ffi } + } + + pub fn instruction_at(&self, offset: u64) -> Option { + self.img_ffi + .get_one_instruction(offset) + .map(Instruction::from) + .ok() + } + pub fn read(&self, offset: u64, max_instrs: usize) -> SleighContextInstructionIterator { + SleighContextInstructionIterator::new(self, offset, max_instrs, false) + } + + pub fn read_until_branch( + &self, + offset: u64, + max_instrs: usize, + ) -> SleighContextInstructionIterator { + SleighContextInstructionIterator::new(self, offset, max_instrs, true) + } +} diff --git a/jingle_sleigh/src/error.rs b/jingle_sleigh/src/error.rs index 30977a9..7206a94 100644 --- a/jingle_sleigh/src/error.rs +++ b/jingle_sleigh/src/error.rs @@ -37,7 +37,7 @@ pub enum JingleSleighError { #[error("Attempted to construct an instruction from an empty slice of instructions")] EmptyInstruction, #[error("Failure to acquire mutex to sleigh FFI function")] - SleighCompilerMutexError + SleighCompilerMutexError, } impl From for std::fmt::Error { diff --git a/jingle_sleigh/src/ffi/context_ffi.rs b/jingle_sleigh/src/ffi/context_ffi.rs index 243d796..4802ff0 100644 --- a/jingle_sleigh/src/ffi/context_ffi.rs +++ b/jingle_sleigh/src/ffi/context_ffi.rs @@ -3,7 +3,7 @@ use bridge::ContextFFI; use cxx::{Exception, UniquePtr}; use std::sync::Mutex; -type ContextGeneratorFp = fn(&str, bridge::Image) -> Result, Exception>; +type ContextGeneratorFp = fn(&str) -> Result, Exception>; pub(crate) static CTX_BUILD_MUTEX: Mutex = Mutex::new(makeContext); @@ -18,6 +18,8 @@ pub(crate) mod bridge { type AddrSpaceHandle = crate::ffi::addrspace::bridge::AddrSpaceHandle; type RegisterInfoFFI = crate::ffi::instruction::bridge::RegisterInfoFFI; + + type SleighImage = crate::ffi::sleigh_image::bridge::SleighImage; } unsafe extern "C++" { @@ -37,6 +39,8 @@ pub(crate) mod bridge { pub(crate) fn getRegisterName(&self, name: VarnodeInfoFFI) -> Result<&str>; pub(crate) fn getRegisters(&self) -> Vec; + + pub(crate) fn makeImageContext(&self, img: Image) -> Result>; } impl Vec {} } diff --git a/jingle_sleigh/src/ffi/cpp/context.cpp b/jingle_sleigh/src/ffi/cpp/context.cpp index b470843..f9195f9 100644 --- a/jingle_sleigh/src/ffi/cpp/context.cpp +++ b/jingle_sleigh/src/ffi/cpp/context.cpp @@ -3,7 +3,7 @@ #include #include -#include "image_context.h" +#include "sleigh_image.h" #include "jingle_sleigh/src/ffi/instruction.rs.h" #include "sleigh/loadimage.hh" @@ -85,6 +85,6 @@ rust::Vec ContextFFI::getRegisters() const { return v; } -std::unique_ptr ContextFFI::makeImageContext(Image img) { - return std::unique_ptr(new SleighImage(img, sleigh)); +std::unique_ptr ContextFFI::makeImageContext(Image img) const { + return std::make_unique(img, sleigh); } diff --git a/jingle_sleigh/src/ffi/cpp/context.h b/jingle_sleigh/src/ffi/cpp/context.h index 090af71..a5f3cdc 100644 --- a/jingle_sleigh/src/ffi/cpp/context.h +++ b/jingle_sleigh/src/ffi/cpp/context.h @@ -9,7 +9,7 @@ #include "sleigh/sleigh.hh" #include "jingle_sleigh/src/ffi/image.rs.h" #include "sleigh/loadimage.hh" -#include "image_context.h" +#include "sleigh_image.h" #include "dummy_load_image.h" class ContextFFI { @@ -22,7 +22,7 @@ class ContextFFI { void set_initial_context(rust::Str name, uint32_t val); - std::unique_ptr makeImageContext(Image img); + std::unique_ptr makeImageContext(Image img) const; [[nodiscard]] std::shared_ptr getSpaceByIndex(ghidra::int4 idx) const; diff --git a/jingle_sleigh/src/ffi/cpp/exception.h b/jingle_sleigh/src/ffi/cpp/exception.h index e6a5d17..8151c57 100644 --- a/jingle_sleigh/src/ffi/cpp/exception.h +++ b/jingle_sleigh/src/ffi/cpp/exception.h @@ -4,7 +4,6 @@ #include "sleigh/error.hh" #include "sleigh/xml.hh" -#include "sleigh/loadimage.hh" namespace rust { namespace behavior { @@ -16,8 +15,6 @@ namespace rust { fail(e.explain); } catch (const ghidra::DecoderError &e) { fail(e.explain); - } catch (const ghidra::DataUnavailError &e){ - fail(e.explain); } catch (const std::exception &e) { fail(e.what()); } diff --git a/jingle_sleigh/src/ffi/cpp/image_context.cpp b/jingle_sleigh/src/ffi/cpp/sleigh_image.cpp similarity index 98% rename from jingle_sleigh/src/ffi/cpp/image_context.cpp rename to jingle_sleigh/src/ffi/cpp/sleigh_image.cpp index 60b33e0..0213269 100644 --- a/jingle_sleigh/src/ffi/cpp/image_context.cpp +++ b/jingle_sleigh/src/ffi/cpp/sleigh_image.cpp @@ -1,7 +1,7 @@ // // Created by mark denhoed on 10/10/24. // -#include "image_context.h" +#include "sleigh_image.h" #include "dummy_load_image.h" #include diff --git a/jingle_sleigh/src/ffi/cpp/image_context.h b/jingle_sleigh/src/ffi/cpp/sleigh_image.h similarity index 81% rename from jingle_sleigh/src/ffi/cpp/image_context.h rename to jingle_sleigh/src/ffi/cpp/sleigh_image.h index dc587fb..8a4eeea 100644 --- a/jingle_sleigh/src/ffi/cpp/image_context.h +++ b/jingle_sleigh/src/ffi/cpp/sleigh_image.h @@ -2,8 +2,8 @@ // Created by toolCHAINZ on 10/10/24. // -#ifndef JINGLE_SLEIGH_IMAGE_CONTEXT_H -#define JINGLE_SLEIGH_IMAGE_CONTEXT_H +#ifndef JINGLE_SLEIGH_SLEIGH_IMAGE_H +#define JINGLE_SLEIGH_SLEIGH_IMAGE_H #include "addrspace_handle.h" #include "jingle_sleigh/src/ffi/instruction.rs.h" @@ -18,7 +18,7 @@ class SleighImage{ DummyLoadImage image; public: - SleighImage(Image img, ghidra::Sleigh& sl); + SleighImage(Image img, ghidra::Sleigh sl); InstructionFFI get_one_instruction(uint64_t offset) const; @@ -33,4 +33,4 @@ class SleighImage{ rust::Vec getRegisters() const; }; -#endif //JINGLE_SLEIGH_IMAGE_CONTEXT_H +#endif //JINGLE_SLEIGH_SLEIGH_IMAGE_H diff --git a/jingle_sleigh/src/ffi/mod.rs b/jingle_sleigh/src/ffi/mod.rs index 226865f..9a1b9d1 100644 --- a/jingle_sleigh/src/ffi/mod.rs +++ b/jingle_sleigh/src/ffi/mod.rs @@ -3,6 +3,7 @@ pub(crate) mod context_ffi; pub(crate) mod image; pub(crate) mod instruction; pub(crate) mod opcode; +pub(crate) mod sleigh_image; // Need to pull this in somewhere so that libz symbols are available // for the `sleigh` CPP code at link-time. diff --git a/jingle_sleigh/src/ffi/sleigh_image.rs b/jingle_sleigh/src/ffi/sleigh_image.rs new file mode 100644 index 0000000..38ec6c7 --- /dev/null +++ b/jingle_sleigh/src/ffi/sleigh_image.rs @@ -0,0 +1,31 @@ +#[cxx::bridge] +pub(crate) mod bridge { + unsafe extern "C++" { + type Image = crate::context::Image; + type InstructionFFI = crate::ffi::instruction::bridge::InstructionFFI; + + type VarnodeInfoFFI = crate::ffi::instruction::bridge::VarnodeInfoFFI; + + type AddrSpaceHandle = crate::ffi::addrspace::bridge::AddrSpaceHandle; + + type RegisterInfoFFI = crate::ffi::instruction::bridge::RegisterInfoFFI; + } + + unsafe extern "C++" { + include!("jingle_sleigh/src/ffi/cpp/sleigh_image.h"); + + pub(crate) type SleighImage; + + pub(crate) fn getSpaceByIndex(&self, idx: i32) -> SharedPtr; + pub(crate) fn getNumSpaces(&self) -> i32; + + pub(crate) fn getRegister(&self, name: &str) -> Result; + pub(crate) fn getRegisterName(&self, name: VarnodeInfoFFI) -> Result<&str>; + + pub(crate) fn getRegisters(&self) -> Vec; + + pub(crate) fn get_one_instruction(&self, offset: u64) -> Result; + } + + impl UniquePtr {} +} diff --git a/jingle_sleigh/src/pcode/mod.rs b/jingle_sleigh/src/pcode/mod.rs index 1ea2b86..c52e382 100644 --- a/jingle_sleigh/src/pcode/mod.rs +++ b/jingle_sleigh/src/pcode/mod.rs @@ -399,78 +399,220 @@ impl PcodeOperation { pub fn inputs(&self) -> Vec { match self { - Copy { input, .. } => {vec![input.into()]} - Load { input, .. } => {vec![input.into(), input.pointer_location.clone().into()]} - Store { input, output } => {vec![input.into(), output.pointer_location.clone().into()]} - Branch { input, .. } => {vec![input.into()]} - CBranch { input0, input1, .. } => {vec![input0.into(), input1.into()]} - BranchInd { input, .. } => {vec![input.into()]} - Call { input, .. } => {vec![input.into()]} - CallInd { input, .. } => {vec![input.into()]} - CallOther { inputs, .. } => {inputs.iter().map(|i|i.into()).collect()} - Return { input, .. } => {vec![input.into()]} - IntEqual { input0, input1, .. } => {vec![input0.into(), input1.into()]} - IntNotEqual { input0, input1, .. } => {vec![input0.into(), input1.into()]} - IntSignedLess { input0, input1, .. } => {vec![input0.into(), input1.into()]} - IntSignedLessEqual { input0, input1, .. } => {vec![input0.into(), input1.into()]} - IntLess { input0, input1, .. } => {vec![input0.into(), input1.into()]} - IntLessEqual { input0, input1, .. } => {vec![input0.into(), input1.into()]} - IntSExt { input, .. } => {vec![input.into()]} - IntZExt { input, .. } => {vec![input.into()]} - IntAdd { input0, input1, .. } => {vec![input0.into(), input1.into()]} - IntSub { input0, input1, .. } => {vec![input0.into(), input1.into()]} - IntCarry { input0, input1, .. } => {vec![input0.into(), input1.into()]} - IntSignedCarry { input0, input1, .. } => {vec![input0.into(), input1.into()]} - IntSignedBorrow { input0, input1, .. } => {vec![input0.into(), input1.into()]} - Int2Comp { input, .. } => {vec![input.into()]} - IntNegate { input, .. } => {vec![input.into()]} - IntXor { input0, input1, .. } => {vec![input0.into(), input1.into()]} - IntAnd { input0, input1, .. } => {vec![input0.into(), input1.into()]} - IntOr { input0, input1, .. } => {vec![input0.into(), input1.into()]} - IntLeftShift { input0, input1, .. } => {vec![input0.into(), input1.into()]} - IntRightShift { input0, input1, .. } => {vec![input0.into(), input1.into()]} - IntSignedRightShift { input0, input1, .. } => {vec![input0.into(), input1.into()]} - IntMult { input0, input1, .. } => {vec![input0.into(), input1.into()]} - IntDiv { input0, input1, .. } => {vec![input0.into(), input1.into()]} - IntSignedDiv { input0, input1, .. } => {vec![input0.into(), input1.into()]} - IntRem { input0, input1, .. } => {vec![input0.into(), input1.into()]} - IntSignedRem { input0, input1, .. } => {vec![input0.into(), input1.into()]} - BoolNegate { input, .. } => {vec![input.into()]} - BoolXor { input0, input1, .. } => {vec![input0.into(), input1.into()]} - BoolAnd { input0, input1, .. } => {vec![input0.into(), input1.into()]} - BoolOr { input0, input1, .. } => {vec![input0.into(), input1.into()]} - FloatEqual { input0, input1, .. } => {vec![input0.into(), input1.into()]} - FloatNotEqual { input0, input1, .. } => {vec![input0.into(), input1.into()]} - FloatLess { input0, input1, .. } => {vec![input0.into(), input1.into()]} - FloatLessEqual { input0, input1, .. } => {vec![input0.into(), input1.into()]} - FloatNaN { input, .. } => {vec![input.into()]} - FloatAdd { input0, input1, .. } => {vec![input0.into(), input1.into()]} - FloatDiv { input0, input1, .. } => {vec![input0.into(), input1.into()]} - FloatMult { input0, input1, .. } => {vec![input0.into(), input1.into()]} - FloatSub { input0, input1, .. } => {vec![input0.into(), input1.into()]} - FloatNeg { input, .. } => {vec![input.into()]} - FloatAbs { input, .. } => {vec![input.into()]} - FloatSqrt { input, .. } => {vec![input.into()]} - FloatIntToFloat { input, .. } => {vec![input.into()]} - FloatFloatToFloat { input, .. } => {vec![input.into()]} - FloatTrunc { input, .. } => {vec![input.into()]} - FloatCeil { input, .. } => {vec![input.into()]} - FloatFloor { input, .. } => {vec![input.into()]} - FloatRound { input, .. } => {vec![input.into()]} - MultiEqual { input0, input1, .. } => {vec![input0.into(), input1.into()]} - Indirect { input0, input1, .. } => {vec![input0.into(), input1.into()]} - Piece { input0, input1, .. } => {vec![input0.into(), input1.into()]} - SubPiece { input0, input1, .. } => {vec![input0.into(), input1.into()]} - Cast { input, .. } => {vec![input.into()]} - PtrAdd { input0, input1, .. } => {vec![input0.into(), input1.into()]} - PtrSub { input0, input1, .. } => {vec![input0.into(), input1.into()]} - SegmentOp { input0, input1, .. } => {vec![input0.into(), input1.into()]} - CPoolRef { input0, input1, .. } => {vec![input0.into(), input1.into()]} - New { input, .. } => {vec![input.into()]} - Insert { input0, input1, .. } => {vec![input0.into(), input1.into()]} - Extract { input0, .. } => {vec![input0.into()]} - PopCount { input, .. } => {vec![input.into()]} - LzCount { input, .. } => {vec![input.into()]} + Copy { input, .. } => { + vec![input.into()] + } + Load { input, .. } => { + vec![input.into(), input.pointer_location.clone().into()] + } + Store { input, output } => { + vec![input.into(), output.pointer_location.clone().into()] + } + Branch { input, .. } => { + vec![input.into()] + } + CBranch { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + BranchInd { input, .. } => { + vec![input.into()] + } + Call { input, .. } => { + vec![input.into()] + } + CallInd { input, .. } => { + vec![input.into()] + } + CallOther { inputs, .. } => inputs.iter().map(|i| i.into()).collect(), + Return { input, .. } => { + vec![input.into()] + } + IntEqual { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + IntNotEqual { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + IntSignedLess { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + IntSignedLessEqual { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + IntLess { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + IntLessEqual { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + IntSExt { input, .. } => { + vec![input.into()] + } + IntZExt { input, .. } => { + vec![input.into()] + } + IntAdd { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + IntSub { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + IntCarry { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + IntSignedCarry { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + IntSignedBorrow { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + Int2Comp { input, .. } => { + vec![input.into()] + } + IntNegate { input, .. } => { + vec![input.into()] + } + IntXor { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + IntAnd { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + IntOr { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + IntLeftShift { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + IntRightShift { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + IntSignedRightShift { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + IntMult { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + IntDiv { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + IntSignedDiv { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + IntRem { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + IntSignedRem { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + BoolNegate { input, .. } => { + vec![input.into()] + } + BoolXor { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + BoolAnd { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + BoolOr { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + FloatEqual { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + FloatNotEqual { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + FloatLess { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + FloatLessEqual { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + FloatNaN { input, .. } => { + vec![input.into()] + } + FloatAdd { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + FloatDiv { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + FloatMult { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + FloatSub { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + FloatNeg { input, .. } => { + vec![input.into()] + } + FloatAbs { input, .. } => { + vec![input.into()] + } + FloatSqrt { input, .. } => { + vec![input.into()] + } + FloatIntToFloat { input, .. } => { + vec![input.into()] + } + FloatFloatToFloat { input, .. } => { + vec![input.into()] + } + FloatTrunc { input, .. } => { + vec![input.into()] + } + FloatCeil { input, .. } => { + vec![input.into()] + } + FloatFloor { input, .. } => { + vec![input.into()] + } + FloatRound { input, .. } => { + vec![input.into()] + } + MultiEqual { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + Indirect { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + Piece { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + SubPiece { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + Cast { input, .. } => { + vec![input.into()] + } + PtrAdd { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + PtrSub { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + SegmentOp { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + CPoolRef { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + New { input, .. } => { + vec![input.into()] + } + Insert { input0, input1, .. } => { + vec![input0.into(), input1.into()] + } + Extract { input0, .. } => { + vec![input0.into()] + } + PopCount { input, .. } => { + vec![input.into()] + } + LzCount { input, .. } => { + vec![input.into()] + } } } pub fn output(&self) -> Option { From 58d56b7bcb61bd2561350ebeb14359908fc3955c Mon Sep 17 00:00:00 2001 From: Mark Date: Thu, 10 Oct 2024 20:48:03 +0100 Subject: [PATCH 054/146] Need to fix tests now --- jingle_sleigh/CMakeLists.txt | 4 +- jingle_sleigh/build.rs | 1 + jingle_sleigh/src/context/mod.rs | 48 +---------- .../sleigh_image/instruction_iterator.rs | 19 ++--- jingle_sleigh/src/context/sleigh_image/mod.rs | 79 ++++++++++++++++++- jingle_sleigh/src/ffi/cpp/context.cpp | 19 +---- jingle_sleigh/src/ffi/cpp/sleigh_image.cpp | 31 ++++++++ .../src/ffi/cpp/varnode_translation.cpp | 16 ++++ .../src/ffi/cpp/varnode_translation.h | 13 +++ jingle_sleigh/src/ffi/mod.rs | 12 +-- 10 files changed, 163 insertions(+), 79 deletions(-) create mode 100644 jingle_sleigh/src/ffi/cpp/varnode_translation.cpp create mode 100644 jingle_sleigh/src/ffi/cpp/varnode_translation.h diff --git a/jingle_sleigh/CMakeLists.txt b/jingle_sleigh/CMakeLists.txt index b553382..acfe038 100644 --- a/jingle_sleigh/CMakeLists.txt +++ b/jingle_sleigh/CMakeLists.txt @@ -33,7 +33,9 @@ add_library(jingle_sleigh_cpp src/ffi/cpp/context.h src/ffi/cpp/sleigh_image.cpp src/ffi/cpp/sleigh_image.h - src/ffi/cpp/exception.h) + src/ffi/cpp/exception.h + src/ffi/cpp/varnode_translation.cpp + src/ffi/cpp/varnode_translation.h) add_executable(sleigh_compile src/ffi/cpp/sleigh/address.cc diff --git a/jingle_sleigh/build.rs b/jingle_sleigh/build.rs index bd20ac6..7ca3e23 100644 --- a/jingle_sleigh/build.rs +++ b/jingle_sleigh/build.rs @@ -54,6 +54,7 @@ fn main() { "src/ffi/cpp/sleigh_image.cpp", "src/ffi/cpp/addrspace_handle.cpp", "src/ffi/cpp/addrspace_manager_handle.cpp", + "src/ffi/cpp/varnode_translation.cpp", ]; // This assumes all your C++ bindings are in lib cxx_build::bridges(rust_sources) diff --git a/jingle_sleigh/src/context/mod.rs b/jingle_sleigh/src/context/mod.rs index d6fbee0..6474944 100644 --- a/jingle_sleigh/src/context/mod.rs +++ b/jingle_sleigh/src/context/mod.rs @@ -128,57 +128,17 @@ impl SleighContext { #[cfg(test)] mod test { - use crate::context::builder::image::Image; - use crate::context::builder::SleighContextBuilder; - use crate::pcode::PcodeOperation; - use crate::{Instruction, RegisterManager, SpaceManager}; - + use crate::context::SleighContextBuilder; + use crate::RegisterManager; use crate::tests::SLEIGH_ARCH; - use crate::varnode; - - #[test] - fn get_one() { - let mov_eax_0: [u8; 6] = [0xb8, 0x00, 0x00, 0x00, 0x00, 0xc3]; - let ctx_builder = - SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); - let ctx = ctx_builder - .set_image(Image::from(mov_eax_0.as_slice())) - .build(SLEIGH_ARCH) - .unwrap(); - let instr = ctx.read(0, 1).last().unwrap(); - assert_eq!(instr.length, 5); - assert!(instr.disassembly.mnemonic.eq("MOV")); - assert!(!instr.ops.is_empty()); - varnode!(&ctx, #0:4).unwrap(); - let _op = PcodeOperation::Copy { - input: varnode!(&ctx, #0:4).unwrap(), - output: varnode!(&ctx, "register"[0]:4).unwrap(), - }; - assert!(matches!(&instr.ops[0], _op)) - } - - #[test] - fn stop_at_branch() { - let mov_eax_0: [u8; 4] = [0x0f, 0x05, 0x0f, 0x05]; - let ctx_builder = - SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); - let ctx = ctx_builder - .set_image(Image::from(mov_eax_0.as_slice())) - .build(SLEIGH_ARCH) - .unwrap(); - let instr: Vec = ctx.read_block(0, 2).collect(); - assert_eq!(instr.len(), 1); - } #[test] fn get_regs() { - let mov_eax_0: [u8; 6] = [0xb8, 0x00, 0x00, 0x00, 0x00, 0xc3]; let ctx_builder = SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); - let ctx = ctx_builder - .set_image(Image::from(mov_eax_0.as_slice())) + let sleigh = ctx_builder .build(SLEIGH_ARCH) .unwrap(); - assert_ne!(ctx.get_registers(), vec![]); + assert_ne!(sleigh.get_registers(), vec![]); } } diff --git a/jingle_sleigh/src/context/sleigh_image/instruction_iterator.rs b/jingle_sleigh/src/context/sleigh_image/instruction_iterator.rs index c96cdf0..ded2e20 100644 --- a/jingle_sleigh/src/context/sleigh_image/instruction_iterator.rs +++ b/jingle_sleigh/src/context/sleigh_image/instruction_iterator.rs @@ -65,18 +65,18 @@ mod test { let mov_eax_0: [u8; 6] = [0xb8, 0x00, 0x00, 0x00, 0x00, 0xc3]; let ctx_builder = SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); - let ctx = ctx_builder - .set_image(Image::from(mov_eax_0.as_slice())) + let sleigh = ctx_builder .build(SLEIGH_ARCH) .unwrap(); - let instr = ctx.read(0, 1).last().unwrap(); + let sleigh = sleigh.load_image(mov_eax_0.as_slice()).unwrap(); + let instr = sleigh.read(0, 1).last().unwrap(); assert_eq!(instr.length, 5); assert!(instr.disassembly.mnemonic.eq("MOV")); assert!(!instr.ops.is_empty()); - varnode!(&ctx, #0:4).unwrap(); + varnode!(&sleigh, #0:4).unwrap(); let _op = PcodeOperation::Copy { - input: varnode!(&ctx, #0:4).unwrap(), - output: varnode!(&ctx, "register"[0]:4).unwrap(), + input: varnode!(&sleigh, #0:4).unwrap(), + output: varnode!(&sleigh, "register"[0]:4).unwrap(), }; assert!(matches!(&instr.ops[0], _op)) } @@ -86,11 +86,12 @@ mod test { let mov_eax_0: [u8; 4] = [0x0f, 0x05, 0x0f, 0x05]; let ctx_builder = SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); - let ctx = ctx_builder - .set_image(Image::from(mov_eax_0.as_slice())) + let sleigh = ctx_builder .build(SLEIGH_ARCH) .unwrap(); - let instr: Vec = ctx.read_block(0, 2).collect(); + let sleigh_img = sleigh.load_image(mov_eax_0.as_slice()).unwrap(); + let instr: Vec = sleigh_img.read(0, 2).collect(); assert_eq!(instr.len(), 1); } + } diff --git a/jingle_sleigh/src/context/sleigh_image/mod.rs b/jingle_sleigh/src/context/sleigh_image/mod.rs index 5314cfc..f52a208 100644 --- a/jingle_sleigh/src/context/sleigh_image/mod.rs +++ b/jingle_sleigh/src/context/sleigh_image/mod.rs @@ -2,17 +2,26 @@ mod instruction_iterator; use crate::context::sleigh_image::instruction_iterator::SleighContextInstructionIterator; use crate::ffi::sleigh_image::bridge::SleighImage as SleighImageFFI; -use crate::Instruction; +use crate::{Instruction, RegisterManager, SpaceInfo, SpaceManager, VarNode}; use cxx::UniquePtr; use std::ops::Index; +use crate::context::SleighContext; +use crate::ffi::instruction::bridge::VarnodeInfoFFI; pub struct SleighImage { img_ffi: UniquePtr, + spaces: Vec, + } impl SleighImage { pub(crate) fn new(ffi: UniquePtr) -> Self { - Self { img_ffi: ffi } + let mut spaces: Vec = Vec::with_capacity(ffi.getNumSpaces() as usize); + for idx in 0..ffi.getNumSpaces() { + spaces.push(SpaceInfo::from(ffi.getSpaceByIndex(idx))); + } + + Self { img_ffi: ffi, spaces } } pub fn instruction_at(&self, offset: u64) -> Option { @@ -33,3 +42,69 @@ impl SleighImage { SleighContextInstructionIterator::new(self, offset, max_instrs, true) } } + +impl SpaceManager for SleighImage { + fn get_space_info(&self, idx: usize) -> Option<&SpaceInfo> { + self.spaces.get(idx) + } + + fn get_all_space_info(&self) -> &[SpaceInfo] { + self.spaces.as_slice() + } + + fn get_code_space_idx(&self) -> usize { + self.img_ffi + .getSpaceByIndex(0) + .getManager() + .getDefaultCodeSpace() + .getIndex() as usize + } +} + +impl RegisterManager for SleighImage { + fn get_register(&self, name: &str) -> Option { + self.img_ffi.getRegister(name).map(VarNode::from).ok() + } + + fn get_register_name(&self, location: VarNode) -> Option<&str> { + let space = self.img_ffi.getSpaceByIndex(location.space_index as i32); + self.img_ffi + .getRegisterName(VarnodeInfoFFI { + space, + offset: location.offset, + size: location.size, + }) + .ok() + } + + fn get_registers(&self) -> Vec<(VarNode, String)> { + self.img_ffi + .getRegisters() + .iter() + .map(|b| (VarNode::from(&b.varnode), b.name.clone())) + .collect() + } +} + +#[cfg(test)] +mod test{ + use crate::context::SleighContextBuilder; + use crate::tests::SLEIGH_ARCH; + + #[test] + fn test_two_images(){ + let mov_eax_0: [u8; 4] = [0x0f, 0x05, 0x0f, 0x05]; + let nops: [u8; 4] = [0x90, 0x90, 0x90, 0x90]; + let ctx_builder = + SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); + let sleigh = ctx_builder + .build(SLEIGH_ARCH) + .unwrap(); + let img1 = sleigh.load_image(mov_eax_0.as_slice()).unwrap(); + let img2 = sleigh.load_image(nops.as_slice()).unwrap(); + let instr1 = img1.instruction_at(0); + let instr2 = img2.instruction_at(0); + assert_eq!(instr1, instr2); + assert_ne!(instr1, None); + } +} \ No newline at end of file diff --git a/jingle_sleigh/src/ffi/cpp/context.cpp b/jingle_sleigh/src/ffi/cpp/context.cpp index f9195f9..13cd7ed 100644 --- a/jingle_sleigh/src/ffi/cpp/context.cpp +++ b/jingle_sleigh/src/ffi/cpp/context.cpp @@ -6,7 +6,7 @@ #include "sleigh_image.h" #include "jingle_sleigh/src/ffi/instruction.rs.h" #include "sleigh/loadimage.hh" - +#include "varnode_translation.h" ContextFFI::ContextFFI(rust::Str slaPath): sleigh(&image, &c_db) { ghidra::AttributeId::initialize(); @@ -23,8 +23,7 @@ ContextFFI::ContextFFI(rust::Str slaPath): sleigh(&image, &c_db) { ghidra::Document *doc = documentStorage.parseDocument(sleighfilename); ghidra::Element *root = doc->getRoot(); documentStorage.registerTag(root); - this->sleigh = ghidra::Sleigh(&img, &c_db); - this->sleigh.initialize(documentStorage); + sleigh.initialize(documentStorage); } @@ -60,20 +59,6 @@ std::unique_ptr makeContext(rust::Str slaPath) { return std::make_unique(slaPath); } -VarnodeInfoFFI varnodeToFFI(ghidra::VarnodeData vn) { - VarnodeInfoFFI info; - info.space = std::make_unique(vn.space); - info.size = vn.size; - info.offset = vn.offset; - return info; -} - -RegisterInfoFFI collectRegInfo(std::tuple el) { - VarnodeInfoFFI varnode = varnodeToFFI(std::get<0>(el)); - rust::String name = std::get<1>(el); - return {varnode, name}; -} - rust::Vec ContextFFI::getRegisters() const { std::map reglist; rust::Vec v; diff --git a/jingle_sleigh/src/ffi/cpp/sleigh_image.cpp b/jingle_sleigh/src/ffi/cpp/sleigh_image.cpp index 0213269..f956616 100644 --- a/jingle_sleigh/src/ffi/cpp/sleigh_image.cpp +++ b/jingle_sleigh/src/ffi/cpp/sleigh_image.cpp @@ -3,6 +3,7 @@ // #include "sleigh_image.h" #include "dummy_load_image.h" +#include "varnode_translation.h" #include @@ -80,3 +81,33 @@ rust::Str SleighImage::getRegisterName(VarnodeInfoFFI vn) const { std::string name = sl.getRegisterName(vn.space->getRaw(), vn.offset, vn.size); return {name}; } + +InstructionFFI SleighImage::get_one_instruction(uint64_t offset) const { + PcodeCacher pcode; + AssemblyCacher assembly; + ghidra::Address a = ghidra::Address(sl.getDefaultCodeSpace(), offset); + sl.printAssembly(assembly, a); + sl.oneInstruction(pcode, a); + size_t length = sl.instructionLength(a); + InstructionFFI i; + Disassembly d; + i.ops = std::move(pcode.ops); + d.args = std::move(assembly.body); + d.mnemonic = std::move(assembly.mnem); + i.disassembly = std::move(d); + i.address = offset; + i.length = length; + return i; +} + + +rust::Vec SleighImage::getRegisters() const { + std::map reglist; + rust::Vec v; + sl.getAllRegisters(reglist); + v.reserve(reglist.size()); + for (auto const &vn: reglist) { + v.emplace_back(collectRegInfo(vn)); + } + return v; +} \ No newline at end of file diff --git a/jingle_sleigh/src/ffi/cpp/varnode_translation.cpp b/jingle_sleigh/src/ffi/cpp/varnode_translation.cpp new file mode 100644 index 0000000..b8d8488 --- /dev/null +++ b/jingle_sleigh/src/ffi/cpp/varnode_translation.cpp @@ -0,0 +1,16 @@ +#include "varnode_translation.h" +#include "addrspace_handle.h" + +VarnodeInfoFFI varnodeToFFI(ghidra::VarnodeData vn) { + VarnodeInfoFFI info; + info.space = std::make_unique(vn.space); + info.size = vn.size; + info.offset = vn.offset; + return info; +} + +RegisterInfoFFI collectRegInfo(std::tuple el) { + VarnodeInfoFFI varnode = varnodeToFFI(std::get<0>(el)); + rust::String name = std::get<1>(el); + return {varnode, name}; +} \ No newline at end of file diff --git a/jingle_sleigh/src/ffi/cpp/varnode_translation.h b/jingle_sleigh/src/ffi/cpp/varnode_translation.h new file mode 100644 index 0000000..2e8ab86 --- /dev/null +++ b/jingle_sleigh/src/ffi/cpp/varnode_translation.h @@ -0,0 +1,13 @@ + +#ifndef JINGLE_SLEIGH_VARNODE_TRANSLATION_H +#define JINGLE_SLEIGH_VARNODE_TRANSLATION_H +#include "sleigh/types.h" +#include "sleigh/translate.hh" +#include "jingle_sleigh/src/ffi/instruction.rs.h" + + +VarnodeInfoFFI varnodeToFFI(ghidra::VarnodeData vn); + +RegisterInfoFFI collectRegInfo(std::tuple el); + +#endif //JINGLE_SLEIGH_VARNODE_TRANSLATION_H diff --git a/jingle_sleigh/src/ffi/mod.rs b/jingle_sleigh/src/ffi/mod.rs index 9a1b9d1..c4bee1c 100644 --- a/jingle_sleigh/src/ffi/mod.rs +++ b/jingle_sleigh/src/ffi/mod.rs @@ -20,11 +20,11 @@ mod tests { let builder = SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); - let bin_sleigh = builder - .set_image(Image::from(bytes.as_slice())) + let sleigh = builder .build("x86:LE:64:default") .unwrap(); - let _lib = bin_sleigh.read(0, 1).next().unwrap(); + let bin_image = sleigh.load_image(bytes.as_slice()).unwrap(); + let _lib = bin_image.instruction_at(0).unwrap(); } #[test] fn test_callother_decode2() { @@ -32,10 +32,10 @@ mod tests { let builder = SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); - let bin_sleigh = builder - .set_image(Image::from(bytes.as_slice())) + let sleigh = builder .build("x86:LE:64:default") .unwrap(); - let _lib = bin_sleigh.read(0, 1).next().unwrap(); + let bin_image = sleigh.load_image(bytes.as_slice()).unwrap(); + let _lib = bin_image.instruction_at(0).unwrap(); } } From e5aee80d6dfe58054c386e0710f97905cd241bf8 Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 11 Oct 2024 10:01:58 +0100 Subject: [PATCH 055/146] Some small tweaks --- jingle_sleigh/src/context/builder/image/elf.rs | 2 +- jingle_sleigh/src/ffi/cpp/context.cpp | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/jingle_sleigh/src/context/builder/image/elf.rs b/jingle_sleigh/src/context/builder/image/elf.rs index 974312c..dd0447e 100644 --- a/jingle_sleigh/src/context/builder/image/elf.rs +++ b/jingle_sleigh/src/context/builder/image/elf.rs @@ -44,7 +44,7 @@ mod tests { use elf::endian::AnyEndian; use elf::ElfBytes; - #[test] + // #[test] fn test_elf() { let path = std::path::PathBuf::from("../bin/vuln"); let file_data = std::fs::read(path).unwrap(); diff --git a/jingle_sleigh/src/ffi/cpp/context.cpp b/jingle_sleigh/src/ffi/cpp/context.cpp index 13cd7ed..abc65be 100644 --- a/jingle_sleigh/src/ffi/cpp/context.cpp +++ b/jingle_sleigh/src/ffi/cpp/context.cpp @@ -8,11 +8,10 @@ #include "sleigh/loadimage.hh" #include "varnode_translation.h" -ContextFFI::ContextFFI(rust::Str slaPath): sleigh(&image, &c_db) { +ContextFFI::ContextFFI(rust::Str slaPath): sleigh(new DummyLoadImage(Image()), new ghidra::ContextInternal()) { ghidra::AttributeId::initialize(); ghidra::ElementId::initialize(); - DummyLoadImage img = DummyLoadImage(Image()); ghidra::DocumentStorage documentStorage = ghidra::DocumentStorage(); std::stringstream sleighfilename; From d662ec3b05bab242593646a195242ab9ed411269 Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 11 Oct 2024 10:18:39 +0100 Subject: [PATCH 056/146] Gitignore, heap-allocate some stuff --- jingle_sleigh/.gitignore | 1 + jingle_sleigh/src/ffi/cpp/sleigh_image.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/jingle_sleigh/.gitignore b/jingle_sleigh/.gitignore index 3954c15..6bcecb0 100644 --- a/jingle_sleigh/.gitignore +++ b/jingle_sleigh/.gitignore @@ -1,3 +1,4 @@ cmake-build-debug .idea +.cache build diff --git a/jingle_sleigh/src/ffi/cpp/sleigh_image.cpp b/jingle_sleigh/src/ffi/cpp/sleigh_image.cpp index f956616..254da51 100644 --- a/jingle_sleigh/src/ffi/cpp/sleigh_image.cpp +++ b/jingle_sleigh/src/ffi/cpp/sleigh_image.cpp @@ -4,7 +4,7 @@ #include "sleigh_image.h" #include "dummy_load_image.h" #include "varnode_translation.h" - +#include "sleigh/sleigh.hh" #include class PcodeCacher : public ghidra::PcodeEmit { @@ -54,8 +54,8 @@ class AssemblyCacher : public ghidra::AssemblyEmit { } }; -SleighImage::SleighImage(Image img, ghidra::Sleigh sl): sl(sl), image(DummyLoadImage(img)) { - sl.reset(&image, &c_db); +SleighImage::SleighImage(Image img, ghidra::Sleigh sl): sl(sl) { + sl.reset(new DummyLoadImage(img), new ghidra::ContextInternal()); } @@ -110,4 +110,4 @@ rust::Vec SleighImage::getRegisters() const { v.emplace_back(collectRegInfo(vn)); } return v; -} \ No newline at end of file +} From 7687a5e8edc73ff40174d3cc94e49d07c33f9e88 Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 11 Oct 2024 11:35:13 +0100 Subject: [PATCH 057/146] Tweaks --- jingle_sleigh/src/ffi/cpp/exception.h | 2 +- jingle_sleigh/src/ffi/cpp/sleigh_image.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/jingle_sleigh/src/ffi/cpp/exception.h b/jingle_sleigh/src/ffi/cpp/exception.h index 8151c57..430ba4f 100644 --- a/jingle_sleigh/src/ffi/cpp/exception.h +++ b/jingle_sleigh/src/ffi/cpp/exception.h @@ -16,7 +16,7 @@ namespace rust { } catch (const ghidra::DecoderError &e) { fail(e.explain); } catch (const std::exception &e) { - fail(e.what()); + throw e; } } } diff --git a/jingle_sleigh/src/ffi/cpp/sleigh_image.cpp b/jingle_sleigh/src/ffi/cpp/sleigh_image.cpp index 254da51..5e95b3c 100644 --- a/jingle_sleigh/src/ffi/cpp/sleigh_image.cpp +++ b/jingle_sleigh/src/ffi/cpp/sleigh_image.cpp @@ -54,8 +54,8 @@ class AssemblyCacher : public ghidra::AssemblyEmit { } }; -SleighImage::SleighImage(Image img, ghidra::Sleigh sl): sl(sl) { - sl.reset(new DummyLoadImage(img), new ghidra::ContextInternal()); +SleighImage::SleighImage(Image img, ghidra::Sleigh sl): sl(ghidra::Sleigh(sl)) { + this->sl.reset(new DummyLoadImage(img), new ghidra::ContextInternal()); } From 9cbc19afea606e938dae7d7ffeaa509d00fde47d Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 11 Oct 2024 14:07:04 +0100 Subject: [PATCH 058/146] Move back to storing all images directly in context --- jingle_sleigh/build.rs | 1 - jingle_sleigh/src/context/mod.rs | 21 +++--- jingle_sleigh/src/ffi/context_ffi.rs | 5 +- jingle_sleigh/src/ffi/cpp/context.cpp | 80 ++++++++++++++++++++-- jingle_sleigh/src/ffi/cpp/context.h | 4 +- jingle_sleigh/src/ffi/cpp/sleigh_image.cpp | 67 ------------------ jingle_sleigh/src/ffi/cpp/sleigh_image.h | 2 - jingle_sleigh/src/ffi/mod.rs | 17 ++--- 8 files changed, 97 insertions(+), 100 deletions(-) diff --git a/jingle_sleigh/build.rs b/jingle_sleigh/build.rs index 7ca3e23..c7e6da3 100644 --- a/jingle_sleigh/build.rs +++ b/jingle_sleigh/build.rs @@ -51,7 +51,6 @@ fn main() { "src/ffi/cpp/sleigh/slghparse.cc", "src/ffi/cpp/context.cpp", "src/ffi/cpp/dummy_load_image.cpp", - "src/ffi/cpp/sleigh_image.cpp", "src/ffi/cpp/addrspace_handle.cpp", "src/ffi/cpp/addrspace_manager_handle.cpp", "src/ffi/cpp/varnode_translation.cpp", diff --git a/jingle_sleigh/src/context/mod.rs b/jingle_sleigh/src/context/mod.rs index 6474944..f723fca 100644 --- a/jingle_sleigh/src/context/mod.rs +++ b/jingle_sleigh/src/context/mod.rs @@ -1,5 +1,4 @@ mod builder; -mod sleigh_image; use crate::error::JingleSleighError; use crate::error::JingleSleighError::{LanguageSpecRead, SleighInitError}; @@ -13,7 +12,6 @@ pub use builder::image::{Image, ImageSection}; pub use builder::SleighContextBuilder; use crate::context::builder::language_def::LanguageDefinition; -use crate::context::sleigh_image::SleighImage; use crate::ffi::context_ffi::CTX_BUILD_MUTEX; use crate::ffi::instruction::bridge::VarnodeInfoFFI; use crate::JingleSleighError::SleighCompilerMutexError; @@ -118,27 +116,32 @@ impl SleighContext { &self.language_id } - pub fn load_image>(&self, img: T) -> Result { + pub fn set_image>(&mut self, img: T) -> Result<(), JingleSleighError> { self.ctx - .makeImageContext(img.into()) - .map(SleighImage::new) + .pin_mut() + .setImage(img.into()) .map_err(|e| JingleSleighError::ImageLoadError) } + + pub fn instruction_at(&self, offset: u64) -> Option { + self.ctx + .get_one_instruction(offset) + .map(Instruction::from) + .ok() + } } #[cfg(test)] mod test { use crate::context::SleighContextBuilder; - use crate::RegisterManager; use crate::tests::SLEIGH_ARCH; + use crate::RegisterManager; #[test] fn get_regs() { let ctx_builder = SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); - let sleigh = ctx_builder - .build(SLEIGH_ARCH) - .unwrap(); + let sleigh = ctx_builder.build(SLEIGH_ARCH).unwrap(); assert_ne!(sleigh.get_registers(), vec![]); } } diff --git a/jingle_sleigh/src/ffi/context_ffi.rs b/jingle_sleigh/src/ffi/context_ffi.rs index 4802ff0..458fcab 100644 --- a/jingle_sleigh/src/ffi/context_ffi.rs +++ b/jingle_sleigh/src/ffi/context_ffi.rs @@ -19,7 +19,6 @@ pub(crate) mod bridge { type RegisterInfoFFI = crate::ffi::instruction::bridge::RegisterInfoFFI; - type SleighImage = crate::ffi::sleigh_image::bridge::SleighImage; } unsafe extern "C++" { @@ -30,7 +29,7 @@ pub(crate) mod bridge { pub(super) fn makeContext(slaPath: &str) -> Result>; pub(crate) fn set_initial_context(self: Pin<&mut ContextFFI>, name: &str, value: u32); - // pub(crate) fn get_one_instruction(&self, offset: u64) -> Result; + pub(crate) fn get_one_instruction(&self, offset: u64) -> Result; pub(crate) fn getSpaceByIndex(&self, idx: i32) -> SharedPtr; pub(crate) fn getNumSpaces(&self) -> i32; @@ -40,7 +39,7 @@ pub(crate) mod bridge { pub(crate) fn getRegisters(&self) -> Vec; - pub(crate) fn makeImageContext(&self, img: Image) -> Result>; + pub(crate) fn setImage(self: Pin<&mut ContextFFI>, img: Image) -> Result<()>; } impl Vec {} } diff --git a/jingle_sleigh/src/ffi/cpp/context.cpp b/jingle_sleigh/src/ffi/cpp/context.cpp index abc65be..e4010dc 100644 --- a/jingle_sleigh/src/ffi/cpp/context.cpp +++ b/jingle_sleigh/src/ffi/cpp/context.cpp @@ -3,11 +3,61 @@ #include #include +#include "sleigh/globalcontext.hh" #include "sleigh_image.h" #include "jingle_sleigh/src/ffi/instruction.rs.h" #include "sleigh/loadimage.hh" #include "varnode_translation.h" + +class PcodeCacher : public ghidra::PcodeEmit { +public: + rust::Vec ops; + + PcodeCacher() = default; + + void dump(const ghidra::Address &addr, ghidra::OpCode opc, ghidra::VarnodeData *outvar, ghidra::VarnodeData *vars, + ghidra::int4 isize) override { + RawPcodeOp op; + op.op = opc; + op.has_output = false; + if (outvar != nullptr && outvar->space != nullptr) { + op.has_output = true; + op.output.offset = outvar->offset; + op.output.size = outvar->size; + op.output.space = std::make_unique(AddrSpaceHandle(outvar->space)); + outvar->space->getType(); + } + op.inputs.reserve(isize); + for (int i = 0; i < isize; i++) { + VarnodeInfoFFI info; + info.space = std::make_unique(vars[i].space); + info.size = vars[i].size; + info.offset = vars[i].offset; + op.space = std::make_unique(addr.getSpace()); + op.inputs.emplace_back(std::move(info)); + } + ops.emplace_back(op); + + } +}; + +class AssemblyCacher : public ghidra::AssemblyEmit { +public: + rust::String mnem; + rust::String body; + + AssemblyCacher() : mnem(""), body("") { + + }; + + void dump(const ghidra::Address &addr, const std::string &mnem, const std::string &body) override { + this->mnem = mnem; + this->body = body; + } +}; + + ContextFFI::ContextFFI(rust::Str slaPath): sleigh(new DummyLoadImage(Image()), new ghidra::ContextInternal()) { ghidra::AttributeId::initialize(); ghidra::ElementId::initialize(); @@ -54,10 +104,6 @@ rust::Str ContextFFI::getRegisterName(VarnodeInfoFFI vn) const { return {name}; } -std::unique_ptr makeContext(rust::Str slaPath) { - return std::make_unique(slaPath); -} - rust::Vec ContextFFI::getRegisters() const { std::map reglist; rust::Vec v; @@ -69,6 +115,28 @@ rust::Vec ContextFFI::getRegisters() const { return v; } -std::unique_ptr ContextFFI::makeImageContext(Image img) const { - return std::make_unique(img, sleigh); +void ContextFFI::setImage(Image img) { + sleigh.reset(new DummyLoadImage(img), new ghidra::ContextInternal()); +} + +InstructionFFI ContextFFI::get_one_instruction(uint64_t offset) const { + PcodeCacher pcode; + AssemblyCacher assembly; + ghidra::Address a = ghidra::Address(sleigh.getDefaultCodeSpace(), offset); + sleigh.printAssembly(assembly, a); + sleigh.oneInstruction(pcode, a); + size_t length = sleigh.instructionLength(a); + InstructionFFI i; + Disassembly d; + i.ops = std::move(pcode.ops); + d.args = std::move(assembly.body); + d.mnemonic = std::move(assembly.mnem); + i.disassembly = std::move(d); + i.address = offset; + i.length = length; + return i; +} + +std::unique_ptr makeContext(rust::Str slaPath) { + return std::make_unique(slaPath); } diff --git a/jingle_sleigh/src/ffi/cpp/context.h b/jingle_sleigh/src/ffi/cpp/context.h index a5f3cdc..16d151c 100644 --- a/jingle_sleigh/src/ffi/cpp/context.h +++ b/jingle_sleigh/src/ffi/cpp/context.h @@ -22,7 +22,9 @@ class ContextFFI { void set_initial_context(rust::Str name, uint32_t val); - std::unique_ptr makeImageContext(Image img) const; + void setImage(Image img); + + InstructionFFI get_one_instruction(uint64_t offset) const; [[nodiscard]] std::shared_ptr getSpaceByIndex(ghidra::int4 idx) const; diff --git a/jingle_sleigh/src/ffi/cpp/sleigh_image.cpp b/jingle_sleigh/src/ffi/cpp/sleigh_image.cpp index 5e95b3c..ae8b442 100644 --- a/jingle_sleigh/src/ffi/cpp/sleigh_image.cpp +++ b/jingle_sleigh/src/ffi/cpp/sleigh_image.cpp @@ -7,59 +7,11 @@ #include "sleigh/sleigh.hh" #include -class PcodeCacher : public ghidra::PcodeEmit { -public: - rust::Vec ops; - - PcodeCacher() = default; - - void dump(const ghidra::Address &addr, ghidra::OpCode opc, ghidra::VarnodeData *outvar, ghidra::VarnodeData *vars, - ghidra::int4 isize) override { - RawPcodeOp op; - op.op = opc; - op.has_output = false; - if (outvar != nullptr && outvar->space != nullptr) { - op.has_output = true; - op.output.offset = outvar->offset; - op.output.size = outvar->size; - op.output.space = std::make_unique(AddrSpaceHandle(outvar->space)); - outvar->space->getType(); - } - op.inputs.reserve(isize); - for (int i = 0; i < isize; i++) { - VarnodeInfoFFI info; - info.space = std::make_unique(vars[i].space); - info.size = vars[i].size; - info.offset = vars[i].offset; - op.space = std::make_unique(addr.getSpace()); - op.inputs.emplace_back(std::move(info)); - } - ops.emplace_back(op); - - } -}; - -class AssemblyCacher : public ghidra::AssemblyEmit { -public: - rust::String mnem; - rust::String body; - - AssemblyCacher() : mnem(""), body("") { - - }; - - void dump(const ghidra::Address &addr, const std::string &mnem, const std::string &body) override { - this->mnem = mnem; - this->body = body; - } -}; SleighImage::SleighImage(Image img, ghidra::Sleigh sl): sl(ghidra::Sleigh(sl)) { this->sl.reset(new DummyLoadImage(img), new ghidra::ContextInternal()); } - - std::shared_ptr SleighImage::getSpaceByIndex(ghidra::int4 idx) const { return std::make_shared(sl.getSpace(idx)); } @@ -82,25 +34,6 @@ rust::Str SleighImage::getRegisterName(VarnodeInfoFFI vn) const { return {name}; } -InstructionFFI SleighImage::get_one_instruction(uint64_t offset) const { - PcodeCacher pcode; - AssemblyCacher assembly; - ghidra::Address a = ghidra::Address(sl.getDefaultCodeSpace(), offset); - sl.printAssembly(assembly, a); - sl.oneInstruction(pcode, a); - size_t length = sl.instructionLength(a); - InstructionFFI i; - Disassembly d; - i.ops = std::move(pcode.ops); - d.args = std::move(assembly.body); - d.mnemonic = std::move(assembly.mnem); - i.disassembly = std::move(d); - i.address = offset; - i.length = length; - return i; -} - - rust::Vec SleighImage::getRegisters() const { std::map reglist; rust::Vec v; diff --git a/jingle_sleigh/src/ffi/cpp/sleigh_image.h b/jingle_sleigh/src/ffi/cpp/sleigh_image.h index 8a4eeea..499bb65 100644 --- a/jingle_sleigh/src/ffi/cpp/sleigh_image.h +++ b/jingle_sleigh/src/ffi/cpp/sleigh_image.h @@ -14,8 +14,6 @@ class SleighImage{ ghidra::Sleigh sl; - ghidra::ContextInternal c_db; - DummyLoadImage image; public: SleighImage(Image img, ghidra::Sleigh sl); diff --git a/jingle_sleigh/src/ffi/mod.rs b/jingle_sleigh/src/ffi/mod.rs index c4bee1c..849259a 100644 --- a/jingle_sleigh/src/ffi/mod.rs +++ b/jingle_sleigh/src/ffi/mod.rs @@ -3,7 +3,6 @@ pub(crate) mod context_ffi; pub(crate) mod image; pub(crate) mod instruction; pub(crate) mod opcode; -pub(crate) mod sleigh_image; // Need to pull this in somewhere so that libz symbols are available // for the `sleigh` CPP code at link-time. @@ -20,11 +19,9 @@ mod tests { let builder = SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); - let sleigh = builder - .build("x86:LE:64:default") - .unwrap(); - let bin_image = sleigh.load_image(bytes.as_slice()).unwrap(); - let _lib = bin_image.instruction_at(0).unwrap(); + let mut sleigh = builder.build("x86:LE:64:default").unwrap(); + sleigh.set_image(bytes.as_slice()).unwrap(); + sleigh.instruction_at(0).unwrap(); } #[test] fn test_callother_decode2() { @@ -32,10 +29,8 @@ mod tests { let builder = SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); - let sleigh = builder - .build("x86:LE:64:default") - .unwrap(); - let bin_image = sleigh.load_image(bytes.as_slice()).unwrap(); - let _lib = bin_image.instruction_at(0).unwrap(); + let mut sleigh = builder.build("x86:LE:64:default").unwrap(); + sleigh.set_image(bytes.as_slice()).unwrap(); + sleigh.instruction_at(0).unwrap(); } } From f8586277bbac194f8a0a58ae934b3822cd120af0 Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 11 Oct 2024 14:50:56 +0100 Subject: [PATCH 059/146] Add test --- jingle_sleigh/src/ffi/mod.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/jingle_sleigh/src/ffi/mod.rs b/jingle_sleigh/src/ffi/mod.rs index 849259a..7de6b8a 100644 --- a/jingle_sleigh/src/ffi/mod.rs +++ b/jingle_sleigh/src/ffi/mod.rs @@ -12,6 +12,7 @@ use libz_sys::inflate; #[cfg(test)] mod tests { use crate::context::{Image, SleighContextBuilder}; + use crate::tests::SLEIGH_ARCH; #[test] fn test_callother_decode() { @@ -33,4 +34,21 @@ mod tests { sleigh.set_image(bytes.as_slice()).unwrap(); sleigh.instruction_at(0).unwrap(); } + + #[test] + fn test_two_images(){ + let mov_eax_0: [u8; 4] = [0x0f, 0x05, 0x0f, 0x05]; + let nops: [u8; 4] = [0x90, 0x90, 0x90, 0x90]; + let ctx_builder = + SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); + let mut sleigh = ctx_builder + .build(SLEIGH_ARCH) + .unwrap(); + sleigh.set_image(mov_eax_0.as_slice()).unwrap(); + let instr1 = sleigh.instruction_at(0); + sleigh.set_image(nops.as_slice()).unwrap(); + let instr2 = sleigh.instruction_at(0); + assert_ne!(instr1, instr2); + assert_ne!(instr1, None); + } } From 38e7770a45ee1baf720659c61df5c886e0697da1 Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 11 Oct 2024 15:36:51 +0100 Subject: [PATCH 060/146] Bump ghidra to 11.2 --- jingle_sleigh/ghidra | 2 +- jingle_sleigh/src/ffi/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/jingle_sleigh/ghidra b/jingle_sleigh/ghidra index febbeb4..5faf793 160000 --- a/jingle_sleigh/ghidra +++ b/jingle_sleigh/ghidra @@ -1 +1 @@ -Subproject commit febbeb447af1f059d583b11d7cefc8758b99f887 +Subproject commit 5faf79368040e33dc385af7a5bc8afc6ca1f5339 diff --git a/jingle_sleigh/src/ffi/mod.rs b/jingle_sleigh/src/ffi/mod.rs index 7de6b8a..e1291c4 100644 --- a/jingle_sleigh/src/ffi/mod.rs +++ b/jingle_sleigh/src/ffi/mod.rs @@ -11,7 +11,7 @@ use libz_sys::inflate; #[cfg(test)] mod tests { - use crate::context::{Image, SleighContextBuilder}; + use crate::context::{SleighContextBuilder}; use crate::tests::SLEIGH_ARCH; #[test] From ed0abaa17ae9b569f3d726d9dd8650fa5fe5a1c9 Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 11 Oct 2024 15:44:41 +0100 Subject: [PATCH 061/146] Fix jingle build --- jingle/src/translator.rs | 3 +-- jingle_sleigh/src/context/builder/image/elf.rs | 2 +- jingle_sleigh/src/context/builder/mod.rs | 5 ++--- jingle_sleigh/src/context/mod.rs | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/jingle/src/translator.rs b/jingle/src/translator.rs index 2927a95..42517c0 100644 --- a/jingle/src/translator.rs +++ b/jingle/src/translator.rs @@ -31,8 +31,7 @@ impl<'ctx> SleighTranslator<'ctx> { ) -> Result, JingleError> { let op = self .sleigh - .read(offset, 1) - .next() + .instruction_at(offset) .ok_or(InstructionDecode)?; self.model_instruction(op) } diff --git a/jingle_sleigh/src/context/builder/image/elf.rs b/jingle_sleigh/src/context/builder/image/elf.rs index dd0447e..d952dae 100644 --- a/jingle_sleigh/src/context/builder/image/elf.rs +++ b/jingle_sleigh/src/context/builder/image/elf.rs @@ -45,7 +45,7 @@ mod tests { use elf::ElfBytes; // #[test] - fn test_elf() { + fn _test_elf() { let path = std::path::PathBuf::from("../bin/vuln"); let file_data = std::fs::read(path).unwrap(); let slice = file_data.as_slice(); diff --git a/jingle_sleigh/src/context/builder/mod.rs b/jingle_sleigh/src/context/builder/mod.rs index 4529c88..085c040 100644 --- a/jingle_sleigh/src/context/builder/mod.rs +++ b/jingle_sleigh/src/context/builder/mod.rs @@ -1,9 +1,8 @@ -use crate::context::builder::image::Image; use crate::context::builder::language_def::{parse_ldef, LanguageDefinition}; use crate::context::builder::processor_spec::parse_pspec; use crate::context::SleighContext; use crate::error::JingleSleighError; -use crate::error::JingleSleighError::{InvalidLanguageId, LanguageSpecRead, NoImageProvided}; +use crate::error::JingleSleighError::{InvalidLanguageId, LanguageSpecRead}; use std::fmt::Debug; use std::fs; use std::path::{Path, PathBuf}; @@ -27,7 +26,7 @@ impl SleighContextBuilder { self.defs.iter().find(|(p, _)| p.id.eq(id)) } #[instrument(skip_all, fields(%id))] - pub fn build(mut self, id: &str) -> Result { + pub fn build(&self, id: &str) -> Result { let (lang, path) = self.get_language(id).ok_or(InvalidLanguageId)?; let mut context = SleighContext::new(lang, path)?; event!(Level::INFO, "Created sleigh context"); diff --git a/jingle_sleigh/src/context/mod.rs b/jingle_sleigh/src/context/mod.rs index f723fca..c174fe7 100644 --- a/jingle_sleigh/src/context/mod.rs +++ b/jingle_sleigh/src/context/mod.rs @@ -120,7 +120,7 @@ impl SleighContext { self.ctx .pin_mut() .setImage(img.into()) - .map_err(|e| JingleSleighError::ImageLoadError) + .map_err(|_| JingleSleighError::ImageLoadError) } pub fn instruction_at(&self, offset: u64) -> Option { From 93d5272fb6a9ef3b89c1c12de6546a7fb89b9230 Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 11 Oct 2024 16:03:32 +0100 Subject: [PATCH 062/146] Fix jingle binary build --- jingle/src/main.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/jingle/src/main.rs b/jingle/src/main.rs index e05944d..ef2a4a7 100644 --- a/jingle/src/main.rs +++ b/jingle/src/main.rs @@ -117,17 +117,17 @@ fn get_instructions( let img = decode(hex_bytes).unwrap(); let max_len = img.len(); let mut offset = 0; - let sleigh = sleigh_build - .set_image(Image::from(img)) + let mut sleigh = sleigh_build .build(&architecture) .unwrap(); + sleigh.set_image(img).unwrap(); let mut instrs = vec![]; while offset < max_len { - for instruction in sleigh.read(offset as u64, 1) { + for instruction in sleigh.instruction_at(offset as u64) { offset += instruction.length; instrs.push(instruction); } - if sleigh.read(offset as u64, 1).next().is_none() { + if sleigh.instruction_at(offset as u64).is_none() { break; } } From 7e739f661dd0860920f38c225fc9039f157ab683 Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 11 Oct 2024 17:11:53 +0100 Subject: [PATCH 063/146] Fixes context variables --- jingle_sleigh/src/context/builder/mod.rs | 4 +-- .../instruction_iterator.rs | 26 +++++++++---------- jingle_sleigh/src/context/mod.rs | 23 +++++++++++++--- jingle_sleigh/src/ffi/context_ffi.rs | 2 +- jingle_sleigh/src/ffi/cpp/context.cpp | 4 +-- 5 files changed, 36 insertions(+), 23 deletions(-) rename jingle_sleigh/src/context/{sleigh_image => }/instruction_iterator.rs (77%) diff --git a/jingle_sleigh/src/context/builder/mod.rs b/jingle_sleigh/src/context/builder/mod.rs index 085c040..1375199 100644 --- a/jingle_sleigh/src/context/builder/mod.rs +++ b/jingle_sleigh/src/context/builder/mod.rs @@ -39,12 +39,12 @@ impl SleighContextBuilder { context.set_initial_context( &set.name, u32::from_str_radix(&set.value[2..], 16).unwrap(), - ) + )?; } else { context.set_initial_context( &set.name, u32::from_str_radix(&set.value, 10).unwrap(), - ) + )?; } } } diff --git a/jingle_sleigh/src/context/sleigh_image/instruction_iterator.rs b/jingle_sleigh/src/context/instruction_iterator.rs similarity index 77% rename from jingle_sleigh/src/context/sleigh_image/instruction_iterator.rs rename to jingle_sleigh/src/context/instruction_iterator.rs index ded2e20..40badca 100644 --- a/jingle_sleigh/src/context/sleigh_image/instruction_iterator.rs +++ b/jingle_sleigh/src/context/instruction_iterator.rs @@ -1,9 +1,8 @@ -use crate::context::sleigh_image::SleighImage; -use crate::context::{Image, SleighContext}; +use crate::context::{SleighContext}; use crate::Instruction; pub struct SleighContextInstructionIterator<'a> { - sleigh: &'a SleighImage, + sleigh: &'a SleighContext, remaining: usize, offset: u64, terminate_branch: bool, @@ -12,7 +11,7 @@ pub struct SleighContextInstructionIterator<'a> { impl<'a> SleighContextInstructionIterator<'a> { pub(crate) fn new( - sleigh: &'a SleighImage, + sleigh: &'a SleighContext, offset: u64, remaining: usize, terminate_branch: bool, @@ -39,7 +38,7 @@ impl<'a> Iterator for SleighContextInstructionIterator<'a> { } let instr = self .sleigh - .img_ffi + .ctx .get_one_instruction(self.offset) .map(Instruction::from) .ok()?; @@ -52,10 +51,9 @@ impl<'a> Iterator for SleighContextInstructionIterator<'a> { #[cfg(test)] mod test { - use crate::context::builder::image::Image; use crate::context::builder::SleighContextBuilder; use crate::pcode::PcodeOperation; - use crate::{Instruction, RegisterManager, SpaceManager}; + use crate::{Instruction, SpaceManager}; use crate::tests::SLEIGH_ARCH; use crate::varnode; @@ -65,10 +63,10 @@ mod test { let mov_eax_0: [u8; 6] = [0xb8, 0x00, 0x00, 0x00, 0x00, 0xc3]; let ctx_builder = SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); - let sleigh = ctx_builder + let mut sleigh = ctx_builder .build(SLEIGH_ARCH) .unwrap(); - let sleigh = sleigh.load_image(mov_eax_0.as_slice()).unwrap(); + sleigh.set_image(mov_eax_0.as_slice()).unwrap(); let instr = sleigh.read(0, 1).last().unwrap(); assert_eq!(instr.length, 5); assert!(instr.disassembly.mnemonic.eq("MOV")); @@ -83,15 +81,15 @@ mod test { #[test] fn stop_at_branch() { - let mov_eax_0: [u8; 4] = [0x0f, 0x05, 0x0f, 0x05]; + let mov_eax_0: [u8; 4] = [0x90, 0x90, 0x90, 0x90]; let ctx_builder = SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); - let sleigh = ctx_builder + let mut sleigh = ctx_builder .build(SLEIGH_ARCH) .unwrap(); - let sleigh_img = sleigh.load_image(mov_eax_0.as_slice()).unwrap(); - let instr: Vec = sleigh_img.read(0, 2).collect(); - assert_eq!(instr.len(), 1); + sleigh.set_image(mov_eax_0.as_slice()).unwrap(); + let instr: Vec = sleigh.read(0, 5).collect(); + assert_eq!(instr.len(), 4); } } diff --git a/jingle_sleigh/src/context/mod.rs b/jingle_sleigh/src/context/mod.rs index c174fe7..7400075 100644 --- a/jingle_sleigh/src/context/mod.rs +++ b/jingle_sleigh/src/context/mod.rs @@ -1,5 +1,7 @@ mod builder; +mod instruction_iterator; +use std::collections::HashMap; use crate::error::JingleSleighError; use crate::error::JingleSleighError::{LanguageSpecRead, SleighInitError}; use crate::ffi::addrspace::bridge::AddrSpaceHandle; @@ -14,11 +16,12 @@ pub use builder::SleighContextBuilder; use crate::context::builder::language_def::LanguageDefinition; use crate::ffi::context_ffi::CTX_BUILD_MUTEX; use crate::ffi::instruction::bridge::VarnodeInfoFFI; -use crate::JingleSleighError::SleighCompilerMutexError; +use crate::JingleSleighError::{ImageLoadError, SleighCompilerMutexError}; use crate::VarNode; use cxx::{SharedPtr, UniquePtr}; use std::fmt::{Debug, Formatter}; use std::path::Path; +use crate::context::instruction_iterator::SleighContextInstructionIterator; pub struct SleighContext { ctx: UniquePtr, @@ -100,8 +103,8 @@ impl SleighContext { } } - pub(crate) fn set_initial_context(&mut self, name: &str, value: u32) { - self.ctx.pin_mut().set_initial_context(name, value); + pub(crate) fn set_initial_context(&mut self, name: &str, value: u32) -> Result<(), JingleSleighError> { + self.ctx.pin_mut().set_initial_context(name, value).map_err(|_| ImageLoadError) } pub fn spaces(&self) -> Vec> { @@ -120,7 +123,7 @@ impl SleighContext { self.ctx .pin_mut() .setImage(img.into()) - .map_err(|_| JingleSleighError::ImageLoadError) + .map_err(|_| ImageLoadError) } pub fn instruction_at(&self, offset: u64) -> Option { @@ -129,6 +132,18 @@ impl SleighContext { .map(Instruction::from) .ok() } + + pub fn read(&self, offset: u64, max_instrs: usize) -> SleighContextInstructionIterator { + SleighContextInstructionIterator::new(self, offset, max_instrs, false) + } + + pub fn read_until_branch( + &self, + offset: u64, + max_instrs: usize, + ) -> SleighContextInstructionIterator { + SleighContextInstructionIterator::new(self, offset, max_instrs, true) + } } #[cfg(test)] diff --git a/jingle_sleigh/src/ffi/context_ffi.rs b/jingle_sleigh/src/ffi/context_ffi.rs index 458fcab..49d7d4c 100644 --- a/jingle_sleigh/src/ffi/context_ffi.rs +++ b/jingle_sleigh/src/ffi/context_ffi.rs @@ -27,7 +27,7 @@ pub(crate) mod bridge { pub(crate) type ContextFFI; pub(super) fn makeContext(slaPath: &str) -> Result>; - pub(crate) fn set_initial_context(self: Pin<&mut ContextFFI>, name: &str, value: u32); + pub(crate) fn set_initial_context(self: Pin<&mut ContextFFI>, name: &str, value: u32) -> Result<()>; pub(crate) fn get_one_instruction(&self, offset: u64) -> Result; diff --git a/jingle_sleigh/src/ffi/cpp/context.cpp b/jingle_sleigh/src/ffi/cpp/context.cpp index e4010dc..d99b5d7 100644 --- a/jingle_sleigh/src/ffi/cpp/context.cpp +++ b/jingle_sleigh/src/ffi/cpp/context.cpp @@ -58,7 +58,7 @@ class AssemblyCacher : public ghidra::AssemblyEmit { }; -ContextFFI::ContextFFI(rust::Str slaPath): sleigh(new DummyLoadImage(Image()), new ghidra::ContextInternal()) { +ContextFFI::ContextFFI(rust::Str slaPath): sleigh(new DummyLoadImage(Image()), &c_db) { ghidra::AttributeId::initialize(); ghidra::ElementId::initialize(); @@ -116,7 +116,7 @@ rust::Vec ContextFFI::getRegisters() const { } void ContextFFI::setImage(Image img) { - sleigh.reset(new DummyLoadImage(img), new ghidra::ContextInternal()); + sleigh.reset(new DummyLoadImage(std::move(img)), &c_db); } InstructionFFI ContextFFI::get_one_instruction(uint64_t offset) const { From 0edbc827904f04f427a10addf44c5ba23e83cdb3 Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 11 Oct 2024 18:21:26 +0100 Subject: [PATCH 064/146] Re-add image --- jingle_sleigh/src/context/mod.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/jingle_sleigh/src/context/mod.rs b/jingle_sleigh/src/context/mod.rs index 7400075..0d72917 100644 --- a/jingle_sleigh/src/context/mod.rs +++ b/jingle_sleigh/src/context/mod.rs @@ -1,7 +1,6 @@ mod builder; mod instruction_iterator; -use std::collections::HashMap; use crate::error::JingleSleighError; use crate::error::JingleSleighError::{LanguageSpecRead, SleighInitError}; use crate::ffi::addrspace::bridge::AddrSpaceHandle; @@ -25,6 +24,7 @@ use crate::context::instruction_iterator::SleighContextInstructionIterator; pub struct SleighContext { ctx: UniquePtr, + image: Option, spaces: Vec, language_id: String, } @@ -96,6 +96,7 @@ impl SleighContext { Ok(Self { ctx, spaces, + image: None, language_id: language_def.id.clone(), }) } @@ -119,13 +120,18 @@ impl SleighContext { &self.language_id } - pub fn set_image>(&mut self, img: T) -> Result<(), JingleSleighError> { + pub fn set_image + Clone>(&mut self, img: T) -> Result<(), JingleSleighError> { + self.image = Some(img.clone().into()); self.ctx .pin_mut() .setImage(img.into()) .map_err(|_| ImageLoadError) } + pub fn get_image(&self) -> Option<&Image>{ + self.image.as_ref() + } + pub fn instruction_at(&self, offset: u64) -> Option { self.ctx .get_one_instruction(offset) From cdf0df60cbf93b6e1db6f22c5ab4e5f76bff6390 Mon Sep 17 00:00:00 2001 From: Mark Date: Sat, 12 Oct 2024 10:53:15 +0100 Subject: [PATCH 065/146] Add initialize call --- jingle_sleigh/src/ffi/cpp/context.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/jingle_sleigh/src/ffi/cpp/context.cpp b/jingle_sleigh/src/ffi/cpp/context.cpp index d99b5d7..52b4af5 100644 --- a/jingle_sleigh/src/ffi/cpp/context.cpp +++ b/jingle_sleigh/src/ffi/cpp/context.cpp @@ -4,6 +4,7 @@ #include #include #include "sleigh/globalcontext.hh" +#include "sleigh/xml.hh" #include "sleigh_image.h" #include "jingle_sleigh/src/ffi/instruction.rs.h" #include "sleigh/loadimage.hh" @@ -117,6 +118,8 @@ rust::Vec ContextFFI::getRegisters() const { void ContextFFI::setImage(Image img) { sleigh.reset(new DummyLoadImage(std::move(img)), &c_db); + ghidra::DocumentStorage documentStorage = ghidra::DocumentStorage(); + sleigh.initialize(documentStorage); } InstructionFFI ContextFFI::get_one_instruction(uint64_t offset) const { From 615ae9f8f1f3bf6553c9edd73106dec9ac1f0a60 Mon Sep 17 00:00:00 2001 From: Mark Date: Sat, 12 Oct 2024 23:24:25 +0100 Subject: [PATCH 066/146] Some bounds checking fixes --- jingle_sleigh/src/context/builder/image/mod.rs | 8 ++++++-- jingle_sleigh/src/context/mod.rs | 11 ++++++++--- jingle_sleigh/src/ffi/cpp/dummy_load_image.cpp | 2 +- jingle_sleigh/src/ffi/mod.rs | 7 ++++++- 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/jingle_sleigh/src/context/builder/image/mod.rs b/jingle_sleigh/src/context/builder/image/mod.rs index ec3d764..ee7033b 100644 --- a/jingle_sleigh/src/context/builder/image/mod.rs +++ b/jingle_sleigh/src/context/builder/image/mod.rs @@ -21,10 +21,14 @@ impl Image { &self.sections } - pub fn contains_address(&self, addr: usize) -> bool { + pub fn contains_address(&self, addr: u64) -> bool { self.sections .iter() - .any(|s| s.base_address <= addr && (s.base_address + s.data.len()) >= addr) + .any(|s| s.base_address <= addr as usize && (s.base_address + s.data.len()) >= addr as usize) + } + + pub fn contains_range(&self, mut range: Range) -> bool { + range.all(|i| self.contains_address(i)) } } diff --git a/jingle_sleigh/src/context/mod.rs b/jingle_sleigh/src/context/mod.rs index 0d72917..379c134 100644 --- a/jingle_sleigh/src/context/mod.rs +++ b/jingle_sleigh/src/context/mod.rs @@ -128,15 +128,20 @@ impl SleighContext { .map_err(|_| ImageLoadError) } - pub fn get_image(&self) -> Option<&Image>{ + pub fn get_image(&self) -> Option<&Image> { self.image.as_ref() } pub fn instruction_at(&self, offset: u64) -> Option { - self.ctx + let instr = self.ctx .get_one_instruction(offset) .map(Instruction::from) - .ok() + .ok()?; + if self.image.as_ref()?.contains_range(offset..(offset + instr.length as u64)) { + Some(instr) + } else { + None + } } pub fn read(&self, offset: u64, max_instrs: usize) -> SleighContextInstructionIterator { diff --git a/jingle_sleigh/src/ffi/cpp/dummy_load_image.cpp b/jingle_sleigh/src/ffi/cpp/dummy_load_image.cpp index dd26e49..ddf576f 100644 --- a/jingle_sleigh/src/ffi/cpp/dummy_load_image.cpp +++ b/jingle_sleigh/src/ffi/cpp/dummy_load_image.cpp @@ -22,7 +22,7 @@ void DummyLoadImage::loadFill(ghidra::uint1 *ptr, ghidra::int4 size, const ghidr bytes_written += len; } } - for (size_t i = offset; i < size; ++i) { + for (size_t i = bytes_written; i < size; ++i) { ptr[i] = 0; } if (bytes_written == 0) { diff --git a/jingle_sleigh/src/ffi/mod.rs b/jingle_sleigh/src/ffi/mod.rs index e1291c4..b738c06 100644 --- a/jingle_sleigh/src/ffi/mod.rs +++ b/jingle_sleigh/src/ffi/mod.rs @@ -38,7 +38,7 @@ mod tests { #[test] fn test_two_images(){ let mov_eax_0: [u8; 4] = [0x0f, 0x05, 0x0f, 0x05]; - let nops: [u8; 4] = [0x90, 0x90, 0x90, 0x90]; + let nops: [u8; 9] = [0x90, 0x90, 0x90, 0x90, 0x0f, 0x05, 0x0f, 0x05, 0x0f]; let ctx_builder = SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); let mut sleigh = ctx_builder @@ -50,5 +50,10 @@ mod tests { let instr2 = sleigh.instruction_at(0); assert_ne!(instr1, instr2); assert_ne!(instr1, None); + let instr2 = sleigh.instruction_at(4); + assert_ne!(instr1, instr2); + assert_ne!(instr2, None); + let instr3 = sleigh.instruction_at(8); + assert_eq!(instr3, None); } } From eacb48a536f4ce419f5a50c110817201d99ed255 Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 14 Oct 2024 10:46:48 +0100 Subject: [PATCH 067/146] Move pcode/assembly emitters into their own files --- jingle_sleigh/CMakeLists.txt | 5 +- jingle_sleigh/build.rs | 2 + jingle_sleigh/src/ffi/cpp/context.cpp | 54 ++----------------- .../src/ffi/cpp/jingle_assembly_emitter.cpp | 11 ++++ .../src/ffi/cpp/jingle_assembly_emitter.h | 21 ++++++++ .../src/ffi/cpp/jingle_pcode_emitter.cpp | 33 ++++++++++++ .../src/ffi/cpp/jingle_pcode_emitter.h | 20 +++++++ 7 files changed, 95 insertions(+), 51 deletions(-) create mode 100644 jingle_sleigh/src/ffi/cpp/jingle_assembly_emitter.cpp create mode 100644 jingle_sleigh/src/ffi/cpp/jingle_assembly_emitter.h create mode 100644 jingle_sleigh/src/ffi/cpp/jingle_pcode_emitter.cpp create mode 100644 jingle_sleigh/src/ffi/cpp/jingle_pcode_emitter.h diff --git a/jingle_sleigh/CMakeLists.txt b/jingle_sleigh/CMakeLists.txt index acfe038..552e320 100644 --- a/jingle_sleigh/CMakeLists.txt +++ b/jingle_sleigh/CMakeLists.txt @@ -35,7 +35,10 @@ add_library(jingle_sleigh_cpp src/ffi/cpp/sleigh_image.h src/ffi/cpp/exception.h src/ffi/cpp/varnode_translation.cpp - src/ffi/cpp/varnode_translation.h) + src/ffi/cpp/varnode_translation.h + src/ffi/cpp/jingle_pcode_emitter.cpp + src/ffi/cpp/jingle_assembly_emitter.cpp + src/ffi/cpp/jingle_assembly_emitter.h) add_executable(sleigh_compile src/ffi/cpp/sleigh/address.cc diff --git a/jingle_sleigh/build.rs b/jingle_sleigh/build.rs index c7e6da3..701b695 100644 --- a/jingle_sleigh/build.rs +++ b/jingle_sleigh/build.rs @@ -54,6 +54,8 @@ fn main() { "src/ffi/cpp/addrspace_handle.cpp", "src/ffi/cpp/addrspace_manager_handle.cpp", "src/ffi/cpp/varnode_translation.cpp", + "src/ffi/cpp/jingle_pcode_emitter.cpp", + "src/ffi/cpp/jingle_assembly_emitter.cpp", ]; // This assumes all your C++ bindings are in lib cxx_build::bridges(rust_sources) diff --git a/jingle_sleigh/src/ffi/cpp/context.cpp b/jingle_sleigh/src/ffi/cpp/context.cpp index 52b4af5..c55f87a 100644 --- a/jingle_sleigh/src/ffi/cpp/context.cpp +++ b/jingle_sleigh/src/ffi/cpp/context.cpp @@ -9,54 +9,8 @@ #include "jingle_sleigh/src/ffi/instruction.rs.h" #include "sleigh/loadimage.hh" #include "varnode_translation.h" - - -class PcodeCacher : public ghidra::PcodeEmit { -public: - rust::Vec ops; - - PcodeCacher() = default; - - void dump(const ghidra::Address &addr, ghidra::OpCode opc, ghidra::VarnodeData *outvar, ghidra::VarnodeData *vars, - ghidra::int4 isize) override { - RawPcodeOp op; - op.op = opc; - op.has_output = false; - if (outvar != nullptr && outvar->space != nullptr) { - op.has_output = true; - op.output.offset = outvar->offset; - op.output.size = outvar->size; - op.output.space = std::make_unique(AddrSpaceHandle(outvar->space)); - outvar->space->getType(); - } - op.inputs.reserve(isize); - for (int i = 0; i < isize; i++) { - VarnodeInfoFFI info; - info.space = std::make_unique(vars[i].space); - info.size = vars[i].size; - info.offset = vars[i].offset; - op.space = std::make_unique(addr.getSpace()); - op.inputs.emplace_back(std::move(info)); - } - ops.emplace_back(op); - - } -}; - -class AssemblyCacher : public ghidra::AssemblyEmit { -public: - rust::String mnem; - rust::String body; - - AssemblyCacher() : mnem(""), body("") { - - }; - - void dump(const ghidra::Address &addr, const std::string &mnem, const std::string &body) override { - this->mnem = mnem; - this->body = body; - } -}; +#include "jingle_pcode_emitter.h" +#include "jingle_assembly_emitter.h" ContextFFI::ContextFFI(rust::Str slaPath): sleigh(new DummyLoadImage(Image()), &c_db) { @@ -123,8 +77,8 @@ void ContextFFI::setImage(Image img) { } InstructionFFI ContextFFI::get_one_instruction(uint64_t offset) const { - PcodeCacher pcode; - AssemblyCacher assembly; + JinglePcodeEmitter pcode; + JingleAssemblyEmitter assembly; ghidra::Address a = ghidra::Address(sleigh.getDefaultCodeSpace(), offset); sleigh.printAssembly(assembly, a); sleigh.oneInstruction(pcode, a); diff --git a/jingle_sleigh/src/ffi/cpp/jingle_assembly_emitter.cpp b/jingle_sleigh/src/ffi/cpp/jingle_assembly_emitter.cpp new file mode 100644 index 0000000..5a0502e --- /dev/null +++ b/jingle_sleigh/src/ffi/cpp/jingle_assembly_emitter.cpp @@ -0,0 +1,11 @@ +// +// Created by toolCHAINZ on 10/14/24. +// + +#include "jingle_assembly_emitter.h" + +void JingleAssemblyEmitter::dump(const ghidra::Address &addr, const std::string &mnem, const std::string &body) { + this->mnem = mnem; + this->body = body; + +} diff --git a/jingle_sleigh/src/ffi/cpp/jingle_assembly_emitter.h b/jingle_sleigh/src/ffi/cpp/jingle_assembly_emitter.h new file mode 100644 index 0000000..517ccd7 --- /dev/null +++ b/jingle_sleigh/src/ffi/cpp/jingle_assembly_emitter.h @@ -0,0 +1,21 @@ +// +// Created by toolCHAINZ on 10/14/24. +// + +#ifndef JINGLE_SLEIGH_JINGLE_ASSEMBLY_EMITTER_H +#define JINGLE_SLEIGH_JINGLE_ASSEMBLY_EMITTER_H + +#include "sleigh/translate.hh" +#include "rust/cxx.h" + +class JingleAssemblyEmitter : public ghidra::AssemblyEmit { + + + void dump(const ghidra::Address &addr, const std::string &mnem, const std::string &body) override; + +public: + rust::String body; + rust::String mnem; +}; + +#endif //JINGLE_SLEIGH_JINGLE_ASSEMBLY_EMITTER_H diff --git a/jingle_sleigh/src/ffi/cpp/jingle_pcode_emitter.cpp b/jingle_sleigh/src/ffi/cpp/jingle_pcode_emitter.cpp new file mode 100644 index 0000000..78798f5 --- /dev/null +++ b/jingle_sleigh/src/ffi/cpp/jingle_pcode_emitter.cpp @@ -0,0 +1,33 @@ + +// +// Created by toolCHAINZ on 10/14/24. +// + +#include "jingle_pcode_emitter.h" +#include "addrspace_handle.h" + +void JinglePcodeEmitter::dump(const ghidra::Address &addr, ghidra::OpCode opc, ghidra::VarnodeData *outvar, + ghidra::VarnodeData *vars, ghidra::int4 isize) { + RawPcodeOp op; + op.op = opc; + op.has_output = false; + if (outvar != nullptr && outvar->space != nullptr) { + op.has_output = true; + op.output.offset = outvar->offset; + op.output.size = outvar->size; + op.output.space = std::make_unique(AddrSpaceHandle(outvar->space)); + outvar->space->getType(); + } + op.inputs.reserve(isize); + for (int i = 0; i < isize; i++) { + VarnodeInfoFFI info; + info.space = std::make_unique(vars[i].space); + info.size = vars[i].size; + info.offset = vars[i].offset; + op.space = std::make_unique(addr.getSpace()); + op.inputs.emplace_back(std::move(info)); + } + ops.emplace_back(op); + + +} diff --git a/jingle_sleigh/src/ffi/cpp/jingle_pcode_emitter.h b/jingle_sleigh/src/ffi/cpp/jingle_pcode_emitter.h new file mode 100644 index 0000000..11bf90f --- /dev/null +++ b/jingle_sleigh/src/ffi/cpp/jingle_pcode_emitter.h @@ -0,0 +1,20 @@ +// +// Created by toolCHAINZ on 10/14/24. +// + +#ifndef JINGLE_SLEIGH_JINGLE_PCODE_EMITTER_H +#define JINGLE_SLEIGH_JINGLE_PCODE_EMITTER_H + +#include "sleigh/translate.hh" +#include "jingle_sleigh/src/ffi/instruction.rs.h" + +class JinglePcodeEmitter : public ghidra::PcodeEmit { + + void dump(const ghidra::Address &addr, ghidra::OpCode opc, ghidra::VarnodeData *outvar, ghidra::VarnodeData *vars, + ghidra::int4 isize) override; + +public: + rust::Vec ops; +}; + +#endif //JINGLE_SLEIGH_JINGLE_PCODE_EMITTER_H From 7aa1c4708c60678f86872a861ecce751fbf6d12e Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 14 Oct 2024 11:26:47 +0100 Subject: [PATCH 068/146] Add test --- jingle_sleigh/src/context/mod.rs | 59 ++++++++++++++++++++++++++++---- 1 file changed, 53 insertions(+), 6 deletions(-) diff --git a/jingle_sleigh/src/context/mod.rs b/jingle_sleigh/src/context/mod.rs index 379c134..8f61993 100644 --- a/jingle_sleigh/src/context/mod.rs +++ b/jingle_sleigh/src/context/mod.rs @@ -13,6 +13,7 @@ pub use builder::image::{Image, ImageSection}; pub use builder::SleighContextBuilder; use crate::context::builder::language_def::LanguageDefinition; +use crate::context::instruction_iterator::SleighContextInstructionIterator; use crate::ffi::context_ffi::CTX_BUILD_MUTEX; use crate::ffi::instruction::bridge::VarnodeInfoFFI; use crate::JingleSleighError::{ImageLoadError, SleighCompilerMutexError}; @@ -20,7 +21,6 @@ use crate::VarNode; use cxx::{SharedPtr, UniquePtr}; use std::fmt::{Debug, Formatter}; use std::path::Path; -use crate::context::instruction_iterator::SleighContextInstructionIterator; pub struct SleighContext { ctx: UniquePtr, @@ -104,8 +104,15 @@ impl SleighContext { } } - pub(crate) fn set_initial_context(&mut self, name: &str, value: u32) -> Result<(), JingleSleighError> { - self.ctx.pin_mut().set_initial_context(name, value).map_err(|_| ImageLoadError) + pub(crate) fn set_initial_context( + &mut self, + name: &str, + value: u32, + ) -> Result<(), JingleSleighError> { + self.ctx + .pin_mut() + .set_initial_context(name, value) + .map_err(|_| ImageLoadError) } pub fn spaces(&self) -> Vec> { @@ -133,11 +140,16 @@ impl SleighContext { } pub fn instruction_at(&self, offset: u64) -> Option { - let instr = self.ctx + let instr = self + .ctx .get_one_instruction(offset) .map(Instruction::from) .ok()?; - if self.image.as_ref()?.contains_range(offset..(offset + instr.length as u64)) { + if self + .image + .as_ref()? + .contains_range(offset..(offset + instr.length as u64)) + { Some(instr) } else { None @@ -161,7 +173,7 @@ impl SleighContext { mod test { use crate::context::SleighContextBuilder; use crate::tests::SLEIGH_ARCH; - use crate::RegisterManager; + use crate::{RegisterManager, VarNode}; #[test] fn get_regs() { @@ -170,4 +182,39 @@ mod test { let sleigh = ctx_builder.build(SLEIGH_ARCH).unwrap(); assert_ne!(sleigh.get_registers(), vec![]); } + + #[test] + fn get_register_name() { + let ctx_builder = + SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); + let sleigh = ctx_builder.build(SLEIGH_ARCH).unwrap(); + for (vn, name) in sleigh.get_registers() { + let addr = sleigh.get_register(&name); + assert_eq!(addr, Some(vn)); + } + } + + #[test] + fn get_invalid_register_name() { + let ctx_builder = + SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); + let sleigh = ctx_builder.build(SLEIGH_ARCH).unwrap(); + assert_eq!(sleigh.get_register("fake"), None); + } + + #[test] + fn get_invalid_register() { + let ctx_builder = + SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); + let sleigh = ctx_builder.build(SLEIGH_ARCH).unwrap(); + + assert_eq!( + sleigh.get_register_name(VarNode { + space_index: 4, + offset: 512, + size: 1 + }), + None + ); + } } From 61ce6d7d3e50976fdcb6561597255de8389ad88c Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 14 Oct 2024 11:42:50 +0100 Subject: [PATCH 069/146] Change get_reg impl for now --- jingle_sleigh/src/context/mod.rs | 43 +++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/jingle_sleigh/src/context/mod.rs b/jingle_sleigh/src/context/mod.rs index 8f61993..c62291c 100644 --- a/jingle_sleigh/src/context/mod.rs +++ b/jingle_sleigh/src/context/mod.rs @@ -27,6 +27,7 @@ pub struct SleighContext { image: Option, spaces: Vec, language_id: String, + registers: Vec<(VarNode, String)> } impl Debug for SleighContext { @@ -55,26 +56,15 @@ impl SpaceManager for SleighContext { impl RegisterManager for SleighContext { fn get_register(&self, name: &str) -> Option { - self.ctx.getRegister(name).map(VarNode::from).ok() + self.registers.iter().find(|(_,reg_name)| reg_name.as_str() == name).map(|(vn,_)| vn.clone()) } fn get_register_name(&self, location: VarNode) -> Option<&str> { - let space = self.ctx.getSpaceByIndex(location.space_index as i32); - self.ctx - .getRegisterName(VarnodeInfoFFI { - space, - offset: location.offset, - size: location.size, - }) - .ok() + self.registers.iter().find(|(vn,_)| vn == &location).map(|(_,name)| name.as_str()) } fn get_registers(&self) -> Vec<(VarNode, String)> { - self.ctx - .getRegisters() - .iter() - .map(|b| (VarNode::from(&b.varnode), b.name.clone())) - .collect() + self.registers.clone() } } @@ -93,11 +83,18 @@ impl SleighContext { for idx in 0..ctx.getNumSpaces() { spaces.push(SpaceInfo::from(ctx.getSpaceByIndex(idx))); } + let registers = ctx + .getRegisters() + .iter() + .map(|b| (VarNode::from(&b.varnode), b.name.clone())) + .collect(); + Ok(Self { ctx, spaces, image: None, language_id: language_def.id.clone(), + registers, }) } Err(_) => Err(SleighCompilerMutexError), @@ -203,7 +200,7 @@ mod test { } #[test] - fn get_invalid_register() { + fn get_valid_register() { let ctx_builder = SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); let sleigh = ctx_builder.build(SLEIGH_ARCH).unwrap(); @@ -214,6 +211,22 @@ mod test { offset: 512, size: 1 }), + Some("CF") + ); + } + + #[test] + fn get_invalid_register() { + let ctx_builder = + SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); + let sleigh = ctx_builder.build(SLEIGH_ARCH).unwrap(); + + assert_eq!( + sleigh.get_register_name(VarNode { + space_index: 40, + offset: 5122, + size: 1 + }), None ); } From 387287456dc04ef3ccc36b4c63f4ea9c98be52f8 Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 14 Oct 2024 12:33:59 +0100 Subject: [PATCH 070/146] Add wrapper to ensure an image is loaded before parsing --- .../src/context/instruction_iterator.rs | 4 +- jingle_sleigh/src/context/loaded.rs | 64 +++++++++++++++++++ jingle_sleigh/src/context/mod.rs | 35 ++-------- jingle_sleigh/src/ffi/mod.rs | 6 +- 4 files changed, 74 insertions(+), 35 deletions(-) create mode 100644 jingle_sleigh/src/context/loaded.rs diff --git a/jingle_sleigh/src/context/instruction_iterator.rs b/jingle_sleigh/src/context/instruction_iterator.rs index 40badca..028b53c 100644 --- a/jingle_sleigh/src/context/instruction_iterator.rs +++ b/jingle_sleigh/src/context/instruction_iterator.rs @@ -66,7 +66,7 @@ mod test { let mut sleigh = ctx_builder .build(SLEIGH_ARCH) .unwrap(); - sleigh.set_image(mov_eax_0.as_slice()).unwrap(); + let sleigh = sleigh.set_image(mov_eax_0.as_slice()).unwrap(); let instr = sleigh.read(0, 1).last().unwrap(); assert_eq!(instr.length, 5); assert!(instr.disassembly.mnemonic.eq("MOV")); @@ -87,7 +87,7 @@ mod test { let mut sleigh = ctx_builder .build(SLEIGH_ARCH) .unwrap(); - sleigh.set_image(mov_eax_0.as_slice()).unwrap(); + let sleigh = sleigh.set_image(mov_eax_0.as_slice()).unwrap(); let instr: Vec = sleigh.read(0, 5).collect(); assert_eq!(instr.len(), 4); } diff --git a/jingle_sleigh/src/context/loaded.rs b/jingle_sleigh/src/context/loaded.rs new file mode 100644 index 0000000..aa7593b --- /dev/null +++ b/jingle_sleigh/src/context/loaded.rs @@ -0,0 +1,64 @@ +use std::fmt::{Debug, Formatter}; +use std::ops::{Deref, DerefMut}; +use crate::context::instruction_iterator::SleighContextInstructionIterator; +use crate::context::{Image, SleighContext}; +use crate::{Instruction, JingleSleighError}; +use crate::JingleSleighError::ImageLoadError; + +pub struct LoadedSleighContext(SleighContext); + +impl Deref for LoadedSleighContext { + type Target = SleighContext; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for LoadedSleighContext { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl LoadedSleighContext { + pub(crate) fn new(sleigh_context: SleighContext) -> Self{ + Self(sleigh_context) + } + pub fn instruction_at(&self, offset: u64) -> Option { + let instr = self + .ctx + .get_one_instruction(offset) + .map(Instruction::from) + .ok()?; + if self + .image + .as_ref()? + .contains_range(offset..(offset + instr.length as u64)) + { + Some(instr) + } else { + None + } + } + + pub fn read(&self, offset: u64, max_instrs: usize) -> SleighContextInstructionIterator { + SleighContextInstructionIterator::new(self, offset, max_instrs, false) + } + + pub fn read_until_branch( + &self, + offset: u64, + max_instrs: usize, + ) -> SleighContextInstructionIterator { + SleighContextInstructionIterator::new(self, offset, max_instrs, true) + } + + pub fn set_image + Clone>(&mut self, img: T) -> Result<(), JingleSleighError> { + self.image = Some(img.clone().into()); + self.ctx + .pin_mut() + .setImage(img.into()) + .map_err(|_| ImageLoadError) + } +} \ No newline at end of file diff --git a/jingle_sleigh/src/context/mod.rs b/jingle_sleigh/src/context/mod.rs index c62291c..6ea5aa1 100644 --- a/jingle_sleigh/src/context/mod.rs +++ b/jingle_sleigh/src/context/mod.rs @@ -1,5 +1,6 @@ mod builder; mod instruction_iterator; +mod loaded; use crate::error::JingleSleighError; use crate::error::JingleSleighError::{LanguageSpecRead, SleighInitError}; @@ -21,6 +22,7 @@ use crate::VarNode; use cxx::{SharedPtr, UniquePtr}; use std::fmt::{Debug, Formatter}; use std::path::Path; +use crate::context::loaded::LoadedSleighContext; pub struct SleighContext { ctx: UniquePtr, @@ -124,46 +126,19 @@ impl SleighContext { &self.language_id } - pub fn set_image + Clone>(&mut self, img: T) -> Result<(), JingleSleighError> { + pub fn set_image + Clone>(mut self, img: T) -> Result { self.image = Some(img.clone().into()); self.ctx .pin_mut() .setImage(img.into()) - .map_err(|_| ImageLoadError) + .map_err(|_| ImageLoadError)?; + Ok(LoadedSleighContext::new(self)) } pub fn get_image(&self) -> Option<&Image> { self.image.as_ref() } - pub fn instruction_at(&self, offset: u64) -> Option { - let instr = self - .ctx - .get_one_instruction(offset) - .map(Instruction::from) - .ok()?; - if self - .image - .as_ref()? - .contains_range(offset..(offset + instr.length as u64)) - { - Some(instr) - } else { - None - } - } - - pub fn read(&self, offset: u64, max_instrs: usize) -> SleighContextInstructionIterator { - SleighContextInstructionIterator::new(self, offset, max_instrs, false) - } - - pub fn read_until_branch( - &self, - offset: u64, - max_instrs: usize, - ) -> SleighContextInstructionIterator { - SleighContextInstructionIterator::new(self, offset, max_instrs, true) - } } #[cfg(test)] diff --git a/jingle_sleigh/src/ffi/mod.rs b/jingle_sleigh/src/ffi/mod.rs index b738c06..4755733 100644 --- a/jingle_sleigh/src/ffi/mod.rs +++ b/jingle_sleigh/src/ffi/mod.rs @@ -21,7 +21,7 @@ mod tests { SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); let mut sleigh = builder.build("x86:LE:64:default").unwrap(); - sleigh.set_image(bytes.as_slice()).unwrap(); + let sleigh = sleigh.set_image(bytes.as_slice()).unwrap(); sleigh.instruction_at(0).unwrap(); } #[test] @@ -31,7 +31,7 @@ mod tests { SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); let mut sleigh = builder.build("x86:LE:64:default").unwrap(); - sleigh.set_image(bytes.as_slice()).unwrap(); + let sleigh = sleigh.set_image(bytes.as_slice()).unwrap(); sleigh.instruction_at(0).unwrap(); } @@ -44,7 +44,7 @@ mod tests { let mut sleigh = ctx_builder .build(SLEIGH_ARCH) .unwrap(); - sleigh.set_image(mov_eax_0.as_slice()).unwrap(); + let mut sleigh = sleigh.set_image(mov_eax_0.as_slice()).unwrap(); let instr1 = sleigh.instruction_at(0); sleigh.set_image(nops.as_slice()).unwrap(); let instr2 = sleigh.instruction_at(0); From 17230839479fdd2288d437b9e697abe2083454fd Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 14 Oct 2024 12:34:18 +0100 Subject: [PATCH 071/146] Fmt --- .../src/context/builder/image/mod.rs | 6 ++--- jingle_sleigh/src/context/builder/mod.rs | 5 +---- .../src/context/instruction_iterator.rs | 11 +++------- jingle_sleigh/src/context/loaded.rs | 12 +++++----- jingle_sleigh/src/context/mod.rs | 22 +++++++++++++------ jingle_sleigh/src/ffi/context_ffi.rs | 6 ++++- jingle_sleigh/src/ffi/mod.rs | 8 +++---- 7 files changed, 36 insertions(+), 34 deletions(-) diff --git a/jingle_sleigh/src/context/builder/image/mod.rs b/jingle_sleigh/src/context/builder/image/mod.rs index ee7033b..139c27d 100644 --- a/jingle_sleigh/src/context/builder/image/mod.rs +++ b/jingle_sleigh/src/context/builder/image/mod.rs @@ -22,9 +22,9 @@ impl Image { } pub fn contains_address(&self, addr: u64) -> bool { - self.sections - .iter() - .any(|s| s.base_address <= addr as usize && (s.base_address + s.data.len()) >= addr as usize) + self.sections.iter().any(|s| { + s.base_address <= addr as usize && (s.base_address + s.data.len()) >= addr as usize + }) } pub fn contains_range(&self, mut range: Range) -> bool { diff --git a/jingle_sleigh/src/context/builder/mod.rs b/jingle_sleigh/src/context/builder/mod.rs index 1375199..57fc97e 100644 --- a/jingle_sleigh/src/context/builder/mod.rs +++ b/jingle_sleigh/src/context/builder/mod.rs @@ -52,9 +52,7 @@ impl SleighContextBuilder { } pub fn load_folder>(path: T) -> Result { let ldef = SleighContextBuilder::_load_folder(path.as_ref())?; - Ok(SleighContextBuilder { - defs: ldef, - }) + Ok(SleighContextBuilder { defs: ldef }) } fn _load_folder(path: &Path) -> Result, JingleSleighError> { @@ -87,7 +85,6 @@ impl SleighContextBuilder { } Ok(SleighContextBuilder { defs }) } - } fn find_ldef(path: &Path) -> Result { diff --git a/jingle_sleigh/src/context/instruction_iterator.rs b/jingle_sleigh/src/context/instruction_iterator.rs index 028b53c..e1059e2 100644 --- a/jingle_sleigh/src/context/instruction_iterator.rs +++ b/jingle_sleigh/src/context/instruction_iterator.rs @@ -1,4 +1,4 @@ -use crate::context::{SleighContext}; +use crate::context::SleighContext; use crate::Instruction; pub struct SleighContextInstructionIterator<'a> { @@ -63,9 +63,7 @@ mod test { let mov_eax_0: [u8; 6] = [0xb8, 0x00, 0x00, 0x00, 0x00, 0xc3]; let ctx_builder = SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); - let mut sleigh = ctx_builder - .build(SLEIGH_ARCH) - .unwrap(); + let mut sleigh = ctx_builder.build(SLEIGH_ARCH).unwrap(); let sleigh = sleigh.set_image(mov_eax_0.as_slice()).unwrap(); let instr = sleigh.read(0, 1).last().unwrap(); assert_eq!(instr.length, 5); @@ -84,12 +82,9 @@ mod test { let mov_eax_0: [u8; 4] = [0x90, 0x90, 0x90, 0x90]; let ctx_builder = SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); - let mut sleigh = ctx_builder - .build(SLEIGH_ARCH) - .unwrap(); + let mut sleigh = ctx_builder.build(SLEIGH_ARCH).unwrap(); let sleigh = sleigh.set_image(mov_eax_0.as_slice()).unwrap(); let instr: Vec = sleigh.read(0, 5).collect(); assert_eq!(instr.len(), 4); } - } diff --git a/jingle_sleigh/src/context/loaded.rs b/jingle_sleigh/src/context/loaded.rs index aa7593b..a3131e7 100644 --- a/jingle_sleigh/src/context/loaded.rs +++ b/jingle_sleigh/src/context/loaded.rs @@ -1,9 +1,9 @@ -use std::fmt::{Debug, Formatter}; -use std::ops::{Deref, DerefMut}; use crate::context::instruction_iterator::SleighContextInstructionIterator; use crate::context::{Image, SleighContext}; -use crate::{Instruction, JingleSleighError}; use crate::JingleSleighError::ImageLoadError; +use crate::{Instruction, JingleSleighError}; +use std::fmt::{Debug, Formatter}; +use std::ops::{Deref, DerefMut}; pub struct LoadedSleighContext(SleighContext); @@ -22,8 +22,8 @@ impl DerefMut for LoadedSleighContext { } impl LoadedSleighContext { - pub(crate) fn new(sleigh_context: SleighContext) -> Self{ - Self(sleigh_context) + pub(crate) fn new(sleigh_context: SleighContext) -> Self { + Self(sleigh_context) } pub fn instruction_at(&self, offset: u64) -> Option { let instr = self @@ -61,4 +61,4 @@ impl LoadedSleighContext { .setImage(img.into()) .map_err(|_| ImageLoadError) } -} \ No newline at end of file +} diff --git a/jingle_sleigh/src/context/mod.rs b/jingle_sleigh/src/context/mod.rs index 6ea5aa1..0863458 100644 --- a/jingle_sleigh/src/context/mod.rs +++ b/jingle_sleigh/src/context/mod.rs @@ -15,6 +15,7 @@ pub use builder::SleighContextBuilder; use crate::context::builder::language_def::LanguageDefinition; use crate::context::instruction_iterator::SleighContextInstructionIterator; +use crate::context::loaded::LoadedSleighContext; use crate::ffi::context_ffi::CTX_BUILD_MUTEX; use crate::ffi::instruction::bridge::VarnodeInfoFFI; use crate::JingleSleighError::{ImageLoadError, SleighCompilerMutexError}; @@ -22,14 +23,13 @@ use crate::VarNode; use cxx::{SharedPtr, UniquePtr}; use std::fmt::{Debug, Formatter}; use std::path::Path; -use crate::context::loaded::LoadedSleighContext; pub struct SleighContext { ctx: UniquePtr, image: Option, spaces: Vec, language_id: String, - registers: Vec<(VarNode, String)> + registers: Vec<(VarNode, String)>, } impl Debug for SleighContext { @@ -58,11 +58,17 @@ impl SpaceManager for SleighContext { impl RegisterManager for SleighContext { fn get_register(&self, name: &str) -> Option { - self.registers.iter().find(|(_,reg_name)| reg_name.as_str() == name).map(|(vn,_)| vn.clone()) + self.registers + .iter() + .find(|(_, reg_name)| reg_name.as_str() == name) + .map(|(vn, _)| vn.clone()) } fn get_register_name(&self, location: VarNode) -> Option<&str> { - self.registers.iter().find(|(vn,_)| vn == &location).map(|(_,name)| name.as_str()) + self.registers + .iter() + .find(|(vn, _)| vn == &location) + .map(|(_, name)| name.as_str()) } fn get_registers(&self) -> Vec<(VarNode, String)> { @@ -85,7 +91,7 @@ impl SleighContext { for idx in 0..ctx.getNumSpaces() { spaces.push(SpaceInfo::from(ctx.getSpaceByIndex(idx))); } - let registers = ctx + let registers = ctx .getRegisters() .iter() .map(|b| (VarNode::from(&b.varnode), b.name.clone())) @@ -126,7 +132,10 @@ impl SleighContext { &self.language_id } - pub fn set_image + Clone>(mut self, img: T) -> Result { + pub fn set_image + Clone>( + mut self, + img: T, + ) -> Result { self.image = Some(img.clone().into()); self.ctx .pin_mut() @@ -138,7 +147,6 @@ impl SleighContext { pub fn get_image(&self) -> Option<&Image> { self.image.as_ref() } - } #[cfg(test)] diff --git a/jingle_sleigh/src/ffi/context_ffi.rs b/jingle_sleigh/src/ffi/context_ffi.rs index 49d7d4c..60a4cca 100644 --- a/jingle_sleigh/src/ffi/context_ffi.rs +++ b/jingle_sleigh/src/ffi/context_ffi.rs @@ -27,7 +27,11 @@ pub(crate) mod bridge { pub(crate) type ContextFFI; pub(super) fn makeContext(slaPath: &str) -> Result>; - pub(crate) fn set_initial_context(self: Pin<&mut ContextFFI>, name: &str, value: u32) -> Result<()>; + pub(crate) fn set_initial_context( + self: Pin<&mut ContextFFI>, + name: &str, + value: u32, + ) -> Result<()>; pub(crate) fn get_one_instruction(&self, offset: u64) -> Result; diff --git a/jingle_sleigh/src/ffi/mod.rs b/jingle_sleigh/src/ffi/mod.rs index 4755733..9059ba9 100644 --- a/jingle_sleigh/src/ffi/mod.rs +++ b/jingle_sleigh/src/ffi/mod.rs @@ -11,7 +11,7 @@ use libz_sys::inflate; #[cfg(test)] mod tests { - use crate::context::{SleighContextBuilder}; + use crate::context::SleighContextBuilder; use crate::tests::SLEIGH_ARCH; #[test] @@ -36,14 +36,12 @@ mod tests { } #[test] - fn test_two_images(){ + fn test_two_images() { let mov_eax_0: [u8; 4] = [0x0f, 0x05, 0x0f, 0x05]; let nops: [u8; 9] = [0x90, 0x90, 0x90, 0x90, 0x0f, 0x05, 0x0f, 0x05, 0x0f]; let ctx_builder = SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); - let mut sleigh = ctx_builder - .build(SLEIGH_ARCH) - .unwrap(); + let mut sleigh = ctx_builder.build(SLEIGH_ARCH).unwrap(); let mut sleigh = sleigh.set_image(mov_eax_0.as_slice()).unwrap(); let instr1 = sleigh.instruction_at(0); sleigh.set_image(nops.as_slice()).unwrap(); From bd1eb46cf3523801a8187bca529d54206b10d1ae Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 14 Oct 2024 12:37:04 +0100 Subject: [PATCH 072/146] Clippy --- jingle_sleigh/src/context/builder/mod.rs | 4 ++-- jingle_sleigh/src/context/instruction_iterator.rs | 8 ++++---- jingle_sleigh/src/context/loaded.rs | 1 - jingle_sleigh/src/context/mod.rs | 2 +- jingle_sleigh/src/ffi/context_ffi.rs | 6 +++--- jingle_sleigh/src/ffi/mod.rs | 12 ++++++------ 6 files changed, 16 insertions(+), 17 deletions(-) diff --git a/jingle_sleigh/src/context/builder/mod.rs b/jingle_sleigh/src/context/builder/mod.rs index 57fc97e..b7db633 100644 --- a/jingle_sleigh/src/context/builder/mod.rs +++ b/jingle_sleigh/src/context/builder/mod.rs @@ -32,7 +32,7 @@ impl SleighContextBuilder { event!(Level::INFO, "Created sleigh context"); let pspec_path = path.join(&lang.processor_spec); let pspec = parse_pspec(&pspec_path)?; - if let Some(ctx_sets) = pspec.context_data.map(|d| d.context_set).flatten() { + if let Some(ctx_sets) = pspec.context_data.and_then(|d| d.context_set) { for set in ctx_sets.sets { // todo: gross hack if set.value.starts_with("0x") { @@ -43,7 +43,7 @@ impl SleighContextBuilder { } else { context.set_initial_context( &set.name, - u32::from_str_radix(&set.value, 10).unwrap(), + set.value.parse::().unwrap(), )?; } } diff --git a/jingle_sleigh/src/context/instruction_iterator.rs b/jingle_sleigh/src/context/instruction_iterator.rs index e1059e2..72095bf 100644 --- a/jingle_sleigh/src/context/instruction_iterator.rs +++ b/jingle_sleigh/src/context/instruction_iterator.rs @@ -63,8 +63,8 @@ mod test { let mov_eax_0: [u8; 6] = [0xb8, 0x00, 0x00, 0x00, 0x00, 0xc3]; let ctx_builder = SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); - let mut sleigh = ctx_builder.build(SLEIGH_ARCH).unwrap(); - let sleigh = sleigh.set_image(mov_eax_0.as_slice()).unwrap(); + let sleigh = ctx_builder.build(SLEIGH_ARCH).unwrap(); + let sleigh = sleigh.initialize_with_image(mov_eax_0.as_slice()).unwrap(); let instr = sleigh.read(0, 1).last().unwrap(); assert_eq!(instr.length, 5); assert!(instr.disassembly.mnemonic.eq("MOV")); @@ -82,8 +82,8 @@ mod test { let mov_eax_0: [u8; 4] = [0x90, 0x90, 0x90, 0x90]; let ctx_builder = SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); - let mut sleigh = ctx_builder.build(SLEIGH_ARCH).unwrap(); - let sleigh = sleigh.set_image(mov_eax_0.as_slice()).unwrap(); + let sleigh = ctx_builder.build(SLEIGH_ARCH).unwrap(); + let sleigh = sleigh.initialize_with_image(mov_eax_0.as_slice()).unwrap(); let instr: Vec = sleigh.read(0, 5).collect(); assert_eq!(instr.len(), 4); } diff --git a/jingle_sleigh/src/context/loaded.rs b/jingle_sleigh/src/context/loaded.rs index a3131e7..4dd2e1a 100644 --- a/jingle_sleigh/src/context/loaded.rs +++ b/jingle_sleigh/src/context/loaded.rs @@ -2,7 +2,6 @@ use crate::context::instruction_iterator::SleighContextInstructionIterator; use crate::context::{Image, SleighContext}; use crate::JingleSleighError::ImageLoadError; use crate::{Instruction, JingleSleighError}; -use std::fmt::{Debug, Formatter}; use std::ops::{Deref, DerefMut}; pub struct LoadedSleighContext(SleighContext); diff --git a/jingle_sleigh/src/context/mod.rs b/jingle_sleigh/src/context/mod.rs index 0863458..58a2370 100644 --- a/jingle_sleigh/src/context/mod.rs +++ b/jingle_sleigh/src/context/mod.rs @@ -132,7 +132,7 @@ impl SleighContext { &self.language_id } - pub fn set_image + Clone>( + pub fn initialize_with_image + Clone>( mut self, img: T, ) -> Result { diff --git a/jingle_sleigh/src/ffi/context_ffi.rs b/jingle_sleigh/src/ffi/context_ffi.rs index 60a4cca..fa0cdc8 100644 --- a/jingle_sleigh/src/ffi/context_ffi.rs +++ b/jingle_sleigh/src/ffi/context_ffi.rs @@ -13,7 +13,7 @@ pub(crate) mod bridge { type Image = crate::context::Image; type InstructionFFI = crate::ffi::instruction::bridge::InstructionFFI; - type VarnodeInfoFFI = crate::ffi::instruction::bridge::VarnodeInfoFFI; + // type VarnodeInfoFFI = crate::ffi::instruction::bridge::VarnodeInfoFFI; type AddrSpaceHandle = crate::ffi::addrspace::bridge::AddrSpaceHandle; @@ -38,8 +38,8 @@ pub(crate) mod bridge { pub(crate) fn getSpaceByIndex(&self, idx: i32) -> SharedPtr; pub(crate) fn getNumSpaces(&self) -> i32; - pub(crate) fn getRegister(&self, name: &str) -> Result; - pub(crate) fn getRegisterName(&self, name: VarnodeInfoFFI) -> Result<&str>; + // pub(crate) fn getRegister(&self, name: &str) -> Result; + // pub(crate) fn getRegisterName(&self, name: VarnodeInfoFFI) -> Result<&str>; pub(crate) fn getRegisters(&self) -> Vec; diff --git a/jingle_sleigh/src/ffi/mod.rs b/jingle_sleigh/src/ffi/mod.rs index 9059ba9..7ace8b9 100644 --- a/jingle_sleigh/src/ffi/mod.rs +++ b/jingle_sleigh/src/ffi/mod.rs @@ -20,8 +20,8 @@ mod tests { let builder = SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); - let mut sleigh = builder.build("x86:LE:64:default").unwrap(); - let sleigh = sleigh.set_image(bytes.as_slice()).unwrap(); + let sleigh = builder.build("x86:LE:64:default").unwrap(); + let sleigh = sleigh.initialize_with_image(bytes.as_slice()).unwrap(); sleigh.instruction_at(0).unwrap(); } #[test] @@ -30,8 +30,8 @@ mod tests { let builder = SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); - let mut sleigh = builder.build("x86:LE:64:default").unwrap(); - let sleigh = sleigh.set_image(bytes.as_slice()).unwrap(); + let sleigh = builder.build("x86:LE:64:default").unwrap(); + let sleigh = sleigh.initialize_with_image(bytes.as_slice()).unwrap(); sleigh.instruction_at(0).unwrap(); } @@ -41,8 +41,8 @@ mod tests { let nops: [u8; 9] = [0x90, 0x90, 0x90, 0x90, 0x0f, 0x05, 0x0f, 0x05, 0x0f]; let ctx_builder = SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); - let mut sleigh = ctx_builder.build(SLEIGH_ARCH).unwrap(); - let mut sleigh = sleigh.set_image(mov_eax_0.as_slice()).unwrap(); + let sleigh = ctx_builder.build(SLEIGH_ARCH).unwrap(); + let mut sleigh = sleigh.initialize_with_image(mov_eax_0.as_slice()).unwrap(); let instr1 = sleigh.instruction_at(0); sleigh.set_image(nops.as_slice()).unwrap(); let instr2 = sleigh.instruction_at(0); From b87c391fb4176db148984df10c4138d836a821a4 Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 14 Oct 2024 12:37:52 +0100 Subject: [PATCH 073/146] More clippy --- jingle_sleigh/src/context/mod.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/jingle_sleigh/src/context/mod.rs b/jingle_sleigh/src/context/mod.rs index 58a2370..eef3073 100644 --- a/jingle_sleigh/src/context/mod.rs +++ b/jingle_sleigh/src/context/mod.rs @@ -6,7 +6,6 @@ use crate::error::JingleSleighError; use crate::error::JingleSleighError::{LanguageSpecRead, SleighInitError}; use crate::ffi::addrspace::bridge::AddrSpaceHandle; use crate::ffi::context_ffi::bridge::ContextFFI; -use crate::instruction::Instruction; use crate::space::{RegisterManager, SpaceInfo, SpaceManager}; #[cfg(feature = "gimli")] pub use builder::image::gimli::map_gimli_architecture; @@ -14,10 +13,8 @@ pub use builder::image::{Image, ImageSection}; pub use builder::SleighContextBuilder; use crate::context::builder::language_def::LanguageDefinition; -use crate::context::instruction_iterator::SleighContextInstructionIterator; use crate::context::loaded::LoadedSleighContext; use crate::ffi::context_ffi::CTX_BUILD_MUTEX; -use crate::ffi::instruction::bridge::VarnodeInfoFFI; use crate::JingleSleighError::{ImageLoadError, SleighCompilerMutexError}; use crate::VarNode; use cxx::{SharedPtr, UniquePtr}; From 0c6669cf0c7cf015433e2b634bcc927054c327bb Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 14 Oct 2024 12:46:29 +0100 Subject: [PATCH 074/146] Fix jingle --- jingle/src/translator.rs | 5 ++-- jingle_sleigh/src/context/loaded.rs | 36 ++++++++++++++++++++++++++++- jingle_sleigh/src/context/mod.rs | 2 +- 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/jingle/src/translator.rs b/jingle/src/translator.rs index 42517c0..3c59193 100644 --- a/jingle/src/translator.rs +++ b/jingle/src/translator.rs @@ -6,6 +6,7 @@ use crate::modeling::ModeledInstruction; use jingle_sleigh::JingleSleighError::InstructionDecode; use jingle_sleigh::SpaceManager; use z3::Context; +use jingle_sleigh::context::loaded::LoadedSleighContext; /// This type wraps z3 and a sleigh context and allows for both modeling instructions that /// sleigh context has already produced, or reading new instructions directly out of sleigh and @@ -13,12 +14,12 @@ use z3::Context; #[derive(Debug, Clone)] pub struct SleighTranslator<'ctx> { z3_ctx: &'ctx Context, - sleigh: &'ctx SleighContext, + sleigh: &'ctx LoadedSleighContext, } impl<'ctx> SleighTranslator<'ctx> { /// Make a new sleigh translator - pub fn new(sleigh: &'ctx SleighContext, z3_ctx: &'ctx Context) -> Self { + pub fn new(sleigh: &'ctx LoadedSleighContext, z3_ctx: &'ctx Context) -> Self { Self { z3_ctx, sleigh } } diff --git a/jingle_sleigh/src/context/loaded.rs b/jingle_sleigh/src/context/loaded.rs index 4dd2e1a..f59904d 100644 --- a/jingle_sleigh/src/context/loaded.rs +++ b/jingle_sleigh/src/context/loaded.rs @@ -1,11 +1,17 @@ +use std::fmt::{Debug, Formatter}; use crate::context::instruction_iterator::SleighContextInstructionIterator; use crate::context::{Image, SleighContext}; use crate::JingleSleighError::ImageLoadError; -use crate::{Instruction, JingleSleighError}; +use crate::{Instruction, JingleSleighError, RegisterManager, SpaceInfo, SpaceManager, VarNode}; use std::ops::{Deref, DerefMut}; pub struct LoadedSleighContext(SleighContext); +impl Debug for LoadedSleighContext{ + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + self.0.fmt(f) + } +} impl Deref for LoadedSleighContext { type Target = SleighContext; @@ -61,3 +67,31 @@ impl LoadedSleighContext { .map_err(|_| ImageLoadError) } } + +impl SpaceManager for LoadedSleighContext{ + fn get_space_info(&self, idx: usize) -> Option<&SpaceInfo> { + self.0.get_space_info(idx) + } + + fn get_all_space_info(&self) -> &[SpaceInfo] { + self.0.get_all_space_info() + } + + fn get_code_space_idx(&self) -> usize { + self.0.get_code_space_idx() + } +} + +impl RegisterManager for LoadedSleighContext{ + fn get_register(&self, name: &str) -> Option { + self.0.get_register(name) + } + + fn get_register_name(&self, location: VarNode) -> Option<&str> { + self.0.get_register_name(location) + } + + fn get_registers(&self) -> Vec<(VarNode, String)> { + self.0.get_registers() + } +} \ No newline at end of file diff --git a/jingle_sleigh/src/context/mod.rs b/jingle_sleigh/src/context/mod.rs index eef3073..fe7b361 100644 --- a/jingle_sleigh/src/context/mod.rs +++ b/jingle_sleigh/src/context/mod.rs @@ -1,6 +1,6 @@ mod builder; mod instruction_iterator; -mod loaded; +pub mod loaded; use crate::error::JingleSleighError; use crate::error::JingleSleighError::{LanguageSpecRead, SleighInitError}; From c45eca7a0e9c55e66307de15e62791ef07596cb0 Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 14 Oct 2024 12:46:40 +0100 Subject: [PATCH 075/146] fmt --- jingle/src/main.rs | 4 +--- jingle/src/translator.rs | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/jingle/src/main.rs b/jingle/src/main.rs index ef2a4a7..5fe877f 100644 --- a/jingle/src/main.rs +++ b/jingle/src/main.rs @@ -117,9 +117,7 @@ fn get_instructions( let img = decode(hex_bytes).unwrap(); let max_len = img.len(); let mut offset = 0; - let mut sleigh = sleigh_build - .build(&architecture) - .unwrap(); + let mut sleigh = sleigh_build.build(&architecture).unwrap(); sleigh.set_image(img).unwrap(); let mut instrs = vec![]; while offset < max_len { diff --git a/jingle/src/translator.rs b/jingle/src/translator.rs index 3c59193..446bdb3 100644 --- a/jingle/src/translator.rs +++ b/jingle/src/translator.rs @@ -3,10 +3,10 @@ use jingle_sleigh::context::SleighContext; use jingle_sleigh::{Instruction, RegisterManager, SpaceInfo, VarNode}; use crate::modeling::ModeledInstruction; +use jingle_sleigh::context::loaded::LoadedSleighContext; use jingle_sleigh::JingleSleighError::InstructionDecode; use jingle_sleigh::SpaceManager; use z3::Context; -use jingle_sleigh::context::loaded::LoadedSleighContext; /// This type wraps z3 and a sleigh context and allows for both modeling instructions that /// sleigh context has already produced, or reading new instructions directly out of sleigh and From db92380e9200029595af2ec0fec5784151b5e468 Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 14 Oct 2024 12:47:00 +0100 Subject: [PATCH 076/146] Clippy --- jingle/src/translator.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/jingle/src/translator.rs b/jingle/src/translator.rs index 446bdb3..e8b473c 100644 --- a/jingle/src/translator.rs +++ b/jingle/src/translator.rs @@ -1,5 +1,4 @@ use crate::error::JingleError; -use jingle_sleigh::context::SleighContext; use jingle_sleigh::{Instruction, RegisterManager, SpaceInfo, VarNode}; use crate::modeling::ModeledInstruction; From 298829a18bea8ee80a259e3f2898785b807a2bdc Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 14 Oct 2024 12:51:28 +0100 Subject: [PATCH 077/146] Fix binary --- jingle/src/main.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/jingle/src/main.rs b/jingle/src/main.rs index 5fe877f..b052b82 100644 --- a/jingle/src/main.rs +++ b/jingle/src/main.rs @@ -2,7 +2,8 @@ use clap::{Parser, Subcommand}; use hex::decode; use jingle::modeling::{ModeledBlock, ModelingContext}; use jingle::JingleContext; -use jingle_sleigh::context::{Image, SleighContext, SleighContextBuilder}; +use jingle_sleigh::context::loaded::LoadedSleighContext; +use jingle_sleigh::context::SleighContextBuilder; use jingle_sleigh::{Disassembly, Instruction, JingleSleighError, PcodeOperation, VarNode}; use serde::{Deserialize, Serialize}; use std::path::PathBuf; @@ -112,16 +113,16 @@ fn get_instructions( config: &JingleConfig, architecture: String, hex_bytes: String, -) -> (SleighContext, Vec) { +) -> (LoadedSleighContext, Vec) { let sleigh_build = config.sleigh_builder().unwrap(); let img = decode(hex_bytes).unwrap(); let max_len = img.len(); let mut offset = 0; - let mut sleigh = sleigh_build.build(&architecture).unwrap(); - sleigh.set_image(img).unwrap(); + let sleigh = sleigh_build.build(&architecture).unwrap(); + let sleigh = sleigh.initialize_with_image(img).unwrap(); let mut instrs = vec![]; while offset < max_len { - for instruction in sleigh.instruction_at(offset as u64) { + if let Some(instruction) = sleigh.instruction_at(offset as u64) { offset += instruction.length; instrs.push(instruction); } From 262d5307cff3433b516f2000b6f5753ca566903a Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 14 Oct 2024 18:32:26 +0100 Subject: [PATCH 078/146] Don't consume varnode in `get_register_name` --- jingle/src/translator.rs | 2 +- jingle_sleigh/src/context/builder/mod.rs | 5 +---- jingle_sleigh/src/context/loaded.rs | 12 ++++++------ jingle_sleigh/src/context/mod.rs | 8 ++++---- jingle_sleigh/src/space.rs | 2 +- 5 files changed, 13 insertions(+), 16 deletions(-) diff --git a/jingle/src/translator.rs b/jingle/src/translator.rs index e8b473c..aab3ebe 100644 --- a/jingle/src/translator.rs +++ b/jingle/src/translator.rs @@ -64,7 +64,7 @@ impl<'ctx> RegisterManager for SleighTranslator<'ctx> { self.sleigh.get_register(name) } - fn get_register_name(&self, location: VarNode) -> Option<&str> { + fn get_register_name(&self, location: &VarNode) -> Option<&str> { self.sleigh.get_register_name(location) } diff --git a/jingle_sleigh/src/context/builder/mod.rs b/jingle_sleigh/src/context/builder/mod.rs index b7db633..ffb28dd 100644 --- a/jingle_sleigh/src/context/builder/mod.rs +++ b/jingle_sleigh/src/context/builder/mod.rs @@ -41,10 +41,7 @@ impl SleighContextBuilder { u32::from_str_radix(&set.value[2..], 16).unwrap(), )?; } else { - context.set_initial_context( - &set.name, - set.value.parse::().unwrap(), - )?; + context.set_initial_context(&set.name, set.value.parse::().unwrap())?; } } } diff --git a/jingle_sleigh/src/context/loaded.rs b/jingle_sleigh/src/context/loaded.rs index f59904d..4ba6a95 100644 --- a/jingle_sleigh/src/context/loaded.rs +++ b/jingle_sleigh/src/context/loaded.rs @@ -1,13 +1,13 @@ -use std::fmt::{Debug, Formatter}; use crate::context::instruction_iterator::SleighContextInstructionIterator; use crate::context::{Image, SleighContext}; use crate::JingleSleighError::ImageLoadError; use crate::{Instruction, JingleSleighError, RegisterManager, SpaceInfo, SpaceManager, VarNode}; +use std::fmt::{Debug, Formatter}; use std::ops::{Deref, DerefMut}; pub struct LoadedSleighContext(SleighContext); -impl Debug for LoadedSleighContext{ +impl Debug for LoadedSleighContext { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { self.0.fmt(f) } @@ -68,7 +68,7 @@ impl LoadedSleighContext { } } -impl SpaceManager for LoadedSleighContext{ +impl SpaceManager for LoadedSleighContext { fn get_space_info(&self, idx: usize) -> Option<&SpaceInfo> { self.0.get_space_info(idx) } @@ -82,16 +82,16 @@ impl SpaceManager for LoadedSleighContext{ } } -impl RegisterManager for LoadedSleighContext{ +impl RegisterManager for LoadedSleighContext { fn get_register(&self, name: &str) -> Option { self.0.get_register(name) } - fn get_register_name(&self, location: VarNode) -> Option<&str> { + fn get_register_name(&self, location: &VarNode) -> Option<&str> { self.0.get_register_name(location) } fn get_registers(&self) -> Vec<(VarNode, String)> { self.0.get_registers() } -} \ No newline at end of file +} diff --git a/jingle_sleigh/src/context/mod.rs b/jingle_sleigh/src/context/mod.rs index fe7b361..f76c126 100644 --- a/jingle_sleigh/src/context/mod.rs +++ b/jingle_sleigh/src/context/mod.rs @@ -61,10 +61,10 @@ impl RegisterManager for SleighContext { .map(|(vn, _)| vn.clone()) } - fn get_register_name(&self, location: VarNode) -> Option<&str> { + fn get_register_name(&self, location: &VarNode) -> Option<&str> { self.registers .iter() - .find(|(vn, _)| vn == &location) + .find(|(vn, _)| vn == location) .map(|(_, name)| name.as_str()) } @@ -186,7 +186,7 @@ mod test { let sleigh = ctx_builder.build(SLEIGH_ARCH).unwrap(); assert_eq!( - sleigh.get_register_name(VarNode { + sleigh.get_register_name(&VarNode { space_index: 4, offset: 512, size: 1 @@ -202,7 +202,7 @@ mod test { let sleigh = ctx_builder.build(SLEIGH_ARCH).unwrap(); assert_eq!( - sleigh.get_register_name(VarNode { + sleigh.get_register_name(&VarNode { space_index: 40, offset: 5122, size: 1 diff --git a/jingle_sleigh/src/space.rs b/jingle_sleigh/src/space.rs index a227e28..72421af 100644 --- a/jingle_sleigh/src/space.rs +++ b/jingle_sleigh/src/space.rs @@ -122,7 +122,7 @@ pub trait RegisterManager: SpaceManager { /// Given a [`VarNode`], get the name of the corresponding architectural register, if one exists - fn get_register_name(&self, location: VarNode) -> Option<&str>; + fn get_register_name(&self, location: &VarNode) -> Option<&str>; /// Get a listing of all register name/[`VarNode`] pairs fn get_registers(&self) -> Vec<(VarNode, String)>; From 00cbd7c7cc068348163d5fc244aded2b89f3f3f0 Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 15 Oct 2024 10:56:17 +0100 Subject: [PATCH 079/146] Initial trait work --- .../src/context/builder/image/mod.rs | 4 +- jingle_sleigh/src/context/builder/mod.rs | 2 +- jingle_sleigh/src/context/image.rs | 5 + jingle_sleigh/src/context/loaded.rs | 13 ++- jingle_sleigh/src/context/mod.rs | 12 +- jingle_sleigh/src/context/sleigh_image/mod.rs | 110 ------------------ jingle_sleigh/src/ffi/context_ffi.rs | 4 +- jingle_sleigh/src/ffi/image.rs | 48 ++++---- 8 files changed, 44 insertions(+), 154 deletions(-) create mode 100644 jingle_sleigh/src/context/image.rs delete mode 100644 jingle_sleigh/src/context/sleigh_image/mod.rs diff --git a/jingle_sleigh/src/context/builder/image/mod.rs b/jingle_sleigh/src/context/builder/image/mod.rs index 139c27d..5c10049 100644 --- a/jingle_sleigh/src/context/builder/image/mod.rs +++ b/jingle_sleigh/src/context/builder/image/mod.rs @@ -1,7 +1,7 @@ -#[cfg(feature = "elf")] +/*#[cfg(feature = "elf")] pub mod elf; #[cfg(feature = "gimli")] -pub mod gimli; +pub mod gimli;*/ pub use crate::ffi::image::bridge::{Image, ImageSection, Perms}; use std::ops::Range; diff --git a/jingle_sleigh/src/context/builder/mod.rs b/jingle_sleigh/src/context/builder/mod.rs index ffb28dd..40f4d34 100644 --- a/jingle_sleigh/src/context/builder/mod.rs +++ b/jingle_sleigh/src/context/builder/mod.rs @@ -8,7 +8,7 @@ use std::fs; use std::path::{Path, PathBuf}; use tracing::{event, instrument, Level}; -pub mod image; +//pub mod image; pub(crate) mod language_def; pub(crate) mod processor_spec; diff --git a/jingle_sleigh/src/context/image.rs b/jingle_sleigh/src/context/image.rs new file mode 100644 index 0000000..c6b8a14 --- /dev/null +++ b/jingle_sleigh/src/context/image.rs @@ -0,0 +1,5 @@ +use crate::VarNode; + +pub trait ImageProvider{ + fn load(vn: &VarNode, output: &mut &[u8]) -> usize; +} \ No newline at end of file diff --git a/jingle_sleigh/src/context/loaded.rs b/jingle_sleigh/src/context/loaded.rs index 4ba6a95..4f646f6 100644 --- a/jingle_sleigh/src/context/loaded.rs +++ b/jingle_sleigh/src/context/loaded.rs @@ -4,8 +4,10 @@ use crate::JingleSleighError::ImageLoadError; use crate::{Instruction, JingleSleighError, RegisterManager, SpaceInfo, SpaceManager, VarNode}; use std::fmt::{Debug, Formatter}; use std::ops::{Deref, DerefMut}; +use crate::context::image::ImageProvider; +use crate::ffi::image::ImageFFI; -pub struct LoadedSleighContext(SleighContext); +pub struct LoadedSleighContext(SleighContext, ImageFFI); impl Debug for LoadedSleighContext { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { @@ -27,8 +29,13 @@ impl DerefMut for LoadedSleighContext { } impl LoadedSleighContext { - pub(crate) fn new(sleigh_context: SleighContext) -> Self { - Self(sleigh_context) + pub(crate) fn new(sleigh_context: SleighContext, img: T) -> Result { + let img = ImageFFI::new(img); + sleigh_context + .pin_mut() + .setImage(&img) + .map_err(|_| ImageLoadError)?; + Self(sleigh_context, img) } pub fn instruction_at(&self, offset: u64) -> Option { let instr = self diff --git a/jingle_sleigh/src/context/mod.rs b/jingle_sleigh/src/context/mod.rs index f76c126..bbf9e34 100644 --- a/jingle_sleigh/src/context/mod.rs +++ b/jingle_sleigh/src/context/mod.rs @@ -1,6 +1,7 @@ mod builder; mod instruction_iterator; pub mod loaded; +pub mod image; use crate::error::JingleSleighError; use crate::error::JingleSleighError::{LanguageSpecRead, SleighInitError}; @@ -20,10 +21,10 @@ use crate::VarNode; use cxx::{SharedPtr, UniquePtr}; use std::fmt::{Debug, Formatter}; use std::path::Path; +use crate::context::image::ImageProvider; pub struct SleighContext { ctx: UniquePtr, - image: Option, spaces: Vec, language_id: String, registers: Vec<(VarNode, String)>, @@ -97,7 +98,6 @@ impl SleighContext { Ok(Self { ctx, spaces, - image: None, language_id: language_def.id.clone(), registers, }) @@ -129,15 +129,11 @@ impl SleighContext { &self.language_id } - pub fn initialize_with_image + Clone>( + pub fn initialize_with_image( mut self, img: T, ) -> Result { - self.image = Some(img.clone().into()); - self.ctx - .pin_mut() - .setImage(img.into()) - .map_err(|_| ImageLoadError)?; + Ok(LoadedSleighContext::new(self)) } diff --git a/jingle_sleigh/src/context/sleigh_image/mod.rs b/jingle_sleigh/src/context/sleigh_image/mod.rs deleted file mode 100644 index f52a208..0000000 --- a/jingle_sleigh/src/context/sleigh_image/mod.rs +++ /dev/null @@ -1,110 +0,0 @@ -mod instruction_iterator; - -use crate::context::sleigh_image::instruction_iterator::SleighContextInstructionIterator; -use crate::ffi::sleigh_image::bridge::SleighImage as SleighImageFFI; -use crate::{Instruction, RegisterManager, SpaceInfo, SpaceManager, VarNode}; -use cxx::UniquePtr; -use std::ops::Index; -use crate::context::SleighContext; -use crate::ffi::instruction::bridge::VarnodeInfoFFI; - -pub struct SleighImage { - img_ffi: UniquePtr, - spaces: Vec, - -} - -impl SleighImage { - pub(crate) fn new(ffi: UniquePtr) -> Self { - let mut spaces: Vec = Vec::with_capacity(ffi.getNumSpaces() as usize); - for idx in 0..ffi.getNumSpaces() { - spaces.push(SpaceInfo::from(ffi.getSpaceByIndex(idx))); - } - - Self { img_ffi: ffi, spaces } - } - - pub fn instruction_at(&self, offset: u64) -> Option { - self.img_ffi - .get_one_instruction(offset) - .map(Instruction::from) - .ok() - } - pub fn read(&self, offset: u64, max_instrs: usize) -> SleighContextInstructionIterator { - SleighContextInstructionIterator::new(self, offset, max_instrs, false) - } - - pub fn read_until_branch( - &self, - offset: u64, - max_instrs: usize, - ) -> SleighContextInstructionIterator { - SleighContextInstructionIterator::new(self, offset, max_instrs, true) - } -} - -impl SpaceManager for SleighImage { - fn get_space_info(&self, idx: usize) -> Option<&SpaceInfo> { - self.spaces.get(idx) - } - - fn get_all_space_info(&self) -> &[SpaceInfo] { - self.spaces.as_slice() - } - - fn get_code_space_idx(&self) -> usize { - self.img_ffi - .getSpaceByIndex(0) - .getManager() - .getDefaultCodeSpace() - .getIndex() as usize - } -} - -impl RegisterManager for SleighImage { - fn get_register(&self, name: &str) -> Option { - self.img_ffi.getRegister(name).map(VarNode::from).ok() - } - - fn get_register_name(&self, location: VarNode) -> Option<&str> { - let space = self.img_ffi.getSpaceByIndex(location.space_index as i32); - self.img_ffi - .getRegisterName(VarnodeInfoFFI { - space, - offset: location.offset, - size: location.size, - }) - .ok() - } - - fn get_registers(&self) -> Vec<(VarNode, String)> { - self.img_ffi - .getRegisters() - .iter() - .map(|b| (VarNode::from(&b.varnode), b.name.clone())) - .collect() - } -} - -#[cfg(test)] -mod test{ - use crate::context::SleighContextBuilder; - use crate::tests::SLEIGH_ARCH; - - #[test] - fn test_two_images(){ - let mov_eax_0: [u8; 4] = [0x0f, 0x05, 0x0f, 0x05]; - let nops: [u8; 4] = [0x90, 0x90, 0x90, 0x90]; - let ctx_builder = - SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); - let sleigh = ctx_builder - .build(SLEIGH_ARCH) - .unwrap(); - let img1 = sleigh.load_image(mov_eax_0.as_slice()).unwrap(); - let img2 = sleigh.load_image(nops.as_slice()).unwrap(); - let instr1 = img1.instruction_at(0); - let instr2 = img2.instruction_at(0); - assert_eq!(instr1, instr2); - assert_ne!(instr1, None); - } -} \ No newline at end of file diff --git a/jingle_sleigh/src/ffi/context_ffi.rs b/jingle_sleigh/src/ffi/context_ffi.rs index fa0cdc8..1035f1a 100644 --- a/jingle_sleigh/src/ffi/context_ffi.rs +++ b/jingle_sleigh/src/ffi/context_ffi.rs @@ -10,7 +10,7 @@ pub(crate) static CTX_BUILD_MUTEX: Mutex = Mutex::new(makeCo #[cxx::bridge] pub(crate) mod bridge { unsafe extern "C++" { - type Image = crate::context::Image; + type ImageFFI = crate::ffi::image::ImageFFI; type InstructionFFI = crate::ffi::instruction::bridge::InstructionFFI; // type VarnodeInfoFFI = crate::ffi::instruction::bridge::VarnodeInfoFFI; @@ -43,7 +43,7 @@ pub(crate) mod bridge { pub(crate) fn getRegisters(&self) -> Vec; - pub(crate) fn setImage(self: Pin<&mut ContextFFI>, img: Image) -> Result<()>; + pub(crate) fn setImage(self: Pin<&mut ContextFFI>, img: &ImageFFI) -> Result<()>; } impl Vec {} } diff --git a/jingle_sleigh/src/ffi/image.rs b/jingle_sleigh/src/ffi/image.rs index b728d08..93fb38c 100644 --- a/jingle_sleigh/src/ffi/image.rs +++ b/jingle_sleigh/src/ffi/image.rs @@ -1,37 +1,29 @@ use std::fmt::{Debug, Formatter}; +use crate::context::image::ImageProvider; +use crate::ffi::instruction::bridge::VarnodeInfoFFI; +use crate::VarNode; -#[cxx::bridge] -pub(crate) mod bridge { - #[derive(Debug, Clone)] - pub struct Perms { - pub(crate) read: bool, - pub(crate) write: bool, - pub(crate) exec: bool, - } +pub(crate) struct ImageFFI{ + provider: Box +} - #[derive(Clone)] - pub struct ImageSection { - pub(crate) data: Vec, - pub(crate) base_address: usize, - pub(crate) perms: Perms, +impl ImageFFI{ + pub(crate) fn new(provider: T) -> Self{ + Self{provider: Box::new(provider)} } - - #[derive(Debug, Clone)] - pub struct Image { - pub sections: Vec, + fn load(&self, vn: &VarnodeInfoFFI, out: &mut [u8]) -> usize{ + self.provider.load(VarNode::from(vn), out) } } -impl Debug for bridge::ImageSection { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let mut d = f.debug_struct("ImageSection"); - d.field("base_address", &self.base_address) - .field("perms", &self.perms); - if self.data.len() > 16 { - d.field("data", &format!("[ < {} bytes > ]", self.data.len())); - } else { - d.field("data", &self.data); - } - d.finish() +#[cxx::bridge] +pub(crate) mod bridge { + extern "C++"{ + type VarnodeInfoFFI = crate::ffi::instruction::bridge::VarnodeInfoFFI; + } + extern "Rust"{ + + type ImageFFI; + fn load(self: &ImageFFI, vn: &VarnodeInfoFFI, out: &mut [u8]) -> usize; } } From 90fc1a786f10657af9b8bda14b872ce5639fb92d Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 15 Oct 2024 11:20:00 +0100 Subject: [PATCH 080/146] Tweaks --- jingle_sleigh/build.rs | 7 +++- jingle_sleigh/src/ffi/cpp/context.cpp | 1 - jingle_sleigh/src/ffi/cpp/context.h | 3 +- .../src/ffi/cpp/dummy_load_image.cpp | 38 ++++--------------- jingle_sleigh/src/ffi/cpp/dummy_load_image.h | 4 -- 5 files changed, 14 insertions(+), 39 deletions(-) diff --git a/jingle_sleigh/build.rs b/jingle_sleigh/build.rs index 701b695..491603b 100644 --- a/jingle_sleigh/build.rs +++ b/jingle_sleigh/build.rs @@ -20,7 +20,7 @@ fn main() { let rust_sources = vec![ "src/ffi/addrspace.rs", "src/ffi/context_ffi.rs", - "src/ffi/sleigh_image.rs", + "src/ffi/image.rs", "src/ffi/instruction.rs", "src/ffi/opcode.rs", "src/ffi/image.rs", @@ -58,7 +58,7 @@ fn main() { "src/ffi/cpp/jingle_assembly_emitter.cpp", ]; // This assumes all your C++ bindings are in lib - cxx_build::bridges(rust_sources) + cxx_build::bridges(&rust_sources) .files(cpp_sources) .flag_if_supported("-std=c++17") .flag_if_supported("-Dmain=c_main") @@ -72,6 +72,9 @@ fn main() { .compile("jingle_sleigh"); println!("cargo::rerun-if-changed=src/ffi/cpp/"); + for src in rust_sources { + println!("cargo::rerun-if-changed={src}"); + } println!("cargo::rerun-if-changed=src/ffi/addrspace.rs"); println!("cargo::rerun-if-changed=src/ffi/context_ffi.rs"); println!("cargo::rerun-if-changed=src/ffi/instruction.rs"); diff --git a/jingle_sleigh/src/ffi/cpp/context.cpp b/jingle_sleigh/src/ffi/cpp/context.cpp index c55f87a..8cabc2a 100644 --- a/jingle_sleigh/src/ffi/cpp/context.cpp +++ b/jingle_sleigh/src/ffi/cpp/context.cpp @@ -5,7 +5,6 @@ #include #include "sleigh/globalcontext.hh" #include "sleigh/xml.hh" -#include "sleigh_image.h" #include "jingle_sleigh/src/ffi/instruction.rs.h" #include "sleigh/loadimage.hh" #include "varnode_translation.h" diff --git a/jingle_sleigh/src/ffi/cpp/context.h b/jingle_sleigh/src/ffi/cpp/context.h index 16d151c..7de2725 100644 --- a/jingle_sleigh/src/ffi/cpp/context.h +++ b/jingle_sleigh/src/ffi/cpp/context.h @@ -9,7 +9,6 @@ #include "sleigh/sleigh.hh" #include "jingle_sleigh/src/ffi/image.rs.h" #include "sleigh/loadimage.hh" -#include "sleigh_image.h" #include "dummy_load_image.h" class ContextFFI { @@ -22,7 +21,7 @@ class ContextFFI { void set_initial_context(rust::Str name, uint32_t val); - void setImage(Image img); + void setImage(ImageFFI const&img); InstructionFFI get_one_instruction(uint64_t offset) const; diff --git a/jingle_sleigh/src/ffi/cpp/dummy_load_image.cpp b/jingle_sleigh/src/ffi/cpp/dummy_load_image.cpp index ddf576f..b5eb474 100644 --- a/jingle_sleigh/src/ffi/cpp/dummy_load_image.cpp +++ b/jingle_sleigh/src/ffi/cpp/dummy_load_image.cpp @@ -1,40 +1,18 @@ #include "dummy_load_image.h" DummyLoadImage::DummyLoadImage() : ghidra::LoadImage("jingle") { - img = Image{}; } -DummyLoadImage::DummyLoadImage(Image image) : ghidra::LoadImage("jingle") { - img = std::move(image); -} -void DummyLoadImage::loadFill(ghidra::uint1 *ptr, ghidra::int4 size, const ghidra::Address &addr) { - size_t offset = addr.getOffset(); - size_t bytes_written = 0; - for (const auto §ion: img.sections) { - size_t start = section.base_address; - size_t end = start + section.data.size(); - if (start <= offset && offset < end) { - size_t len = std::min((size_t) size, (size_t) end - (size_t) offset); - size_t start_idx = offset - start; - std::memcpy(ptr, §ion.data[start_idx], len); - offset = offset + len; - bytes_written += len; - } - } - for (size_t i = bytes_written; i < size; ++i) { - ptr[i] = 0; - } - if (bytes_written == 0) { - ghidra::ostringstream errmsg; - errmsg << "Unable to load " << std::dec << size << " bytes at " << addr.getShortcut(); - addr.printRaw(errmsg); - throw ghidra::DataUnavailError(errmsg.str()); - } +void DummyLoadImage::loadFill(ghidra::uint1 *ptr, ghidra::int4 size, + const ghidra::Address &addr) { + ghidra::ostringstream errmsg; + errmsg << "Unable to load " << std::dec << size << " bytes at " + << addr.getShortcut(); + addr.printRaw(errmsg); + throw ghidra::DataUnavailError(errmsg.str()); } void DummyLoadImage::adjustVma(long adjust) {} -std::string DummyLoadImage::getArchType() const { - return "placeholder"; -} +std::string DummyLoadImage::getArchType() const { return "placeholder"; } diff --git a/jingle_sleigh/src/ffi/cpp/dummy_load_image.h b/jingle_sleigh/src/ffi/cpp/dummy_load_image.h index 935aeea..1657040 100644 --- a/jingle_sleigh/src/ffi/cpp/dummy_load_image.h +++ b/jingle_sleigh/src/ffi/cpp/dummy_load_image.h @@ -3,17 +3,13 @@ #define JINGLE_SLEIGH_DUMMY_LOAD_IMAGE_H -#include "jingle_sleigh/src/ffi/image.rs.h" #include "sleigh/loadimage.hh" class DummyLoadImage : public ghidra::LoadImage { - Image img; public: DummyLoadImage(); - DummyLoadImage(Image img); - void loadFill(ghidra::uint1 *ptr, ghidra::int4 size, const ghidra::Address &addr) override; std::string getArchType(void) const override; From 62a479e37f4f79bcc98eabd1e65fabe60404fabf Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 15 Oct 2024 11:34:54 +0100 Subject: [PATCH 081/146] Some build fixes --- jingle_sleigh/src/ffi/cpp/context.cpp | 125 +++++++++++++------------- jingle_sleigh/src/ffi/image.rs | 22 ++--- 2 files changed, 73 insertions(+), 74 deletions(-) diff --git a/jingle_sleigh/src/ffi/cpp/context.cpp b/jingle_sleigh/src/ffi/cpp/context.cpp index 8cabc2a..ea2a3d3 100644 --- a/jingle_sleigh/src/ffi/cpp/context.cpp +++ b/jingle_sleigh/src/ffi/cpp/context.cpp @@ -1,98 +1,95 @@ #include "context.h" -#include -#include -#include "sleigh/globalcontext.hh" -#include "sleigh/xml.hh" +#include "jingle_assembly_emitter.h" +#include "jingle_pcode_emitter.h" #include "jingle_sleigh/src/ffi/instruction.rs.h" +#include "sleigh/globalcontext.hh" #include "sleigh/loadimage.hh" +#include "sleigh/xml.hh" #include "varnode_translation.h" -#include "jingle_pcode_emitter.h" -#include "jingle_assembly_emitter.h" - - -ContextFFI::ContextFFI(rust::Str slaPath): sleigh(new DummyLoadImage(Image()), &c_db) { - ghidra::AttributeId::initialize(); - ghidra::ElementId::initialize(); +#include +#include - ghidra::DocumentStorage documentStorage = ghidra::DocumentStorage(); +ContextFFI::ContextFFI(rust::Str slaPath) + : sleigh(new DummyLoadImage(), &c_db) { + ghidra::AttributeId::initialize(); + ghidra::ElementId::initialize(); - std::stringstream sleighfilename; - sleighfilename << ""; - sleighfilename << slaPath; - sleighfilename << ""; + ghidra::DocumentStorage documentStorage = ghidra::DocumentStorage(); - ghidra::Document *doc = documentStorage.parseDocument(sleighfilename); - ghidra::Element *root = doc->getRoot(); - documentStorage.registerTag(root); - sleigh.initialize(documentStorage); + std::stringstream sleighfilename; + sleighfilename << ""; + sleighfilename << slaPath; + sleighfilename << ""; + ghidra::Document *doc = documentStorage.parseDocument(sleighfilename); + ghidra::Element *root = doc->getRoot(); + documentStorage.registerTag(root); + sleigh.initialize(documentStorage); } void ContextFFI::set_initial_context(rust::Str name, uint32_t val) { - sleigh.setContextDefault(name.operator std::string(), val); + sleigh.setContextDefault(name.operator std::string(), val); } - - -std::shared_ptr ContextFFI::getSpaceByIndex(ghidra::int4 idx) const { - return std::make_shared(sleigh.getSpace(idx)); +std::shared_ptr +ContextFFI::getSpaceByIndex(ghidra::int4 idx) const { + return std::make_shared(sleigh.getSpace(idx)); } -ghidra::int4 ContextFFI::getNumSpaces() const { - return sleigh.numSpaces(); -} +ghidra::int4 ContextFFI::getNumSpaces() const { return sleigh.numSpaces(); } VarnodeInfoFFI ContextFFI::getRegister(rust::Str name) const { - ghidra::VarnodeData vn = sleigh.getRegister(name.operator std::string()); - VarnodeInfoFFI info; - info.space = std::make_unique(vn.space); - info.size = vn.size; - info.offset = vn.offset; - return info; + ghidra::VarnodeData vn = sleigh.getRegister(name.operator std::string()); + VarnodeInfoFFI info; + info.space = std::make_unique(vn.space); + info.size = vn.size; + info.offset = vn.offset; + return info; }; rust::Str ContextFFI::getRegisterName(VarnodeInfoFFI vn) const { - std::string name = sleigh.getRegisterName(vn.space->getRaw(), vn.offset, vn.size); - return {name}; + std::string name = + sleigh.getRegisterName(vn.space->getRaw(), vn.offset, vn.size); + return {name}; } rust::Vec ContextFFI::getRegisters() const { - std::map reglist; - rust::Vec v; - sleigh.getAllRegisters(reglist); - v.reserve(reglist.size()); - for (auto const &vn: reglist) { - v.emplace_back(collectRegInfo(vn)); - } - return v; + std::map reglist; + rust::Vec v; + sleigh.getAllRegisters(reglist); + v.reserve(reglist.size()); + for (auto const &vn : reglist) { + v.emplace_back(collectRegInfo(vn)); + } + return v; } -void ContextFFI::setImage(Image img) { - sleigh.reset(new DummyLoadImage(std::move(img)), &c_db); - ghidra::DocumentStorage documentStorage = ghidra::DocumentStorage(); - sleigh.initialize(documentStorage); +void ContextFFI::setImage(ImageFFI const &img) { + sleigh.reset(new DummyLoadImage(), &c_db); + ghidra::DocumentStorage documentStorage = ghidra::DocumentStorage(); + sleigh.initialize(documentStorage); } InstructionFFI ContextFFI::get_one_instruction(uint64_t offset) const { - JinglePcodeEmitter pcode; - JingleAssemblyEmitter assembly; - ghidra::Address a = ghidra::Address(sleigh.getDefaultCodeSpace(), offset); - sleigh.printAssembly(assembly, a); - sleigh.oneInstruction(pcode, a); - size_t length = sleigh.instructionLength(a); - InstructionFFI i; - Disassembly d; - i.ops = std::move(pcode.ops); - d.args = std::move(assembly.body); - d.mnemonic = std::move(assembly.mnem); - i.disassembly = std::move(d); - i.address = offset; - i.length = length; - return i; + JinglePcodeEmitter pcode; + JingleAssemblyEmitter assembly; + ghidra::Address a = ghidra::Address(sleigh.getDefaultCodeSpace(), offset); + sleigh.printAssembly(assembly, a); + sleigh.oneInstruction(pcode, a); + size_t length = sleigh.instructionLength(a); + InstructionFFI i; + Disassembly d; + i.ops = std::move(pcode.ops); + d.args = std::move(assembly.body); + d.mnemonic = std::move(assembly.mnem); + i.disassembly = std::move(d); + i.address = offset; + i.length = length; + return i; } std::unique_ptr makeContext(rust::Str slaPath) { - return std::make_unique(slaPath); + return std::make_unique(slaPath); } diff --git a/jingle_sleigh/src/ffi/image.rs b/jingle_sleigh/src/ffi/image.rs index 93fb38c..e5ee8ef 100644 --- a/jingle_sleigh/src/ffi/image.rs +++ b/jingle_sleigh/src/ffi/image.rs @@ -1,28 +1,30 @@ -use std::fmt::{Debug, Formatter}; use crate::context::image::ImageProvider; use crate::ffi::instruction::bridge::VarnodeInfoFFI; use crate::VarNode; +use std::fmt::{Debug, Formatter}; -pub(crate) struct ImageFFI{ - provider: Box +pub(crate) struct ImageFFI { + provider: Box, } -impl ImageFFI{ - pub(crate) fn new(provider: T) -> Self{ - Self{provider: Box::new(provider)} +impl ImageFFI { + pub(crate) fn new(provider: T) -> Self { + Self { + provider: Box::new(provider), + } } - fn load(&self, vn: &VarnodeInfoFFI, out: &mut [u8]) -> usize{ + fn load(&self, vn: &VarnodeInfoFFI, out: &mut [u8]) -> usize { self.provider.load(VarNode::from(vn), out) } } #[cxx::bridge] pub(crate) mod bridge { - extern "C++"{ + unsafe extern "C++" { type VarnodeInfoFFI = crate::ffi::instruction::bridge::VarnodeInfoFFI; } - extern "Rust"{ - + extern "Rust" { + include!("jingle_sleigh/src/ffi/instruction.rs.h"); type ImageFFI; fn load(self: &ImageFFI, vn: &VarnodeInfoFFI, out: &mut [u8]) -> usize; } From 3e6b0be80e65a32ea491e67d02738b1a6791c25a Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 15 Oct 2024 12:18:23 +0100 Subject: [PATCH 082/146] More stuff --- jingle_sleigh/CMakeLists.txt | 4 ++- jingle_sleigh/build.rs | 1 + jingle_sleigh/src/context/image.rs | 4 ++- jingle_sleigh/src/context/loaded.rs | 31 +++++++++---------- jingle_sleigh/src/context/mod.rs | 11 +++---- jingle_sleigh/src/ffi/context_ffi.rs | 2 +- jingle_sleigh/src/ffi/cpp/context.cpp | 3 +- .../src/ffi/cpp/dummy_load_image.cpp | 10 +++--- jingle_sleigh/src/ffi/cpp/rust_load_image.cpp | 28 +++++++++++++++++ jingle_sleigh/src/ffi/cpp/rust_load_image.h | 24 ++++++++++++++ jingle_sleigh/src/ffi/image.rs | 16 ++++++---- 11 files changed, 96 insertions(+), 38 deletions(-) create mode 100644 jingle_sleigh/src/ffi/cpp/rust_load_image.cpp create mode 100644 jingle_sleigh/src/ffi/cpp/rust_load_image.h diff --git a/jingle_sleigh/CMakeLists.txt b/jingle_sleigh/CMakeLists.txt index 552e320..3f25b7f 100644 --- a/jingle_sleigh/CMakeLists.txt +++ b/jingle_sleigh/CMakeLists.txt @@ -38,7 +38,9 @@ add_library(jingle_sleigh_cpp src/ffi/cpp/varnode_translation.h src/ffi/cpp/jingle_pcode_emitter.cpp src/ffi/cpp/jingle_assembly_emitter.cpp - src/ffi/cpp/jingle_assembly_emitter.h) + src/ffi/cpp/jingle_assembly_emitter.h + src/ffi/cpp/rust_load_image.cpp + src/ffi/cpp/rust_load_image.h) add_executable(sleigh_compile src/ffi/cpp/sleigh/address.cc diff --git a/jingle_sleigh/build.rs b/jingle_sleigh/build.rs index 491603b..a01f6f9 100644 --- a/jingle_sleigh/build.rs +++ b/jingle_sleigh/build.rs @@ -51,6 +51,7 @@ fn main() { "src/ffi/cpp/sleigh/slghparse.cc", "src/ffi/cpp/context.cpp", "src/ffi/cpp/dummy_load_image.cpp", + "src/ffi/cpp/rust_load_image.cpp", "src/ffi/cpp/addrspace_handle.cpp", "src/ffi/cpp/addrspace_manager_handle.cpp", "src/ffi/cpp/varnode_translation.cpp", diff --git a/jingle_sleigh/src/context/image.rs b/jingle_sleigh/src/context/image.rs index c6b8a14..14513b7 100644 --- a/jingle_sleigh/src/context/image.rs +++ b/jingle_sleigh/src/context/image.rs @@ -1,5 +1,7 @@ use crate::VarNode; pub trait ImageProvider{ - fn load(vn: &VarNode, output: &mut &[u8]) -> usize; + fn load(&self, vn: &VarNode, output: &mut [u8]) -> usize; + + fn has_range(&self, vn: &VarNode) -> bool; } \ No newline at end of file diff --git a/jingle_sleigh/src/context/loaded.rs b/jingle_sleigh/src/context/loaded.rs index 4f646f6..e953db6 100644 --- a/jingle_sleigh/src/context/loaded.rs +++ b/jingle_sleigh/src/context/loaded.rs @@ -7,14 +7,14 @@ use std::ops::{Deref, DerefMut}; use crate::context::image::ImageProvider; use crate::ffi::image::ImageFFI; -pub struct LoadedSleighContext(SleighContext, ImageFFI); +pub struct LoadedSleighContext<'a>(SleighContext, ImageFFI<'a>); -impl Debug for LoadedSleighContext { +impl<'a> Debug for LoadedSleighContext<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { self.0.fmt(f) } } -impl Deref for LoadedSleighContext { +impl<'a> Deref for LoadedSleighContext<'a> { type Target = SleighContext; fn deref(&self) -> &Self::Target { @@ -22,20 +22,20 @@ impl Deref for LoadedSleighContext { } } -impl DerefMut for LoadedSleighContext { +impl<'a> DerefMut for LoadedSleighContext<'a> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } -impl LoadedSleighContext { - pub(crate) fn new(sleigh_context: SleighContext, img: T) -> Result { +impl<'a> LoadedSleighContext<'a> { + pub(crate) fn new(mut sleigh_context: SleighContext, img: T) -> Result { let img = ImageFFI::new(img); sleigh_context - .pin_mut() + .ctx.pin_mut() .setImage(&img) .map_err(|_| ImageLoadError)?; - Self(sleigh_context, img) + Ok(Self(sleigh_context, img)) } pub fn instruction_at(&self, offset: u64) -> Option { let instr = self @@ -43,10 +43,9 @@ impl LoadedSleighContext { .get_one_instruction(offset) .map(Instruction::from) .ok()?; + let vn = VarNode { space_index: self.0.get_code_space_idx(), size: instr.length, offset }; if self - .image - .as_ref()? - .contains_range(offset..(offset + instr.length as u64)) + .1.has_range(&vn) { Some(instr) } else { @@ -66,16 +65,16 @@ impl LoadedSleighContext { SleighContextInstructionIterator::new(self, offset, max_instrs, true) } - pub fn set_image + Clone>(&mut self, img: T) -> Result<(), JingleSleighError> { - self.image = Some(img.clone().into()); + pub fn set_image(&mut self, img: T) -> Result<(), JingleSleighError> { + self.1 = ImageFFI::new(img); self.ctx .pin_mut() - .setImage(img.into()) + .setImage(&self.1) .map_err(|_| ImageLoadError) } } -impl SpaceManager for LoadedSleighContext { +impl<'a> SpaceManager for LoadedSleighContext<'a> { fn get_space_info(&self, idx: usize) -> Option<&SpaceInfo> { self.0.get_space_info(idx) } @@ -89,7 +88,7 @@ impl SpaceManager for LoadedSleighContext { } } -impl RegisterManager for LoadedSleighContext { +impl<'a> RegisterManager for LoadedSleighContext<'a> { fn get_register(&self, name: &str) -> Option { self.0.get_register(name) } diff --git a/jingle_sleigh/src/context/mod.rs b/jingle_sleigh/src/context/mod.rs index bbf9e34..c0dc499 100644 --- a/jingle_sleigh/src/context/mod.rs +++ b/jingle_sleigh/src/context/mod.rs @@ -129,17 +129,14 @@ impl SleighContext { &self.language_id } - pub fn initialize_with_image( - mut self, + pub fn initialize_with_image<'b, T: ImageProvider + 'b>( + self, img: T, - ) -> Result { + ) -> Result, JingleSleighError> { - Ok(LoadedSleighContext::new(self)) + LoadedSleighContext::new(self, img) } - pub fn get_image(&self) -> Option<&Image> { - self.image.as_ref() - } } #[cfg(test)] diff --git a/jingle_sleigh/src/ffi/context_ffi.rs b/jingle_sleigh/src/ffi/context_ffi.rs index 1035f1a..15437d0 100644 --- a/jingle_sleigh/src/ffi/context_ffi.rs +++ b/jingle_sleigh/src/ffi/context_ffi.rs @@ -10,7 +10,7 @@ pub(crate) static CTX_BUILD_MUTEX: Mutex = Mutex::new(makeCo #[cxx::bridge] pub(crate) mod bridge { unsafe extern "C++" { - type ImageFFI = crate::ffi::image::ImageFFI; + type ImageFFI<'a> = crate::ffi::image::ImageFFI<'a>; type InstructionFFI = crate::ffi::instruction::bridge::InstructionFFI; // type VarnodeInfoFFI = crate::ffi::instruction::bridge::VarnodeInfoFFI; diff --git a/jingle_sleigh/src/ffi/cpp/context.cpp b/jingle_sleigh/src/ffi/cpp/context.cpp index ea2a3d3..b3afdf8 100644 --- a/jingle_sleigh/src/ffi/cpp/context.cpp +++ b/jingle_sleigh/src/ffi/cpp/context.cpp @@ -8,6 +8,7 @@ #include "sleigh/loadimage.hh" #include "sleigh/xml.hh" #include "varnode_translation.h" +#include "rust_load_image.h" #include #include @@ -67,7 +68,7 @@ rust::Vec ContextFFI::getRegisters() const { } void ContextFFI::setImage(ImageFFI const &img) { - sleigh.reset(new DummyLoadImage(), &c_db); + sleigh.reset(new RustLoadImage(img), &c_db); ghidra::DocumentStorage documentStorage = ghidra::DocumentStorage(); sleigh.initialize(documentStorage); } diff --git a/jingle_sleigh/src/ffi/cpp/dummy_load_image.cpp b/jingle_sleigh/src/ffi/cpp/dummy_load_image.cpp index b5eb474..4c472a5 100644 --- a/jingle_sleigh/src/ffi/cpp/dummy_load_image.cpp +++ b/jingle_sleigh/src/ffi/cpp/dummy_load_image.cpp @@ -6,11 +6,11 @@ DummyLoadImage::DummyLoadImage() : ghidra::LoadImage("jingle") { void DummyLoadImage::loadFill(ghidra::uint1 *ptr, ghidra::int4 size, const ghidra::Address &addr) { - ghidra::ostringstream errmsg; - errmsg << "Unable to load " << std::dec << size << " bytes at " - << addr.getShortcut(); - addr.printRaw(errmsg); - throw ghidra::DataUnavailError(errmsg.str()); + ghidra::ostringstream errmsg; + errmsg << "Unable to load " << std::dec << size << " bytes at " + << addr.getShortcut(); + addr.printRaw(errmsg); + throw ghidra::DataUnavailError(errmsg.str()); } void DummyLoadImage::adjustVma(long adjust) {} diff --git a/jingle_sleigh/src/ffi/cpp/rust_load_image.cpp b/jingle_sleigh/src/ffi/cpp/rust_load_image.cpp new file mode 100644 index 0000000..3d5abe1 --- /dev/null +++ b/jingle_sleigh/src/ffi/cpp/rust_load_image.cpp @@ -0,0 +1,28 @@ +// +// Created by toolCHAINZ on 10/15/24. +// + +#include "rust_load_image.h" +#include "sleigh/pcoderaw.hh" +#include "varnode_translation.h" + +void RustLoadImage::loadFill(ghidra::uint1 *ptr, ghidra::int4 size, const ghidra::Address &addr) { + ghidra::VarnodeData vn = {addr.getSpace(), addr.getOffset(), static_cast(size)}; + + size_t result = img.load(varnodeToFFI(vn), rust::Slice(ptr, size)); + if(result == 0){ + ghidra::ostringstream errmsg; + errmsg << "Unable to load " << std::dec << size << " bytes at " + << addr.getShortcut(); + addr.printRaw(errmsg); + throw ghidra::DataUnavailError(errmsg.str()); + } +} + +std::string RustLoadImage::getArchType(void) const { + return "placeholder"; +} + +void RustLoadImage::adjustVma(long adjust) { + +} diff --git a/jingle_sleigh/src/ffi/cpp/rust_load_image.h b/jingle_sleigh/src/ffi/cpp/rust_load_image.h new file mode 100644 index 0000000..6ce5995 --- /dev/null +++ b/jingle_sleigh/src/ffi/cpp/rust_load_image.h @@ -0,0 +1,24 @@ +// +// Created by toolCHAINZ on 10/15/24. +// + +#ifndef JINGLE_SLEIGH_RUST_LOAD_IMAGE_H +#define JINGLE_SLEIGH_RUST_LOAD_IMAGE_H + +#include "jingle_sleigh/src/ffi/image.rs.h" +#include "sleigh/loadimage.hh" + +class RustLoadImage : public ghidra::LoadImage { + ImageFFI const &img; +public: + RustLoadImage(ImageFFI const& img) : LoadImage("placeholder"), img(img) {}; + + void loadFill(ghidra::uint1 *ptr, ghidra::int4 size, const ghidra::Address &addr) override; + + std::string getArchType(void) const override; + + void adjustVma(long adjust) override; + +}; + +#endif //JINGLE_SLEIGH_RUST_LOAD_IMAGE_H diff --git a/jingle_sleigh/src/ffi/image.rs b/jingle_sleigh/src/ffi/image.rs index e5ee8ef..8ee4bb4 100644 --- a/jingle_sleigh/src/ffi/image.rs +++ b/jingle_sleigh/src/ffi/image.rs @@ -3,18 +3,22 @@ use crate::ffi::instruction::bridge::VarnodeInfoFFI; use crate::VarNode; use std::fmt::{Debug, Formatter}; -pub(crate) struct ImageFFI { - provider: Box, +pub(crate) struct ImageFFI<'a> { + provider: Box, } -impl ImageFFI { - pub(crate) fn new(provider: T) -> Self { +impl<'a> ImageFFI<'a> { + pub(crate) fn new(provider: T) -> Self { Self { provider: Box::new(provider), } } fn load(&self, vn: &VarnodeInfoFFI, out: &mut [u8]) -> usize { - self.provider.load(VarNode::from(vn), out) + self.provider.load(&VarNode::from(vn), out) + } + + pub(crate) fn has_range(&self, vn: &VarNode) -> bool { + self.provider.has_range(vn) } } @@ -25,7 +29,7 @@ pub(crate) mod bridge { } extern "Rust" { include!("jingle_sleigh/src/ffi/instruction.rs.h"); - type ImageFFI; + type ImageFFI<'a>; fn load(self: &ImageFFI, vn: &VarnodeInfoFFI, out: &mut [u8]) -> usize; } } From 34c4393a90124f64127f46941c7922311fc724da Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 15 Oct 2024 12:33:49 +0100 Subject: [PATCH 083/146] Maybe just need to add the impls now? --- jingle_sleigh/src/context/loaded.rs | 13 ++++++++++--- jingle_sleigh/src/context/mod.rs | 1 - jingle_sleigh/src/ffi/image.rs | 6 ++++++ 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/jingle_sleigh/src/context/loaded.rs b/jingle_sleigh/src/context/loaded.rs index e953db6..0c999c9 100644 --- a/jingle_sleigh/src/context/loaded.rs +++ b/jingle_sleigh/src/context/loaded.rs @@ -3,7 +3,9 @@ use crate::context::{Image, SleighContext}; use crate::JingleSleighError::ImageLoadError; use crate::{Instruction, JingleSleighError, RegisterManager, SpaceInfo, SpaceManager, VarNode}; use std::fmt::{Debug, Formatter}; +use std::mem; use std::ops::{Deref, DerefMut}; +use cxx::UniquePtr; use crate::context::image::ImageProvider; use crate::ffi::image::ImageFFI; @@ -66,12 +68,17 @@ impl<'a> LoadedSleighContext<'a> { } pub fn set_image(&mut self, img: T) -> Result<(), JingleSleighError> { - self.1 = ImageFFI::new(img); - self.ctx + let (sleigh, img_ref) = self.borrow_parts(); + *img_ref = ImageFFI::new(img); + sleigh.ctx .pin_mut() - .setImage(&self.1) + .setImage(img_ref) .map_err(|_| ImageLoadError) } + + fn borrow_parts<'b>(&'b mut self) -> (&'b mut SleighContext, &'b mut ImageFFI<'a>) { + (&mut self.0, &mut self.1) + } } impl<'a> SpaceManager for LoadedSleighContext<'a> { diff --git a/jingle_sleigh/src/context/mod.rs b/jingle_sleigh/src/context/mod.rs index c0dc499..faae4e5 100644 --- a/jingle_sleigh/src/context/mod.rs +++ b/jingle_sleigh/src/context/mod.rs @@ -10,7 +10,6 @@ use crate::ffi::context_ffi::bridge::ContextFFI; use crate::space::{RegisterManager, SpaceInfo, SpaceManager}; #[cfg(feature = "gimli")] pub use builder::image::gimli::map_gimli_architecture; -pub use builder::image::{Image, ImageSection}; pub use builder::SleighContextBuilder; use crate::context::builder::language_def::LanguageDefinition; diff --git a/jingle_sleigh/src/ffi/image.rs b/jingle_sleigh/src/ffi/image.rs index 8ee4bb4..b8a6e47 100644 --- a/jingle_sleigh/src/ffi/image.rs +++ b/jingle_sleigh/src/ffi/image.rs @@ -2,6 +2,7 @@ use crate::context::image::ImageProvider; use crate::ffi::instruction::bridge::VarnodeInfoFFI; use crate::VarNode; use std::fmt::{Debug, Formatter}; +use cxx::ExternType; pub(crate) struct ImageFFI<'a> { provider: Box, @@ -22,6 +23,11 @@ impl<'a> ImageFFI<'a> { } } +unsafe impl<'a> ExternType for ImageFFI<'a>{ + type Id = cxx::type_id!("ImageFFI"); + type Kind = cxx::kind::Opaque; +} + #[cxx::bridge] pub(crate) mod bridge { unsafe extern "C++" { From a9248f61d6132a5e71ee3bfb9cbbc5a37be0485d Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 15 Oct 2024 12:35:08 +0100 Subject: [PATCH 084/146] Build fixed --- jingle/src/translator.rs | 2 +- jingle_sleigh/src/context/loaded.rs | 2 +- jingle_sleigh/src/context/mod.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/jingle/src/translator.rs b/jingle/src/translator.rs index aab3ebe..51fe35b 100644 --- a/jingle/src/translator.rs +++ b/jingle/src/translator.rs @@ -13,7 +13,7 @@ use z3::Context; #[derive(Debug, Clone)] pub struct SleighTranslator<'ctx> { z3_ctx: &'ctx Context, - sleigh: &'ctx LoadedSleighContext, + sleigh: &'ctx LoadedSleighContext<'ctx>, } impl<'ctx> SleighTranslator<'ctx> { diff --git a/jingle_sleigh/src/context/loaded.rs b/jingle_sleigh/src/context/loaded.rs index 0c999c9..230aabc 100644 --- a/jingle_sleigh/src/context/loaded.rs +++ b/jingle_sleigh/src/context/loaded.rs @@ -1,5 +1,5 @@ use crate::context::instruction_iterator::SleighContextInstructionIterator; -use crate::context::{Image, SleighContext}; +use crate::context::{SleighContext}; use crate::JingleSleighError::ImageLoadError; use crate::{Instruction, JingleSleighError, RegisterManager, SpaceInfo, SpaceManager, VarNode}; use std::fmt::{Debug, Formatter}; diff --git a/jingle_sleigh/src/context/mod.rs b/jingle_sleigh/src/context/mod.rs index faae4e5..2fd8689 100644 --- a/jingle_sleigh/src/context/mod.rs +++ b/jingle_sleigh/src/context/mod.rs @@ -8,8 +8,8 @@ use crate::error::JingleSleighError::{LanguageSpecRead, SleighInitError}; use crate::ffi::addrspace::bridge::AddrSpaceHandle; use crate::ffi::context_ffi::bridge::ContextFFI; use crate::space::{RegisterManager, SpaceInfo, SpaceManager}; -#[cfg(feature = "gimli")] -pub use builder::image::gimli::map_gimli_architecture; +//#[cfg(feature = "gimli")] +//pub use builder::image::gimli::map_gimli_architecture; pub use builder::SleighContextBuilder; use crate::context::builder::language_def::LanguageDefinition; From ebfe8af4441d54a35d14332f592e2b1acac7d1b2 Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 15 Oct 2024 12:55:44 +0100 Subject: [PATCH 085/146] fmt --- jingle_sleigh/src/context/image.rs | 39 ++++++++++++++++++++++++++--- jingle_sleigh/src/context/loaded.rs | 29 +++++++++++++-------- jingle_sleigh/src/context/mod.rs | 6 ++--- jingle_sleigh/src/ffi/image.rs | 6 ++--- jingle_sleigh/src/varnode/mod.rs | 18 +++++++++++++ 5 files changed, 77 insertions(+), 21 deletions(-) diff --git a/jingle_sleigh/src/context/image.rs b/jingle_sleigh/src/context/image.rs index 14513b7..9a3ec1d 100644 --- a/jingle_sleigh/src/context/image.rs +++ b/jingle_sleigh/src/context/image.rs @@ -1,7 +1,40 @@ use crate::VarNode; +use object::ReadRef; +use std::ops::Range; -pub trait ImageProvider{ +pub trait ImageProvider { fn load(&self, vn: &VarNode, output: &mut [u8]) -> usize; - fn has_range(&self, vn: &VarNode) -> bool; -} \ No newline at end of file + fn has_full_range(&self, vn: &VarNode) -> bool; +} + +impl ImageProvider for &[u8] { + fn load(&self, vn: &VarNode, output: &mut [u8]) -> usize { + //todo: check the space. Ignoring for now + if vn.offset >= self.len() as u64 { + output.fill(0); + 0 + } else { + let vn_range: Range = Range::from(vn); + let output_len = output.len(); + output.copy_from_slice(&self[vn_range.clone()]); + output[vn_range.end..output_len].fill(0); + vn_range.len() + } + } + + fn has_full_range(&self, vn: &VarNode) -> bool { + let vn_range: Range = Range::from(vn); + vn_range.start > 0 && vn_range.start < self.len() && vn_range.end < self.len() + } +} + +impl ImageProvider for Vec { + fn load(&self, vn: &VarNode, output: &mut [u8]) -> usize { + self.as_slice().load(vn, output) + } + + fn has_full_range(&self, vn: &VarNode) -> bool { + self.as_slice().has_full_range(vn) + } +} diff --git a/jingle_sleigh/src/context/loaded.rs b/jingle_sleigh/src/context/loaded.rs index 230aabc..c19cb29 100644 --- a/jingle_sleigh/src/context/loaded.rs +++ b/jingle_sleigh/src/context/loaded.rs @@ -1,13 +1,13 @@ +use crate::context::image::ImageProvider; use crate::context::instruction_iterator::SleighContextInstructionIterator; -use crate::context::{SleighContext}; +use crate::context::SleighContext; +use crate::ffi::image::ImageFFI; use crate::JingleSleighError::ImageLoadError; use crate::{Instruction, JingleSleighError, RegisterManager, SpaceInfo, SpaceManager, VarNode}; +use cxx::UniquePtr; use std::fmt::{Debug, Formatter}; use std::mem; use std::ops::{Deref, DerefMut}; -use cxx::UniquePtr; -use crate::context::image::ImageProvider; -use crate::ffi::image::ImageFFI; pub struct LoadedSleighContext<'a>(SleighContext, ImageFFI<'a>); @@ -31,10 +31,14 @@ impl<'a> DerefMut for LoadedSleighContext<'a> { } impl<'a> LoadedSleighContext<'a> { - pub(crate) fn new(mut sleigh_context: SleighContext, img: T) -> Result { + pub(crate) fn new( + mut sleigh_context: SleighContext, + img: T, + ) -> Result { let img = ImageFFI::new(img); sleigh_context - .ctx.pin_mut() + .ctx + .pin_mut() .setImage(&img) .map_err(|_| ImageLoadError)?; Ok(Self(sleigh_context, img)) @@ -45,10 +49,12 @@ impl<'a> LoadedSleighContext<'a> { .get_one_instruction(offset) .map(Instruction::from) .ok()?; - let vn = VarNode { space_index: self.0.get_code_space_idx(), size: instr.length, offset }; - if self - .1.has_range(&vn) - { + let vn = VarNode { + space_index: self.0.get_code_space_idx(), + size: instr.length, + offset, + }; + if self.1.has_range(&vn) { Some(instr) } else { None @@ -70,7 +76,8 @@ impl<'a> LoadedSleighContext<'a> { pub fn set_image(&mut self, img: T) -> Result<(), JingleSleighError> { let (sleigh, img_ref) = self.borrow_parts(); *img_ref = ImageFFI::new(img); - sleigh.ctx + sleigh + .ctx .pin_mut() .setImage(img_ref) .map_err(|_| ImageLoadError) diff --git a/jingle_sleigh/src/context/mod.rs b/jingle_sleigh/src/context/mod.rs index 2fd8689..2850c54 100644 --- a/jingle_sleigh/src/context/mod.rs +++ b/jingle_sleigh/src/context/mod.rs @@ -1,7 +1,7 @@ mod builder; +pub mod image; mod instruction_iterator; pub mod loaded; -pub mod image; use crate::error::JingleSleighError; use crate::error::JingleSleighError::{LanguageSpecRead, SleighInitError}; @@ -13,6 +13,7 @@ use crate::space::{RegisterManager, SpaceInfo, SpaceManager}; pub use builder::SleighContextBuilder; use crate::context::builder::language_def::LanguageDefinition; +use crate::context::image::ImageProvider; use crate::context::loaded::LoadedSleighContext; use crate::ffi::context_ffi::CTX_BUILD_MUTEX; use crate::JingleSleighError::{ImageLoadError, SleighCompilerMutexError}; @@ -20,7 +21,6 @@ use crate::VarNode; use cxx::{SharedPtr, UniquePtr}; use std::fmt::{Debug, Formatter}; use std::path::Path; -use crate::context::image::ImageProvider; pub struct SleighContext { ctx: UniquePtr, @@ -132,10 +132,8 @@ impl SleighContext { self, img: T, ) -> Result, JingleSleighError> { - LoadedSleighContext::new(self, img) } - } #[cfg(test)] diff --git a/jingle_sleigh/src/ffi/image.rs b/jingle_sleigh/src/ffi/image.rs index b8a6e47..3b65666 100644 --- a/jingle_sleigh/src/ffi/image.rs +++ b/jingle_sleigh/src/ffi/image.rs @@ -1,8 +1,8 @@ use crate::context::image::ImageProvider; use crate::ffi::instruction::bridge::VarnodeInfoFFI; use crate::VarNode; -use std::fmt::{Debug, Formatter}; use cxx::ExternType; +use std::fmt::{Debug, Formatter}; pub(crate) struct ImageFFI<'a> { provider: Box, @@ -19,11 +19,11 @@ impl<'a> ImageFFI<'a> { } pub(crate) fn has_range(&self, vn: &VarNode) -> bool { - self.provider.has_range(vn) + self.provider.has_full_range(vn) } } -unsafe impl<'a> ExternType for ImageFFI<'a>{ +unsafe impl<'a> ExternType for ImageFFI<'a> { type Id = cxx::type_id!("ImageFFI"); type Kind = cxx::kind::Opaque; } diff --git a/jingle_sleigh/src/varnode/mod.rs b/jingle_sleigh/src/varnode/mod.rs index 6c9ff79..3b75022 100644 --- a/jingle_sleigh/src/varnode/mod.rs +++ b/jingle_sleigh/src/varnode/mod.rs @@ -9,6 +9,7 @@ pub use crate::varnode::display::{ }; use serde::{Deserialize, Serialize}; use std::fmt::Debug; +use std::ops::Range; /// A [`VarNode`] is `SLEIGH`'s generalization of an address. It describes a sized-location in /// a given memory space. @@ -53,6 +54,23 @@ impl VarNode { } } +impl From<&VarNode> for Range { + fn from(value: &VarNode) -> Self { + Range { + start: value.offset, + end: value.offset + value.size as u64, + } + } +} + +impl From<&VarNode> for Range { + fn from(value: &VarNode) -> Self { + Range { + start: value.offset as usize, + end: value.offset as usize + value.size, + } + } +} #[macro_export] macro_rules! varnode { ($ctx:expr, #$offset:literal:$size:literal) => { From b77e6665e93ef130cca745935b47f3588fcf77c8 Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 15 Oct 2024 12:57:06 +0100 Subject: [PATCH 086/146] Clippy --- jingle_sleigh/src/context/image.rs | 1 - jingle_sleigh/src/context/loaded.rs | 2 -- jingle_sleigh/src/ffi/image.rs | 1 - 3 files changed, 4 deletions(-) diff --git a/jingle_sleigh/src/context/image.rs b/jingle_sleigh/src/context/image.rs index 9a3ec1d..6958b6b 100644 --- a/jingle_sleigh/src/context/image.rs +++ b/jingle_sleigh/src/context/image.rs @@ -1,5 +1,4 @@ use crate::VarNode; -use object::ReadRef; use std::ops::Range; pub trait ImageProvider { diff --git a/jingle_sleigh/src/context/loaded.rs b/jingle_sleigh/src/context/loaded.rs index c19cb29..01df662 100644 --- a/jingle_sleigh/src/context/loaded.rs +++ b/jingle_sleigh/src/context/loaded.rs @@ -4,9 +4,7 @@ use crate::context::SleighContext; use crate::ffi::image::ImageFFI; use crate::JingleSleighError::ImageLoadError; use crate::{Instruction, JingleSleighError, RegisterManager, SpaceInfo, SpaceManager, VarNode}; -use cxx::UniquePtr; use std::fmt::{Debug, Formatter}; -use std::mem; use std::ops::{Deref, DerefMut}; pub struct LoadedSleighContext<'a>(SleighContext, ImageFFI<'a>); diff --git a/jingle_sleigh/src/ffi/image.rs b/jingle_sleigh/src/ffi/image.rs index 3b65666..c7e5432 100644 --- a/jingle_sleigh/src/ffi/image.rs +++ b/jingle_sleigh/src/ffi/image.rs @@ -2,7 +2,6 @@ use crate::context::image::ImageProvider; use crate::ffi::instruction::bridge::VarnodeInfoFFI; use crate::VarNode; use cxx::ExternType; -use std::fmt::{Debug, Formatter}; pub(crate) struct ImageFFI<'a> { provider: Box, From 61876662a95b4b1b63cda54b756d376713db94f8 Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 15 Oct 2024 14:03:48 +0100 Subject: [PATCH 087/146] Actually fix build --- jingle_sleigh/build.rs | 2 -- jingle_sleigh/src/context/loaded.rs | 2 +- jingle_sleigh/src/ffi/context_ffi.rs | 14 ++++++++++++-- jingle_sleigh/src/ffi/image.rs | 18 ++---------------- 4 files changed, 15 insertions(+), 21 deletions(-) diff --git a/jingle_sleigh/build.rs b/jingle_sleigh/build.rs index a01f6f9..680790e 100644 --- a/jingle_sleigh/build.rs +++ b/jingle_sleigh/build.rs @@ -20,10 +20,8 @@ fn main() { let rust_sources = vec![ "src/ffi/addrspace.rs", "src/ffi/context_ffi.rs", - "src/ffi/image.rs", "src/ffi/instruction.rs", "src/ffi/opcode.rs", - "src/ffi/image.rs", ]; let cpp_sources = vec![ diff --git a/jingle_sleigh/src/context/loaded.rs b/jingle_sleigh/src/context/loaded.rs index 01df662..8e481b7 100644 --- a/jingle_sleigh/src/context/loaded.rs +++ b/jingle_sleigh/src/context/loaded.rs @@ -1,11 +1,11 @@ use crate::context::image::ImageProvider; use crate::context::instruction_iterator::SleighContextInstructionIterator; use crate::context::SleighContext; -use crate::ffi::image::ImageFFI; use crate::JingleSleighError::ImageLoadError; use crate::{Instruction, JingleSleighError, RegisterManager, SpaceInfo, SpaceManager, VarNode}; use std::fmt::{Debug, Formatter}; use std::ops::{Deref, DerefMut}; +use crate::ffi::context_ffi::ImageFFI; pub struct LoadedSleighContext<'a>(SleighContext, ImageFFI<'a>); diff --git a/jingle_sleigh/src/ffi/context_ffi.rs b/jingle_sleigh/src/ffi/context_ffi.rs index 15437d0..c042ce4 100644 --- a/jingle_sleigh/src/ffi/context_ffi.rs +++ b/jingle_sleigh/src/ffi/context_ffi.rs @@ -2,6 +2,7 @@ use crate::ffi::context_ffi::bridge::makeContext; use bridge::ContextFFI; use cxx::{Exception, UniquePtr}; use std::sync::Mutex; +use crate::context::image::ImageProvider; type ContextGeneratorFp = fn(&str) -> Result, Exception>; @@ -10,10 +11,9 @@ pub(crate) static CTX_BUILD_MUTEX: Mutex = Mutex::new(makeCo #[cxx::bridge] pub(crate) mod bridge { unsafe extern "C++" { - type ImageFFI<'a> = crate::ffi::image::ImageFFI<'a>; type InstructionFFI = crate::ffi::instruction::bridge::InstructionFFI; - // type VarnodeInfoFFI = crate::ffi::instruction::bridge::VarnodeInfoFFI; + type VarnodeInfoFFI = crate::ffi::instruction::bridge::VarnodeInfoFFI; type AddrSpaceHandle = crate::ffi::addrspace::bridge::AddrSpaceHandle; @@ -45,5 +45,15 @@ pub(crate) mod bridge { pub(crate) fn setImage(self: Pin<&mut ContextFFI>, img: &ImageFFI) -> Result<()>; } + + extern "Rust" { + include!("jingle_sleigh/src/ffi/instruction.rs.h"); + type ImageFFI<'a>; + fn load(self: &ImageFFI, vn: &VarnodeInfoFFI, out: &mut [u8]) -> usize; + } impl Vec {} } + +pub(crate) struct ImageFFI<'a> { + pub(crate) provider: Box, +} \ No newline at end of file diff --git a/jingle_sleigh/src/ffi/image.rs b/jingle_sleigh/src/ffi/image.rs index c7e5432..1a807d3 100644 --- a/jingle_sleigh/src/ffi/image.rs +++ b/jingle_sleigh/src/ffi/image.rs @@ -2,10 +2,8 @@ use crate::context::image::ImageProvider; use crate::ffi::instruction::bridge::VarnodeInfoFFI; use crate::VarNode; use cxx::ExternType; +use crate::ffi::context_ffi::ImageFFI; -pub(crate) struct ImageFFI<'a> { - provider: Box, -} impl<'a> ImageFFI<'a> { pub(crate) fn new(provider: T) -> Self { @@ -13,7 +11,7 @@ impl<'a> ImageFFI<'a> { provider: Box::new(provider), } } - fn load(&self, vn: &VarnodeInfoFFI, out: &mut [u8]) -> usize { + pub(crate) fn load(&self, vn: &VarnodeInfoFFI, out: &mut [u8]) -> usize { self.provider.load(&VarNode::from(vn), out) } @@ -26,15 +24,3 @@ unsafe impl<'a> ExternType for ImageFFI<'a> { type Id = cxx::type_id!("ImageFFI"); type Kind = cxx::kind::Opaque; } - -#[cxx::bridge] -pub(crate) mod bridge { - unsafe extern "C++" { - type VarnodeInfoFFI = crate::ffi::instruction::bridge::VarnodeInfoFFI; - } - extern "Rust" { - include!("jingle_sleigh/src/ffi/instruction.rs.h"); - type ImageFFI<'a>; - fn load(self: &ImageFFI, vn: &VarnodeInfoFFI, out: &mut [u8]) -> usize; - } -} From 768602f27362e41d84b4261d72fcba07c759eb7c Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 15 Oct 2024 16:43:25 +0100 Subject: [PATCH 088/146] Fix crashes --- jingle_sleigh/src/context/image.rs | 22 ++++++++++++------- .../src/context/instruction_iterator.rs | 4 ++-- jingle_sleigh/src/context/loaded.rs | 10 +++++---- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/jingle_sleigh/src/context/image.rs b/jingle_sleigh/src/context/image.rs index 6958b6b..cd4b041 100644 --- a/jingle_sleigh/src/context/image.rs +++ b/jingle_sleigh/src/context/image.rs @@ -1,3 +1,4 @@ +use std::cmp::min; use crate::VarNode; use std::ops::Range; @@ -10,21 +11,26 @@ pub trait ImageProvider { impl ImageProvider for &[u8] { fn load(&self, vn: &VarNode, output: &mut [u8]) -> usize { //todo: check the space. Ignoring for now - if vn.offset >= self.len() as u64 { + let vn_range: Range = Range::from(vn); + let vn_range = Range{start: vn_range.start, end: min(vn_range.end, self.len())}; + if let Some(s) = self.get(vn_range) { + if let Some(mut o) = output.get_mut(0..s.len()) { + o.copy_from_slice(s) + } + let o_len = output.len(); + if let Some( o) = output.get_mut(s.len()..o_len){ + o.fill(0); + } + return s.len(); + } else { output.fill(0); 0 - } else { - let vn_range: Range = Range::from(vn); - let output_len = output.len(); - output.copy_from_slice(&self[vn_range.clone()]); - output[vn_range.end..output_len].fill(0); - vn_range.len() } } fn has_full_range(&self, vn: &VarNode) -> bool { let vn_range: Range = Range::from(vn); - vn_range.start > 0 && vn_range.start < self.len() && vn_range.end < self.len() + vn_range.start >= 0 && vn_range.start < self.len() && vn_range.end <= self.len() } } diff --git a/jingle_sleigh/src/context/instruction_iterator.rs b/jingle_sleigh/src/context/instruction_iterator.rs index 72095bf..2b2b612 100644 --- a/jingle_sleigh/src/context/instruction_iterator.rs +++ b/jingle_sleigh/src/context/instruction_iterator.rs @@ -79,11 +79,11 @@ mod test { #[test] fn stop_at_branch() { - let mov_eax_0: [u8; 4] = [0x90, 0x90, 0x90, 0x90]; + let mov_eax_0: Vec = vec![0x90, 0x90, 0x90, 0x90]; let ctx_builder = SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); let sleigh = ctx_builder.build(SLEIGH_ARCH).unwrap(); - let sleigh = sleigh.initialize_with_image(mov_eax_0.as_slice()).unwrap(); + let sleigh = sleigh.initialize_with_image(mov_eax_0).unwrap(); let instr: Vec = sleigh.read(0, 5).collect(); assert_eq!(instr.len(), 4); } diff --git a/jingle_sleigh/src/context/loaded.rs b/jingle_sleigh/src/context/loaded.rs index 8e481b7..2884821 100644 --- a/jingle_sleigh/src/context/loaded.rs +++ b/jingle_sleigh/src/context/loaded.rs @@ -7,7 +7,7 @@ use std::fmt::{Debug, Formatter}; use std::ops::{Deref, DerefMut}; use crate::ffi::context_ffi::ImageFFI; -pub struct LoadedSleighContext<'a>(SleighContext, ImageFFI<'a>); +pub struct LoadedSleighContext<'a>(SleighContext, Box>); impl<'a> Debug for LoadedSleighContext<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { @@ -33,13 +33,15 @@ impl<'a> LoadedSleighContext<'a> { mut sleigh_context: SleighContext, img: T, ) -> Result { - let img = ImageFFI::new(img); - sleigh_context + let img = Box::new(ImageFFI::new(img)); + let mut s = Self(sleigh_context, img); + let (ctx, img) = s.borrow_parts(); + ctx .ctx .pin_mut() .setImage(&img) .map_err(|_| ImageLoadError)?; - Ok(Self(sleigh_context, img)) + Ok(s) } pub fn instruction_at(&self, offset: u64) -> Option { let instr = self From 8acf32cf231c3ca06b3a4cf6ddaf29cc39a9a314 Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 15 Oct 2024 17:11:41 +0100 Subject: [PATCH 089/146] Start on gimli --- .../src/context/builder/image/gimli.rs | 42 +++--------- .../src/context/builder/image/mod.rs | 65 +------------------ jingle_sleigh/src/context/builder/mod.rs | 2 +- 3 files changed, 12 insertions(+), 97 deletions(-) diff --git a/jingle_sleigh/src/context/builder/image/gimli.rs b/jingle_sleigh/src/context/builder/image/gimli.rs index 4ba9049..8b2ea8b 100644 --- a/jingle_sleigh/src/context/builder/image/gimli.rs +++ b/jingle_sleigh/src/context/builder/image/gimli.rs @@ -1,42 +1,18 @@ use crate::context::builder::image::Perms; use crate::context::{Image, ImageSection}; -use crate::JingleSleighError; +use crate::{JingleSleighError, VarNode}; use crate::JingleSleighError::ImageLoadError; use object::{Architecture, Endianness, File, Object, ObjectSection, SectionKind}; use tracing::{event, instrument, Level}; +use crate::context::image::ImageProvider; -impl<'d> TryFrom> for Image { - type Error = JingleSleighError; - #[instrument(skip_all)] - fn try_from(value: File) -> Result { - let mut img: Image = Image { sections: vec![] }; - for x in value - .sections() - .filter(|s| matches!(s.kind(), SectionKind::Text)) - { - let base_address = x.address(); - let data = x.data().map_err(|_| ImageLoadError)?.to_vec(); - let perms = map_kind(&x.kind()); - let name = x.name().unwrap_or(""); - let start = base_address; - let end = base_address + data.len() as u64; - event!( - Level::TRACE, - "Selecting section {} ({:x}-{:x})", - name, - start, - end - ); - img.sections.push(ImageSection { - perms, - data, - base_address: base_address as usize, - }) - } - if img.sections.is_empty() { - event!(Level::WARN, "No executable sections loaded from file") - } - Ok(img) +impl<'a> ImageProvider for File<'a>{ + fn load(&self, vn: &VarNode, output: &mut [u8]) -> usize { + todo!() + } + + fn has_full_range(&self, vn: &VarNode) -> bool { + todo!() } } diff --git a/jingle_sleigh/src/context/builder/image/mod.rs b/jingle_sleigh/src/context/builder/image/mod.rs index 5c10049..f243f19 100644 --- a/jingle_sleigh/src/context/builder/image/mod.rs +++ b/jingle_sleigh/src/context/builder/image/mod.rs @@ -1,65 +1,4 @@ /*#[cfg(feature = "elf")] -pub mod elf; +pub mod elf;*/ #[cfg(feature = "gimli")] -pub mod gimli;*/ - -pub use crate::ffi::image::bridge::{Image, ImageSection, Perms}; -use std::ops::Range; - -impl Image { - pub fn get_range(&self) -> Option> { - let min = self.sections.iter().map(|s| s.base_address).min(); - let max = self - .sections - .iter() - .map(|s| s.base_address + s.data.len()) - .max(); - min.zip(max).map(|(min, max)| min..max) - } - - pub fn sections(&self) -> &[ImageSection] { - &self.sections - } - - pub fn contains_address(&self, addr: u64) -> bool { - self.sections.iter().any(|s| { - s.base_address <= addr as usize && (s.base_address + s.data.len()) >= addr as usize - }) - } - - pub fn contains_range(&self, mut range: Range) -> bool { - range.all(|i| self.contains_address(i)) - } -} - -impl From<&[u8]> for Image { - fn from(value: &[u8]) -> Self { - Self { - sections: vec![ImageSection { - data: value.to_vec(), - perms: Perms { - read: true, - write: true, - exec: true, - }, - base_address: 0, - }], - } - } -} - -impl From> for Image { - fn from(value: Vec) -> Self { - Self { - sections: vec![ImageSection { - data: value, - perms: Perms { - read: true, - write: true, - exec: true, - }, - base_address: 0, - }], - } - } -} +pub mod gimli; diff --git a/jingle_sleigh/src/context/builder/mod.rs b/jingle_sleigh/src/context/builder/mod.rs index 40f4d34..ffb28dd 100644 --- a/jingle_sleigh/src/context/builder/mod.rs +++ b/jingle_sleigh/src/context/builder/mod.rs @@ -8,7 +8,7 @@ use std::fs; use std::path::{Path, PathBuf}; use tracing::{event, instrument, Level}; -//pub mod image; +pub mod image; pub(crate) mod language_def; pub(crate) mod processor_spec; From 27859732f5776d9df58125057474fdc17afc08d7 Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 16 Oct 2024 07:53:18 +0100 Subject: [PATCH 090/146] Impl gimli --- .../src/context/builder/image/gimli.rs | 55 +++++++++---------- jingle_sleigh/src/context/loaded.rs | 5 +- jingle_sleigh/src/ffi/context_ffi.rs | 3 +- jingle_sleigh/src/ffi/image.rs | 2 +- 4 files changed, 33 insertions(+), 32 deletions(-) diff --git a/jingle_sleigh/src/context/builder/image/gimli.rs b/jingle_sleigh/src/context/builder/image/gimli.rs index 8b2ea8b..72034a6 100644 --- a/jingle_sleigh/src/context/builder/image/gimli.rs +++ b/jingle_sleigh/src/context/builder/image/gimli.rs @@ -1,14 +1,33 @@ -use crate::context::builder::image::Perms; -use crate::context::{Image, ImageSection}; -use crate::{JingleSleighError, VarNode}; -use crate::JingleSleighError::ImageLoadError; -use object::{Architecture, Endianness, File, Object, ObjectSection, SectionKind}; -use tracing::{event, instrument, Level}; +use std::cmp::{max, min}; +use crate::{VarNode}; +use object::{Architecture, Endianness, File, Object, ObjectSection, ReadRef, SectionKind}; use crate::context::image::ImageProvider; -impl<'a> ImageProvider for File<'a>{ +impl<'a> ImageProvider for File<'a> { fn load(&self, vn: &VarNode, output: &mut [u8]) -> usize { - todo!() + let mut written = 0; + output.fill(0); + let output_start_addr = vn.offset as usize; + let output_end_addr = output_start_addr + vn.size; + for x in self.sections().filter(|s| s.kind() == SectionKind::Text) { + if let Ok(data) = x.data() { + let input_start_addr = x.address() as usize; + let input_end_addr = input_start_addr + data.len(); + let start_addr = max(input_start_addr, output_start_addr); + let end_addr = max(min(input_end_addr, output_end_addr), start_addr); + if end_addr > start_addr{ + let i_s = start_addr - x.address() as usize; + let i_e = end_addr - x.address() as usize; + let o_s = start_addr - vn.offset as usize; + let o_e = end_addr - vn.offset as usize; + let out_slice = &mut output[o_s..o_e]; + let in_slice = &data[i_s..i_e]; + out_slice.copy_from_slice(in_slice); + written += (end_addr - start_addr); + } + } + } + written } fn has_full_range(&self, vn: &VarNode) -> bool { @@ -16,26 +35,6 @@ impl<'a> ImageProvider for File<'a>{ } } -fn map_kind(kind: &SectionKind) -> Perms { - Perms { - exec: matches!(kind, SectionKind::Text), - write: matches!(kind, SectionKind::Data) - && !matches!( - kind, - SectionKind::ReadOnlyData - | SectionKind::ReadOnlyString - | SectionKind::ReadOnlyDataWithRel - ), - read: matches!( - kind, - SectionKind::Data - | SectionKind::ReadOnlyData - | SectionKind::ReadOnlyString - | SectionKind::ReadOnlyDataWithRel - ), - } -} - pub fn map_gimli_architecture(file: &File) -> Option<&'static str> { match &file.architecture() { Architecture::Unknown => None, diff --git a/jingle_sleigh/src/context/loaded.rs b/jingle_sleigh/src/context/loaded.rs index 2884821..bccfc22 100644 --- a/jingle_sleigh/src/context/loaded.rs +++ b/jingle_sleigh/src/context/loaded.rs @@ -5,9 +5,10 @@ use crate::JingleSleighError::ImageLoadError; use crate::{Instruction, JingleSleighError, RegisterManager, SpaceInfo, SpaceManager, VarNode}; use std::fmt::{Debug, Formatter}; use std::ops::{Deref, DerefMut}; +use std::pin::Pin; use crate::ffi::context_ffi::ImageFFI; -pub struct LoadedSleighContext<'a>(SleighContext, Box>); +pub struct LoadedSleighContext<'a>(SleighContext, Pin>>); impl<'a> Debug for LoadedSleighContext<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { @@ -33,7 +34,7 @@ impl<'a> LoadedSleighContext<'a> { mut sleigh_context: SleighContext, img: T, ) -> Result { - let img = Box::new(ImageFFI::new(img)); + let img = Box::pin(ImageFFI::new(img)); let mut s = Self(sleigh_context, img); let (ctx, img) = s.borrow_parts(); ctx diff --git a/jingle_sleigh/src/ffi/context_ffi.rs b/jingle_sleigh/src/ffi/context_ffi.rs index c042ce4..f6b78d7 100644 --- a/jingle_sleigh/src/ffi/context_ffi.rs +++ b/jingle_sleigh/src/ffi/context_ffi.rs @@ -1,3 +1,4 @@ +use std::pin::Pin; use crate::ffi::context_ffi::bridge::makeContext; use bridge::ContextFFI; use cxx::{Exception, UniquePtr}; @@ -55,5 +56,5 @@ pub(crate) mod bridge { } pub(crate) struct ImageFFI<'a> { - pub(crate) provider: Box, + pub(crate) provider: Pin>, } \ No newline at end of file diff --git a/jingle_sleigh/src/ffi/image.rs b/jingle_sleigh/src/ffi/image.rs index 1a807d3..7f7d946 100644 --- a/jingle_sleigh/src/ffi/image.rs +++ b/jingle_sleigh/src/ffi/image.rs @@ -8,7 +8,7 @@ use crate::ffi::context_ffi::ImageFFI; impl<'a> ImageFFI<'a> { pub(crate) fn new(provider: T) -> Self { Self { - provider: Box::new(provider), + provider: Box::pin(provider), } } pub(crate) fn load(&self, vn: &VarnodeInfoFFI, out: &mut [u8]) -> usize { From 2c3cd6252bd9a77832717fb0c62b0d2fa70661d8 Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 16 Oct 2024 08:30:56 +0100 Subject: [PATCH 091/146] actually actually fix build --- jingle/Cargo.toml | 1 - jingle_sleigh/Cargo.toml | 4 +--- jingle_sleigh/src/ffi/context_ffi.rs | 24 ++++++++++++++++++++- jingle_sleigh/src/ffi/cpp/context.h | 3 ++- jingle_sleigh/src/ffi/cpp/rust_load_image.h | 2 +- jingle_sleigh/src/ffi/cpp/sleigh_image.h | 1 - jingle_sleigh/src/ffi/image.rs | 18 ---------------- 7 files changed, 27 insertions(+), 26 deletions(-) diff --git a/jingle/Cargo.toml b/jingle/Cargo.toml index 9659432..e4a926d 100644 --- a/jingle/Cargo.toml +++ b/jingle/Cargo.toml @@ -30,5 +30,4 @@ hex = { version = "0.4.3" , optional = true} [features] default = [] bin_features = ["dep:clap", "dep:confy", "dep:hex"] -elf = ["jingle_sleigh/elf"] gimli = ["jingle_sleigh/gimli"] diff --git a/jingle_sleigh/Cargo.toml b/jingle_sleigh/Cargo.toml index d7168ee..e6a95e9 100644 --- a/jingle_sleigh/Cargo.toml +++ b/jingle_sleigh/Cargo.toml @@ -24,7 +24,6 @@ cxx = "1.0.122" serde = { version = "1.0.203", features = ["derive"] } serde-xml-rs = "0.6.0" thiserror = { version = "1.0.61", features = [] } -elf = { version = "0.7.4", optional = true } object = { version = "0.36.0", optional = true } libz-sys = { version = "1.1.18", default-features = false, features = ["libc"] } tracing = "0.1.40" @@ -33,8 +32,7 @@ tracing = "0.1.40" cxx-build = "1.0.122" [features] -elf = ["dep:elf"] gimli = ["dep:object"] -default = ["elf", "gimli"] +default = ["gimli"] diff --git a/jingle_sleigh/src/ffi/context_ffi.rs b/jingle_sleigh/src/ffi/context_ffi.rs index f6b78d7..0470222 100644 --- a/jingle_sleigh/src/ffi/context_ffi.rs +++ b/jingle_sleigh/src/ffi/context_ffi.rs @@ -1,9 +1,11 @@ use std::pin::Pin; use crate::ffi::context_ffi::bridge::makeContext; use bridge::ContextFFI; -use cxx::{Exception, UniquePtr}; +use cxx::{Exception, ExternType, UniquePtr}; use std::sync::Mutex; use crate::context::image::ImageProvider; +use crate::ffi::instruction::bridge::VarnodeInfoFFI; +use crate::VarNode; type ContextGeneratorFp = fn(&str) -> Result, Exception>; @@ -57,4 +59,24 @@ pub(crate) mod bridge { pub(crate) struct ImageFFI<'a> { pub(crate) provider: Pin>, +} + +impl<'a> ImageFFI<'a> { + pub(crate) fn new(provider: T) -> Self { + Self { + provider: Box::pin(provider), + } + } + pub(crate) fn load(&self, vn: &VarnodeInfoFFI, out: &mut [u8]) -> usize { + self.provider.load(&VarNode::from(vn), out) + } + + pub(crate) fn has_range(&self, vn: &VarNode) -> bool { + self.provider.has_full_range(vn) + } +} + +unsafe impl<'a> ExternType for ImageFFI<'a> { + type Id = cxx::type_id!("ImageFFI"); + type Kind = cxx::kind::Opaque; } \ No newline at end of file diff --git a/jingle_sleigh/src/ffi/cpp/context.h b/jingle_sleigh/src/ffi/cpp/context.h index 7de2725..3110d0f 100644 --- a/jingle_sleigh/src/ffi/cpp/context.h +++ b/jingle_sleigh/src/ffi/cpp/context.h @@ -1,13 +1,14 @@ #ifndef JINGLE_SLEIGH_CONTEXT_H #define JINGLE_SLEIGH_CONTEXT_H +class ContextFFI; +#include "jingle_sleigh/src/ffi/context_ffi.rs.h" #include "rust/cxx.h" #include "sleigh/types.h" #include "addrspace_handle.h" #include "jingle_sleigh/src/ffi/instruction.rs.h" #include "sleigh/globalcontext.hh" #include "sleigh/sleigh.hh" -#include "jingle_sleigh/src/ffi/image.rs.h" #include "sleigh/loadimage.hh" #include "dummy_load_image.h" diff --git a/jingle_sleigh/src/ffi/cpp/rust_load_image.h b/jingle_sleigh/src/ffi/cpp/rust_load_image.h index 6ce5995..6f076b3 100644 --- a/jingle_sleigh/src/ffi/cpp/rust_load_image.h +++ b/jingle_sleigh/src/ffi/cpp/rust_load_image.h @@ -5,7 +5,7 @@ #ifndef JINGLE_SLEIGH_RUST_LOAD_IMAGE_H #define JINGLE_SLEIGH_RUST_LOAD_IMAGE_H -#include "jingle_sleigh/src/ffi/image.rs.h" +#include "context.h" #include "sleigh/loadimage.hh" class RustLoadImage : public ghidra::LoadImage { diff --git a/jingle_sleigh/src/ffi/cpp/sleigh_image.h b/jingle_sleigh/src/ffi/cpp/sleigh_image.h index 499bb65..f0b7d36 100644 --- a/jingle_sleigh/src/ffi/cpp/sleigh_image.h +++ b/jingle_sleigh/src/ffi/cpp/sleigh_image.h @@ -9,7 +9,6 @@ #include "jingle_sleigh/src/ffi/instruction.rs.h" #include "sleigh/sleigh.hh" #include "rust/cxx.h" -#include "jingle_sleigh/src/ffi/image.rs.h" #include "dummy_load_image.h" class SleighImage{ diff --git a/jingle_sleigh/src/ffi/image.rs b/jingle_sleigh/src/ffi/image.rs index 7f7d946..72ec90e 100644 --- a/jingle_sleigh/src/ffi/image.rs +++ b/jingle_sleigh/src/ffi/image.rs @@ -5,22 +5,4 @@ use cxx::ExternType; use crate::ffi::context_ffi::ImageFFI; -impl<'a> ImageFFI<'a> { - pub(crate) fn new(provider: T) -> Self { - Self { - provider: Box::pin(provider), - } - } - pub(crate) fn load(&self, vn: &VarnodeInfoFFI, out: &mut [u8]) -> usize { - self.provider.load(&VarNode::from(vn), out) - } - pub(crate) fn has_range(&self, vn: &VarNode) -> bool { - self.provider.has_full_range(vn) - } -} - -unsafe impl<'a> ExternType for ImageFFI<'a> { - type Id = cxx::type_id!("ImageFFI"); - type Kind = cxx::kind::Opaque; -} From a6a553825e6ac54de4e79dc9ad0d24adfadcc928 Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 16 Oct 2024 09:09:46 +0100 Subject: [PATCH 092/146] Fmt and gimli tweak --- .../src/context/builder/image/gimli.rs | 22 +++++++++++++------ jingle_sleigh/src/context/image.rs | 11 ++++++---- jingle_sleigh/src/context/loaded.rs | 5 ++--- jingle_sleigh/src/ffi/context_ffi.rs | 10 ++++----- jingle_sleigh/src/ffi/image.rs | 5 +---- 5 files changed, 30 insertions(+), 23 deletions(-) diff --git a/jingle_sleigh/src/context/builder/image/gimli.rs b/jingle_sleigh/src/context/builder/image/gimli.rs index 72034a6..a162c3a 100644 --- a/jingle_sleigh/src/context/builder/image/gimli.rs +++ b/jingle_sleigh/src/context/builder/image/gimli.rs @@ -1,21 +1,25 @@ -use std::cmp::{max, min}; -use crate::{VarNode}; -use object::{Architecture, Endianness, File, Object, ObjectSection, ReadRef, SectionKind}; use crate::context::image::ImageProvider; +use crate::VarNode; +use object::{Architecture, Endianness, File, Object, ObjectSection, ReadRef, SectionKind}; +use std::cmp::{max, min}; impl<'a> ImageProvider for File<'a> { fn load(&self, vn: &VarNode, output: &mut [u8]) -> usize { let mut written = 0; output.fill(0); - let output_start_addr = vn.offset as usize; + let output_start_addr = vn.offset; let output_end_addr = output_start_addr + vn.size; - for x in self.sections().filter(|s| s.kind() == SectionKind::Text) { + if let Some(x) = self.sections().find(|s| { + s.kind() == SectionKind::Text + && output_start_addr > s.address() + && output_start_addr < (s.address() + s.size()) + }) { if let Ok(data) = x.data() { let input_start_addr = x.address() as usize; let input_end_addr = input_start_addr + data.len(); let start_addr = max(input_start_addr, output_start_addr); let end_addr = max(min(input_end_addr, output_end_addr), start_addr); - if end_addr > start_addr{ + if end_addr > start_addr { let i_s = start_addr - x.address() as usize; let i_e = end_addr - x.address() as usize; let o_s = start_addr - vn.offset as usize; @@ -31,7 +35,11 @@ impl<'a> ImageProvider for File<'a> { } fn has_full_range(&self, vn: &VarNode) -> bool { - todo!() + self.sections() + .filter(|s| s.kind() == SectionKind::Text) + .any(|s| { + s.address() <= vn.offset && (s.address() + s.size()) >= (vn.offset + vn.size as u64) + }) } } diff --git a/jingle_sleigh/src/context/image.rs b/jingle_sleigh/src/context/image.rs index cd4b041..cdbd9e1 100644 --- a/jingle_sleigh/src/context/image.rs +++ b/jingle_sleigh/src/context/image.rs @@ -1,5 +1,5 @@ -use std::cmp::min; use crate::VarNode; +use std::cmp::min; use std::ops::Range; pub trait ImageProvider { @@ -12,13 +12,16 @@ impl ImageProvider for &[u8] { fn load(&self, vn: &VarNode, output: &mut [u8]) -> usize { //todo: check the space. Ignoring for now let vn_range: Range = Range::from(vn); - let vn_range = Range{start: vn_range.start, end: min(vn_range.end, self.len())}; - if let Some(s) = self.get(vn_range) { + let vn_range = Range { + start: vn_range.start, + end: min(vn_range.end, self.len()), + }; + if let Some(s) = self.get(vn_range) { if let Some(mut o) = output.get_mut(0..s.len()) { o.copy_from_slice(s) } let o_len = output.len(); - if let Some( o) = output.get_mut(s.len()..o_len){ + if let Some(o) = output.get_mut(s.len()..o_len) { o.fill(0); } return s.len(); diff --git a/jingle_sleigh/src/context/loaded.rs b/jingle_sleigh/src/context/loaded.rs index bccfc22..5fd1075 100644 --- a/jingle_sleigh/src/context/loaded.rs +++ b/jingle_sleigh/src/context/loaded.rs @@ -1,12 +1,12 @@ use crate::context::image::ImageProvider; use crate::context::instruction_iterator::SleighContextInstructionIterator; use crate::context::SleighContext; +use crate::ffi::context_ffi::ImageFFI; use crate::JingleSleighError::ImageLoadError; use crate::{Instruction, JingleSleighError, RegisterManager, SpaceInfo, SpaceManager, VarNode}; use std::fmt::{Debug, Formatter}; use std::ops::{Deref, DerefMut}; use std::pin::Pin; -use crate::ffi::context_ffi::ImageFFI; pub struct LoadedSleighContext<'a>(SleighContext, Pin>>); @@ -37,8 +37,7 @@ impl<'a> LoadedSleighContext<'a> { let img = Box::pin(ImageFFI::new(img)); let mut s = Self(sleigh_context, img); let (ctx, img) = s.borrow_parts(); - ctx - .ctx + ctx.ctx .pin_mut() .setImage(&img) .map_err(|_| ImageLoadError)?; diff --git a/jingle_sleigh/src/ffi/context_ffi.rs b/jingle_sleigh/src/ffi/context_ffi.rs index 0470222..55f328f 100644 --- a/jingle_sleigh/src/ffi/context_ffi.rs +++ b/jingle_sleigh/src/ffi/context_ffi.rs @@ -1,11 +1,11 @@ -use std::pin::Pin; +use crate::context::image::ImageProvider; use crate::ffi::context_ffi::bridge::makeContext; +use crate::ffi::instruction::bridge::VarnodeInfoFFI; +use crate::VarNode; use bridge::ContextFFI; use cxx::{Exception, ExternType, UniquePtr}; +use std::pin::Pin; use std::sync::Mutex; -use crate::context::image::ImageProvider; -use crate::ffi::instruction::bridge::VarnodeInfoFFI; -use crate::VarNode; type ContextGeneratorFp = fn(&str) -> Result, Exception>; @@ -79,4 +79,4 @@ impl<'a> ImageFFI<'a> { unsafe impl<'a> ExternType for ImageFFI<'a> { type Id = cxx::type_id!("ImageFFI"); type Kind = cxx::kind::Opaque; -} \ No newline at end of file +} diff --git a/jingle_sleigh/src/ffi/image.rs b/jingle_sleigh/src/ffi/image.rs index 72ec90e..3f8ef0e 100644 --- a/jingle_sleigh/src/ffi/image.rs +++ b/jingle_sleigh/src/ffi/image.rs @@ -1,8 +1,5 @@ use crate::context::image::ImageProvider; +use crate::ffi::context_ffi::ImageFFI; use crate::ffi::instruction::bridge::VarnodeInfoFFI; use crate::VarNode; use cxx::ExternType; -use crate::ffi::context_ffi::ImageFFI; - - - From 87a504588ac862c6737ccfd7b736a4eb9c4e571f Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 16 Oct 2024 09:10:21 +0100 Subject: [PATCH 093/146] Remove unused file --- jingle_sleigh/src/ffi/image.rs | 5 ----- jingle_sleigh/src/ffi/mod.rs | 1 - 2 files changed, 6 deletions(-) delete mode 100644 jingle_sleigh/src/ffi/image.rs diff --git a/jingle_sleigh/src/ffi/image.rs b/jingle_sleigh/src/ffi/image.rs deleted file mode 100644 index 3f8ef0e..0000000 --- a/jingle_sleigh/src/ffi/image.rs +++ /dev/null @@ -1,5 +0,0 @@ -use crate::context::image::ImageProvider; -use crate::ffi::context_ffi::ImageFFI; -use crate::ffi::instruction::bridge::VarnodeInfoFFI; -use crate::VarNode; -use cxx::ExternType; diff --git a/jingle_sleigh/src/ffi/mod.rs b/jingle_sleigh/src/ffi/mod.rs index 7ace8b9..fd5fdaa 100644 --- a/jingle_sleigh/src/ffi/mod.rs +++ b/jingle_sleigh/src/ffi/mod.rs @@ -1,6 +1,5 @@ pub(crate) mod addrspace; pub(crate) mod context_ffi; -pub(crate) mod image; pub(crate) mod instruction; pub(crate) mod opcode; From af56c88d3fec212a36ffbde96243c7c56fc46108 Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 16 Oct 2024 09:10:51 +0100 Subject: [PATCH 094/146] Remove more unused files --- jingle_sleigh/src/ffi/cpp/sleigh_image.cpp | 46 ---------------------- jingle_sleigh/src/ffi/cpp/sleigh_image.h | 33 ---------------- jingle_sleigh/src/ffi/sleigh_image.rs | 31 --------------- 3 files changed, 110 deletions(-) delete mode 100644 jingle_sleigh/src/ffi/cpp/sleigh_image.cpp delete mode 100644 jingle_sleigh/src/ffi/cpp/sleigh_image.h delete mode 100644 jingle_sleigh/src/ffi/sleigh_image.rs diff --git a/jingle_sleigh/src/ffi/cpp/sleigh_image.cpp b/jingle_sleigh/src/ffi/cpp/sleigh_image.cpp deleted file mode 100644 index ae8b442..0000000 --- a/jingle_sleigh/src/ffi/cpp/sleigh_image.cpp +++ /dev/null @@ -1,46 +0,0 @@ -// -// Created by mark denhoed on 10/10/24. -// -#include "sleigh_image.h" -#include "dummy_load_image.h" -#include "varnode_translation.h" -#include "sleigh/sleigh.hh" -#include - - -SleighImage::SleighImage(Image img, ghidra::Sleigh sl): sl(ghidra::Sleigh(sl)) { - this->sl.reset(new DummyLoadImage(img), new ghidra::ContextInternal()); -} - -std::shared_ptr SleighImage::getSpaceByIndex(ghidra::int4 idx) const { - return std::make_shared(sl.getSpace(idx)); -} - -ghidra::int4 SleighImage::getNumSpaces() const { - return sl.numSpaces(); -} - -VarnodeInfoFFI SleighImage::getRegister(rust::Str name) const { - ghidra::VarnodeData vn = sl.getRegister(name.operator std::string()); - VarnodeInfoFFI info; - info.space = std::make_unique(vn.space); - info.size = vn.size; - info.offset = vn.offset; - return info; -}; - -rust::Str SleighImage::getRegisterName(VarnodeInfoFFI vn) const { - std::string name = sl.getRegisterName(vn.space->getRaw(), vn.offset, vn.size); - return {name}; -} - -rust::Vec SleighImage::getRegisters() const { - std::map reglist; - rust::Vec v; - sl.getAllRegisters(reglist); - v.reserve(reglist.size()); - for (auto const &vn: reglist) { - v.emplace_back(collectRegInfo(vn)); - } - return v; -} diff --git a/jingle_sleigh/src/ffi/cpp/sleigh_image.h b/jingle_sleigh/src/ffi/cpp/sleigh_image.h deleted file mode 100644 index f0b7d36..0000000 --- a/jingle_sleigh/src/ffi/cpp/sleigh_image.h +++ /dev/null @@ -1,33 +0,0 @@ -// -// Created by toolCHAINZ on 10/10/24. -// - -#ifndef JINGLE_SLEIGH_SLEIGH_IMAGE_H -#define JINGLE_SLEIGH_SLEIGH_IMAGE_H - -#include "addrspace_handle.h" -#include "jingle_sleigh/src/ffi/instruction.rs.h" -#include "sleigh/sleigh.hh" -#include "rust/cxx.h" -#include "dummy_load_image.h" - -class SleighImage{ - ghidra::Sleigh sl; - -public: - SleighImage(Image img, ghidra::Sleigh sl); - - InstructionFFI get_one_instruction(uint64_t offset) const; - - [[nodiscard]] std::shared_ptr getSpaceByIndex(ghidra::int4 idx) const; - - int getNumSpaces() const; - - VarnodeInfoFFI getRegister(rust::Str name) const; - - rust::Str getRegisterName(VarnodeInfoFFI name) const; - - rust::Vec getRegisters() const; -}; - -#endif //JINGLE_SLEIGH_SLEIGH_IMAGE_H diff --git a/jingle_sleigh/src/ffi/sleigh_image.rs b/jingle_sleigh/src/ffi/sleigh_image.rs deleted file mode 100644 index 38ec6c7..0000000 --- a/jingle_sleigh/src/ffi/sleigh_image.rs +++ /dev/null @@ -1,31 +0,0 @@ -#[cxx::bridge] -pub(crate) mod bridge { - unsafe extern "C++" { - type Image = crate::context::Image; - type InstructionFFI = crate::ffi::instruction::bridge::InstructionFFI; - - type VarnodeInfoFFI = crate::ffi::instruction::bridge::VarnodeInfoFFI; - - type AddrSpaceHandle = crate::ffi::addrspace::bridge::AddrSpaceHandle; - - type RegisterInfoFFI = crate::ffi::instruction::bridge::RegisterInfoFFI; - } - - unsafe extern "C++" { - include!("jingle_sleigh/src/ffi/cpp/sleigh_image.h"); - - pub(crate) type SleighImage; - - pub(crate) fn getSpaceByIndex(&self, idx: i32) -> SharedPtr; - pub(crate) fn getNumSpaces(&self) -> i32; - - pub(crate) fn getRegister(&self, name: &str) -> Result; - pub(crate) fn getRegisterName(&self, name: VarnodeInfoFFI) -> Result<&str>; - - pub(crate) fn getRegisters(&self) -> Vec; - - pub(crate) fn get_one_instruction(&self, offset: u64) -> Result; - } - - impl UniquePtr {} -} From 6a00c8668bfd84da4ddeb591a0a0fdcf6701010a Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 16 Oct 2024 09:16:58 +0100 Subject: [PATCH 095/146] Fix build --- jingle_sleigh/src/context/builder/image/gimli.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jingle_sleigh/src/context/builder/image/gimli.rs b/jingle_sleigh/src/context/builder/image/gimli.rs index a162c3a..6491580 100644 --- a/jingle_sleigh/src/context/builder/image/gimli.rs +++ b/jingle_sleigh/src/context/builder/image/gimli.rs @@ -7,12 +7,12 @@ impl<'a> ImageProvider for File<'a> { fn load(&self, vn: &VarNode, output: &mut [u8]) -> usize { let mut written = 0; output.fill(0); - let output_start_addr = vn.offset; + let output_start_addr = vn.offset as usize; let output_end_addr = output_start_addr + vn.size; if let Some(x) = self.sections().find(|s| { s.kind() == SectionKind::Text - && output_start_addr > s.address() - && output_start_addr < (s.address() + s.size()) + && output_start_addr > s.address() as usize + && output_start_addr < (s.address() + s.size()) as usize }) { if let Ok(data) = x.data() { let input_start_addr = x.address() as usize; From c557053c3264d6f03360ee1c982adaa56e0a8d72 Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 16 Oct 2024 09:18:22 +0100 Subject: [PATCH 096/146] clippy --fix --- jingle_sleigh/src/context/builder/image/gimli.rs | 2 +- jingle_sleigh/src/context/image.rs | 4 ++-- jingle_sleigh/src/context/loaded.rs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/jingle_sleigh/src/context/builder/image/gimli.rs b/jingle_sleigh/src/context/builder/image/gimli.rs index 6491580..c5fc167 100644 --- a/jingle_sleigh/src/context/builder/image/gimli.rs +++ b/jingle_sleigh/src/context/builder/image/gimli.rs @@ -27,7 +27,7 @@ impl<'a> ImageProvider for File<'a> { let out_slice = &mut output[o_s..o_e]; let in_slice = &data[i_s..i_e]; out_slice.copy_from_slice(in_slice); - written += (end_addr - start_addr); + written += end_addr - start_addr; } } } diff --git a/jingle_sleigh/src/context/image.rs b/jingle_sleigh/src/context/image.rs index cdbd9e1..3f5d7d6 100644 --- a/jingle_sleigh/src/context/image.rs +++ b/jingle_sleigh/src/context/image.rs @@ -17,14 +17,14 @@ impl ImageProvider for &[u8] { end: min(vn_range.end, self.len()), }; if let Some(s) = self.get(vn_range) { - if let Some(mut o) = output.get_mut(0..s.len()) { + if let Some(o) = output.get_mut(0..s.len()) { o.copy_from_slice(s) } let o_len = output.len(); if let Some(o) = output.get_mut(s.len()..o_len) { o.fill(0); } - return s.len(); + s.len() } else { output.fill(0); 0 diff --git a/jingle_sleigh/src/context/loaded.rs b/jingle_sleigh/src/context/loaded.rs index 5fd1075..58a0bc3 100644 --- a/jingle_sleigh/src/context/loaded.rs +++ b/jingle_sleigh/src/context/loaded.rs @@ -31,7 +31,7 @@ impl<'a> DerefMut for LoadedSleighContext<'a> { impl<'a> LoadedSleighContext<'a> { pub(crate) fn new( - mut sleigh_context: SleighContext, + sleigh_context: SleighContext, img: T, ) -> Result { let img = Box::pin(ImageFFI::new(img)); @@ -39,7 +39,7 @@ impl<'a> LoadedSleighContext<'a> { let (ctx, img) = s.borrow_parts(); ctx.ctx .pin_mut() - .setImage(&img) + .setImage(img) .map_err(|_| ImageLoadError)?; Ok(s) } From ccd66ad2e0a779a791c6cc842851427655782563 Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 16 Oct 2024 09:21:40 +0100 Subject: [PATCH 097/146] Clippy fixes --- jingle_sleigh/src/context/builder/image/gimli.rs | 2 +- jingle_sleigh/src/context/image.rs | 2 +- jingle_sleigh/src/context/mod.rs | 4 ++-- jingle_sleigh/src/error.rs | 4 ---- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/jingle_sleigh/src/context/builder/image/gimli.rs b/jingle_sleigh/src/context/builder/image/gimli.rs index c5fc167..f874a78 100644 --- a/jingle_sleigh/src/context/builder/image/gimli.rs +++ b/jingle_sleigh/src/context/builder/image/gimli.rs @@ -1,6 +1,6 @@ use crate::context::image::ImageProvider; use crate::VarNode; -use object::{Architecture, Endianness, File, Object, ObjectSection, ReadRef, SectionKind}; +use object::{Architecture, Endianness, File, Object, ObjectSection, SectionKind}; use std::cmp::{max, min}; impl<'a> ImageProvider for File<'a> { diff --git a/jingle_sleigh/src/context/image.rs b/jingle_sleigh/src/context/image.rs index 3f5d7d6..9ca041a 100644 --- a/jingle_sleigh/src/context/image.rs +++ b/jingle_sleigh/src/context/image.rs @@ -33,7 +33,7 @@ impl ImageProvider for &[u8] { fn has_full_range(&self, vn: &VarNode) -> bool { let vn_range: Range = Range::from(vn); - vn_range.start >= 0 && vn_range.start < self.len() && vn_range.end <= self.len() + vn_range.start < self.len() && vn_range.end <= self.len() } } diff --git a/jingle_sleigh/src/context/mod.rs b/jingle_sleigh/src/context/mod.rs index 2850c54..ef016f9 100644 --- a/jingle_sleigh/src/context/mod.rs +++ b/jingle_sleigh/src/context/mod.rs @@ -8,8 +8,8 @@ use crate::error::JingleSleighError::{LanguageSpecRead, SleighInitError}; use crate::ffi::addrspace::bridge::AddrSpaceHandle; use crate::ffi::context_ffi::bridge::ContextFFI; use crate::space::{RegisterManager, SpaceInfo, SpaceManager}; -//#[cfg(feature = "gimli")] -//pub use builder::image::gimli::map_gimli_architecture; +#[cfg(feature = "gimli")] +pub use builder::image::gimli::map_gimli_architecture; pub use builder::SleighContextBuilder; use crate::context::builder::language_def::LanguageDefinition; diff --git a/jingle_sleigh/src/error.rs b/jingle_sleigh/src/error.rs index 7206a94..3d6b3ef 100644 --- a/jingle_sleigh/src/error.rs +++ b/jingle_sleigh/src/error.rs @@ -19,10 +19,6 @@ pub enum JingleSleighError { /// Unable to load the provided binary image for sleigh #[error("Something went wrong putting bytes into sleigh")] ImageLoadError, - /// Unable to parse the provided elf for sleigh - #[cfg(feature = "elf")] - #[error("Trouble loading an elf")] - ElfLoadError(#[from] elf::ParseError), /// Attempted to initialize sleigh with an empty image #[error("You didn't provide any bytes to sleigh")] NoImageProvided, From a35acb25eb4e4a0647a6e3b01c2043ce1fd58949 Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 16 Oct 2024 10:57:59 +0100 Subject: [PATCH 098/146] Changes to traits --- .../src/context/builder/image/gimli.rs | 42 ++++++++-- jingle_sleigh/src/context/image.rs | 77 +++++++++++++++++++ jingle_sleigh/src/context/loaded.rs | 6 +- jingle_sleigh/src/context/mod.rs | 4 +- jingle_sleigh/src/ffi/context_ffi.rs | 4 +- 5 files changed, 121 insertions(+), 12 deletions(-) diff --git a/jingle_sleigh/src/context/builder/image/gimli.rs b/jingle_sleigh/src/context/builder/image/gimli.rs index f874a78..0c211c7 100644 --- a/jingle_sleigh/src/context/builder/image/gimli.rs +++ b/jingle_sleigh/src/context/builder/image/gimli.rs @@ -1,7 +1,10 @@ -use crate::context::image::ImageProvider; +use crate::context::image::{ImageProvider, ImageProviderExt, ImageSection, Perms}; use crate::VarNode; -use object::{Architecture, Endianness, File, Object, ObjectSection, SectionKind}; +use object::elf::{SHF_EXECINSTR, SHF_WRITE}; +use object::{Architecture, Endianness, File, Object, ObjectSection, SectionFlags, SectionKind}; use std::cmp::{max, min}; +use std::io::empty; +use std::iter::once; impl<'a> ImageProvider for File<'a> { fn load(&self, vn: &VarNode, output: &mut [u8]) -> usize { @@ -10,8 +13,7 @@ impl<'a> ImageProvider for File<'a> { let output_start_addr = vn.offset as usize; let output_end_addr = output_start_addr + vn.size; if let Some(x) = self.sections().find(|s| { - s.kind() == SectionKind::Text - && output_start_addr > s.address() as usize + output_start_addr > s.address() as usize && output_start_addr < (s.address() + s.size()) as usize }) { if let Ok(data) = x.data() { @@ -36,11 +38,28 @@ impl<'a> ImageProvider for File<'a> { fn has_full_range(&self, vn: &VarNode) -> bool { self.sections() - .filter(|s| s.kind() == SectionKind::Text) .any(|s| { s.address() <= vn.offset && (s.address() + s.size()) >= (vn.offset + vn.size as u64) }) } + + +} + +impl<'a> ImageProviderExt for File<'a>{ + fn get_section_info(&self) -> impl Iterator { + self.sections().filter_map(|s| { + if let Ok(data) = s.data() { + Some(ImageSection { + data, + base_address: s.address() as usize, + perms: map_sec_kind(&s.kind()), + }) + } else { + None + } + }) + } } pub fn map_gimli_architecture(file: &File) -> Option<&'static str> { @@ -71,3 +90,16 @@ pub fn map_gimli_architecture(file: &File) -> Option<&'static str> { _ => None, } } + +fn map_sec_kind(kind: &SectionKind) -> Perms { + match kind { + SectionKind::Unknown => Perms::RWX, + SectionKind::Text => Perms::RX, + SectionKind::Data => Perms::RW, + SectionKind::ReadOnlyData => Perms::R, + SectionKind::ReadOnlyDataWithRel => Perms::R, + SectionKind::ReadOnlyString => Perms::R, + SectionKind::UninitializedData => Perms::RW, + _ => Perms::NONE + } +} \ No newline at end of file diff --git a/jingle_sleigh/src/context/image.rs b/jingle_sleigh/src/context/image.rs index 9ca041a..03903c7 100644 --- a/jingle_sleigh/src/context/image.rs +++ b/jingle_sleigh/src/context/image.rs @@ -1,5 +1,6 @@ use crate::VarNode; use std::cmp::min; +use std::iter::once; use std::ops::Range; pub trait ImageProvider { @@ -8,6 +9,10 @@ pub trait ImageProvider { fn has_full_range(&self, vn: &VarNode) -> bool; } +pub trait ImageProviderExt: ImageProvider { + fn get_section_info(&self) -> impl Iterator; +} + impl ImageProvider for &[u8] { fn load(&self, vn: &VarNode, output: &mut [u8]) -> usize { //todo: check the space. Ignoring for now @@ -37,6 +42,20 @@ impl ImageProvider for &[u8] { } } +impl ImageProviderExt for &[u8] { + fn get_section_info(&self) -> impl Iterator { + once(ImageSection { + data: &self, + base_address: 0, + perms: Perms { + read: true, + write: false, + exec: true, + }, + }) + } +} + impl ImageProvider for Vec { fn load(&self, vn: &VarNode, output: &mut [u8]) -> usize { self.as_slice().load(vn, output) @@ -46,3 +65,61 @@ impl ImageProvider for Vec { self.as_slice().has_full_range(vn) } } + +impl ImageProviderExt for Vec { + fn get_section_info(&self) -> impl Iterator { + once(ImageSection { + data: &self, + base_address: 0, + perms: Perms { + read: true, + write: false, + exec: true, + }, + }) + } +} + +#[derive(Debug, Clone)] +pub struct Perms { + pub(crate) read: bool, + pub(crate) write: bool, + pub(crate) exec: bool, +} + +impl Perms { + pub const RWX: Perms = Perms { + read: true, + write: true, + exec: true, + }; + pub const RX: Perms = Perms { + read: true, + write: false, + exec: true, + }; + + pub const RW: Perms = Perms { + read: true, + write: true, + exec: false, + }; + pub const R: Perms = Perms { + read: true, + write: false, + exec: false, + }; + + pub const NONE: Perms = Perms { + read: false, + write: false, + exec: false, + }; +} + +#[derive(Debug, Clone)] +pub struct ImageSection<'a> { + pub(crate) data: &'a [u8], + pub(crate) base_address: usize, + pub(crate) perms: Perms, +} diff --git a/jingle_sleigh/src/context/loaded.rs b/jingle_sleigh/src/context/loaded.rs index 58a0bc3..2b9052f 100644 --- a/jingle_sleigh/src/context/loaded.rs +++ b/jingle_sleigh/src/context/loaded.rs @@ -1,4 +1,4 @@ -use crate::context::image::ImageProvider; +use crate::context::image::{ImageProvider, ImageProviderExt}; use crate::context::instruction_iterator::SleighContextInstructionIterator; use crate::context::SleighContext; use crate::ffi::context_ffi::ImageFFI; @@ -30,7 +30,7 @@ impl<'a> DerefMut for LoadedSleighContext<'a> { } impl<'a> LoadedSleighContext<'a> { - pub(crate) fn new( + pub(crate) fn new( sleigh_context: SleighContext, img: T, ) -> Result { @@ -73,7 +73,7 @@ impl<'a> LoadedSleighContext<'a> { SleighContextInstructionIterator::new(self, offset, max_instrs, true) } - pub fn set_image(&mut self, img: T) -> Result<(), JingleSleighError> { + pub fn set_image(&mut self, img: T) -> Result<(), JingleSleighError> { let (sleigh, img_ref) = self.borrow_parts(); *img_ref = ImageFFI::new(img); sleigh diff --git a/jingle_sleigh/src/context/mod.rs b/jingle_sleigh/src/context/mod.rs index ef016f9..171f326 100644 --- a/jingle_sleigh/src/context/mod.rs +++ b/jingle_sleigh/src/context/mod.rs @@ -13,7 +13,7 @@ pub use builder::image::gimli::map_gimli_architecture; pub use builder::SleighContextBuilder; use crate::context::builder::language_def::LanguageDefinition; -use crate::context::image::ImageProvider; +use crate::context::image::{ImageProvider, ImageProviderExt}; use crate::context::loaded::LoadedSleighContext; use crate::ffi::context_ffi::CTX_BUILD_MUTEX; use crate::JingleSleighError::{ImageLoadError, SleighCompilerMutexError}; @@ -128,7 +128,7 @@ impl SleighContext { &self.language_id } - pub fn initialize_with_image<'b, T: ImageProvider + 'b>( + pub fn initialize_with_image<'b, T: ImageProviderExt + 'b>( self, img: T, ) -> Result, JingleSleighError> { diff --git a/jingle_sleigh/src/ffi/context_ffi.rs b/jingle_sleigh/src/ffi/context_ffi.rs index 55f328f..4aa86ba 100644 --- a/jingle_sleigh/src/ffi/context_ffi.rs +++ b/jingle_sleigh/src/ffi/context_ffi.rs @@ -1,4 +1,4 @@ -use crate::context::image::ImageProvider; +use crate::context::image::{ImageProvider, ImageProviderExt}; use crate::ffi::context_ffi::bridge::makeContext; use crate::ffi::instruction::bridge::VarnodeInfoFFI; use crate::VarNode; @@ -62,7 +62,7 @@ pub(crate) struct ImageFFI<'a> { } impl<'a> ImageFFI<'a> { - pub(crate) fn new(provider: T) -> Self { + pub(crate) fn new(provider: T) -> Self { Self { provider: Box::pin(provider), } From 6f76225d1e6c05b087455a4d10fb25141030a14a Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 16 Oct 2024 10:58:09 +0100 Subject: [PATCH 099/146] fmt --- .../src/context/builder/image/gimli.rs | 17 +++++++---------- jingle_sleigh/src/context/image.rs | 6 +++--- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/jingle_sleigh/src/context/builder/image/gimli.rs b/jingle_sleigh/src/context/builder/image/gimli.rs index 0c211c7..7969446 100644 --- a/jingle_sleigh/src/context/builder/image/gimli.rs +++ b/jingle_sleigh/src/context/builder/image/gimli.rs @@ -37,17 +37,14 @@ impl<'a> ImageProvider for File<'a> { } fn has_full_range(&self, vn: &VarNode) -> bool { - self.sections() - .any(|s| { - s.address() <= vn.offset && (s.address() + s.size()) >= (vn.offset + vn.size as u64) - }) + self.sections().any(|s| { + s.address() <= vn.offset && (s.address() + s.size()) >= (vn.offset + vn.size as u64) + }) } - - } -impl<'a> ImageProviderExt for File<'a>{ - fn get_section_info(&self) -> impl Iterator { +impl<'a> ImageProviderExt for File<'a> { + fn get_section_info(&self) -> impl Iterator { self.sections().filter_map(|s| { if let Ok(data) = s.data() { Some(ImageSection { @@ -100,6 +97,6 @@ fn map_sec_kind(kind: &SectionKind) -> Perms { SectionKind::ReadOnlyDataWithRel => Perms::R, SectionKind::ReadOnlyString => Perms::R, SectionKind::UninitializedData => Perms::RW, - _ => Perms::NONE + _ => Perms::NONE, } -} \ No newline at end of file +} diff --git a/jingle_sleigh/src/context/image.rs b/jingle_sleigh/src/context/image.rs index 03903c7..c99cc95 100644 --- a/jingle_sleigh/src/context/image.rs +++ b/jingle_sleigh/src/context/image.rs @@ -10,7 +10,7 @@ pub trait ImageProvider { } pub trait ImageProviderExt: ImageProvider { - fn get_section_info(&self) -> impl Iterator; + fn get_section_info(&self) -> impl Iterator; } impl ImageProvider for &[u8] { @@ -43,7 +43,7 @@ impl ImageProvider for &[u8] { } impl ImageProviderExt for &[u8] { - fn get_section_info(&self) -> impl Iterator { + fn get_section_info(&self) -> impl Iterator { once(ImageSection { data: &self, base_address: 0, @@ -67,7 +67,7 @@ impl ImageProvider for Vec { } impl ImageProviderExt for Vec { - fn get_section_info(&self) -> impl Iterator { + fn get_section_info(&self) -> impl Iterator { once(ImageSection { data: &self, base_address: 0, From 450a42e3e762aaebcb598a56f3b3bc8592f35bdc Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 16 Oct 2024 10:59:58 +0100 Subject: [PATCH 100/146] Clippy --- jingle_sleigh/src/context/builder/image/gimli.rs | 5 +---- jingle_sleigh/src/context/image.rs | 10 +++++----- jingle_sleigh/src/context/loaded.rs | 2 +- jingle_sleigh/src/context/mod.rs | 2 +- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/jingle_sleigh/src/context/builder/image/gimli.rs b/jingle_sleigh/src/context/builder/image/gimli.rs index 7969446..6cd3426 100644 --- a/jingle_sleigh/src/context/builder/image/gimli.rs +++ b/jingle_sleigh/src/context/builder/image/gimli.rs @@ -1,10 +1,7 @@ use crate::context::image::{ImageProvider, ImageProviderExt, ImageSection, Perms}; use crate::VarNode; -use object::elf::{SHF_EXECINSTR, SHF_WRITE}; -use object::{Architecture, Endianness, File, Object, ObjectSection, SectionFlags, SectionKind}; +use object::{Architecture, Endianness, File, Object, ObjectSection, SectionKind}; use std::cmp::{max, min}; -use std::io::empty; -use std::iter::once; impl<'a> ImageProvider for File<'a> { fn load(&self, vn: &VarNode, output: &mut [u8]) -> usize { diff --git a/jingle_sleigh/src/context/image.rs b/jingle_sleigh/src/context/image.rs index c99cc95..03adfdf 100644 --- a/jingle_sleigh/src/context/image.rs +++ b/jingle_sleigh/src/context/image.rs @@ -45,7 +45,7 @@ impl ImageProvider for &[u8] { impl ImageProviderExt for &[u8] { fn get_section_info(&self) -> impl Iterator { once(ImageSection { - data: &self, + data: self, base_address: 0, perms: Perms { read: true, @@ -69,7 +69,7 @@ impl ImageProvider for Vec { impl ImageProviderExt for Vec { fn get_section_info(&self) -> impl Iterator { once(ImageSection { - data: &self, + data: self, base_address: 0, perms: Perms { read: true, @@ -119,7 +119,7 @@ impl Perms { #[derive(Debug, Clone)] pub struct ImageSection<'a> { - pub(crate) data: &'a [u8], - pub(crate) base_address: usize, - pub(crate) perms: Perms, + pub data: &'a [u8], + pub base_address: usize, + pub perms: Perms, } diff --git a/jingle_sleigh/src/context/loaded.rs b/jingle_sleigh/src/context/loaded.rs index 2b9052f..34d512c 100644 --- a/jingle_sleigh/src/context/loaded.rs +++ b/jingle_sleigh/src/context/loaded.rs @@ -1,4 +1,4 @@ -use crate::context::image::{ImageProvider, ImageProviderExt}; +use crate::context::image::ImageProviderExt; use crate::context::instruction_iterator::SleighContextInstructionIterator; use crate::context::SleighContext; use crate::ffi::context_ffi::ImageFFI; diff --git a/jingle_sleigh/src/context/mod.rs b/jingle_sleigh/src/context/mod.rs index 171f326..edb3cc6 100644 --- a/jingle_sleigh/src/context/mod.rs +++ b/jingle_sleigh/src/context/mod.rs @@ -13,7 +13,7 @@ pub use builder::image::gimli::map_gimli_architecture; pub use builder::SleighContextBuilder; use crate::context::builder::language_def::LanguageDefinition; -use crate::context::image::{ImageProvider, ImageProviderExt}; +use crate::context::image::ImageProviderExt; use crate::context::loaded::LoadedSleighContext; use crate::ffi::context_ffi::CTX_BUILD_MUTEX; use crate::JingleSleighError::{ImageLoadError, SleighCompilerMutexError}; From e6dd1b5458693d6521da1035c981fce1d3f7b65a Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 16 Oct 2024 11:00:23 +0100 Subject: [PATCH 101/146] pub perms --- jingle_sleigh/src/context/image.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jingle_sleigh/src/context/image.rs b/jingle_sleigh/src/context/image.rs index 03adfdf..90cef86 100644 --- a/jingle_sleigh/src/context/image.rs +++ b/jingle_sleigh/src/context/image.rs @@ -82,9 +82,9 @@ impl ImageProviderExt for Vec { #[derive(Debug, Clone)] pub struct Perms { - pub(crate) read: bool, - pub(crate) write: bool, - pub(crate) exec: bool, + pub read: bool, + pub write: bool, + pub exec: bool, } impl Perms { From d9a38ec511988de1c04aab416f78aabf068a21e8 Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 16 Oct 2024 11:14:01 +0100 Subject: [PATCH 102/146] More trait stuff --- jingle_sleigh/src/context/builder/image/gimli.rs | 4 +--- jingle_sleigh/src/context/image.rs | 13 +++---------- jingle_sleigh/src/context/loaded.rs | 6 +++--- jingle_sleigh/src/context/mod.rs | 4 ++-- jingle_sleigh/src/ffi/context_ffi.rs | 4 ++-- 5 files changed, 11 insertions(+), 20 deletions(-) diff --git a/jingle_sleigh/src/context/builder/image/gimli.rs b/jingle_sleigh/src/context/builder/image/gimli.rs index 6cd3426..61d3234 100644 --- a/jingle_sleigh/src/context/builder/image/gimli.rs +++ b/jingle_sleigh/src/context/builder/image/gimli.rs @@ -1,4 +1,4 @@ -use crate::context::image::{ImageProvider, ImageProviderExt, ImageSection, Perms}; +use crate::context::image::{ImageProvider, ImageSection, Perms}; use crate::VarNode; use object::{Architecture, Endianness, File, Object, ObjectSection, SectionKind}; use std::cmp::{max, min}; @@ -38,9 +38,7 @@ impl<'a> ImageProvider for File<'a> { s.address() <= vn.offset && (s.address() + s.size()) >= (vn.offset + vn.size as u64) }) } -} -impl<'a> ImageProviderExt for File<'a> { fn get_section_info(&self) -> impl Iterator { self.sections().filter_map(|s| { if let Ok(data) = s.data() { diff --git a/jingle_sleigh/src/context/image.rs b/jingle_sleigh/src/context/image.rs index 90cef86..9d5298b 100644 --- a/jingle_sleigh/src/context/image.rs +++ b/jingle_sleigh/src/context/image.rs @@ -7,10 +7,7 @@ pub trait ImageProvider { fn load(&self, vn: &VarNode, output: &mut [u8]) -> usize; fn has_full_range(&self, vn: &VarNode) -> bool; -} - -pub trait ImageProviderExt: ImageProvider { - fn get_section_info(&self) -> impl Iterator; + fn get_section_info(&self) -> impl Iterator where Self: Sized; } impl ImageProvider for &[u8] { @@ -40,10 +37,8 @@ impl ImageProvider for &[u8] { let vn_range: Range = Range::from(vn); vn_range.start < self.len() && vn_range.end <= self.len() } -} -impl ImageProviderExt for &[u8] { - fn get_section_info(&self) -> impl Iterator { + fn get_section_info(&self) -> impl Iterator { once(ImageSection { data: self, base_address: 0, @@ -64,10 +59,8 @@ impl ImageProvider for Vec { fn has_full_range(&self, vn: &VarNode) -> bool { self.as_slice().has_full_range(vn) } -} -impl ImageProviderExt for Vec { - fn get_section_info(&self) -> impl Iterator { + fn get_section_info(&self) -> impl Iterator { once(ImageSection { data: self, base_address: 0, diff --git a/jingle_sleigh/src/context/loaded.rs b/jingle_sleigh/src/context/loaded.rs index 34d512c..7bdd63f 100644 --- a/jingle_sleigh/src/context/loaded.rs +++ b/jingle_sleigh/src/context/loaded.rs @@ -1,4 +1,3 @@ -use crate::context::image::ImageProviderExt; use crate::context::instruction_iterator::SleighContextInstructionIterator; use crate::context::SleighContext; use crate::ffi::context_ffi::ImageFFI; @@ -7,6 +6,7 @@ use crate::{Instruction, JingleSleighError, RegisterManager, SpaceInfo, SpaceMan use std::fmt::{Debug, Formatter}; use std::ops::{Deref, DerefMut}; use std::pin::Pin; +use crate::context::image::ImageProvider; pub struct LoadedSleighContext<'a>(SleighContext, Pin>>); @@ -30,7 +30,7 @@ impl<'a> DerefMut for LoadedSleighContext<'a> { } impl<'a> LoadedSleighContext<'a> { - pub(crate) fn new( + pub(crate) fn new( sleigh_context: SleighContext, img: T, ) -> Result { @@ -73,7 +73,7 @@ impl<'a> LoadedSleighContext<'a> { SleighContextInstructionIterator::new(self, offset, max_instrs, true) } - pub fn set_image(&mut self, img: T) -> Result<(), JingleSleighError> { + pub fn set_image(&mut self, img: T) -> Result<(), JingleSleighError> { let (sleigh, img_ref) = self.borrow_parts(); *img_ref = ImageFFI::new(img); sleigh diff --git a/jingle_sleigh/src/context/mod.rs b/jingle_sleigh/src/context/mod.rs index edb3cc6..eda9486 100644 --- a/jingle_sleigh/src/context/mod.rs +++ b/jingle_sleigh/src/context/mod.rs @@ -13,7 +13,6 @@ pub use builder::image::gimli::map_gimli_architecture; pub use builder::SleighContextBuilder; use crate::context::builder::language_def::LanguageDefinition; -use crate::context::image::ImageProviderExt; use crate::context::loaded::LoadedSleighContext; use crate::ffi::context_ffi::CTX_BUILD_MUTEX; use crate::JingleSleighError::{ImageLoadError, SleighCompilerMutexError}; @@ -21,6 +20,7 @@ use crate::VarNode; use cxx::{SharedPtr, UniquePtr}; use std::fmt::{Debug, Formatter}; use std::path::Path; +use crate::context::image::ImageProvider; pub struct SleighContext { ctx: UniquePtr, @@ -128,7 +128,7 @@ impl SleighContext { &self.language_id } - pub fn initialize_with_image<'b, T: ImageProviderExt + 'b>( + pub fn initialize_with_image<'b, T: ImageProvider + 'b>( self, img: T, ) -> Result, JingleSleighError> { diff --git a/jingle_sleigh/src/ffi/context_ffi.rs b/jingle_sleigh/src/ffi/context_ffi.rs index 4aa86ba..d37f8fa 100644 --- a/jingle_sleigh/src/ffi/context_ffi.rs +++ b/jingle_sleigh/src/ffi/context_ffi.rs @@ -1,4 +1,4 @@ -use crate::context::image::{ImageProvider, ImageProviderExt}; +use crate::context::image::{ImageProvider}; use crate::ffi::context_ffi::bridge::makeContext; use crate::ffi::instruction::bridge::VarnodeInfoFFI; use crate::VarNode; @@ -62,7 +62,7 @@ pub(crate) struct ImageFFI<'a> { } impl<'a> ImageFFI<'a> { - pub(crate) fn new(provider: T) -> Self { + pub(crate) fn new(provider: T) -> Self { Self { provider: Box::pin(provider), } From 2e641f18dc03ae3f7260401db6abcf84124fbb60 Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 16 Oct 2024 11:15:24 +0100 Subject: [PATCH 103/146] Convert LoadedSleighContext to struct --- jingle_sleigh/src/context/loaded.rs | 34 +++++++++++++++++------------ 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/jingle_sleigh/src/context/loaded.rs b/jingle_sleigh/src/context/loaded.rs index 7bdd63f..b732593 100644 --- a/jingle_sleigh/src/context/loaded.rs +++ b/jingle_sleigh/src/context/loaded.rs @@ -8,24 +8,27 @@ use std::ops::{Deref, DerefMut}; use std::pin::Pin; use crate::context::image::ImageProvider; -pub struct LoadedSleighContext<'a>(SleighContext, Pin>>); +pub struct LoadedSleighContext<'a> { + sleigh: SleighContext, + img: Pin>>, +} impl<'a> Debug for LoadedSleighContext<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - self.0.fmt(f) + self.sleigh.fmt(f) } } impl<'a> Deref for LoadedSleighContext<'a> { type Target = SleighContext; fn deref(&self) -> &Self::Target { - &self.0 + &self.sleigh } } impl<'a> DerefMut for LoadedSleighContext<'a> { fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 + &mut self.sleigh } } @@ -35,7 +38,10 @@ impl<'a> LoadedSleighContext<'a> { img: T, ) -> Result { let img = Box::pin(ImageFFI::new(img)); - let mut s = Self(sleigh_context, img); + let mut s = Self { + sleigh: sleigh_context, + img: img + }; let (ctx, img) = s.borrow_parts(); ctx.ctx .pin_mut() @@ -50,11 +56,11 @@ impl<'a> LoadedSleighContext<'a> { .map(Instruction::from) .ok()?; let vn = VarNode { - space_index: self.0.get_code_space_idx(), + space_index: self.sleigh.get_code_space_idx(), size: instr.length, offset, }; - if self.1.has_range(&vn) { + if self.img.has_range(&vn) { Some(instr) } else { None @@ -84,34 +90,34 @@ impl<'a> LoadedSleighContext<'a> { } fn borrow_parts<'b>(&'b mut self) -> (&'b mut SleighContext, &'b mut ImageFFI<'a>) { - (&mut self.0, &mut self.1) + (&mut self.sleigh, &mut self.img) } } impl<'a> SpaceManager for LoadedSleighContext<'a> { fn get_space_info(&self, idx: usize) -> Option<&SpaceInfo> { - self.0.get_space_info(idx) + self.sleigh.get_space_info(idx) } fn get_all_space_info(&self) -> &[SpaceInfo] { - self.0.get_all_space_info() + self.sleigh.get_all_space_info() } fn get_code_space_idx(&self) -> usize { - self.0.get_code_space_idx() + self.sleigh.get_code_space_idx() } } impl<'a> RegisterManager for LoadedSleighContext<'a> { fn get_register(&self, name: &str) -> Option { - self.0.get_register(name) + self.sleigh.get_register(name) } fn get_register_name(&self, location: &VarNode) -> Option<&str> { - self.0.get_register_name(location) + self.sleigh.get_register_name(location) } fn get_registers(&self) -> Vec<(VarNode, String)> { - self.0.get_registers() + self.sleigh.get_registers() } } From dedcb08e2ca6b73d609a004aaed4aff57dd9399f Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 16 Oct 2024 11:33:06 +0100 Subject: [PATCH 104/146] Trying more stuff --- .../src/context/builder/image/gimli.rs | 8 +++---- jingle_sleigh/src/context/image.rs | 24 +++++++++++++------ jingle_sleigh/src/context/loaded.rs | 9 +++++-- 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/jingle_sleigh/src/context/builder/image/gimli.rs b/jingle_sleigh/src/context/builder/image/gimli.rs index 61d3234..af22abe 100644 --- a/jingle_sleigh/src/context/builder/image/gimli.rs +++ b/jingle_sleigh/src/context/builder/image/gimli.rs @@ -1,4 +1,4 @@ -use crate::context::image::{ImageProvider, ImageSection, Perms}; +use crate::context::image::{ImageProvider, ImageSection, ImageSectionIterator, Perms}; use crate::VarNode; use object::{Architecture, Endianness, File, Object, ObjectSection, SectionKind}; use std::cmp::{max, min}; @@ -39,8 +39,8 @@ impl<'a> ImageProvider for File<'a> { }) } - fn get_section_info(&self) -> impl Iterator { - self.sections().filter_map(|s| { + fn get_section_info(&self) -> ImageSectionIterator { + ImageSectionIterator::new(self.sections().filter_map(|s| { if let Ok(data) = s.data() { Some(ImageSection { data, @@ -50,7 +50,7 @@ impl<'a> ImageProvider for File<'a> { } else { None } - }) + })) } } diff --git a/jingle_sleigh/src/context/image.rs b/jingle_sleigh/src/context/image.rs index 9d5298b..9485429 100644 --- a/jingle_sleigh/src/context/image.rs +++ b/jingle_sleigh/src/context/image.rs @@ -7,7 +7,17 @@ pub trait ImageProvider { fn load(&self, vn: &VarNode, output: &mut [u8]) -> usize; fn has_full_range(&self, vn: &VarNode) -> bool; - fn get_section_info(&self) -> impl Iterator where Self: Sized; + fn get_section_info(&self) -> ImageSectionIterator; +} + +pub struct ImageSectionIterator<'a> { + pub(crate) iter: Box> + 'a>, +} + +impl<'a> ImageSectionIterator<'a> { + pub(crate) fn new> + 'a>(iter: T) -> Self { + Self { iter: Box::new(iter) } + } } impl ImageProvider for &[u8] { @@ -38,8 +48,8 @@ impl ImageProvider for &[u8] { vn_range.start < self.len() && vn_range.end <= self.len() } - fn get_section_info(&self) -> impl Iterator { - once(ImageSection { + fn get_section_info(&self) -> ImageSectionIterator { + ImageSectionIterator::new(once(ImageSection { data: self, base_address: 0, perms: Perms { @@ -47,7 +57,7 @@ impl ImageProvider for &[u8] { write: false, exec: true, }, - }) + })) } } @@ -60,8 +70,8 @@ impl ImageProvider for Vec { self.as_slice().has_full_range(vn) } - fn get_section_info(&self) -> impl Iterator { - once(ImageSection { + fn get_section_info(&self) -> ImageSectionIterator { + ImageSectionIterator::new(once(ImageSection { data: self, base_address: 0, perms: Perms { @@ -69,7 +79,7 @@ impl ImageProvider for Vec { write: false, exec: true, }, - }) + })) } } diff --git a/jingle_sleigh/src/context/loaded.rs b/jingle_sleigh/src/context/loaded.rs index b732593..0a0dbc8 100644 --- a/jingle_sleigh/src/context/loaded.rs +++ b/jingle_sleigh/src/context/loaded.rs @@ -33,7 +33,7 @@ impl<'a> DerefMut for LoadedSleighContext<'a> { } impl<'a> LoadedSleighContext<'a> { - pub(crate) fn new( + pub(crate) fn new( sleigh_context: SleighContext, img: T, ) -> Result { @@ -79,7 +79,7 @@ impl<'a> LoadedSleighContext<'a> { SleighContextInstructionIterator::new(self, offset, max_instrs, true) } - pub fn set_image(&mut self, img: T) -> Result<(), JingleSleighError> { + pub fn set_image(&mut self, img: T) -> Result<(), JingleSleighError> { let (sleigh, img_ref) = self.borrow_parts(); *img_ref = ImageFFI::new(img); sleigh @@ -89,9 +89,14 @@ impl<'a> LoadedSleighContext<'a> { .map_err(|_| ImageLoadError) } + pub fn get_img_provider(&self) -> Pin<&dyn ImageProvider> { + self.img.provider.as_ref() + } + fn borrow_parts<'b>(&'b mut self) -> (&'b mut SleighContext, &'b mut ImageFFI<'a>) { (&mut self.sleigh, &mut self.img) } + } impl<'a> SpaceManager for LoadedSleighContext<'a> { From 8f31dcc10553c2b0f5eb420371fc58caf842bba0 Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 16 Oct 2024 11:42:16 +0100 Subject: [PATCH 105/146] More trait gymnastics --- jingle_sleigh/src/context/image.rs | 25 ++++++++++++++++++++++--- jingle_sleigh/src/context/loaded.rs | 6 +++--- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/jingle_sleigh/src/context/image.rs b/jingle_sleigh/src/context/image.rs index 9485429..0d80db5 100644 --- a/jingle_sleigh/src/context/image.rs +++ b/jingle_sleigh/src/context/image.rs @@ -11,7 +11,7 @@ pub trait ImageProvider { } pub struct ImageSectionIterator<'a> { - pub(crate) iter: Box> + 'a>, + iter: Box> + 'a>, } impl<'a> ImageSectionIterator<'a> { @@ -20,6 +20,13 @@ impl<'a> ImageSectionIterator<'a> { } } +impl<'a> Iterator for ImageSectionIterator<'a>{ + type Item = ImageSection<'a>; + + fn next(&mut self) -> Option { + self.iter.next() + } +} impl ImageProvider for &[u8] { fn load(&self, vn: &VarNode, output: &mut [u8]) -> usize { //todo: check the space. Ignoring for now @@ -83,7 +90,7 @@ impl ImageProvider for Vec { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct Perms { pub read: bool, pub write: bool, @@ -120,9 +127,21 @@ impl Perms { }; } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct ImageSection<'a> { pub data: &'a [u8], pub base_address: usize, pub perms: Perms, } + +#[cfg(test)] +mod tests{ + use crate::context::image::{ImageProvider, ImageSection}; + + #[test] + fn test_vec_sections(){ + let data: Vec = vec![1,2,3]; + let sections: Vec = data.get_section_info().collect(); + assert_ne!(sections, vec![]) + } +} \ No newline at end of file diff --git a/jingle_sleigh/src/context/loaded.rs b/jingle_sleigh/src/context/loaded.rs index 0a0dbc8..31823c5 100644 --- a/jingle_sleigh/src/context/loaded.rs +++ b/jingle_sleigh/src/context/loaded.rs @@ -6,7 +6,7 @@ use crate::{Instruction, JingleSleighError, RegisterManager, SpaceInfo, SpaceMan use std::fmt::{Debug, Formatter}; use std::ops::{Deref, DerefMut}; use std::pin::Pin; -use crate::context::image::ImageProvider; +use crate::context::image::{ImageProvider, ImageSection}; pub struct LoadedSleighContext<'a> { sleigh: SleighContext, @@ -89,8 +89,8 @@ impl<'a> LoadedSleighContext<'a> { .map_err(|_| ImageLoadError) } - pub fn get_img_provider(&self) -> Pin<&dyn ImageProvider> { - self.img.provider.as_ref() + pub fn get_sections(&self) -> impl Iterator { + self.img.provider.get_section_info() } fn borrow_parts<'b>(&'b mut self) -> (&'b mut SleighContext, &'b mut ImageFFI<'a>) { From 221bf34c414f0476541e2412d1a729cc6b3f8e20 Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 16 Oct 2024 11:43:13 +0100 Subject: [PATCH 106/146] Clippy --- jingle_sleigh/src/context/loaded.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jingle_sleigh/src/context/loaded.rs b/jingle_sleigh/src/context/loaded.rs index 31823c5..0e80c33 100644 --- a/jingle_sleigh/src/context/loaded.rs +++ b/jingle_sleigh/src/context/loaded.rs @@ -40,7 +40,7 @@ impl<'a> LoadedSleighContext<'a> { let img = Box::pin(ImageFFI::new(img)); let mut s = Self { sleigh: sleigh_context, - img: img + img }; let (ctx, img) = s.borrow_parts(); ctx.ctx From ed97ea8130aacdcdcfc1b6fa621cbf009b070250 Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 16 Oct 2024 11:46:57 +0100 Subject: [PATCH 107/146] Remove unused generic bounds --- jingle_sleigh/src/context/loaded.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jingle_sleigh/src/context/loaded.rs b/jingle_sleigh/src/context/loaded.rs index 0e80c33..55dc4c3 100644 --- a/jingle_sleigh/src/context/loaded.rs +++ b/jingle_sleigh/src/context/loaded.rs @@ -89,7 +89,7 @@ impl<'a> LoadedSleighContext<'a> { .map_err(|_| ImageLoadError) } - pub fn get_sections(&self) -> impl Iterator { + pub fn get_sections(&self) -> impl Iterator { self.img.provider.get_section_info() } From 73c4afbdcf38b420f755f6ddcb662703022ef873 Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 16 Oct 2024 14:29:31 +0100 Subject: [PATCH 108/146] Add owned file --- .../src/context/builder/image/gimli.rs | 87 ++++++++++++++++++- 1 file changed, 85 insertions(+), 2 deletions(-) diff --git a/jingle_sleigh/src/context/builder/image/gimli.rs b/jingle_sleigh/src/context/builder/image/gimli.rs index af22abe..895d201 100644 --- a/jingle_sleigh/src/context/builder/image/gimli.rs +++ b/jingle_sleigh/src/context/builder/image/gimli.rs @@ -1,8 +1,91 @@ use crate::context::image::{ImageProvider, ImageSection, ImageSectionIterator, Perms}; -use crate::VarNode; -use object::{Architecture, Endianness, File, Object, ObjectSection, SectionKind}; +use crate::{JingleSleighError, VarNode}; +use object::{Architecture, Endianness, File, Object, ObjectSection, Section, SectionKind}; use std::cmp::{max, min}; + +pub struct OwnedSection { + data: Vec, + perms: Perms, + base_address: usize, +} + +impl<'a> From<&'a OwnedSection> for ImageSection<'a> { + fn from(value: &'a OwnedSection) -> Self { + ImageSection { + data: value.data.as_slice(), + perms: value.perms.clone(), + base_address: value.base_address.clone(), + } + } +} + +impl<'a, 'b> TryFrom> for OwnedSection { + type Error = JingleSleighError; + + fn try_from(value: Section) -> Result { + let data = value.data().map_err(|_| JingleSleighError::ImageLoadError)?.to_vec(); + Ok(OwnedSection { + data, + perms: map_sec_kind(&value.kind()), + base_address: value.address() as usize, + }) + } +} + +pub struct OwnedFile { + sections: Vec, +} + +impl OwnedFile { + pub fn new(file: &File) -> Result { + let mut sections = vec![]; + for x in file.sections() { + sections.push(x.try_into()?); + } + Ok(Self { sections }) + } +} + +impl ImageProvider for OwnedFile { + fn load(&self, vn: &VarNode, output: &mut [u8]) -> usize { + let mut written = 0; + output.fill(0); + let output_start_addr = vn.offset as usize; + let output_end_addr = output_start_addr + vn.size; + if let Some(x) = self.get_section_info().find(|s| { + output_start_addr > s.base_address + && output_start_addr < (s.base_address + s.data.len()) + }) { + let input_start_addr = x.base_address; + let input_end_addr = input_start_addr + x.data.len(); + let start_addr = max(input_start_addr, output_start_addr); + let end_addr = max(min(input_end_addr, output_end_addr), start_addr); + if end_addr > start_addr { + let i_s = start_addr - x.base_address; + let i_e = end_addr - x.base_address as usize; + let o_s = start_addr - vn.offset as usize; + let o_e = end_addr - vn.offset as usize; + let out_slice = &mut output[o_s..o_e]; + let in_slice = &x.data[i_s..i_e]; + out_slice.copy_from_slice(in_slice); + written += end_addr - start_addr; + } + } + written + } + + fn has_full_range(&self, vn: &VarNode) -> bool { + self.get_section_info().any(|s| { + s.base_address <= vn.offset as usize && (s.base_address + s.data.len()) >= (vn.offset as usize + vn.size) + }) + } + + fn get_section_info(&self) -> ImageSectionIterator { + ImageSectionIterator::new(self.sections.iter().map(ImageSection::from)) + } +} + impl<'a> ImageProvider for File<'a> { fn load(&self, vn: &VarNode, output: &mut [u8]) -> usize { let mut written = 0; From fe0b3395606c0e16e56c3676536d6c404f56399a Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 16 Oct 2024 14:36:42 +0100 Subject: [PATCH 109/146] Pub all of gimli --- jingle_sleigh/src/context/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jingle_sleigh/src/context/mod.rs b/jingle_sleigh/src/context/mod.rs index eda9486..987f899 100644 --- a/jingle_sleigh/src/context/mod.rs +++ b/jingle_sleigh/src/context/mod.rs @@ -9,7 +9,7 @@ use crate::ffi::addrspace::bridge::AddrSpaceHandle; use crate::ffi::context_ffi::bridge::ContextFFI; use crate::space::{RegisterManager, SpaceInfo, SpaceManager}; #[cfg(feature = "gimli")] -pub use builder::image::gimli::map_gimli_architecture; +pub use builder::image::gimli; pub use builder::SleighContextBuilder; use crate::context::builder::language_def::LanguageDefinition; From f599396e54b50bc236ef6a73a3656f169ddde8b3 Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 16 Oct 2024 14:40:26 +0100 Subject: [PATCH 110/146] Reshuffle --- jingle_sleigh/src/context/builder/image/mod.rs | 4 ---- jingle_sleigh/src/context/builder/mod.rs | 1 - jingle_sleigh/src/context/{builder => }/image/elf.rs | 0 jingle_sleigh/src/context/{builder => }/image/gimli.rs | 0 jingle_sleigh/src/context/{image.rs => image/mod.rs} | 5 ++++- jingle_sleigh/src/context/mod.rs | 2 -- 6 files changed, 4 insertions(+), 8 deletions(-) delete mode 100644 jingle_sleigh/src/context/builder/image/mod.rs rename jingle_sleigh/src/context/{builder => }/image/elf.rs (100%) rename jingle_sleigh/src/context/{builder => }/image/gimli.rs (100%) rename jingle_sleigh/src/context/{image.rs => image/mod.rs} (98%) diff --git a/jingle_sleigh/src/context/builder/image/mod.rs b/jingle_sleigh/src/context/builder/image/mod.rs deleted file mode 100644 index f243f19..0000000 --- a/jingle_sleigh/src/context/builder/image/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -/*#[cfg(feature = "elf")] -pub mod elf;*/ -#[cfg(feature = "gimli")] -pub mod gimli; diff --git a/jingle_sleigh/src/context/builder/mod.rs b/jingle_sleigh/src/context/builder/mod.rs index ffb28dd..7aa632b 100644 --- a/jingle_sleigh/src/context/builder/mod.rs +++ b/jingle_sleigh/src/context/builder/mod.rs @@ -8,7 +8,6 @@ use std::fs; use std::path::{Path, PathBuf}; use tracing::{event, instrument, Level}; -pub mod image; pub(crate) mod language_def; pub(crate) mod processor_spec; diff --git a/jingle_sleigh/src/context/builder/image/elf.rs b/jingle_sleigh/src/context/image/elf.rs similarity index 100% rename from jingle_sleigh/src/context/builder/image/elf.rs rename to jingle_sleigh/src/context/image/elf.rs diff --git a/jingle_sleigh/src/context/builder/image/gimli.rs b/jingle_sleigh/src/context/image/gimli.rs similarity index 100% rename from jingle_sleigh/src/context/builder/image/gimli.rs rename to jingle_sleigh/src/context/image/gimli.rs diff --git a/jingle_sleigh/src/context/image.rs b/jingle_sleigh/src/context/image/mod.rs similarity index 98% rename from jingle_sleigh/src/context/image.rs rename to jingle_sleigh/src/context/image/mod.rs index 0d80db5..198bbbe 100644 --- a/jingle_sleigh/src/context/image.rs +++ b/jingle_sleigh/src/context/image/mod.rs @@ -3,6 +3,9 @@ use std::cmp::min; use std::iter::once; use std::ops::Range; +#[cfg(feature = "gimli")] +pub mod gimli; + pub trait ImageProvider { fn load(&self, vn: &VarNode, output: &mut [u8]) -> usize; @@ -144,4 +147,4 @@ mod tests{ let sections: Vec = data.get_section_info().collect(); assert_ne!(sections, vec![]) } -} \ No newline at end of file +} diff --git a/jingle_sleigh/src/context/mod.rs b/jingle_sleigh/src/context/mod.rs index 987f899..e83429e 100644 --- a/jingle_sleigh/src/context/mod.rs +++ b/jingle_sleigh/src/context/mod.rs @@ -8,8 +8,6 @@ use crate::error::JingleSleighError::{LanguageSpecRead, SleighInitError}; use crate::ffi::addrspace::bridge::AddrSpaceHandle; use crate::ffi::context_ffi::bridge::ContextFFI; use crate::space::{RegisterManager, SpaceInfo, SpaceManager}; -#[cfg(feature = "gimli")] -pub use builder::image::gimli; pub use builder::SleighContextBuilder; use crate::context::builder::language_def::LanguageDefinition; From faa8c408978d74412c4498c0b843b2dcfca8c6af Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 16 Oct 2024 16:31:49 +0100 Subject: [PATCH 111/146] Filter --- jingle_sleigh/src/context/image/gimli.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jingle_sleigh/src/context/image/gimli.rs b/jingle_sleigh/src/context/image/gimli.rs index 895d201..1d09283 100644 --- a/jingle_sleigh/src/context/image/gimli.rs +++ b/jingle_sleigh/src/context/image/gimli.rs @@ -3,7 +3,7 @@ use crate::{JingleSleighError, VarNode}; use object::{Architecture, Endianness, File, Object, ObjectSection, Section, SectionKind}; use std::cmp::{max, min}; - +#[derive(Debug, PartialEq, Eq)] pub struct OwnedSection { data: Vec, perms: Perms, @@ -40,7 +40,7 @@ pub struct OwnedFile { impl OwnedFile { pub fn new(file: &File) -> Result { let mut sections = vec![]; - for x in file.sections() { + for x in file.sections().filter(|f|f.kind() == SectionKind::Text) { sections.push(x.try_into()?); } Ok(Self { sections }) From 0bd3e0c6a7e83c345ae23af3c863c6fca8a84f7a Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 16 Oct 2024 16:53:14 +0100 Subject: [PATCH 112/146] Fix loading --- jingle_sleigh/src/context/image/gimli.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/jingle_sleigh/src/context/image/gimli.rs b/jingle_sleigh/src/context/image/gimli.rs index 1d09283..5b9c471 100644 --- a/jingle_sleigh/src/context/image/gimli.rs +++ b/jingle_sleigh/src/context/image/gimli.rs @@ -33,6 +33,7 @@ impl<'a, 'b> TryFrom> for OwnedSection { } } +#[derive(Debug)] pub struct OwnedFile { sections: Vec, } @@ -54,7 +55,7 @@ impl ImageProvider for OwnedFile { let output_start_addr = vn.offset as usize; let output_end_addr = output_start_addr + vn.size; if let Some(x) = self.get_section_info().find(|s| { - output_start_addr > s.base_address + output_start_addr >= s.base_address && output_start_addr < (s.base_address + s.data.len()) }) { let input_start_addr = x.base_address; @@ -93,7 +94,7 @@ impl<'a> ImageProvider for File<'a> { let output_start_addr = vn.offset as usize; let output_end_addr = output_start_addr + vn.size; if let Some(x) = self.sections().find(|s| { - output_start_addr > s.address() as usize + output_start_addr >= s.address() as usize && output_start_addr < (s.address() + s.size()) as usize }) { if let Ok(data) = x.data() { From 04d30fc5f85970cae3713a5b430f4211894bb49a Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 21 Oct 2024 11:25:55 +0100 Subject: [PATCH 113/146] Display register names --- jingle/src/varnode/mod.rs | 4 ++-- jingle_sleigh/src/instruction.rs | 9 ++++----- jingle_sleigh/src/pcode/display.rs | 9 +++++++-- jingle_sleigh/src/pcode/mod.rs | 4 ++-- jingle_sleigh/src/varnode/display.rs | 20 +++++++++++++++++--- jingle_sleigh/src/varnode/mod.rs | 15 ++++++++++----- 6 files changed, 42 insertions(+), 19 deletions(-) diff --git a/jingle/src/varnode/mod.rs b/jingle/src/varnode/mod.rs index b255e64..adbaca6 100644 --- a/jingle/src/varnode/mod.rs +++ b/jingle/src/varnode/mod.rs @@ -3,7 +3,7 @@ mod display; use crate::error::JingleError; use crate::error::JingleError::UnmodeledSpace; use crate::varnode::display::{ResolvedIndirectVarNodeDisplay, ResolvedVarNodeDisplay}; -use jingle_sleigh::SpaceManager; +use jingle_sleigh::RegisterManager; use jingle_sleigh::VarNode; use std::hash::Hash; use z3::ast::BV; @@ -26,7 +26,7 @@ pub enum ResolvedVarnode<'ctx> { } impl<'ctx> ResolvedVarnode<'ctx> { - pub fn display(&self, ctx: &T) -> Result { + pub fn display(&self, ctx: &T) -> Result { match self { ResolvedVarnode::Direct(d) => Ok(ResolvedVarNodeDisplay::Direct(d.display(ctx)?)), ResolvedVarnode::Indirect(i) => Ok(ResolvedVarNodeDisplay::Indirect( diff --git a/jingle_sleigh/src/instruction.rs b/jingle_sleigh/src/instruction.rs index 440f771..907b50e 100644 --- a/jingle_sleigh/src/instruction.rs +++ b/jingle_sleigh/src/instruction.rs @@ -3,9 +3,8 @@ pub use crate::ffi::instruction::bridge::Disassembly; use crate::ffi::instruction::bridge::InstructionFFI; use crate::pcode::display::PcodeOperationDisplay; use crate::pcode::PcodeOperation; -use crate::space::SpaceManager; use crate::JingleSleighError::EmptyInstruction; -use crate::OpCode; +use crate::{OpCode, RegisterManager}; use serde::{Deserialize, Serialize}; use std::fmt::{Display, Formatter}; @@ -24,13 +23,13 @@ pub struct Instruction { /// A helper structure allowing displaying an instruction and its semantics /// without requiring lots of pcode metadata to be stored in the instruction itself -pub struct InstructionDisplay<'a, T: SpaceManager> { +pub struct InstructionDisplay<'a, T: RegisterManager> { pub disassembly: Disassembly, pub ops: Vec>, } impl Instruction { - pub fn display<'a, T: SpaceManager>( + pub fn display<'a, T: RegisterManager>( &'a self, ctx: &'a T, ) -> Result, JingleSleighError> { @@ -62,7 +61,7 @@ impl Instruction { } } -impl<'a, T: SpaceManager> Display for InstructionDisplay<'a, T> { +impl<'a, T: RegisterManager> Display for InstructionDisplay<'a, T> { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { writeln!(f, "{} {}", self.disassembly.mnemonic, self.disassembly.args)?; for x in &self.ops { diff --git a/jingle_sleigh/src/pcode/display.rs b/jingle_sleigh/src/pcode/display.rs index 9526460..007d21d 100644 --- a/jingle_sleigh/src/pcode/display.rs +++ b/jingle_sleigh/src/pcode/display.rs @@ -7,15 +7,20 @@ use crate::pcode::PcodeOperation::{ }; use crate::space::SpaceManager; use std::fmt::{Display, Formatter}; +use crate::RegisterManager; -pub struct PcodeOperationDisplay<'a, T: SpaceManager> { +pub struct PcodeOperationDisplay<'a, T: RegisterManager> { pub(crate) op: PcodeOperation, pub(crate) spaces: &'a T, } +impl<'a, T: RegisterManager> PcodeOperationDisplay<'a, T>{ + +} + impl<'a, T> Display for PcodeOperationDisplay<'a, T> where - T: SpaceManager, + T: RegisterManager, { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match &self.op { diff --git a/jingle_sleigh/src/pcode/mod.rs b/jingle_sleigh/src/pcode/mod.rs index c52e382..4395bdb 100644 --- a/jingle_sleigh/src/pcode/mod.rs +++ b/jingle_sleigh/src/pcode/mod.rs @@ -18,7 +18,7 @@ pub use crate::ffi::opcode::OpCode; use crate::pcode::display::PcodeOperationDisplay; use crate::space::SpaceManager; use crate::varnode::{IndirectVarNode, VarNode}; -use crate::GeneralizedVarNode; +use crate::{GeneralizedVarNode, RegisterManager}; use serde::{Deserialize, Serialize}; use std::fmt::Debug; @@ -387,7 +387,7 @@ impl PcodeOperation { ) } - pub fn display<'a, T: SpaceManager>( + pub fn display<'a, T: RegisterManager>( &self, ctx: &'a T, ) -> Result, JingleSleighError> { diff --git a/jingle_sleigh/src/varnode/display.rs b/jingle_sleigh/src/varnode/display.rs index d1ab1bd..95eefb3 100644 --- a/jingle_sleigh/src/varnode/display.rs +++ b/jingle_sleigh/src/varnode/display.rs @@ -1,9 +1,14 @@ use crate::ffi::addrspace::bridge::SpaceType; use crate::space::SpaceInfo; -use std::fmt::{Display, Formatter}; +use std::fmt::{Debug, Display, Formatter}; #[derive(Clone, Debug)] -pub struct VarNodeDisplay { +pub enum VarNodeDisplay{ + Raw(RawVarNodeDisplay), + Register(String) +} +#[derive(Clone, Debug)] +pub struct RawVarNodeDisplay { pub offset: u64, pub size: usize, pub space_info: SpaceInfo, @@ -22,7 +27,7 @@ pub enum GeneralizedVarNodeDisplay { Indirect(IndirectVarNodeDisplay), } -impl Display for VarNodeDisplay { +impl Display for RawVarNodeDisplay{ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { if self.space_info._type == SpaceType::IPTR_CONSTANT { write!(f, "{:x}:{:x}", self.offset, self.size) @@ -35,6 +40,15 @@ impl Display for VarNodeDisplay { } } } +impl Display for VarNodeDisplay { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self{ + VarNodeDisplay::Raw(r) => {write!(f, "{}", r)} + VarNodeDisplay::Register(a) => {write!(f, "{}", a)} + } + + } +} impl Display for IndirectVarNodeDisplay { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { diff --git a/jingle_sleigh/src/varnode/mod.rs b/jingle_sleigh/src/varnode/mod.rs index 3b75022..ad92b8f 100644 --- a/jingle_sleigh/src/varnode/mod.rs +++ b/jingle_sleigh/src/varnode/mod.rs @@ -10,6 +10,7 @@ pub use crate::varnode::display::{ use serde::{Deserialize, Serialize}; use std::fmt::Debug; use std::ops::Range; +use crate::{RawVarNodeDisplay, RegisterManager}; /// A [`VarNode`] is `SLEIGH`'s generalization of an address. It describes a sized-location in /// a given memory space. @@ -34,14 +35,18 @@ pub struct VarNode { } impl VarNode { - pub fn display(&self, ctx: &T) -> Result { + pub fn display(&self, ctx: &T) -> Result { + if let Some(name) = ctx.get_register_name(self) { + Ok(VarNodeDisplay::Register(name.to_string())) + }else{ ctx.get_space_info(self.space_index) - .map(|space_info| VarNodeDisplay { + .map(|space_info| VarNodeDisplay::Raw(RawVarNodeDisplay { size: self.size, offset: self.offset, space_info: space_info.clone(), - }) + })) .ok_or(JingleSleighError::InvalidSpaceName) + } } pub fn covers(&self, other: &VarNode) -> bool { @@ -107,7 +112,7 @@ pub struct IndirectVarNode { } impl IndirectVarNode { - pub fn display( + pub fn display( &self, ctx: &T, ) -> Result { @@ -132,7 +137,7 @@ pub enum GeneralizedVarNode { } impl GeneralizedVarNode { - pub fn display( + pub fn display( &self, ctx: &T, ) -> Result { From 3d64bd902ccd13b6cfb031e0ab6739e803f29748 Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 21 Oct 2024 11:55:58 +0100 Subject: [PATCH 114/146] Change display impl --- jingle_sleigh/src/ffi/opcode.rs | 2 + jingle_sleigh/src/pcode/display.rs | 288 +++-------------------------- jingle_sleigh/src/pcode/mod.rs | 2 +- 3 files changed, 24 insertions(+), 268 deletions(-) diff --git a/jingle_sleigh/src/ffi/opcode.rs b/jingle_sleigh/src/ffi/opcode.rs index ffa27e1..2fbec7c 100644 --- a/jingle_sleigh/src/ffi/opcode.rs +++ b/jingle_sleigh/src/ffi/opcode.rs @@ -1,3 +1,4 @@ +use std::fmt::{Display, Formatter}; pub use bridge::OpCode; #[cxx::bridge] @@ -165,3 +166,4 @@ pub(crate) mod bridge { } } + diff --git a/jingle_sleigh/src/pcode/display.rs b/jingle_sleigh/src/pcode/display.rs index 007d21d..60165a7 100644 --- a/jingle_sleigh/src/pcode/display.rs +++ b/jingle_sleigh/src/pcode/display.rs @@ -11,279 +11,33 @@ use crate::RegisterManager; pub struct PcodeOperationDisplay<'a, T: RegisterManager> { pub(crate) op: PcodeOperation, - pub(crate) spaces: &'a T, + pub(crate) ctx: &'a T, } -impl<'a, T: RegisterManager> PcodeOperationDisplay<'a, T>{ - -} +impl<'a, T: RegisterManager> PcodeOperationDisplay<'a, T> {} impl<'a, T> Display for PcodeOperationDisplay<'a, T> -where - T: RegisterManager, + where + T: RegisterManager, { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match &self.op { - Copy { input, output } => { - write!( - f, - "{} = {}", - output.display(self.spaces)?, - input.display(self.spaces)? - ) - } - PopCount { input, output } => { - write!( - f, - "{} = popcount({})", - output.display(self.spaces)?, - input.display(self.spaces)? - ) - } - IntZExt { input, output } => { - write!( - f, - "{} = zext({})", - output.display(self.spaces)?, - input.display(self.spaces)? - ) - } - IntSExt { input, output } => { - write!( - f, - "{} = sext({})", - output.display(self.spaces)?, - input.display(self.spaces)? - ) - } - Store { output, input } => { - write!( - f, - "{} = {}", - output.display(self.spaces)?, - input.display(self.spaces)? - ) - } - Load { input, output } => { - write!( - f, - "{} = {}", - output.display(self.spaces)?, - input.display(self.spaces)? - ) - } - IntCarry { - output, - input0, - input1, - } => write!( - f, - "{} = carry({}, {})", - output.display(self.spaces)?, - input0.display(self.spaces)?, - input1.display(self.spaces)? - ), - IntSignedCarry { - output, - input0, - input1, - } => write!( - f, - "{} = s.carry({}, {})", - output.display(self.spaces)?, - input0.display(self.spaces)?, - input1.display(self.spaces)? - ), - IntSignedBorrow { - output, - input0, - input1, - } => write!( - f, - "{} = s.borrow({}, {})", - output.display(self.spaces)?, - input0.display(self.spaces)?, - input1.display(self.spaces)? - ), - Int2Comp { output, input } => write!( - f, - "{} = -{}", - output.display(self.spaces)?, - input.display(self.spaces)? - ), - IntAdd { - output, - input0, - input1, - } => write!( - f, - "{} = {} + {}", - output.display(self.spaces)?, - input0.display(self.spaces)?, - input1.display(self.spaces)?, - ), - IntSub { - output, - input0, - input1, - } => write!( - f, - "{} = {} - {}", - output.display(self.spaces)?, - input0.display(self.spaces)?, - input1.display(self.spaces)?, - ), - IntAnd { - output, - input0, - input1, - } => write!( - f, - "{} = {} & {}", - output.display(self.spaces)?, - input0.display(self.spaces)?, - input1.display(self.spaces)?, - ), - IntOr { - output, - input0, - input1, - } => write!( - f, - "{} = {} v {}", - output.display(self.spaces)?, - input0.display(self.spaces)?, - input1.display(self.spaces)?, - ), - IntXor { - output, - input0, - input1, - } => write!( - f, - "{} = {} ^ {}", - output.display(self.spaces)?, - input0.display(self.spaces)?, - input1.display(self.spaces)?, - ), - IntRightShift { - output, - input0, - input1, - } => write!( - f, - "{} = {} >> {}", - output.display(self.spaces)?, - input0.display(self.spaces)?, - input1.display(self.spaces)?, - ), - IntLeftShift { - output, - input0, - input1, - } => write!( - f, - "{} = {} << {}", - output.display(self.spaces)?, - input0.display(self.spaces)?, - input1.display(self.spaces)?, - ), - IntLess { - output, - input0, - input1, - } => write!( - f, - "{} = {} < {}", - output.display(self.spaces)?, - input0.display(self.spaces)?, - input1.display(self.spaces)?, - ), - IntLessEqual { - output, - input0, - input1, - } => write!( - f, - "{} = {} <= {}", - output.display(self.spaces)?, - input0.display(self.spaces)?, - input1.display(self.spaces)?, - ), - IntSignedLess { - output, - input0, - input1, - } => write!( - f, - "{} = {} s< {}", - output.display(self.spaces)?, - input0.display(self.spaces)?, - input1.display(self.spaces)?, - ), - IntSignedLessEqual { - output, - input0, - input1, - } => write!( - f, - "{} = {} s<= {}", - output.display(self.spaces)?, - input0.display(self.spaces)?, - input1.display(self.spaces)?, - ), - IntEqual { - output, - input0, - input1, - } => write!( - f, - "{} = {} == {}", - output.display(self.spaces)?, - input0.display(self.spaces)?, - input1.display(self.spaces)?, - ), - IntNotEqual { - output, - input0, - input1, - } => write!( - f, - "{} = {} != {}", - output.display(self.spaces)?, - input0.display(self.spaces)?, - input1.display(self.spaces)?, - ), - CallOther { output, inputs } => { - if let Some(output) = output { - write!(f, "{} = ", output.display(self.spaces)?)?; - } - write!(f, "userop(")?; - let mut args = Vec::with_capacity(inputs.len()); - for i in inputs { - args.push(format!("{}", i.display(self.spaces)?)); - } - write!(f, "{}", args.join(", "))?; - write!(f, ")") - } - CallInd { input } => write!(f, "call [{}]", input.display(self.spaces)?), - Return { input } => write!(f, "return [{}]", input.display(self.spaces)?), - Branch { input } => write!(f, "branch {}", input.display(self.spaces)?), - CBranch { input0, input1 } => write!( - f, - "if {} branch {}", - input1.display(self.spaces)?, - input0.display(self.spaces)? - ), - BranchInd { input } => write!(f, "branch [{}]", input.display(self.spaces)?), - Call { input } => write!(f, "call {}", input.display(self.spaces)?), - IntNegate { input, output } => write!( - f, - "{} = ~{}", - output.display(self.spaces)?, - input.display(self.spaces)? - ), - _ => write!(f, " {:?}", self.op), + if let Some(o) = self.op.output() { + write!(f, "{} = ", o.display(self.ctx)?)?; } + write!(f, "{} ", self.op.opcode())?; + let mut args: Vec = vec![]; + for x in self.op.inputs() { + args.push(format!("{}", x.display(self.ctx)?)); + } + write!(f, "{}", args.join(", "))?; + Ok(()) } } + + +impl Display for crate::ffi::opcode::bridge::OpCode{ + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let d = format!("{:?}", self); + write!(f, "{}", d[5..].to_string()) + } +} \ No newline at end of file diff --git a/jingle_sleigh/src/pcode/mod.rs b/jingle_sleigh/src/pcode/mod.rs index 4395bdb..58ac434 100644 --- a/jingle_sleigh/src/pcode/mod.rs +++ b/jingle_sleigh/src/pcode/mod.rs @@ -393,7 +393,7 @@ impl PcodeOperation { ) -> Result, JingleSleighError> { Ok(PcodeOperationDisplay { op: self.clone(), - spaces: ctx, + ctx: ctx, }) } From e14534ebcad25ab609319816187ecbea6617d682 Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 21 Oct 2024 11:56:08 +0100 Subject: [PATCH 115/146] fmt --- jingle/src/varnode/mod.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/jingle/src/varnode/mod.rs b/jingle/src/varnode/mod.rs index adbaca6..79b13a8 100644 --- a/jingle/src/varnode/mod.rs +++ b/jingle/src/varnode/mod.rs @@ -26,7 +26,10 @@ pub enum ResolvedVarnode<'ctx> { } impl<'ctx> ResolvedVarnode<'ctx> { - pub fn display(&self, ctx: &T) -> Result { + pub fn display( + &self, + ctx: &T, + ) -> Result { match self { ResolvedVarnode::Direct(d) => Ok(ResolvedVarNodeDisplay::Direct(d.display(ctx)?)), ResolvedVarnode::Indirect(i) => Ok(ResolvedVarNodeDisplay::Indirect( From 0084aa360b0c3319ef7953c71c621443652d9f38 Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 21 Oct 2024 11:57:27 +0100 Subject: [PATCH 116/146] clippy --- jingle_sleigh/src/context/image/gimli.rs | 4 ++-- jingle_sleigh/src/ffi/opcode.rs | 1 - jingle_sleigh/src/pcode/display.rs | 9 +-------- jingle_sleigh/src/pcode/mod.rs | 3 +-- 4 files changed, 4 insertions(+), 13 deletions(-) diff --git a/jingle_sleigh/src/context/image/gimli.rs b/jingle_sleigh/src/context/image/gimli.rs index 5b9c471..99a34be 100644 --- a/jingle_sleigh/src/context/image/gimli.rs +++ b/jingle_sleigh/src/context/image/gimli.rs @@ -15,7 +15,7 @@ impl<'a> From<&'a OwnedSection> for ImageSection<'a> { ImageSection { data: value.data.as_slice(), perms: value.perms.clone(), - base_address: value.base_address.clone(), + base_address: value.base_address, } } } @@ -64,7 +64,7 @@ impl ImageProvider for OwnedFile { let end_addr = max(min(input_end_addr, output_end_addr), start_addr); if end_addr > start_addr { let i_s = start_addr - x.base_address; - let i_e = end_addr - x.base_address as usize; + let i_e = end_addr - x.base_address; let o_s = start_addr - vn.offset as usize; let o_e = end_addr - vn.offset as usize; let out_slice = &mut output[o_s..o_e]; diff --git a/jingle_sleigh/src/ffi/opcode.rs b/jingle_sleigh/src/ffi/opcode.rs index 2fbec7c..6b071af 100644 --- a/jingle_sleigh/src/ffi/opcode.rs +++ b/jingle_sleigh/src/ffi/opcode.rs @@ -1,4 +1,3 @@ -use std::fmt::{Display, Formatter}; pub use bridge::OpCode; #[cxx::bridge] diff --git a/jingle_sleigh/src/pcode/display.rs b/jingle_sleigh/src/pcode/display.rs index 60165a7..2c8b936 100644 --- a/jingle_sleigh/src/pcode/display.rs +++ b/jingle_sleigh/src/pcode/display.rs @@ -1,11 +1,4 @@ use crate::pcode::PcodeOperation; -use crate::pcode::PcodeOperation::{ - Branch, BranchInd, CBranch, Call, CallInd, CallOther, Copy, Int2Comp, IntAdd, IntAnd, IntCarry, - IntEqual, IntLeftShift, IntLess, IntLessEqual, IntNegate, IntNotEqual, IntOr, IntRightShift, - IntSExt, IntSignedBorrow, IntSignedCarry, IntSignedLess, IntSignedLessEqual, IntSub, IntXor, - IntZExt, Load, PopCount, Return, Store, -}; -use crate::space::SpaceManager; use std::fmt::{Display, Formatter}; use crate::RegisterManager; @@ -38,6 +31,6 @@ impl<'a, T> Display for PcodeOperationDisplay<'a, T> impl Display for crate::ffi::opcode::bridge::OpCode{ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let d = format!("{:?}", self); - write!(f, "{}", d[5..].to_string()) + write!(f, "{}", &d[5..]) } } \ No newline at end of file diff --git a/jingle_sleigh/src/pcode/mod.rs b/jingle_sleigh/src/pcode/mod.rs index 58ac434..d0a7012 100644 --- a/jingle_sleigh/src/pcode/mod.rs +++ b/jingle_sleigh/src/pcode/mod.rs @@ -16,7 +16,6 @@ use crate::error::JingleSleighError; use crate::ffi::instruction::bridge::RawPcodeOp; pub use crate::ffi::opcode::OpCode; use crate::pcode::display::PcodeOperationDisplay; -use crate::space::SpaceManager; use crate::varnode::{IndirectVarNode, VarNode}; use crate::{GeneralizedVarNode, RegisterManager}; use serde::{Deserialize, Serialize}; @@ -393,7 +392,7 @@ impl PcodeOperation { ) -> Result, JingleSleighError> { Ok(PcodeOperationDisplay { op: self.clone(), - ctx: ctx, + ctx, }) } From 19b12c8318c571abb8fbbd87dd96626d4e5f827a Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 21 Oct 2024 11:57:38 +0100 Subject: [PATCH 117/146] fmt --- jingle_sleigh/src/context/image/gimli.rs | 10 +++++++--- jingle_sleigh/src/context/image/mod.rs | 16 ++++++++------- jingle_sleigh/src/context/loaded.rs | 12 +++++++----- jingle_sleigh/src/context/mod.rs | 2 +- jingle_sleigh/src/ffi/context_ffi.rs | 2 +- jingle_sleigh/src/ffi/opcode.rs | 1 - jingle_sleigh/src/pcode/display.rs | 11 +++++------ jingle_sleigh/src/varnode/display.rs | 17 +++++++++------- jingle_sleigh/src/varnode/mod.rs | 25 ++++++++++++++---------- 9 files changed, 55 insertions(+), 41 deletions(-) diff --git a/jingle_sleigh/src/context/image/gimli.rs b/jingle_sleigh/src/context/image/gimli.rs index 99a34be..f8b65f3 100644 --- a/jingle_sleigh/src/context/image/gimli.rs +++ b/jingle_sleigh/src/context/image/gimli.rs @@ -24,7 +24,10 @@ impl<'a, 'b> TryFrom> for OwnedSection { type Error = JingleSleighError; fn try_from(value: Section) -> Result { - let data = value.data().map_err(|_| JingleSleighError::ImageLoadError)?.to_vec(); + let data = value + .data() + .map_err(|_| JingleSleighError::ImageLoadError)? + .to_vec(); Ok(OwnedSection { data, perms: map_sec_kind(&value.kind()), @@ -41,7 +44,7 @@ pub struct OwnedFile { impl OwnedFile { pub fn new(file: &File) -> Result { let mut sections = vec![]; - for x in file.sections().filter(|f|f.kind() == SectionKind::Text) { + for x in file.sections().filter(|f| f.kind() == SectionKind::Text) { sections.push(x.try_into()?); } Ok(Self { sections }) @@ -78,7 +81,8 @@ impl ImageProvider for OwnedFile { fn has_full_range(&self, vn: &VarNode) -> bool { self.get_section_info().any(|s| { - s.base_address <= vn.offset as usize && (s.base_address + s.data.len()) >= (vn.offset as usize + vn.size) + s.base_address <= vn.offset as usize + && (s.base_address + s.data.len()) >= (vn.offset as usize + vn.size) }) } diff --git a/jingle_sleigh/src/context/image/mod.rs b/jingle_sleigh/src/context/image/mod.rs index 198bbbe..b5a70e1 100644 --- a/jingle_sleigh/src/context/image/mod.rs +++ b/jingle_sleigh/src/context/image/mod.rs @@ -14,16 +14,18 @@ pub trait ImageProvider { } pub struct ImageSectionIterator<'a> { - iter: Box> + 'a>, + iter: Box> + 'a>, } impl<'a> ImageSectionIterator<'a> { - pub(crate) fn new> + 'a>(iter: T) -> Self { - Self { iter: Box::new(iter) } + pub(crate) fn new> + 'a>(iter: T) -> Self { + Self { + iter: Box::new(iter), + } } } -impl<'a> Iterator for ImageSectionIterator<'a>{ +impl<'a> Iterator for ImageSectionIterator<'a> { type Item = ImageSection<'a>; fn next(&mut self) -> Option { @@ -138,12 +140,12 @@ pub struct ImageSection<'a> { } #[cfg(test)] -mod tests{ +mod tests { use crate::context::image::{ImageProvider, ImageSection}; #[test] - fn test_vec_sections(){ - let data: Vec = vec![1,2,3]; + fn test_vec_sections() { + let data: Vec = vec![1, 2, 3]; let sections: Vec = data.get_section_info().collect(); assert_ne!(sections, vec![]) } diff --git a/jingle_sleigh/src/context/loaded.rs b/jingle_sleigh/src/context/loaded.rs index 55dc4c3..8865a5e 100644 --- a/jingle_sleigh/src/context/loaded.rs +++ b/jingle_sleigh/src/context/loaded.rs @@ -1,3 +1,4 @@ +use crate::context::image::{ImageProvider, ImageSection}; use crate::context::instruction_iterator::SleighContextInstructionIterator; use crate::context::SleighContext; use crate::ffi::context_ffi::ImageFFI; @@ -6,7 +7,6 @@ use crate::{Instruction, JingleSleighError, RegisterManager, SpaceInfo, SpaceMan use std::fmt::{Debug, Formatter}; use std::ops::{Deref, DerefMut}; use std::pin::Pin; -use crate::context::image::{ImageProvider, ImageSection}; pub struct LoadedSleighContext<'a> { sleigh: SleighContext, @@ -40,7 +40,7 @@ impl<'a> LoadedSleighContext<'a> { let img = Box::pin(ImageFFI::new(img)); let mut s = Self { sleigh: sleigh_context, - img + img, }; let (ctx, img) = s.borrow_parts(); ctx.ctx @@ -79,7 +79,10 @@ impl<'a> LoadedSleighContext<'a> { SleighContextInstructionIterator::new(self, offset, max_instrs, true) } - pub fn set_image(&mut self, img: T) -> Result<(), JingleSleighError> { + pub fn set_image( + &mut self, + img: T, + ) -> Result<(), JingleSleighError> { let (sleigh, img_ref) = self.borrow_parts(); *img_ref = ImageFFI::new(img); sleigh @@ -89,14 +92,13 @@ impl<'a> LoadedSleighContext<'a> { .map_err(|_| ImageLoadError) } - pub fn get_sections(&self) -> impl Iterator { + pub fn get_sections(&self) -> impl Iterator { self.img.provider.get_section_info() } fn borrow_parts<'b>(&'b mut self) -> (&'b mut SleighContext, &'b mut ImageFFI<'a>) { (&mut self.sleigh, &mut self.img) } - } impl<'a> SpaceManager for LoadedSleighContext<'a> { diff --git a/jingle_sleigh/src/context/mod.rs b/jingle_sleigh/src/context/mod.rs index e83429e..62dff14 100644 --- a/jingle_sleigh/src/context/mod.rs +++ b/jingle_sleigh/src/context/mod.rs @@ -11,6 +11,7 @@ use crate::space::{RegisterManager, SpaceInfo, SpaceManager}; pub use builder::SleighContextBuilder; use crate::context::builder::language_def::LanguageDefinition; +use crate::context::image::ImageProvider; use crate::context::loaded::LoadedSleighContext; use crate::ffi::context_ffi::CTX_BUILD_MUTEX; use crate::JingleSleighError::{ImageLoadError, SleighCompilerMutexError}; @@ -18,7 +19,6 @@ use crate::VarNode; use cxx::{SharedPtr, UniquePtr}; use std::fmt::{Debug, Formatter}; use std::path::Path; -use crate::context::image::ImageProvider; pub struct SleighContext { ctx: UniquePtr, diff --git a/jingle_sleigh/src/ffi/context_ffi.rs b/jingle_sleigh/src/ffi/context_ffi.rs index d37f8fa..55f328f 100644 --- a/jingle_sleigh/src/ffi/context_ffi.rs +++ b/jingle_sleigh/src/ffi/context_ffi.rs @@ -1,4 +1,4 @@ -use crate::context::image::{ImageProvider}; +use crate::context::image::ImageProvider; use crate::ffi::context_ffi::bridge::makeContext; use crate::ffi::instruction::bridge::VarnodeInfoFFI; use crate::VarNode; diff --git a/jingle_sleigh/src/ffi/opcode.rs b/jingle_sleigh/src/ffi/opcode.rs index 6b071af..ffa27e1 100644 --- a/jingle_sleigh/src/ffi/opcode.rs +++ b/jingle_sleigh/src/ffi/opcode.rs @@ -165,4 +165,3 @@ pub(crate) mod bridge { } } - diff --git a/jingle_sleigh/src/pcode/display.rs b/jingle_sleigh/src/pcode/display.rs index 2c8b936..75f611e 100644 --- a/jingle_sleigh/src/pcode/display.rs +++ b/jingle_sleigh/src/pcode/display.rs @@ -1,6 +1,6 @@ use crate::pcode::PcodeOperation; -use std::fmt::{Display, Formatter}; use crate::RegisterManager; +use std::fmt::{Display, Formatter}; pub struct PcodeOperationDisplay<'a, T: RegisterManager> { pub(crate) op: PcodeOperation, @@ -10,8 +10,8 @@ pub struct PcodeOperationDisplay<'a, T: RegisterManager> { impl<'a, T: RegisterManager> PcodeOperationDisplay<'a, T> {} impl<'a, T> Display for PcodeOperationDisplay<'a, T> - where - T: RegisterManager, +where + T: RegisterManager, { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { if let Some(o) = self.op.output() { @@ -27,10 +27,9 @@ impl<'a, T> Display for PcodeOperationDisplay<'a, T> } } - -impl Display for crate::ffi::opcode::bridge::OpCode{ +impl Display for crate::ffi::opcode::bridge::OpCode { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let d = format!("{:?}", self); write!(f, "{}", &d[5..]) } -} \ No newline at end of file +} diff --git a/jingle_sleigh/src/varnode/display.rs b/jingle_sleigh/src/varnode/display.rs index 95eefb3..13c9267 100644 --- a/jingle_sleigh/src/varnode/display.rs +++ b/jingle_sleigh/src/varnode/display.rs @@ -3,9 +3,9 @@ use crate::space::SpaceInfo; use std::fmt::{Debug, Display, Formatter}; #[derive(Clone, Debug)] -pub enum VarNodeDisplay{ +pub enum VarNodeDisplay { Raw(RawVarNodeDisplay), - Register(String) + Register(String), } #[derive(Clone, Debug)] pub struct RawVarNodeDisplay { @@ -27,7 +27,7 @@ pub enum GeneralizedVarNodeDisplay { Indirect(IndirectVarNodeDisplay), } -impl Display for RawVarNodeDisplay{ +impl Display for RawVarNodeDisplay { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { if self.space_info._type == SpaceType::IPTR_CONSTANT { write!(f, "{:x}:{:x}", self.offset, self.size) @@ -42,11 +42,14 @@ impl Display for RawVarNodeDisplay{ } impl Display for VarNodeDisplay { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match self{ - VarNodeDisplay::Raw(r) => {write!(f, "{}", r)} - VarNodeDisplay::Register(a) => {write!(f, "{}", a)} + match self { + VarNodeDisplay::Raw(r) => { + write!(f, "{}", r) + } + VarNodeDisplay::Register(a) => { + write!(f, "{}", a) + } } - } } diff --git a/jingle_sleigh/src/varnode/mod.rs b/jingle_sleigh/src/varnode/mod.rs index ad92b8f..cfde425 100644 --- a/jingle_sleigh/src/varnode/mod.rs +++ b/jingle_sleigh/src/varnode/mod.rs @@ -7,10 +7,10 @@ use crate::space::SpaceManager; pub use crate::varnode::display::{ GeneralizedVarNodeDisplay, IndirectVarNodeDisplay, VarNodeDisplay, }; +use crate::{RawVarNodeDisplay, RegisterManager}; use serde::{Deserialize, Serialize}; use std::fmt::Debug; use std::ops::Range; -use crate::{RawVarNodeDisplay, RegisterManager}; /// A [`VarNode`] is `SLEIGH`'s generalization of an address. It describes a sized-location in /// a given memory space. @@ -35,17 +35,22 @@ pub struct VarNode { } impl VarNode { - pub fn display(&self, ctx: &T) -> Result { + pub fn display( + &self, + ctx: &T, + ) -> Result { if let Some(name) = ctx.get_register_name(self) { Ok(VarNodeDisplay::Register(name.to_string())) - }else{ - ctx.get_space_info(self.space_index) - .map(|space_info| VarNodeDisplay::Raw(RawVarNodeDisplay { - size: self.size, - offset: self.offset, - space_info: space_info.clone(), - })) - .ok_or(JingleSleighError::InvalidSpaceName) + } else { + ctx.get_space_info(self.space_index) + .map(|space_info| { + VarNodeDisplay::Raw(RawVarNodeDisplay { + size: self.size, + offset: self.offset, + space_info: space_info.clone(), + }) + }) + .ok_or(JingleSleighError::InvalidSpaceName) } } From 2acef2594c1e61dcb6340529a0c7bd171828048c Mon Sep 17 00:00:00 2001 From: Mark Date: Sun, 27 Oct 2024 12:04:36 +0000 Subject: [PATCH 118/146] Name tweak --- jingle_sleigh/src/ffi/addrspace.rs | 9 +++++---- jingle_sleigh/src/lib.rs | 1 + 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/jingle_sleigh/src/ffi/addrspace.rs b/jingle_sleigh/src/ffi/addrspace.rs index 566b8da..77f5d85 100644 --- a/jingle_sleigh/src/ffi/addrspace.rs +++ b/jingle_sleigh/src/ffi/addrspace.rs @@ -1,10 +1,10 @@ #[cxx::bridge] pub(crate) mod bridge { - #[rust_name = "SpaceType"] + #[cxx_name = "spacetype"] #[namespace = "ghidra"] #[derive(Debug, Hash, Clone, Copy, Eq, PartialEq, Serialize, Deserialize)] #[repr(u32)] - pub enum spacetype { + pub enum SpaceType { ///< Special space to represent constants IPTR_CONSTANT = 0, ///< Normal spaces modelled by processor @@ -37,9 +37,10 @@ pub(crate) mod bridge { } unsafe extern "C++" { + include!("jingle_sleigh/src/ffi/cpp/sleigh/space.hh"); #[namespace = "ghidra"] - #[rust_name = "SpaceType"] - type spacetype; + #[cxx_name = "spacetype"] + type SpaceType; } unsafe extern "C++" { diff --git a/jingle_sleigh/src/lib.rs b/jingle_sleigh/src/lib.rs index a247e55..a477805 100644 --- a/jingle_sleigh/src/lib.rs +++ b/jingle_sleigh/src/lib.rs @@ -1,3 +1,4 @@ + pub mod context; pub(crate) mod error; From 13c35da144a36c2b127089d6deccf64105b36af6 Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 30 Oct 2024 11:06:58 +0000 Subject: [PATCH 119/146] Add read_bytes --- jingle_sleigh/src/context/loaded.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/jingle_sleigh/src/context/loaded.rs b/jingle_sleigh/src/context/loaded.rs index 8865a5e..f7fca13 100644 --- a/jingle_sleigh/src/context/loaded.rs +++ b/jingle_sleigh/src/context/loaded.rs @@ -71,6 +71,14 @@ impl<'a> LoadedSleighContext<'a> { SleighContextInstructionIterator::new(self, offset, max_instrs, false) } + pub fn read_bytes(&self, vn: &VarNode) -> Option> { + if vn.space_index == self.get_code_space_idx() { + self.img.provider.get_bytes(vn) + } else { + None + } + } + pub fn read_until_branch( &self, offset: u64, From 0d3f6402ee46190d163b9049ebc52aa139172283 Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 30 Oct 2024 11:11:11 +0000 Subject: [PATCH 120/146] cherrypick get_bytes --- jingle_sleigh/src/context/image/mod.rs | 10 ++++++++++ jingle_sleigh/src/lib.rs | 1 - 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/jingle_sleigh/src/context/image/mod.rs b/jingle_sleigh/src/context/image/mod.rs index b5a70e1..194fd7e 100644 --- a/jingle_sleigh/src/context/image/mod.rs +++ b/jingle_sleigh/src/context/image/mod.rs @@ -11,6 +11,16 @@ pub trait ImageProvider { fn has_full_range(&self, vn: &VarNode) -> bool; fn get_section_info(&self) -> ImageSectionIterator; + + fn get_bytes(&self, vn: &VarNode) -> Option> { + let mut vec = vec![0u8; vn.size]; + let size = self.load(vn, &mut vec); + if size < vn.size { + None + } else { + Some(vec) + } + } } pub struct ImageSectionIterator<'a> { diff --git a/jingle_sleigh/src/lib.rs b/jingle_sleigh/src/lib.rs index a477805..a247e55 100644 --- a/jingle_sleigh/src/lib.rs +++ b/jingle_sleigh/src/lib.rs @@ -1,4 +1,3 @@ - pub mod context; pub(crate) mod error; From fad7e0fa0f59b4fd3929e4df95a10aced01dbe8f Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 1 Nov 2024 20:58:50 +0000 Subject: [PATCH 121/146] Add helper to summarize branches --- jingle_sleigh/src/pcode/branch.rs | 27 +++++++++++++++++++++++++++ jingle_sleigh/src/pcode/mod.rs | 1 + 2 files changed, 28 insertions(+) create mode 100644 jingle_sleigh/src/pcode/branch.rs diff --git a/jingle_sleigh/src/pcode/branch.rs b/jingle_sleigh/src/pcode/branch.rs new file mode 100644 index 0000000..06233cc --- /dev/null +++ b/jingle_sleigh/src/pcode/branch.rs @@ -0,0 +1,27 @@ +use crate::pcode::branch::PcodeBranchDestination::{ + Branch, Conditional, IndirectBranch, IndirectCall, Return, +}; +use crate::{IndirectVarNode, PcodeOperation, VarNode}; + +pub enum PcodeBranchDestination { + Branch(VarNode), + Call(VarNode), + Conditional(VarNode), + IndirectBranch(IndirectVarNode), + IndirectCall(IndirectVarNode), + Return(IndirectVarNode), +} +impl PcodeOperation { + pub fn branch_destination(&self) -> Option { + match self { + PcodeOperation::Branch { input } | PcodeOperation::Call { input } => { + Some(Branch(input.clone())) + } + PcodeOperation::CBranch { input0, .. } => Some(Conditional(input0.clone())), + PcodeOperation::BranchInd { input } => Some(IndirectBranch(input.clone())), + PcodeOperation::CallInd { input } => Some(IndirectCall(input.clone())), + PcodeOperation::Return { input } => Some(Return(input.clone())), + _ => None, + } + } +} diff --git a/jingle_sleigh/src/pcode/mod.rs b/jingle_sleigh/src/pcode/mod.rs index d0a7012..aa52ddc 100644 --- a/jingle_sleigh/src/pcode/mod.rs +++ b/jingle_sleigh/src/pcode/mod.rs @@ -1,4 +1,5 @@ pub mod display; +pub mod branch; use crate::pcode::PcodeOperation::{ BoolAnd, BoolNegate, BoolOr, BoolXor, Branch, BranchInd, CBranch, CPoolRef, Call, CallInd, From ed9566cb1fb9b60dc2c444fe515224ab79172344 Mon Sep 17 00:00:00 2001 From: toolCHAINZ Date: Mon, 4 Nov 2024 21:23:07 +0000 Subject: [PATCH 122/146] Update logo --- jingle.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jingle.svg b/jingle.svg index f0783f6..5b3ea25 100644 --- a/jingle.svg +++ b/jingle.svg @@ -1 +1 @@ - \ No newline at end of file + From e77167b9fd3d15b0e58e0c46dfdd9d072fff76e7 Mon Sep 17 00:00:00 2001 From: toolCHAINZ Date: Tue, 5 Nov 2024 00:16:16 +0000 Subject: [PATCH 123/146] Update jingle.svg --- jingle.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jingle.svg b/jingle.svg index 5b3ea25..3f9b4bf 100644 --- a/jingle.svg +++ b/jingle.svg @@ -1 +1 @@ - + From 0a6f667b2223fb1a7d7f9008073451bbd2c65203 Mon Sep 17 00:00:00 2001 From: chf0x <163881601+chf0x@users.noreply.github.com> Date: Wed, 13 Nov 2024 00:44:50 +0100 Subject: [PATCH 124/146] Made ImageSectionIterator::new pub This would allow users to implement ImageProvider trait for their datatypes --- jingle_sleigh/src/context/image/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jingle_sleigh/src/context/image/mod.rs b/jingle_sleigh/src/context/image/mod.rs index 194fd7e..0b27ca3 100644 --- a/jingle_sleigh/src/context/image/mod.rs +++ b/jingle_sleigh/src/context/image/mod.rs @@ -28,7 +28,7 @@ pub struct ImageSectionIterator<'a> { } impl<'a> ImageSectionIterator<'a> { - pub(crate) fn new> + 'a>(iter: T) -> Self { + pub fn new> + 'a>(iter: T) -> Self { Self { iter: Box::new(iter), } From 71f3ae74ca89b2729afbc231cfeda40bfe587b6f Mon Sep 17 00:00:00 2001 From: Mark Date: Sun, 17 Nov 2024 22:02:17 +0000 Subject: [PATCH 125/146] Target master branch of z3.rs --- jingle/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jingle/Cargo.toml b/jingle/Cargo.toml index e4a926d..332eac8 100644 --- a/jingle/Cargo.toml +++ b/jingle/Cargo.toml @@ -20,7 +20,7 @@ required-features = ["bin_features"] [dependencies] jingle_sleigh = { path = "../jingle_sleigh", version = "0.1.1" } -z3 = { git = "https://github.com/prove-rs/z3.rs.git", rev = "c126e07" } +z3 = { git = "https://github.com/prove-rs/z3.rs.git", branch = "master" } thiserror = "1.0.58" serde = { version = "1.0.197", features = ["derive"] } tracing = "0.1.40" From 4e4b842b53afb2b836a1d9f6c8ff75c578b1da05 Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 18 Nov 2024 09:45:14 +0000 Subject: [PATCH 126/146] Add rebasing API --- jingle_sleigh/src/context/loaded.rs | 119 +++++++++++++++++++++++++++- jingle_sleigh/src/pcode/mod.rs | 2 +- 2 files changed, 116 insertions(+), 5 deletions(-) diff --git a/jingle_sleigh/src/context/loaded.rs b/jingle_sleigh/src/context/loaded.rs index f7fca13..797b54d 100644 --- a/jingle_sleigh/src/context/loaded.rs +++ b/jingle_sleigh/src/context/loaded.rs @@ -8,9 +8,17 @@ use std::fmt::{Debug, Formatter}; use std::ops::{Deref, DerefMut}; use std::pin::Pin; +/// A guard type representing a sleigh context initialized with an image. +/// In addition to the methods in [SleighContext], is able to +/// query bytes for address ranges from its source image, as well +/// as ISA instructions (and associated `p-code`). pub struct LoadedSleighContext<'a> { + /// A handle to `sleigh`. By construction, this context is initialized with an image sleigh: SleighContext, + /// A handle to the image source being queried by the [SleighContext]. img: Pin>>, + /// The current virtual base address for the image loaded by this context. + base_offset: u64, } impl<'a> Debug for LoadedSleighContext<'a> { @@ -33,6 +41,9 @@ impl<'a> DerefMut for LoadedSleighContext<'a> { } impl<'a> LoadedSleighContext<'a> { + /// Consumes a [SleighContext] and an image provider, initializes + /// sleigh with the image provider, and combines them into a single + /// [LoadedSleigh*Context] guard value. pub(crate) fn new( sleigh_context: SleighContext, img: T, @@ -41,6 +52,7 @@ impl<'a> LoadedSleighContext<'a> { let mut s = Self { sleigh: sleigh_context, img, + base_offset: 0, }; let (ctx, img) = s.borrow_parts(); ctx.ctx @@ -49,7 +61,11 @@ impl<'a> LoadedSleighContext<'a> { .map_err(|_| ImageLoadError)?; Ok(s) } + /// Query `sleigh` for the instruction associated with the given offset in the default code + /// space. + /// todo: consider using a varnode instead of a raw offset. pub fn instruction_at(&self, offset: u64) -> Option { + let offset = self.adjust_base_address(offset); let instr = self .ctx .get_one_instruction(offset) @@ -67,26 +83,45 @@ impl<'a> LoadedSleighContext<'a> { } } + /// Read an iterator of at most `max_instrs` [`Instruction`]s from `offset` in the default code + /// space. + /// todo: consider using a varnode instead of a raw offset pub fn read(&self, offset: u64, max_instrs: usize) -> SleighContextInstructionIterator { - SleighContextInstructionIterator::new(self, offset, max_instrs, false) + SleighContextInstructionIterator::new( + self, + self.adjust_base_address(offset), + max_instrs, + false, + ) } + /// Read the byte range specified by the given [`VarNode`] from the configured image provider. pub fn read_bytes(&self, vn: &VarNode) -> Option> { if vn.space_index == self.get_code_space_idx() { - self.img.provider.get_bytes(vn) + self.img.provider.get_bytes(&self.adjust_varnode_vma(vn)) } else { None } } + /// Read an iterator of at most `max_instrs` [`Instruction`]s from `offset` in the default code + /// space, terminating if a branch is encountered. + /// todo: consider using a varnode instead of a raw offset pub fn read_until_branch( &self, offset: u64, max_instrs: usize, ) -> SleighContextInstructionIterator { - SleighContextInstructionIterator::new(self, offset, max_instrs, true) + SleighContextInstructionIterator::new( + self, + self.adjust_base_address(offset), + max_instrs, + true, + ) } + /// Re-initialize `sleigh` with a new image, without re-parsing the `.sla` definitions. This + /// is _much_ faster than generating a new context. pub fn set_image( &mut self, img: T, @@ -100,13 +135,40 @@ impl<'a> LoadedSleighContext<'a> { .map_err(|_| ImageLoadError) } + /// Returns an iterator of entries describing the sections of the configured image provider. pub fn get_sections(&self) -> impl Iterator { - self.img.provider.get_section_info() + self.img.provider.get_section_info().map(|mut s| { + s.base_address = s.base_address + self.base_offset as usize; + s + }) } fn borrow_parts<'b>(&'b mut self) -> (&'b mut SleighContext, &'b mut ImageFFI<'a>) { (&mut self.sleigh, &mut self.img) } + + /// Rebase the loaded image to `offset` + pub fn set_base_address(&mut self, offset: u64) { + self.base_offset = offset; + } + + /// Get the current base address + pub fn get_base_address(&self) -> u64 { + self.base_offset + } + + fn adjust_base_address(&self, offset: u64) -> u64 { + offset.wrapping_sub(self.base_offset) + } + + // todo: properly account for spaces with non-byte-based indexing + fn adjust_varnode_vma(&self, vn: &VarNode) -> VarNode { + VarNode { + space_index: vn.space_index, + size: vn.size, + offset: vn.offset.wrapping_sub(self.base_offset), + } + } } impl<'a> SpaceManager for LoadedSleighContext<'a> { @@ -136,3 +198,52 @@ impl<'a> RegisterManager for LoadedSleighContext<'a> { self.sleigh.get_registers() } } + +#[cfg(test)] +mod tests { + use crate::context::SleighContextBuilder; + use crate::tests::SLEIGH_ARCH; + use crate::VarNode; + + #[test] + fn test_adjust_vma() { + let ctx_builder = + SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); + let sleigh = ctx_builder.build(SLEIGH_ARCH).unwrap(); + let img: [u8; 5] = [0x55, 1, 2, 3, 4]; + let mut loaded = sleigh.initialize_with_image(img.as_slice()).unwrap(); + let first = loaded + .read_bytes(&VarNode { + space_index: 3, + size: 5, + offset: 0, + }) + .unwrap(); + assert_eq!(first.as_slice(), img.as_slice()); + let instr1 = loaded.instruction_at(0).unwrap(); + assert_eq!(instr1.disassembly.mnemonic, "PUSH"); + loaded.set_base_address(100); + assert!(loaded.instruction_at(0).is_none()); + assert_eq!( + loaded.read_bytes(&VarNode { + space_index: 3, + size: 5, + offset: 0 + }), + None + ); + let second = loaded + .read_bytes(&VarNode { + space_index: 3, + size: 5, + offset: 100, + }) + .unwrap(); + assert_eq!(second.as_slice(), img.as_slice()); + let instr2 = loaded.instruction_at(100).unwrap(); + assert_eq!(instr2.disassembly.mnemonic, "PUSH"); + for (a, b) in instr2.ops.iter().zip(instr1.ops) { + assert_eq!(a.opcode(), b.opcode()) + } + } +} diff --git a/jingle_sleigh/src/pcode/mod.rs b/jingle_sleigh/src/pcode/mod.rs index aa52ddc..356402d 100644 --- a/jingle_sleigh/src/pcode/mod.rs +++ b/jingle_sleigh/src/pcode/mod.rs @@ -1,5 +1,5 @@ -pub mod display; pub mod branch; +pub mod display; use crate::pcode::PcodeOperation::{ BoolAnd, BoolNegate, BoolOr, BoolXor, Branch, BranchInd, CBranch, CPoolRef, Call, CallInd, From f97eacfc9a22b24202bf6d5064ad0a695cfae2ba Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 18 Nov 2024 11:16:05 +0000 Subject: [PATCH 127/146] Fix rebasing API --- jingle_sleigh/src/context/loaded.rs | 37 +++++++++++++++++----------- jingle_sleigh/src/ffi/context_ffi.rs | 26 ++++++++++++++++--- 2 files changed, 46 insertions(+), 17 deletions(-) diff --git a/jingle_sleigh/src/context/loaded.rs b/jingle_sleigh/src/context/loaded.rs index 797b54d..45b8f8d 100644 --- a/jingle_sleigh/src/context/loaded.rs +++ b/jingle_sleigh/src/context/loaded.rs @@ -17,8 +17,6 @@ pub struct LoadedSleighContext<'a> { sleigh: SleighContext, /// A handle to the image source being queried by the [SleighContext]. img: Pin>>, - /// The current virtual base address for the image loaded by this context. - base_offset: u64, } impl<'a> Debug for LoadedSleighContext<'a> { @@ -52,7 +50,6 @@ impl<'a> LoadedSleighContext<'a> { let mut s = Self { sleigh: sleigh_context, img, - base_offset: 0, }; let (ctx, img) = s.borrow_parts(); ctx.ctx @@ -65,7 +62,6 @@ impl<'a> LoadedSleighContext<'a> { /// space. /// todo: consider using a varnode instead of a raw offset. pub fn instruction_at(&self, offset: u64) -> Option { - let offset = self.adjust_base_address(offset); let instr = self .ctx .get_one_instruction(offset) @@ -89,7 +85,7 @@ impl<'a> LoadedSleighContext<'a> { pub fn read(&self, offset: u64, max_instrs: usize) -> SleighContextInstructionIterator { SleighContextInstructionIterator::new( self, - self.adjust_base_address(offset), + offset, max_instrs, false, ) @@ -114,7 +110,7 @@ impl<'a> LoadedSleighContext<'a> { ) -> SleighContextInstructionIterator { SleighContextInstructionIterator::new( self, - self.adjust_base_address(offset), + offset, max_instrs, true, ) @@ -138,7 +134,7 @@ impl<'a> LoadedSleighContext<'a> { /// Returns an iterator of entries describing the sections of the configured image provider. pub fn get_sections(&self) -> impl Iterator { self.img.provider.get_section_info().map(|mut s| { - s.base_address = s.base_address + self.base_offset as usize; + s.base_address = s.base_address + self.get_base_address() as usize; s }) } @@ -149,16 +145,12 @@ impl<'a> LoadedSleighContext<'a> { /// Rebase the loaded image to `offset` pub fn set_base_address(&mut self, offset: u64) { - self.base_offset = offset; + self.img.set_base_address(offset); } /// Get the current base address pub fn get_base_address(&self) -> u64 { - self.base_offset - } - - fn adjust_base_address(&self, offset: u64) -> u64 { - offset.wrapping_sub(self.base_offset) + self.img.get_base_address() } // todo: properly account for spaces with non-byte-based indexing @@ -166,7 +158,7 @@ impl<'a> LoadedSleighContext<'a> { VarNode { space_index: vn.space_index, size: vn.size, - offset: vn.offset.wrapping_sub(self.base_offset), + offset: vn.offset.wrapping_sub(self.get_base_address()), } } } @@ -202,6 +194,7 @@ impl<'a> RegisterManager for LoadedSleighContext<'a> { #[cfg(test)] mod tests { use crate::context::SleighContextBuilder; + use crate::PcodeOperation::Branch; use crate::tests::SLEIGH_ARCH; use crate::VarNode; @@ -246,4 +239,20 @@ mod tests { assert_eq!(a.opcode(), b.opcode()) } } + + #[test] + pub fn relative_addresses(){ + let ctx_builder = + SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); + let sleigh = ctx_builder.build(SLEIGH_ARCH).unwrap(); + // JMP $+5 + let img: [u8; 2] = [0xeb, 0x05]; + let mut loaded = sleigh.initialize_with_image(img.as_slice()).unwrap(); + let instr = loaded.instruction_at(0).unwrap(); + assert_eq!(instr.ops[0], Branch {input: VarNode{ space_index: 3, size: 8, offset: 7}}); + loaded.set_base_address(0x100); + let instr2 = loaded.instruction_at(0x100).unwrap(); + assert_eq!(instr2.ops[0], Branch {input: VarNode{ space_index: 3, size: 8, offset: 0x107}}); + + } } diff --git a/jingle_sleigh/src/ffi/context_ffi.rs b/jingle_sleigh/src/ffi/context_ffi.rs index 55f328f..03ab254 100644 --- a/jingle_sleigh/src/ffi/context_ffi.rs +++ b/jingle_sleigh/src/ffi/context_ffi.rs @@ -59,20 +59,40 @@ pub(crate) mod bridge { pub(crate) struct ImageFFI<'a> { pub(crate) provider: Pin>, + /// The current virtual base address for the image loaded by this context. + pub(crate) base_offset: u64, } impl<'a> ImageFFI<'a> { pub(crate) fn new(provider: T) -> Self { Self { - provider: Box::pin(provider), + provider: Box::pin(provider), base_offset: 0 } } pub(crate) fn load(&self, vn: &VarnodeInfoFFI, out: &mut [u8]) -> usize { - self.provider.load(&VarNode::from(vn), out) + let addr = VarNode::from(vn); + let adjusted = self.adjust_varnode_vma(&addr); + self.provider.load(&adjusted, out) } pub(crate) fn has_range(&self, vn: &VarNode) -> bool { - self.provider.has_full_range(vn) + self.provider.has_full_range(&self.adjust_varnode_vma(vn)) + } + + pub(crate) fn get_base_address(&self) -> u64{ + self.base_offset + } + + pub(crate) fn set_base_address(&mut self, offset: u64){ + self.base_offset = offset + } + // todo: properly account for spaces with non-byte-based indexing + fn adjust_varnode_vma(&self, vn: &VarNode) -> VarNode { + VarNode { + space_index: vn.space_index, + size: vn.size, + offset: vn.offset.wrapping_sub(self.base_offset), + } } } From 1eb34550ff4cb80c1b26cdc131c5f7d423c45b41 Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 18 Nov 2024 18:44:24 +0000 Subject: [PATCH 128/146] Context refactor --- jingle/src/context.rs | 42 +++++++++++++--- jingle/src/lib.rs | 6 +++ jingle/src/main.rs | 2 +- jingle/src/modeling/block.rs | 26 +++++----- jingle/src/modeling/branch.rs | 12 ++--- jingle/src/modeling/instruction.rs | 19 ++++---- jingle/src/modeling/mod.rs | 63 ++++++++++++------------ jingle/src/modeling/slice.rs | 5 +- jingle/src/modeling/state/mod.rs | 78 ++++++++++++++++++------------ jingle/src/modeling/state/space.rs | 36 ++++++++++---- jingle/src/translator.rs | 8 +-- 11 files changed, 185 insertions(+), 112 deletions(-) diff --git a/jingle/src/context.rs b/jingle/src/context.rs index b983b3f..8142c3f 100644 --- a/jingle/src/context.rs +++ b/jingle/src/context.rs @@ -1,26 +1,41 @@ +use std::ops::Deref; +use std::rc::Rc; use crate::modeling::State; -use jingle_sleigh::{SpaceInfo, SpaceManager}; +use jingle_sleigh::{RegisterManager, SpaceInfo, SpaceManager, VarNode}; use z3::Context; #[derive(Clone, Debug)] -pub struct JingleContext<'ctx> { +pub struct JingleContextInternal<'ctx> { pub z3: &'ctx Context, spaces: Vec, default_code_space_index: usize, + registers: Vec<(VarNode, String)>, } +#[derive(Clone, Debug)] +pub struct JingleContext<'ctx>(Rc>); + + +impl<'ctx> Deref for JingleContext<'ctx>{ + type Target = JingleContextInternal<'ctx>; + + fn deref(&self) -> &Self::Target { + self.0.as_ref() + } +} impl<'ctx> JingleContext<'ctx> { - pub fn new(z3: &'ctx Context, r: &S) -> Self { + pub fn new(z3: &'ctx Context, r: &S) -> Self { let spaces = r.get_all_space_info().to_vec(); let default_code_space_index = r.get_code_space_idx(); - Self { + Self(Rc::new(JingleContextInternal { z3, spaces, default_code_space_index, - } + registers: r.get_registers(), + })) } pub fn fresh_state(&self) -> State<'ctx> { - State::new(self.z3, self) + State::new(self) } } @@ -37,3 +52,18 @@ impl<'ctx> SpaceManager for JingleContext<'ctx> { self.default_code_space_index } } + + +impl<'ctx> RegisterManager for JingleContext<'ctx> { + fn get_register(&self, name: &str) -> Option { + self.registers.iter().find_map(|i| i.1.eq(name).then_some(i.0.clone())) + } + + fn get_register_name(&self, location: &VarNode) -> Option<&str> { + self.registers.iter().find_map(|i| i.0.eq(location).then_some(i.1.as_str())) + } + + fn get_registers(&self) -> Vec<(VarNode, String)> { + self.registers.clone() + } +} \ No newline at end of file diff --git a/jingle/src/lib.rs b/jingle/src/lib.rs index 3deec73..97dcbea 100644 --- a/jingle/src/lib.rs +++ b/jingle/src/lib.rs @@ -9,3 +9,9 @@ pub use jingle_sleigh as sleigh; pub use context::JingleContext; pub use error::JingleError; pub use translator::SleighTranslator; + +#[cfg(test)] +mod tests{ + pub(crate) const SLEIGH_ARCH: &str = "x86:LE:64:default"; + +} \ No newline at end of file diff --git a/jingle/src/main.rs b/jingle/src/main.rs index b052b82..bf55744 100644 --- a/jingle/src/main.rs +++ b/jingle/src/main.rs @@ -174,7 +174,7 @@ fn model(config: &JingleConfig, architecture: String, hex_bytes: String) { }); let jingle_ctx = JingleContext::new(&z3, &sleigh); - let block = ModeledBlock::read(&z3, &sleigh, instrs.into_iter()).unwrap(); + let block = ModeledBlock::read(&jingle_ctx, instrs.into_iter()).unwrap(); let final_state = jingle_ctx.fresh_state(); solver.assert(&final_state._eq(block.get_final_state()).unwrap().simplify()); println!("{}", solver.to_smt2()) diff --git a/jingle/src/modeling/block.rs b/jingle/src/modeling/block.rs index 4b56f3a..4f62b98 100644 --- a/jingle/src/modeling/block.rs +++ b/jingle/src/modeling/block.rs @@ -5,17 +5,18 @@ use crate::modeling::state::State; use crate::modeling::{ModelingContext, TranslationContext}; use crate::varnode::ResolvedVarnode; use crate::JingleError::EmptyBlock; -use jingle_sleigh::Instruction; +use jingle_sleigh::{Instruction, RegisterManager, VarNode}; use jingle_sleigh::PcodeOperation; use jingle_sleigh::{SpaceInfo, SpaceManager}; use std::collections::HashSet; use std::fmt::{Display, Formatter}; use z3::Context; +use crate::JingleContext; /// A `jingle` model of a basic block #[derive(Debug, Clone)] pub struct ModeledBlock<'ctx> { - z3: &'ctx Context, + jingle: JingleContext<'ctx>, pub instructions: Vec, state: State<'ctx>, original_state: State<'ctx>, @@ -36,11 +37,11 @@ impl<'ctx> Display for ModeledBlock<'ctx> { impl<'ctx, T: ModelingContext<'ctx>> TryFrom<&'ctx [T]> for ModeledBlock<'ctx> { type Error = JingleError; fn try_from(vec: &'ctx [T]) -> Result { - let z3 = vec.first().ok_or(EmptyBlock)?.get_z3(); - let original_state = State::new(z3, vec[0].get_original_state()); + let jingle = vec.first().ok_or(EmptyBlock)?.get_jingle(); + let original_state = State::new(jingle); let state = original_state.clone(); let mut new_block: Self = Self { - z3, + jingle: jingle.clone(), instructions: Default::default(), state, original_state, @@ -61,12 +62,11 @@ impl<'ctx, T: ModelingContext<'ctx>> TryFrom<&'ctx [T]> for ModeledBlock<'ctx> { } impl<'ctx> ModeledBlock<'ctx> { - pub fn read, S: SpaceManager>( - z3: &'ctx Context, - space_manager: &S, + pub fn read>( + jingle: &JingleContext<'ctx>, instr_iter: T, ) -> Result { - let original_state = State::new(z3, space_manager); + let original_state = State::new(jingle); let state = original_state.clone(); let mut block_terminated = false; @@ -95,7 +95,7 @@ impl<'ctx> ModeledBlock<'ctx> { ); let mut model = Self { - z3, + jingle: jingle.clone(), instructions, state, original_state, @@ -110,7 +110,7 @@ impl<'ctx> ModeledBlock<'ctx> { } pub fn fresh(&self) -> Result { - ModeledBlock::read(self.z3, self, self.instructions.clone().into_iter()) + ModeledBlock::read(&self.jingle, self.instructions.clone().into_iter()) } pub fn get_first_address(&self) -> u64 { @@ -137,8 +137,8 @@ impl<'ctx> SpaceManager for ModeledBlock<'ctx> { } impl<'ctx> ModelingContext<'ctx> for ModeledBlock<'ctx> { - fn get_z3(&self) -> &'ctx Context { - self.z3 + fn get_jingle(&self) -> &JingleContext<'ctx> { + &self.jingle } fn get_address(&self) -> u64 { diff --git a/jingle/src/modeling/branch.rs b/jingle/src/modeling/branch.rs index ddcae87..d1f8bbc 100644 --- a/jingle/src/modeling/branch.rs +++ b/jingle/src/modeling/branch.rs @@ -29,7 +29,7 @@ impl BlockEndBehavior { ctx: &'a T, ) -> Result, JingleError> { match self { - Fallthrough(f) => Ok(BV::from_u64(ctx.get_z3(), 0, (f.size * 8) as u32)), + Fallthrough(f) => Ok(BV::from_u64(ctx.get_jingle().z3, 0, (f.size * 8) as u32)), UnconditionalBranch(b) => { match b { // Direct branch @@ -47,12 +47,12 @@ impl BlockEndBehavior { ctx: &'a T, ) -> Result, JingleError> { match self { - Fallthrough(f) => Ok(BV::from_u64(ctx.get_z3(), f.offset, (f.size * 8) as u32)), + Fallthrough(f) => Ok(BV::from_u64(ctx.get_jingle().z3, f.offset, (f.size * 8) as u32)), UnconditionalBranch(b) => { match b { // Direct branch GeneralizedVarNode::Direct(d) => { - Ok(BV::from_u64(ctx.get_z3(), d.offset, (d.size * 8) as u32)) + Ok(BV::from_u64(ctx.get_jingle().z3, d.offset, (d.size * 8) as u32)) } // Indirect branch, we want to only inspect the pointer GeneralizedVarNode::Indirect(i) => ctx @@ -104,14 +104,14 @@ impl BranchConstraint { .get_final_state() .read_varnode(&cond_branch.condition)? ._eq(&BV::from_i64( - ctx.get_z3(), + ctx.get_jingle().z3, 0, (cond_branch.condition.size * 8) as u32, )) .not(); let branch_dest = match &cond_branch.destination { GeneralizedVarNode::Direct(d) => { - BV::from_u64(ctx.get_z3(), d.offset, (d.size * 8) as u32) + BV::from_u64(ctx.get_jingle().z3, d.offset, (d.size * 8) as u32) } GeneralizedVarNode::Indirect(a) => ctx.get_final_state().read(a.into())?, }; @@ -130,7 +130,7 @@ impl BranchConstraint { .get_final_state() .read_varnode_metadata(&cond_branch.condition)? ._eq(&BV::from_i64( - ctx.get_z3(), + ctx.get_jingle().z3, 0, (&cond_branch.condition.size * 8) as u32, )) diff --git a/jingle/src/modeling/instruction.rs b/jingle/src/modeling/instruction.rs index 565a7e7..d88b829 100644 --- a/jingle/src/modeling/instruction.rs +++ b/jingle/src/modeling/instruction.rs @@ -8,14 +8,14 @@ use crate::modeling::branch::BranchConstraint; use crate::modeling::state::State; use crate::varnode::ResolvedVarnode; -use crate::JingleError; +use crate::{JingleContext, JingleError}; use jingle_sleigh::{SpaceInfo, SpaceManager}; use z3::Context; /// A `jingle` model of an individual SLEIGH instruction #[derive(Debug, Clone)] pub struct ModeledInstruction<'ctx> { - z3: &'ctx Context, + jingle: JingleContext<'ctx>, pub instr: Instruction, state: State<'ctx>, original_state: State<'ctx>, @@ -25,19 +25,18 @@ pub struct ModeledInstruction<'ctx> { } impl<'ctx> ModeledInstruction<'ctx> { - pub fn new( + pub fn new( instr: Instruction, - sleigh: &T, - z3: &'ctx Context, + jingle: &JingleContext<'ctx>, ) -> Result { - let original_state = State::new(z3, sleigh); + let original_state = State::new(jingle); let state = original_state.clone(); let next_vn = state.get_default_code_space_info().make_varnode( instr.next_addr(), state.get_default_code_space_info().index_size_bytes as usize, ); let mut model = Self { - z3, + jingle: jingle.clone(), instr, state, original_state, @@ -52,7 +51,7 @@ impl<'ctx> ModeledInstruction<'ctx> { } pub fn fresh(&self) -> Result { - ModeledInstruction::new(self.instr.clone(), self, self.z3) + ModeledInstruction::new(self.instr.clone(), &self.jingle) } } @@ -71,8 +70,8 @@ impl<'ctx> SpaceManager for ModeledInstruction<'ctx> { } impl<'ctx> ModelingContext<'ctx> for ModeledInstruction<'ctx> { - fn get_z3(&self) -> &'ctx Context { - self.z3 + fn get_jingle(&self) -> &JingleContext<'ctx> { + &self.jingle } fn get_address(&self) -> u64 { diff --git a/jingle/src/modeling/mod.rs b/jingle/src/modeling/mod.rs index bcc0521..fd12f23 100644 --- a/jingle/src/modeling/mod.rs +++ b/jingle/src/modeling/mod.rs @@ -22,6 +22,7 @@ pub use block::ModeledBlock; pub use branch::*; pub use instruction::ModeledInstruction; pub use state::State; +use crate::JingleContext; /// `jingle` models straight-line traces of computations. This trait represents all the information /// needed to model a given trace. @@ -29,8 +30,8 @@ pub use state::State; /// defines several helper functions for building formulae /// todo: this should probably be separated out with the extension trait pattern pub trait ModelingContext<'ctx>: SpaceManager + Debug + Sized { - /// Get a handle to the z3 context associated with this modeling context - fn get_z3(&self) -> &'ctx Context; + /// Get a handle to the jingle context associated with this modeling context + fn get_jingle(&self) -> &JingleContext<'ctx>; /// Get the address this context is associated with (e.g. for an instruction, it is the address, /// for a basic block, it is the address of the first instruction). @@ -110,7 +111,7 @@ pub trait ModelingContext<'ctx>: SpaceManager + Debug + Sized { } let p_terms: Vec<&Bool> = premise_terms.iter().collect(); - let premise = Bool::and(self.get_z3(), p_terms.as_slice()); + let premise = Bool::and(self.get_jingle().z3, p_terms.as_slice()); Ok(premise) } @@ -139,7 +140,7 @@ pub trait ModelingContext<'ctx>: SpaceManager + Debug + Sized { } } let imp_terms: Vec<&Bool> = output_terms.iter().collect(); - let outputs_pairwise_equal = Bool::and(self.get_z3(), imp_terms.as_slice()); + let outputs_pairwise_equal = Bool::and(self.get_jingle().z3, imp_terms.as_slice()); Ok(outputs_pairwise_equal) } @@ -172,7 +173,7 @@ pub trait ModelingContext<'ctx>: SpaceManager + Debug + Sized { zext_to_match(self_bv_metadata.simplify(), &other_bv_metadata.simplify()); let other_bv_metadata = zext_to_match(other_bv_metadata, &self_bv_metadata); Ok(Some(Bool::and( - self.get_z3(), + self.get_jingle().z3, &[ self_bv._eq(&other_bv).simplify(), self_bv_metadata._eq(&other_bv_metadata).simplify(), @@ -184,7 +185,7 @@ pub trait ModelingContext<'ctx>: SpaceManager + Debug + Sized { /// branch to the given [u64] fn can_branch_to_address(&self, addr: u64) -> Result, JingleError> { let branch_constraint = self.get_branch_constraint().build_bv(self)?; - let addr_bv = BV::from_i64(self.get_z3(), addr as i64, branch_constraint.get_size()); + let addr_bv = BV::from_i64(self.get_jingle().z3, addr as i64, branch_constraint.get_size()); Ok(branch_constraint._eq(&addr_bv)) } } @@ -458,8 +459,8 @@ pub(crate) trait TranslationContext<'ctx>: ModelingContext<'ctx> { // bool arg seems to be for whether this check is signed let carry_bool = in0.bvadd_no_overflow(&in1, false); let out_bv = carry_bool.ite( - &BV::from_i64(self.get_z3(), 0, 8), - &BV::from_i64(self.get_z3(), 1, 8), + &BV::from_i64(self.get_jingle().z3, 0, 8), + &BV::from_i64(self.get_jingle().z3, 1, 8), ); self.write(&output.into(), out_bv) } @@ -473,8 +474,8 @@ pub(crate) trait TranslationContext<'ctx>: ModelingContext<'ctx> { // bool arg seems to be for whether this check is signed let carry_bool = in0.bvadd_no_overflow(&in1, true); let out_bv = carry_bool.ite( - &BV::from_i64(self.get_z3(), 0, 8), - &BV::from_i64(self.get_z3(), 1, 8), + &BV::from_i64(self.get_jingle().z3, 0, 8), + &BV::from_i64(self.get_jingle().z3, 1, 8), ); self.write(&output.into(), out_bv) } @@ -489,8 +490,8 @@ pub(crate) trait TranslationContext<'ctx>: ModelingContext<'ctx> { // meaning of "overflow" is in sleigh vs what it means in z3 let borrow_bool = in0.bvsub_no_underflow(&in1, true); let out_bv = borrow_bool.ite( - &BV::from_i64(self.get_z3(), 0, 8), - &BV::from_i64(self.get_z3(), 1, 8), + &BV::from_i64(self.get_jingle().z3, 0, 8), + &BV::from_i64(self.get_jingle().z3, 1, 8), ); self.write(&output.into(), out_bv) } @@ -498,7 +499,7 @@ pub(crate) trait TranslationContext<'ctx>: ModelingContext<'ctx> { let in0 = self.read_and_track(input.into())?; let flipped = in0 .bvneg() - .add(BV::from_u64(self.get_z3(), 1, in0.get_size())); + .add(BV::from_u64(self.get_jingle().z3, 1, in0.get_size())); self.write(&output.into(), flipped) } PcodeOperation::IntSignedLess { @@ -510,8 +511,8 @@ pub(crate) trait TranslationContext<'ctx>: ModelingContext<'ctx> { let in1 = self.read_and_track(input1.into())?; let out_bool = in0.bvslt(&in1); let out_bv = out_bool.ite( - &BV::from_i64(self.get_z3(), 1, 8), - &BV::from_i64(self.get_z3(), 0, 8), + &BV::from_i64(self.get_jingle().z3, 1, 8), + &BV::from_i64(self.get_jingle().z3, 0, 8), ); self.write(&output.into(), out_bv) } @@ -524,8 +525,8 @@ pub(crate) trait TranslationContext<'ctx>: ModelingContext<'ctx> { let in1 = self.read_and_track(input1.into())?; let out_bool = in0.bvsle(&in1); let out_bv = out_bool.ite( - &BV::from_i64(self.get_z3(), 1, 8), - &BV::from_i64(self.get_z3(), 0, 8), + &BV::from_i64(self.get_jingle().z3, 1, 8), + &BV::from_i64(self.get_jingle().z3, 0, 8), ); self.write(&output.into(), out_bv) } @@ -538,8 +539,8 @@ pub(crate) trait TranslationContext<'ctx>: ModelingContext<'ctx> { let in1 = self.read_and_track(input1.into())?; let out_bool = in0.bvult(&in1); let out_bv = out_bool.ite( - &BV::from_i64(self.get_z3(), 1, 8), - &BV::from_i64(self.get_z3(), 0, 8), + &BV::from_i64(self.get_jingle().z3, 1, 8), + &BV::from_i64(self.get_jingle().z3, 0, 8), ); self.write(&output.into(), out_bv) } @@ -552,8 +553,8 @@ pub(crate) trait TranslationContext<'ctx>: ModelingContext<'ctx> { let in1 = self.read_and_track(input1.into())?; let out_bool = in0.bvule(&in1); let out_bv = out_bool.ite( - &BV::from_i64(self.get_z3(), 1, 8), - &BV::from_i64(self.get_z3(), 0, 8), + &BV::from_i64(self.get_jingle().z3, 1, 8), + &BV::from_i64(self.get_jingle().z3, 0, 8), ); self.write(&output.into(), out_bv) } @@ -567,8 +568,8 @@ pub(crate) trait TranslationContext<'ctx>: ModelingContext<'ctx> { let outsize = output.size as u32; let out_bool = in0._eq(&in1); let out_bv = out_bool.ite( - &BV::from_i64(self.get_z3(), 1, outsize * 8), - &BV::from_i64(self.get_z3(), 0, outsize * 8), + &BV::from_i64(self.get_jingle().z3, 1, outsize * 8), + &BV::from_i64(self.get_jingle().z3, 0, outsize * 8), ); self.write(&output.into(), out_bv) } @@ -582,8 +583,8 @@ pub(crate) trait TranslationContext<'ctx>: ModelingContext<'ctx> { let outsize = output.size as u32; let out_bool = in0._eq(&in1).not(); let out_bv = out_bool.ite( - &BV::from_i64(self.get_z3(), 1, outsize * 8), - &BV::from_i64(self.get_z3(), 0, outsize * 8), + &BV::from_i64(self.get_jingle().z3, 1, outsize * 8), + &BV::from_i64(self.get_jingle().z3, 0, outsize * 8), ); self.write(&output.into(), out_bv) } @@ -596,14 +597,14 @@ pub(crate) trait TranslationContext<'ctx>: ModelingContext<'ctx> { let i1 = self.read_and_track(input1.into())?; let result = i0 .bvand(&i1) - .bvand(&BV::from_u64(self.get_z3(), 1, i0.get_size())); + .bvand(&BV::from_u64(self.get_jingle().z3, 1, i0.get_size())); self.write(&output.into(), result) } PcodeOperation::BoolNegate { input, output } => { let val = self.read_and_track(input.into())?; let negated = val .bvneg() - .bvand(&BV::from_u64(self.get_z3(), 1, val.get_size())); + .bvand(&BV::from_u64(self.get_jingle().z3, 1, val.get_size())); self.write(&output.into(), negated) } PcodeOperation::BoolOr { @@ -615,7 +616,7 @@ pub(crate) trait TranslationContext<'ctx>: ModelingContext<'ctx> { let i1 = self.read_and_track(input1.into())?; let result = i0 .bvor(&i1) - .bvand(&BV::from_u64(self.get_z3(), 1, i0.get_size())); + .bvand(&BV::from_u64(self.get_jingle().z3, 1, i0.get_size())); self.write(&output.into(), result) } PcodeOperation::BoolXor { @@ -627,13 +628,13 @@ pub(crate) trait TranslationContext<'ctx>: ModelingContext<'ctx> { let i1 = self.read_and_track(input1.into())?; let result = i0 .bvxor(&i1) - .bvand(&BV::from_u64(self.get_z3(), 1, i0.get_size())); + .bvand(&BV::from_u64(self.get_jingle().z3, 1, i0.get_size())); self.write(&output.into(), result) } PcodeOperation::PopCount { input, output } => { let size = output.size as u32; let in0 = self.read_and_track(input.into())?; - let mut outbv = BV::from_i64(self.get_z3(), 0, output.size as u32 * 8); + let mut outbv = BV::from_i64(self.get_jingle().z3, 0, output.size as u32 * 8); for i in 0..size * 8 { let extract = in0.extract(i, i); let extend = extract.zero_ext((size * 8) - 1); @@ -715,7 +716,7 @@ pub(crate) trait TranslationContext<'ctx>: ModelingContext<'ctx> { self.get_branch_builder().set_last(&hash_vn.into()); if let Some(out) = output { let size = out.size * 8; - let hash_bv = BV::from_u64(self.get_z3(), hash, size as u32); + let hash_bv = BV::from_u64(self.get_jingle().z3, hash, size as u32); let metadata = self .get_final_state() .immediate_metadata_array(true, out.size); diff --git a/jingle/src/modeling/slice.rs b/jingle/src/modeling/slice.rs index ce24e67..14e92d9 100644 --- a/jingle/src/modeling/slice.rs +++ b/jingle/src/modeling/slice.rs @@ -3,10 +3,11 @@ use crate::varnode::ResolvedVarnode; use jingle_sleigh::PcodeOperation; use std::collections::HashSet; use z3::Context; +use crate::JingleContext; impl<'ctx, T: ModelingContext<'ctx>> ModelingContext<'ctx> for &[T] { - fn get_z3(&self) -> &'ctx Context { - self[0].get_z3() + fn get_jingle(&self) -> &JingleContext<'ctx> { + self[0].get_jingle() } fn get_address(&self) -> u64 { diff --git a/jingle/src/modeling/state/mod.rs b/jingle/src/modeling/state/mod.rs index 8d8b325..25091ab 100644 --- a/jingle/src/modeling/state/mod.rs +++ b/jingle/src/modeling/state/mod.rs @@ -8,49 +8,60 @@ use crate::error::JingleError::{ use crate::modeling::state::space::ModeledSpace; use crate::varnode::ResolvedVarnode; -use jingle_sleigh::{ - GeneralizedVarNode, IndirectVarNode, SpaceInfo, SpaceManager, SpaceType, VarNode, -}; +use jingle_sleigh::{GeneralizedVarNode, IndirectVarNode, RegisterManager, SpaceInfo, SpaceManager, SpaceType, VarNode}; use std::ops::Add; +use std::rc::Rc; use z3::ast::{Array, Ast, Bool, BV}; use z3::Context; +use crate::JingleContext; /// Represents the modeled combined memory state of the system. State /// is represented with Z3 formulas built up as select and store operations /// on an initial state #[derive(Clone, Debug)] pub struct State<'ctx> { - z3: &'ctx Context, - space_info: Vec, + jingle: JingleContext<'ctx>, spaces: Vec>, - default_code_space_index: usize, } impl<'ctx> SpaceManager for State<'ctx> { fn get_space_info(&self, idx: usize) -> Option<&SpaceInfo> { - self.space_info.get(idx) + self.jingle.get_space_info(idx) } fn get_all_space_info(&self) -> &[SpaceInfo] { - self.space_info.as_slice() + self.jingle.get_all_space_info() } fn get_code_space_idx(&self) -> usize { - self.default_code_space_index + self.jingle.get_code_space_idx() + } +} + +impl<'ctx> RegisterManager for State<'ctx> { + fn get_register(&self, name: &str) -> Option { + self.jingle.get_register(name) + } + + fn get_register_name(&self, location: &VarNode) -> Option<&str> { + self.jingle.get_register_name(location) + } + + fn get_registers(&self) -> Vec<(VarNode, String)> { + self.jingle.get_registers() } } impl<'ctx> State<'ctx> { - pub fn new(z3: &'ctx Context, other: &T) -> Self { + pub fn new(jingle: &JingleContext<'ctx>) -> Self { + let mut spaces: Vec = Default::default(); + for space_info in jingle.get_all_space_info() { + spaces.push(ModeledSpace::new(jingle, space_info)); + } let mut s: Self = Self { - z3, - space_info: other.get_all_space_info().to_vec(), + jingle: jingle.clone(), spaces: Default::default(), - default_code_space_index: other.get_code_space_idx(), }; - for space_info in other.get_all_space_info() { - s.spaces.push(ModeledSpace::new(s.z3, space_info)); - } s } @@ -67,13 +78,13 @@ impl<'ctx> State<'ctx> { .ok_or(UnmodeledSpace)?; match space._type { SpaceType::IPTR_CONSTANT => Ok(BV::from_i64( - self.z3, + self.jingle.z3, varnode.offset as i64, (varnode.size * 8) as u32, )), _ => { let offset = - BV::from_i64(self.z3, varnode.offset as i64, space.index_size_bytes * 8); + BV::from_i64(self.jingle.z3, varnode.offset as i64, space.index_size_bytes * 8); let arr = self.spaces.get(varnode.space_index).ok_or(UnmodeledSpace)?; arr.read_data(&offset, varnode.size) } @@ -85,7 +96,7 @@ impl<'ctx> State<'ctx> { .get_space_info(varnode.space_index) .ok_or(UnmodeledSpace)?; - let offset = BV::from_i64(self.z3, varnode.offset as i64, space.index_size_bytes * 8); + let offset = BV::from_i64(self.jingle.z3, varnode.offset as i64, space.index_size_bytes * 8); let arr = self.spaces.get(varnode.space_index).ok_or(UnmodeledSpace)?; arr.read_metadata(&offset, varnode.size) } @@ -151,7 +162,8 @@ impl<'ctx> State<'ctx> { if dest.size as u32 * 8 != val.get_size() { return Err(MismatchedWordSize); } - match self.space_info[dest.space_index]._type { + let info = self.jingle.get_space_info(dest.space_index).ok_or(UnmodeledSpace)?; + match info._type { SpaceType::IPTR_CONSTANT => Err(ConstantWrite), _ => { let space = self @@ -161,9 +173,9 @@ impl<'ctx> State<'ctx> { space.write_data( &val, &BV::from_u64( - self.z3, + self.jingle.z3, dest.offset, - self.space_info[dest.space_index].index_size_bytes * 8, + info.index_size_bytes * 8, ), )?; Ok(()) @@ -185,12 +197,14 @@ impl<'ctx> State<'ctx> { .spaces .get_mut(dest.space_index) .ok_or(UnmodeledSpace)?; + let info = self.jingle.get_space_info(dest.space_index).ok_or(UnmodeledSpace)?; + space.write_metadata( &val, &BV::from_u64( - self.z3, + self.jingle.z3, dest.offset, - self.space_info[dest.space_index].index_size_bytes * 8, + info.index_size_bytes * 8, ), )?; Ok(()) @@ -202,7 +216,9 @@ impl<'ctx> State<'ctx> { dest: &IndirectVarNode, val: BV<'ctx>, ) -> Result<(), JingleError> { - if self.space_info[dest.pointer_space_index]._type == SpaceType::IPTR_CONSTANT { + let info = self.jingle.get_space_info(dest.pointer_space_index).ok_or(UnmodeledSpace)?; + + if info._type == SpaceType::IPTR_CONSTANT { return Err(ConstantWrite); } let ptr = self.read_varnode(&dest.pointer_location)?; @@ -215,7 +231,9 @@ impl<'ctx> State<'ctx> { dest: &IndirectVarNode, val: BV<'ctx>, ) -> Result<(), JingleError> { - if self.space_info[dest.pointer_space_index]._type == SpaceType::IPTR_CONSTANT { + let info = self.jingle.get_space_info(dest.pointer_space_index).ok_or(UnmodeledSpace)?; + + if info._type == SpaceType::IPTR_CONSTANT { return Err(ConstantWrite); } let ptr = self.read_varnode(&dest.pointer_location)?; @@ -245,11 +263,11 @@ impl<'ctx> State<'ctx> { } pub fn get_default_code_space(&self) -> &Array<'ctx> { - self.spaces[self.default_code_space_index].get_space() + self.spaces[self.jingle.get_code_space_idx()].get_space() } pub fn get_default_code_space_info(&self) -> &SpaceInfo { - &self.space_info[self.default_code_space_index] + &self.jingle.get_space_info(self.jingle.get_code_space_idx()).unwrap() } pub(crate) fn immediate_metadata_array(&self, val: bool, s: usize) -> BV<'ctx> { @@ -258,7 +276,7 @@ impl<'ctx> State<'ctx> { false => 0, }; (0..s) - .map(|_| BV::from_u64(self.z3, val, 1)) + .map(|_| BV::from_u64(self.jingle.z3, val, 1)) .reduce(|a, b| a.concat(&b)) .map(|b| b.simplify()) .unwrap() @@ -277,6 +295,6 @@ impl<'ctx> State<'ctx> { terms.push(self_space._eq(other_space)) } let eq_terms: Vec<&Bool> = terms.iter().collect(); - Ok(Bool::and(self.z3, eq_terms.as_slice())) + Ok(Bool::and(self.jingle.z3, eq_terms.as_slice())) } } diff --git a/jingle/src/modeling/state/space.rs b/jingle/src/modeling/state/space.rs index 9969693..a343282 100644 --- a/jingle/src/modeling/state/space.rs +++ b/jingle/src/modeling/state/space.rs @@ -1,7 +1,8 @@ -use crate::JingleError; +use crate::{JingleContext, JingleError}; use crate::JingleError::{MismatchedAddressSize, UnexpectedArraySort, ZeroSizedVarnode}; use jingle_sleigh::{SleighEndianness, SpaceInfo}; use std::ops::Add; +use std::rc::Rc; use z3::ast::{Array, BV}; use z3::{Context, Sort}; @@ -23,13 +24,13 @@ pub(crate) struct ModeledSpace<'ctx> { impl<'ctx> ModeledSpace<'ctx> { /// Create a new modeling space with the given z3 context, using the provided space metadata - pub(crate) fn new(z3: &'ctx Context, space_info: &SpaceInfo) -> Self { - let domain = Sort::bitvector(z3, space_info.index_size_bytes * 8); - let range = Sort::bitvector(z3, space_info.word_size_bytes * 8); + pub(crate) fn new(jingle: &JingleContext<'ctx>, space_info: &SpaceInfo) -> Self { + let domain = Sort::bitvector(jingle.z3, space_info.index_size_bytes * 8); + let range = Sort::bitvector(jingle.z3, space_info.word_size_bytes * 8); Self { endianness: space_info.endianness, - data: Array::fresh_const(z3, &space_info.name, &domain, &range), - metadata: Array::const_array(z3, &domain, &BV::from_u64(z3, 0, 1)), + data: Array::fresh_const(jingle.z3, &space_info.name, &domain, &range), + metadata: Array::const_array(jingle.z3, &domain, &BV::from_u64(jingle.z3, 0, 1)), space_info: space_info.clone(), } } @@ -137,8 +138,11 @@ mod tests { use jingle_sleigh::{SleighEndianness, SpaceInfo, SpaceType}; use z3::ast::{Ast, BV}; use z3::{Config, Context}; + use jingle_sleigh::context::SleighContextBuilder; + use crate::JingleContext; + use crate::tests::SLEIGH_ARCH; - fn make_space(z3: &Context, endianness: SleighEndianness) -> ModeledSpace { + fn make_space<'ctx>(z3: &JingleContext<'ctx>, endianness: SleighEndianness) -> ModeledSpace<'ctx> { let space_info = SpaceInfo { endianness, name: "ram".to_string(), @@ -150,8 +154,12 @@ mod tests { ModeledSpace::new(z3, &space_info) } fn test_endian_write(e: SleighEndianness) { + let ctx_builder = + SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); + let sleigh = ctx_builder.build(SLEIGH_ARCH).unwrap(); let z3 = Context::new(&Config::new()); - let mut space = make_space(&z3, e); + let jingle = JingleContext::new(&z3, &sleigh); + let mut space = make_space(&jingle, e); space .write_data( &BV::from_u64(&z3, 0xdead_beef, 32), @@ -173,8 +181,12 @@ mod tests { } fn test_endian_read(e: SleighEndianness) { + let ctx_builder = + SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); + let sleigh = ctx_builder.build(SLEIGH_ARCH).unwrap(); let z3 = Context::new(&Config::new()); - let mut space = make_space(&z3, e); + let jingle = JingleContext::new(&z3, &sleigh); + let mut space = make_space(&jingle, e); let byte_layout = match e { SleighEndianness::Big => [0xde, 0xad, 0xbe, 0xef], SleighEndianness::Little => [0xef, 0xbe, 0xad, 0xde], @@ -196,8 +208,12 @@ mod tests { } fn test_single_write(e: SleighEndianness) { + let ctx_builder = + SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); + let sleigh = ctx_builder.build(SLEIGH_ARCH).unwrap(); let z3 = Context::new(&Config::new()); - let mut space = make_space(&z3, e); + let jingle = JingleContext::new(&z3, &sleigh); + let mut space = make_space(&jingle, e); space .write_data(&BV::from_u64(&z3, 0x42, 8), &BV::from_u64(&z3, 0, 32)) .unwrap(); diff --git a/jingle/src/translator.rs b/jingle/src/translator.rs index 51fe35b..ae63ae3 100644 --- a/jingle/src/translator.rs +++ b/jingle/src/translator.rs @@ -6,20 +6,22 @@ use jingle_sleigh::context::loaded::LoadedSleighContext; use jingle_sleigh::JingleSleighError::InstructionDecode; use jingle_sleigh::SpaceManager; use z3::Context; +use crate::JingleContext; /// This type wraps z3 and a sleigh context and allows for both modeling instructions that /// sleigh context has already produced, or reading new instructions directly out of sleigh and /// modeling them in one go #[derive(Debug, Clone)] pub struct SleighTranslator<'ctx> { - z3_ctx: &'ctx Context, + jingle: JingleContext<'ctx>, sleigh: &'ctx LoadedSleighContext<'ctx>, } impl<'ctx> SleighTranslator<'ctx> { /// Make a new sleigh translator pub fn new(sleigh: &'ctx LoadedSleighContext, z3_ctx: &'ctx Context) -> Self { - Self { z3_ctx, sleigh } + let jingle = JingleContext::new(z3_ctx, sleigh); + Self { jingle, sleigh } } /// Ask sleigh to read one instruction from the given offset and attempt @@ -41,7 +43,7 @@ impl<'ctx> SleighTranslator<'ctx> { &self, instr: Instruction, ) -> Result, JingleError> { - ModeledInstruction::new(instr, self.sleigh, self.z3_ctx) + ModeledInstruction::new(instr, &self.jingle) } } From 450238a22fda504e74d2607b91f45069398a424e Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 22 Nov 2024 10:16:30 +0000 Subject: [PATCH 129/146] Fix formatting --- jingle_sleigh/src/pcode/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jingle_sleigh/src/pcode/mod.rs b/jingle_sleigh/src/pcode/mod.rs index 356402d..e8ce24a 100644 --- a/jingle_sleigh/src/pcode/mod.rs +++ b/jingle_sleigh/src/pcode/mod.rs @@ -403,10 +403,10 @@ impl PcodeOperation { vec![input.into()] } Load { input, .. } => { - vec![input.into(), input.pointer_location.clone().into()] + vec![input.into()] } - Store { input, output } => { - vec![input.into(), output.pointer_location.clone().into()] + Store { input, .. } => { + vec![input.into()] } Branch { input, .. } => { vec![input.into()] From f13ab5d3623d622db9c3f2b63cd44f4d32e3b650 Mon Sep 17 00:00:00 2001 From: Mark Date: Sun, 24 Nov 2024 11:00:14 +0000 Subject: [PATCH 130/146] fmt --- jingle/src/context.rs | 18 +++++---- jingle/src/lib.rs | 5 +-- jingle/src/modeling/block.rs | 7 ++-- jingle/src/modeling/branch.rs | 14 +++++-- jingle/src/modeling/instruction.rs | 6 +-- jingle/src/modeling/mod.rs | 38 ++++++++++-------- jingle/src/modeling/slice.rs | 3 +- jingle/src/modeling/state/mod.rs | 64 ++++++++++++++++++------------ jingle/src/modeling/state/space.rs | 16 ++++---- jingle/src/translator.rs | 2 +- 10 files changed, 97 insertions(+), 76 deletions(-) diff --git a/jingle/src/context.rs b/jingle/src/context.rs index 8142c3f..9dff251 100644 --- a/jingle/src/context.rs +++ b/jingle/src/context.rs @@ -1,7 +1,7 @@ -use std::ops::Deref; -use std::rc::Rc; use crate::modeling::State; use jingle_sleigh::{RegisterManager, SpaceInfo, SpaceManager, VarNode}; +use std::ops::Deref; +use std::rc::Rc; use z3::Context; #[derive(Clone, Debug)] @@ -15,8 +15,7 @@ pub struct JingleContextInternal<'ctx> { #[derive(Clone, Debug)] pub struct JingleContext<'ctx>(Rc>); - -impl<'ctx> Deref for JingleContext<'ctx>{ +impl<'ctx> Deref for JingleContext<'ctx> { type Target = JingleContextInternal<'ctx>; fn deref(&self) -> &Self::Target { @@ -53,17 +52,20 @@ impl<'ctx> SpaceManager for JingleContext<'ctx> { } } - impl<'ctx> RegisterManager for JingleContext<'ctx> { fn get_register(&self, name: &str) -> Option { - self.registers.iter().find_map(|i| i.1.eq(name).then_some(i.0.clone())) + self.registers + .iter() + .find_map(|i| i.1.eq(name).then_some(i.0.clone())) } fn get_register_name(&self, location: &VarNode) -> Option<&str> { - self.registers.iter().find_map(|i| i.0.eq(location).then_some(i.1.as_str())) + self.registers + .iter() + .find_map(|i| i.0.eq(location).then_some(i.1.as_str())) } fn get_registers(&self) -> Vec<(VarNode, String)> { self.registers.clone() } -} \ No newline at end of file +} diff --git a/jingle/src/lib.rs b/jingle/src/lib.rs index 97dcbea..ec10ef6 100644 --- a/jingle/src/lib.rs +++ b/jingle/src/lib.rs @@ -11,7 +11,6 @@ pub use error::JingleError; pub use translator::SleighTranslator; #[cfg(test)] -mod tests{ +mod tests { pub(crate) const SLEIGH_ARCH: &str = "x86:LE:64:default"; - -} \ No newline at end of file +} diff --git a/jingle/src/modeling/block.rs b/jingle/src/modeling/block.rs index 4f62b98..61806bf 100644 --- a/jingle/src/modeling/block.rs +++ b/jingle/src/modeling/block.rs @@ -4,14 +4,13 @@ use crate::modeling::branch::BranchConstraint; use crate::modeling::state::State; use crate::modeling::{ModelingContext, TranslationContext}; use crate::varnode::ResolvedVarnode; +use crate::JingleContext; use crate::JingleError::EmptyBlock; -use jingle_sleigh::{Instruction, RegisterManager, VarNode}; use jingle_sleigh::PcodeOperation; +use jingle_sleigh::{Instruction}; use jingle_sleigh::{SpaceInfo, SpaceManager}; use std::collections::HashSet; use std::fmt::{Display, Formatter}; -use z3::Context; -use crate::JingleContext; /// A `jingle` model of a basic block #[derive(Debug, Clone)] @@ -62,7 +61,7 @@ impl<'ctx, T: ModelingContext<'ctx>> TryFrom<&'ctx [T]> for ModeledBlock<'ctx> { } impl<'ctx> ModeledBlock<'ctx> { - pub fn read>( + pub fn read>( jingle: &JingleContext<'ctx>, instr_iter: T, ) -> Result { diff --git a/jingle/src/modeling/branch.rs b/jingle/src/modeling/branch.rs index d1f8bbc..84a7089 100644 --- a/jingle/src/modeling/branch.rs +++ b/jingle/src/modeling/branch.rs @@ -47,13 +47,19 @@ impl BlockEndBehavior { ctx: &'a T, ) -> Result, JingleError> { match self { - Fallthrough(f) => Ok(BV::from_u64(ctx.get_jingle().z3, f.offset, (f.size * 8) as u32)), + Fallthrough(f) => Ok(BV::from_u64( + ctx.get_jingle().z3, + f.offset, + (f.size * 8) as u32, + )), UnconditionalBranch(b) => { match b { // Direct branch - GeneralizedVarNode::Direct(d) => { - Ok(BV::from_u64(ctx.get_jingle().z3, d.offset, (d.size * 8) as u32)) - } + GeneralizedVarNode::Direct(d) => Ok(BV::from_u64( + ctx.get_jingle().z3, + d.offset, + (d.size * 8) as u32, + )), // Indirect branch, we want to only inspect the pointer GeneralizedVarNode::Indirect(i) => ctx .get_final_state() diff --git a/jingle/src/modeling/instruction.rs b/jingle/src/modeling/instruction.rs index d88b829..ccb73f9 100644 --- a/jingle/src/modeling/instruction.rs +++ b/jingle/src/modeling/instruction.rs @@ -10,7 +10,6 @@ use crate::modeling::state::State; use crate::varnode::ResolvedVarnode; use crate::{JingleContext, JingleError}; use jingle_sleigh::{SpaceInfo, SpaceManager}; -use z3::Context; /// A `jingle` model of an individual SLEIGH instruction #[derive(Debug, Clone)] @@ -25,10 +24,7 @@ pub struct ModeledInstruction<'ctx> { } impl<'ctx> ModeledInstruction<'ctx> { - pub fn new( - instr: Instruction, - jingle: &JingleContext<'ctx>, - ) -> Result { + pub fn new(instr: Instruction, jingle: &JingleContext<'ctx>) -> Result { let original_state = State::new(jingle); let state = original_state.clone(); let next_vn = state.get_default_code_space_info().make_varnode( diff --git a/jingle/src/modeling/mod.rs b/jingle/src/modeling/mod.rs index fd12f23..a76bba5 100644 --- a/jingle/src/modeling/mod.rs +++ b/jingle/src/modeling/mod.rs @@ -18,11 +18,11 @@ mod instruction; mod slice; mod state; +use crate::JingleContext; pub use block::ModeledBlock; pub use branch::*; pub use instruction::ModeledInstruction; pub use state::State; -use crate::JingleContext; /// `jingle` models straight-line traces of computations. This trait represents all the information /// needed to model a given trace. @@ -185,7 +185,11 @@ pub trait ModelingContext<'ctx>: SpaceManager + Debug + Sized { /// branch to the given [u64] fn can_branch_to_address(&self, addr: u64) -> Result, JingleError> { let branch_constraint = self.get_branch_constraint().build_bv(self)?; - let addr_bv = BV::from_i64(self.get_jingle().z3, addr as i64, branch_constraint.get_size()); + let addr_bv = BV::from_i64( + self.get_jingle().z3, + addr as i64, + branch_constraint.get_size(), + ); Ok(branch_constraint._eq(&addr_bv)) } } @@ -497,9 +501,9 @@ pub(crate) trait TranslationContext<'ctx>: ModelingContext<'ctx> { } PcodeOperation::Int2Comp { input, output } => { let in0 = self.read_and_track(input.into())?; - let flipped = in0 - .bvneg() - .add(BV::from_u64(self.get_jingle().z3, 1, in0.get_size())); + let flipped = + in0.bvneg() + .add(BV::from_u64(self.get_jingle().z3, 1, in0.get_size())); self.write(&output.into(), flipped) } PcodeOperation::IntSignedLess { @@ -595,16 +599,16 @@ pub(crate) trait TranslationContext<'ctx>: ModelingContext<'ctx> { } => { let i0 = self.read_and_track(input0.into())?; let i1 = self.read_and_track(input1.into())?; - let result = i0 - .bvand(&i1) - .bvand(&BV::from_u64(self.get_jingle().z3, 1, i0.get_size())); + let result = + i0.bvand(&i1) + .bvand(&BV::from_u64(self.get_jingle().z3, 1, i0.get_size())); self.write(&output.into(), result) } PcodeOperation::BoolNegate { input, output } => { let val = self.read_and_track(input.into())?; - let negated = val - .bvneg() - .bvand(&BV::from_u64(self.get_jingle().z3, 1, val.get_size())); + let negated = + val.bvneg() + .bvand(&BV::from_u64(self.get_jingle().z3, 1, val.get_size())); self.write(&output.into(), negated) } PcodeOperation::BoolOr { @@ -614,9 +618,9 @@ pub(crate) trait TranslationContext<'ctx>: ModelingContext<'ctx> { } => { let i0 = self.read_and_track(input0.into())?; let i1 = self.read_and_track(input1.into())?; - let result = i0 - .bvor(&i1) - .bvand(&BV::from_u64(self.get_jingle().z3, 1, i0.get_size())); + let result = + i0.bvor(&i1) + .bvand(&BV::from_u64(self.get_jingle().z3, 1, i0.get_size())); self.write(&output.into(), result) } PcodeOperation::BoolXor { @@ -626,9 +630,9 @@ pub(crate) trait TranslationContext<'ctx>: ModelingContext<'ctx> { } => { let i0 = self.read_and_track(input0.into())?; let i1 = self.read_and_track(input1.into())?; - let result = i0 - .bvxor(&i1) - .bvand(&BV::from_u64(self.get_jingle().z3, 1, i0.get_size())); + let result = + i0.bvxor(&i1) + .bvand(&BV::from_u64(self.get_jingle().z3, 1, i0.get_size())); self.write(&output.into(), result) } PcodeOperation::PopCount { input, output } => { diff --git a/jingle/src/modeling/slice.rs b/jingle/src/modeling/slice.rs index 14e92d9..6dbf046 100644 --- a/jingle/src/modeling/slice.rs +++ b/jingle/src/modeling/slice.rs @@ -1,9 +1,8 @@ use crate::modeling::{BranchConstraint, ModelingContext, State}; use crate::varnode::ResolvedVarnode; +use crate::JingleContext; use jingle_sleigh::PcodeOperation; use std::collections::HashSet; -use z3::Context; -use crate::JingleContext; impl<'ctx, T: ModelingContext<'ctx>> ModelingContext<'ctx> for &[T] { fn get_jingle(&self) -> &JingleContext<'ctx> { diff --git a/jingle/src/modeling/state/mod.rs b/jingle/src/modeling/state/mod.rs index 25091ab..ffb2151 100644 --- a/jingle/src/modeling/state/mod.rs +++ b/jingle/src/modeling/state/mod.rs @@ -8,12 +8,13 @@ use crate::error::JingleError::{ use crate::modeling::state::space::ModeledSpace; use crate::varnode::ResolvedVarnode; -use jingle_sleigh::{GeneralizedVarNode, IndirectVarNode, RegisterManager, SpaceInfo, SpaceManager, SpaceType, VarNode}; +use crate::JingleContext; +use jingle_sleigh::{ + GeneralizedVarNode, IndirectVarNode, RegisterManager, SpaceInfo, SpaceManager, SpaceType, + VarNode, +}; use std::ops::Add; -use std::rc::Rc; use z3::ast::{Array, Ast, Bool, BV}; -use z3::Context; -use crate::JingleContext; /// Represents the modeled combined memory state of the system. State /// is represented with Z3 formulas built up as select and store operations @@ -58,11 +59,10 @@ impl<'ctx> State<'ctx> { for space_info in jingle.get_all_space_info() { spaces.push(ModeledSpace::new(jingle, space_info)); } - let mut s: Self = Self { + Self { jingle: jingle.clone(), spaces: Default::default(), - }; - s + } } pub fn get_space(&self, idx: usize) -> Result<&Array<'ctx>, JingleError> { @@ -83,8 +83,11 @@ impl<'ctx> State<'ctx> { (varnode.size * 8) as u32, )), _ => { - let offset = - BV::from_i64(self.jingle.z3, varnode.offset as i64, space.index_size_bytes * 8); + let offset = BV::from_i64( + self.jingle.z3, + varnode.offset as i64, + space.index_size_bytes * 8, + ); let arr = self.spaces.get(varnode.space_index).ok_or(UnmodeledSpace)?; arr.read_data(&offset, varnode.size) } @@ -96,7 +99,11 @@ impl<'ctx> State<'ctx> { .get_space_info(varnode.space_index) .ok_or(UnmodeledSpace)?; - let offset = BV::from_i64(self.jingle.z3, varnode.offset as i64, space.index_size_bytes * 8); + let offset = BV::from_i64( + self.jingle.z3, + varnode.offset as i64, + space.index_size_bytes * 8, + ); let arr = self.spaces.get(varnode.space_index).ok_or(UnmodeledSpace)?; arr.read_metadata(&offset, varnode.size) } @@ -162,7 +169,10 @@ impl<'ctx> State<'ctx> { if dest.size as u32 * 8 != val.get_size() { return Err(MismatchedWordSize); } - let info = self.jingle.get_space_info(dest.space_index).ok_or(UnmodeledSpace)?; + let info = self + .jingle + .get_space_info(dest.space_index) + .ok_or(UnmodeledSpace)?; match info._type { SpaceType::IPTR_CONSTANT => Err(ConstantWrite), _ => { @@ -172,11 +182,7 @@ impl<'ctx> State<'ctx> { .ok_or(UnmodeledSpace)?; space.write_data( &val, - &BV::from_u64( - self.jingle.z3, - dest.offset, - info.index_size_bytes * 8, - ), + &BV::from_u64(self.jingle.z3, dest.offset, info.index_size_bytes * 8), )?; Ok(()) } @@ -197,15 +203,14 @@ impl<'ctx> State<'ctx> { .spaces .get_mut(dest.space_index) .ok_or(UnmodeledSpace)?; - let info = self.jingle.get_space_info(dest.space_index).ok_or(UnmodeledSpace)?; + let info = self + .jingle + .get_space_info(dest.space_index) + .ok_or(UnmodeledSpace)?; space.write_metadata( &val, - &BV::from_u64( - self.jingle.z3, - dest.offset, - info.index_size_bytes * 8, - ), + &BV::from_u64(self.jingle.z3, dest.offset, info.index_size_bytes * 8), )?; Ok(()) } @@ -216,7 +221,10 @@ impl<'ctx> State<'ctx> { dest: &IndirectVarNode, val: BV<'ctx>, ) -> Result<(), JingleError> { - let info = self.jingle.get_space_info(dest.pointer_space_index).ok_or(UnmodeledSpace)?; + let info = self + .jingle + .get_space_info(dest.pointer_space_index) + .ok_or(UnmodeledSpace)?; if info._type == SpaceType::IPTR_CONSTANT { return Err(ConstantWrite); @@ -231,7 +239,10 @@ impl<'ctx> State<'ctx> { dest: &IndirectVarNode, val: BV<'ctx>, ) -> Result<(), JingleError> { - let info = self.jingle.get_space_info(dest.pointer_space_index).ok_or(UnmodeledSpace)?; + let info = self + .jingle + .get_space_info(dest.pointer_space_index) + .ok_or(UnmodeledSpace)?; if info._type == SpaceType::IPTR_CONSTANT { return Err(ConstantWrite); @@ -267,7 +278,10 @@ impl<'ctx> State<'ctx> { } pub fn get_default_code_space_info(&self) -> &SpaceInfo { - &self.jingle.get_space_info(self.jingle.get_code_space_idx()).unwrap() + self + .jingle + .get_space_info(self.jingle.get_code_space_idx()) + .unwrap() } pub(crate) fn immediate_metadata_array(&self, val: bool, s: usize) -> BV<'ctx> { diff --git a/jingle/src/modeling/state/space.rs b/jingle/src/modeling/state/space.rs index a343282..e75886a 100644 --- a/jingle/src/modeling/state/space.rs +++ b/jingle/src/modeling/state/space.rs @@ -1,10 +1,9 @@ -use crate::{JingleContext, JingleError}; use crate::JingleError::{MismatchedAddressSize, UnexpectedArraySort, ZeroSizedVarnode}; +use crate::{JingleContext, JingleError}; use jingle_sleigh::{SleighEndianness, SpaceInfo}; use std::ops::Add; -use std::rc::Rc; use z3::ast::{Array, BV}; -use z3::{Context, Sort}; +use z3::Sort; /// SLEIGH models programs using many spaces. This struct serves as a helper for modeling a single /// space. `jingle` uses an SMT Array sort to model a space. @@ -135,14 +134,17 @@ fn write_to_array<'ctx, const W: u32>( #[cfg(test)] mod tests { use crate::modeling::state::space::ModeledSpace; + use crate::tests::SLEIGH_ARCH; + use crate::JingleContext; + use jingle_sleigh::context::SleighContextBuilder; use jingle_sleigh::{SleighEndianness, SpaceInfo, SpaceType}; use z3::ast::{Ast, BV}; use z3::{Config, Context}; - use jingle_sleigh::context::SleighContextBuilder; - use crate::JingleContext; - use crate::tests::SLEIGH_ARCH; - fn make_space<'ctx>(z3: &JingleContext<'ctx>, endianness: SleighEndianness) -> ModeledSpace<'ctx> { + fn make_space<'ctx>( + z3: &JingleContext<'ctx>, + endianness: SleighEndianness, + ) -> ModeledSpace<'ctx> { let space_info = SpaceInfo { endianness, name: "ram".to_string(), diff --git a/jingle/src/translator.rs b/jingle/src/translator.rs index ae63ae3..01116b1 100644 --- a/jingle/src/translator.rs +++ b/jingle/src/translator.rs @@ -2,11 +2,11 @@ use crate::error::JingleError; use jingle_sleigh::{Instruction, RegisterManager, SpaceInfo, VarNode}; use crate::modeling::ModeledInstruction; +use crate::JingleContext; use jingle_sleigh::context::loaded::LoadedSleighContext; use jingle_sleigh::JingleSleighError::InstructionDecode; use jingle_sleigh::SpaceManager; use z3::Context; -use crate::JingleContext; /// This type wraps z3 and a sleigh context and allows for both modeling instructions that /// sleigh context has already produced, or reading new instructions directly out of sleigh and From ae1a9a6e6dd9d2a6ba2fa5fe53c07164e38d3296 Mon Sep 17 00:00:00 2001 From: Mark Date: Sun, 24 Nov 2024 11:07:19 +0000 Subject: [PATCH 131/146] Clippy --- jingle/src/modeling/mod.rs | 1 - jingle_sleigh/src/context/loaded.rs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/jingle/src/modeling/mod.rs b/jingle/src/modeling/mod.rs index a76bba5..69ceb61 100644 --- a/jingle/src/modeling/mod.rs +++ b/jingle/src/modeling/mod.rs @@ -10,7 +10,6 @@ use std::hash::{DefaultHasher, Hash, Hasher}; use std::ops::{Add, Neg}; use tracing::instrument; use z3::ast::{Ast, Bool, BV}; -use z3::Context; mod block; mod branch; diff --git a/jingle_sleigh/src/context/loaded.rs b/jingle_sleigh/src/context/loaded.rs index 45b8f8d..009bf4c 100644 --- a/jingle_sleigh/src/context/loaded.rs +++ b/jingle_sleigh/src/context/loaded.rs @@ -134,7 +134,7 @@ impl<'a> LoadedSleighContext<'a> { /// Returns an iterator of entries describing the sections of the configured image provider. pub fn get_sections(&self) -> impl Iterator { self.img.provider.get_section_info().map(|mut s| { - s.base_address = s.base_address + self.get_base_address() as usize; + s.base_address += self.get_base_address() as usize; s }) } From 9520912a5520ec059277b39d30bda8fdb0d57291 Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 26 Nov 2024 10:08:53 +0000 Subject: [PATCH 132/146] Only expose image bytes in the code space --- jingle/src/modeling/block.rs | 2 +- jingle/src/modeling/state/mod.rs | 3 +- jingle_sleigh/src/context/loaded.rs | 45 ++++++++++++++++------------ jingle_sleigh/src/ffi/context_ffi.rs | 22 ++++++++++---- 4 files changed, 45 insertions(+), 27 deletions(-) diff --git a/jingle/src/modeling/block.rs b/jingle/src/modeling/block.rs index 61806bf..c81366f 100644 --- a/jingle/src/modeling/block.rs +++ b/jingle/src/modeling/block.rs @@ -6,8 +6,8 @@ use crate::modeling::{ModelingContext, TranslationContext}; use crate::varnode::ResolvedVarnode; use crate::JingleContext; use crate::JingleError::EmptyBlock; +use jingle_sleigh::Instruction; use jingle_sleigh::PcodeOperation; -use jingle_sleigh::{Instruction}; use jingle_sleigh::{SpaceInfo, SpaceManager}; use std::collections::HashSet; use std::fmt::{Display, Formatter}; diff --git a/jingle/src/modeling/state/mod.rs b/jingle/src/modeling/state/mod.rs index ffb2151..af8554a 100644 --- a/jingle/src/modeling/state/mod.rs +++ b/jingle/src/modeling/state/mod.rs @@ -278,8 +278,7 @@ impl<'ctx> State<'ctx> { } pub fn get_default_code_space_info(&self) -> &SpaceInfo { - self - .jingle + self.jingle .get_space_info(self.jingle.get_code_space_idx()) .unwrap() } diff --git a/jingle_sleigh/src/context/loaded.rs b/jingle_sleigh/src/context/loaded.rs index 009bf4c..1c76254 100644 --- a/jingle_sleigh/src/context/loaded.rs +++ b/jingle_sleigh/src/context/loaded.rs @@ -46,7 +46,7 @@ impl<'a> LoadedSleighContext<'a> { sleigh_context: SleighContext, img: T, ) -> Result { - let img = Box::pin(ImageFFI::new(img)); + let img = Box::pin(ImageFFI::new(img, sleigh_context.get_code_space_idx())); let mut s = Self { sleigh: sleigh_context, img, @@ -83,12 +83,7 @@ impl<'a> LoadedSleighContext<'a> { /// space. /// todo: consider using a varnode instead of a raw offset pub fn read(&self, offset: u64, max_instrs: usize) -> SleighContextInstructionIterator { - SleighContextInstructionIterator::new( - self, - offset, - max_instrs, - false, - ) + SleighContextInstructionIterator::new(self, offset, max_instrs, false) } /// Read the byte range specified by the given [`VarNode`] from the configured image provider. @@ -108,12 +103,7 @@ impl<'a> LoadedSleighContext<'a> { offset: u64, max_instrs: usize, ) -> SleighContextInstructionIterator { - SleighContextInstructionIterator::new( - self, - offset, - max_instrs, - true, - ) + SleighContextInstructionIterator::new(self, offset, max_instrs, true) } /// Re-initialize `sleigh` with a new image, without re-parsing the `.sla` definitions. This @@ -123,7 +113,7 @@ impl<'a> LoadedSleighContext<'a> { img: T, ) -> Result<(), JingleSleighError> { let (sleigh, img_ref) = self.borrow_parts(); - *img_ref = ImageFFI::new(img); + *img_ref = ImageFFI::new(img, sleigh.get_code_space_idx()); sleigh .ctx .pin_mut() @@ -194,8 +184,8 @@ impl<'a> RegisterManager for LoadedSleighContext<'a> { #[cfg(test)] mod tests { use crate::context::SleighContextBuilder; - use crate::PcodeOperation::Branch; use crate::tests::SLEIGH_ARCH; + use crate::PcodeOperation::Branch; use crate::VarNode; #[test] @@ -241,7 +231,7 @@ mod tests { } #[test] - pub fn relative_addresses(){ + pub fn relative_addresses() { let ctx_builder = SleighContextBuilder::load_ghidra_installation("/Applications/ghidra").unwrap(); let sleigh = ctx_builder.build(SLEIGH_ARCH).unwrap(); @@ -249,10 +239,27 @@ mod tests { let img: [u8; 2] = [0xeb, 0x05]; let mut loaded = sleigh.initialize_with_image(img.as_slice()).unwrap(); let instr = loaded.instruction_at(0).unwrap(); - assert_eq!(instr.ops[0], Branch {input: VarNode{ space_index: 3, size: 8, offset: 7}}); + assert_eq!( + instr.ops[0], + Branch { + input: VarNode { + space_index: 3, + size: 8, + offset: 7 + } + } + ); loaded.set_base_address(0x100); let instr2 = loaded.instruction_at(0x100).unwrap(); - assert_eq!(instr2.ops[0], Branch {input: VarNode{ space_index: 3, size: 8, offset: 0x107}}); - + assert_eq!( + instr2.ops[0], + Branch { + input: VarNode { + space_index: 3, + size: 8, + offset: 0x107 + } + } + ); } } diff --git a/jingle_sleigh/src/ffi/context_ffi.rs b/jingle_sleigh/src/ffi/context_ffi.rs index 03ab254..687ae63 100644 --- a/jingle_sleigh/src/ffi/context_ffi.rs +++ b/jingle_sleigh/src/ffi/context_ffi.rs @@ -58,32 +58,44 @@ pub(crate) mod bridge { } pub(crate) struct ImageFFI<'a> { + /// A thing that has bytes at addresses pub(crate) provider: Pin>, /// The current virtual base address for the image loaded by this context. pub(crate) base_offset: u64, + /// The space that this image is attached to. For now, always the + /// default code space. + pub(crate) space_index: usize, } impl<'a> ImageFFI<'a> { - pub(crate) fn new(provider: T) -> Self { + pub(crate) fn new(provider: T, idx: usize) -> Self { Self { - provider: Box::pin(provider), base_offset: 0 + provider: Box::pin(provider), + base_offset: 0, + space_index: idx, } } pub(crate) fn load(&self, vn: &VarnodeInfoFFI, out: &mut [u8]) -> usize { let addr = VarNode::from(vn); + if addr.space_index != self.space_index { + return 0; + } let adjusted = self.adjust_varnode_vma(&addr); self.provider.load(&adjusted, out) } pub(crate) fn has_range(&self, vn: &VarNode) -> bool { + if vn.space_index != self.space_index { + return false; + } self.provider.has_full_range(&self.adjust_varnode_vma(vn)) } - pub(crate) fn get_base_address(&self) -> u64{ + pub(crate) fn get_base_address(&self) -> u64 { self.base_offset } - - pub(crate) fn set_base_address(&mut self, offset: u64){ + + pub(crate) fn set_base_address(&mut self, offset: u64) { self.base_offset = offset } // todo: properly account for spaces with non-byte-based indexing From 63ac5d48bf700256717a73e6161f37db716fe5f4 Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 26 Nov 2024 19:05:55 +0000 Subject: [PATCH 133/146] Blanket impl for ImageProvider --- jingle_sleigh/src/context/image/mod.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/jingle_sleigh/src/context/image/mod.rs b/jingle_sleigh/src/context/image/mod.rs index 0b27ca3..c339feb 100644 --- a/jingle_sleigh/src/context/image/mod.rs +++ b/jingle_sleigh/src/context/image/mod.rs @@ -105,6 +105,20 @@ impl ImageProvider for Vec { } } +impl ImageProvider for &T{ + fn load(&self, vn: &VarNode, output: &mut [u8]) -> usize { + (*self).load(vn, output) + } + + fn has_full_range(&self, vn: &VarNode) -> bool { + (*self).has_full_range(vn) + } + + fn get_section_info(&self) -> ImageSectionIterator { + (*self).get_section_info() + } +} + #[derive(Debug, Clone, PartialEq, Eq)] pub struct Perms { pub read: bool, From e4566cd18f2c2dfd8f1d73802c9bfb248bb61724 Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 26 Nov 2024 19:09:58 +0000 Subject: [PATCH 134/146] Fmt --- jingle_sleigh/src/context/image/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jingle_sleigh/src/context/image/mod.rs b/jingle_sleigh/src/context/image/mod.rs index c339feb..90435cd 100644 --- a/jingle_sleigh/src/context/image/mod.rs +++ b/jingle_sleigh/src/context/image/mod.rs @@ -105,7 +105,7 @@ impl ImageProvider for Vec { } } -impl ImageProvider for &T{ +impl ImageProvider for &T { fn load(&self, vn: &VarNode, output: &mut [u8]) -> usize { (*self).load(vn, output) } From 4d21670c043033b6173a23653bbd201270abf093 Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 27 Nov 2024 15:06:54 +0000 Subject: [PATCH 135/146] Fix spaces --- jingle/src/modeling/state/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jingle/src/modeling/state/mod.rs b/jingle/src/modeling/state/mod.rs index af8554a..53c5330 100644 --- a/jingle/src/modeling/state/mod.rs +++ b/jingle/src/modeling/state/mod.rs @@ -61,7 +61,7 @@ impl<'ctx> State<'ctx> { } Self { jingle: jingle.clone(), - spaces: Default::default(), + spaces, } } From 8a0d2d512e8ebf17fe3a4401b2bf91ac7a0207f0 Mon Sep 17 00:00:00 2001 From: toolCHAINZ Date: Wed, 27 Nov 2024 17:00:42 +0000 Subject: [PATCH 136/146] Bundle Zlib (#23) * Experiment with bundling zlib * Check if testing works in CI * Suppress warnings * Revert workflow change * Re-add all-features --- .github/workflows/check.yml | 2 +- jingle_sleigh/Cargo.toml | 1 - jingle_sleigh/build.rs | 59 ++++++++++++++++++++++------ jingle_sleigh/src/ffi/cpp/.gitignore | 3 +- jingle_sleigh/src/ffi/mod.rs | 5 --- 5 files changed, 51 insertions(+), 19 deletions(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 2997fb3..676e117 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -10,4 +10,4 @@ jobs: - uses: actions-rs/toolchain@v1 with: toolchain: stable - - run: cargo build --all-features + - run: cargo build --workspace --all-features diff --git a/jingle_sleigh/Cargo.toml b/jingle_sleigh/Cargo.toml index e6a95e9..792d39e 100644 --- a/jingle_sleigh/Cargo.toml +++ b/jingle_sleigh/Cargo.toml @@ -25,7 +25,6 @@ serde = { version = "1.0.203", features = ["derive"] } serde-xml-rs = "0.6.0" thiserror = { version = "1.0.61", features = [] } object = { version = "0.36.0", optional = true } -libz-sys = { version = "1.1.18", default-features = false, features = ["libc"] } tracing = "0.1.40" [build-dependencies] diff --git a/jingle_sleigh/build.rs b/jingle_sleigh/build.rs index 680790e..c36d42f 100644 --- a/jingle_sleigh/build.rs +++ b/jingle_sleigh/build.rs @@ -1,11 +1,11 @@ use std::fs; use std::fs::copy; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; fn main() { if cfg!(target_os = "macos") { println!("cargo::rustc-link-search=/opt/homebrew/lib") } - if !cpp_src_path().exists() { + if !sleigh_path().exists() | !zlib_path().exists() { let submod = submod_path(); if !submod.read_dir().is_ok_and(|f| f.count() != 0) { panic!( @@ -25,6 +25,13 @@ fn main() { ]; let cpp_sources = vec![ + "src/ffi/cpp/zlib/inflate.c", + "src/ffi/cpp/zlib/zutil.c", + "src/ffi/cpp/zlib/inftrees.c", + "src/ffi/cpp/zlib/inffast.c", + "src/ffi/cpp/zlib/adler32.c", + "src/ffi/cpp/zlib/trees.c", + "src/ffi/cpp/sleigh/address.cc", "src/ffi/cpp/sleigh/compression.cc", "src/ffi/cpp/sleigh/context.cc", @@ -60,7 +67,11 @@ fn main() { cxx_build::bridges(&rust_sources) .files(cpp_sources) .flag_if_supported("-std=c++17") - .flag_if_supported("-Dmain=c_main") + .flag_if_supported("-DLOCAL_ZLIB") + .flag_if_supported("-DNO_GZIP") + .flag_if_supported("-Wno-register") + .flag_if_supported("-Wno-deprecated") + .flag_if_supported("-Wno-unused-const-variable") .flag_if_supported("-Wno-unused-parameter") .flag_if_supported("-Wno-unused-function") .flag_if_supported("-Wno-unneeded-internal-declaration") @@ -79,25 +90,30 @@ fn main() { println!("cargo::rerun-if-changed=src/ffi/instruction.rs"); println!( "cargo::rerun-if-changed={}", - ghidra_cpp_path().to_str().unwrap() + ghidra_sleigh_path().to_str().unwrap() ); } fn copy_sources() { - fs::create_dir(cpp_src_path()).unwrap(); - for path in fs::read_dir(ghidra_cpp_path()).unwrap().flatten() { + copy_cpp_sources(ghidra_sleigh_path(), sleigh_path()); + copy_cpp_sources(ghidra_zlib_path(), zlib_path()); +} + +fn copy_cpp_sources,E: AsRef>(inpath: T, outpath: E){ + let _ = fs::create_dir(&outpath); + for path in fs::read_dir(inpath).unwrap().flatten() { if let Some(name) = path.file_name().to_str() { - if name.ends_with(".cc") || name.ends_with(".hh") || name.ends_with(".h") { - let mut result = cpp_src_path(); + if name.ends_with(".cc") || name.ends_with(".c") || name.ends_with(".hh") || name.ends_with(".h") { + let mut result = PathBuf::from(outpath.as_ref()); result.push(name); copy(path.path().as_path(), result.as_path()).unwrap(); - println!("Copying {}", name) + println!("Copying {} ({} => {})", name, path.path().to_str().unwrap(), result.to_str().unwrap()); } } } } -fn cpp_src_path() -> PathBuf { +fn sleigh_path() -> PathBuf { let mut p = PathBuf::new(); p.push("src"); p.push("ffi"); @@ -106,13 +122,22 @@ fn cpp_src_path() -> PathBuf { p } +fn zlib_path() -> PathBuf { + let mut p = PathBuf::new(); + p.push("src"); + p.push("ffi"); + p.push("cpp"); + p.push("zlib"); + p +} + fn submod_path() -> PathBuf { let mut p = PathBuf::new(); p.push("ghidra"); p } -fn ghidra_cpp_path() -> PathBuf { +fn ghidra_sleigh_path() -> PathBuf { let mut p = PathBuf::new(); p.push(submod_path()); p.push("Ghidra"); @@ -123,3 +148,15 @@ fn ghidra_cpp_path() -> PathBuf { p.push("cpp"); p } + +fn ghidra_zlib_path() -> PathBuf { + let mut p = PathBuf::new(); + p.push(submod_path()); + p.push("Ghidra"); + p.push("Features"); + p.push("Decompiler"); + p.push("src"); + p.push("decompile"); + p.push("zlib"); + p +} \ No newline at end of file diff --git a/jingle_sleigh/src/ffi/cpp/.gitignore b/jingle_sleigh/src/ffi/cpp/.gitignore index faa8791..c5401cf 100644 --- a/jingle_sleigh/src/ffi/cpp/.gitignore +++ b/jingle_sleigh/src/ffi/cpp/.gitignore @@ -1 +1,2 @@ -sleigh/** \ No newline at end of file +sleigh/** +zlib/** \ No newline at end of file diff --git a/jingle_sleigh/src/ffi/mod.rs b/jingle_sleigh/src/ffi/mod.rs index fd5fdaa..3b18d7d 100644 --- a/jingle_sleigh/src/ffi/mod.rs +++ b/jingle_sleigh/src/ffi/mod.rs @@ -3,11 +3,6 @@ pub(crate) mod context_ffi; pub(crate) mod instruction; pub(crate) mod opcode; -// Need to pull this in somewhere so that libz symbols are available -// for the `sleigh` CPP code at link-time. -#[allow(unused_imports)] -use libz_sys::inflate; - #[cfg(test)] mod tests { use crate::context::SleighContextBuilder; From a99e35e370f16062e31e8e5e9bd44259aa2409d2 Mon Sep 17 00:00:00 2001 From: toolCHAINZ Date: Wed, 27 Nov 2024 18:35:00 +0000 Subject: [PATCH 137/146] Multiplatform CI (#24) * Enforce Fmt and Lint in CI * Build jingle_sleigh on linux, macos, and windows * Build jingle on linux --- .github/workflows/check.yml | 13 ---- .github/workflows/jingle.yml | 54 ++++++++++++++++ .github/workflows/jingle_sleigh.yml | 63 +++++++++++++++++++ .github/workflows/style.yml | 38 +++++++++++ jingle/src/main.rs | 6 +- jingle_sleigh/Cargo.toml | 4 +- jingle_sleigh/build.rs | 31 ++++++--- jingle_sleigh/src/ffi/cpp/rust_load_image.cpp | 2 +- 8 files changed, 183 insertions(+), 28 deletions(-) delete mode 100644 .github/workflows/check.yml create mode 100644 .github/workflows/jingle.yml create mode 100644 .github/workflows/jingle_sleigh.yml create mode 100644 .github/workflows/style.yml diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml deleted file mode 100644 index 676e117..0000000 --- a/.github/workflows/check.yml +++ /dev/null @@ -1,13 +0,0 @@ -name: Check -on: [push] -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - with: - submodules: true - - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - - run: cargo build --workspace --all-features diff --git a/.github/workflows/jingle.yml b/.github/workflows/jingle.yml new file mode 100644 index 0000000..8d7dcf6 --- /dev/null +++ b/.github/workflows/jingle.yml @@ -0,0 +1,54 @@ +name: jingle + +on: + push: + branches: + - main + - dev + paths: + - jingle/** + - Cargo.lock + - Cargo.toml + pull_request: + paths: + - jingle/** + - Cargo.lock + - Cargo.toml + +jobs: + jingle-build-test: + name: Build jingle on Ubuntu + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + with: + submodules: true + - name: Set up Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + + - name: Cache Cargo registry + uses: actions/cache@v3 + with: + path: ~/.cargo/registry + key: ubuntu-cargo-registry-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ubuntu-cargo-registry- + + - name: Cache Cargo build + uses: actions/cache@v3 + with: + path: target + key: ubuntu-cargo-build-jingle-${{ hashFiles('jingle/**', 'Cargo.lock') }} + restore-keys: | + ubuntu-cargo-build-jingle- + + - name: Build jingle + run: cargo build --manifest-path jingle/Cargo.toml + +# - name: Test jingle +# run: cargo test --manifest-path jingle/Cargo.toml diff --git a/.github/workflows/jingle_sleigh.yml b/.github/workflows/jingle_sleigh.yml new file mode 100644 index 0000000..b431a63 --- /dev/null +++ b/.github/workflows/jingle_sleigh.yml @@ -0,0 +1,63 @@ +name: jingle_sleigh + +on: + push: + branches: + - main + - dev + paths: + - jingle_sleigh/** + - Cargo.lock + - Cargo.toml + pull_request: + paths: + - jingle_sleigh/** + - Cargo.lock + - Cargo.toml + +jobs: + jingle_sleigh-build-test: + name: Build jingle_sleigh on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + rust: [stable] + + steps: + - name: Checkout code + uses: actions/checkout@v3 + with: + submodules: true + - name: Install Dependencies (Windows Only) + if: matrix.os == 'windows-latest' + run: | + choco install -y llvm + + - name: Set up Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: ${{ matrix.rust }} + override: true + + - name: Cache Cargo registry + uses: actions/cache@v3 + with: + path: ~/.cargo/registry + key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo-registry- + + - name: Cache Cargo build + uses: actions/cache@v3 + with: + path: target + key: ${{ runner.os }}-cargo-build-jingle_sleigh-${{ hashFiles('jingle_sleigh/**', 'Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo-build-jingle_sleigh- + + - name: Build jingle_sleigh + run: cargo build --manifest-path jingle_sleigh/Cargo.toml + +# - name: Test jingle_sleigh +# run: cargo test --manifest-path jingle_sleigh/Cargo.toml diff --git a/.github/workflows/style.yml b/.github/workflows/style.yml new file mode 100644 index 0000000..4de7e40 --- /dev/null +++ b/.github/workflows/style.yml @@ -0,0 +1,38 @@ +name: Style + +on: + push: + branches: + - main + - dev + paths: + - '**/*.rs' + - Cargo.toml + - Cargo.lock + pull_request: + paths: + - '**/*.rs' + - Cargo.toml + - Cargo.lock + +jobs: + lint: + name: Fmt and Clippy + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + with: + submodules: true + - name: Set up Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + + - name: Check formatting with cargo fmt + run: cargo fmt --all -- --check + + - name: Check code with cargo clippy + run: cargo clippy --all-targets --all-features -- -D warnings diff --git a/jingle/src/main.rs b/jingle/src/main.rs index bf55744..1f4028d 100644 --- a/jingle/src/main.rs +++ b/jingle/src/main.rs @@ -23,7 +23,7 @@ impl JingleConfig { impl Default for JingleConfig { fn default() -> Self { - return if cfg!(target_os = "windows") { + if cfg!(target_os = "windows") { let path = PathBuf::from(r"C:\Program Files\ghidra"); Self { ghidra_path: path } } else if cfg!(target_os = "macos") { @@ -32,7 +32,7 @@ impl Default for JingleConfig { } else { let path = PathBuf::from(r"/opt/ghidra"); Self { ghidra_path: path } - }; + } } } @@ -41,7 +41,7 @@ impl From<&JingleParams> for JingleConfig { let path = value.ghidra_path.clone(); Self { ghidra_path: path - .map(|p| PathBuf::from(p)) + .map(PathBuf::from) .unwrap_or(JingleConfig::default().ghidra_path), } } diff --git a/jingle_sleigh/Cargo.toml b/jingle_sleigh/Cargo.toml index 792d39e..61f0126 100644 --- a/jingle_sleigh/Cargo.toml +++ b/jingle_sleigh/Cargo.toml @@ -20,7 +20,7 @@ include = [ # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -cxx = "1.0.122" +cxx = "1.0.131" serde = { version = "1.0.203", features = ["derive"] } serde-xml-rs = "0.6.0" thiserror = { version = "1.0.61", features = [] } @@ -28,7 +28,7 @@ object = { version = "0.36.0", optional = true } tracing = "0.1.40" [build-dependencies] -cxx-build = "1.0.122" +cxx-build = "1.0.131" [features] gimli = ["dep:object"] diff --git a/jingle_sleigh/build.rs b/jingle_sleigh/build.rs index c36d42f..b34c8f3 100644 --- a/jingle_sleigh/build.rs +++ b/jingle_sleigh/build.rs @@ -5,7 +5,7 @@ fn main() { if cfg!(target_os = "macos") { println!("cargo::rustc-link-search=/opt/homebrew/lib") } - if !sleigh_path().exists() | !zlib_path().exists() { + if !sleigh_path().exists() | !zlib_path().exists() { let submod = submod_path(); if !submod.read_dir().is_ok_and(|f| f.count() != 0) { panic!( @@ -31,7 +31,6 @@ fn main() { "src/ffi/cpp/zlib/inffast.c", "src/ffi/cpp/zlib/adler32.c", "src/ffi/cpp/zlib/trees.c", - "src/ffi/cpp/sleigh/address.cc", "src/ffi/cpp/sleigh/compression.cc", "src/ffi/cpp/sleigh/context.cc", @@ -64,7 +63,8 @@ fn main() { "src/ffi/cpp/jingle_assembly_emitter.cpp", ]; // This assumes all your C++ bindings are in lib - cxx_build::bridges(&rust_sources) + let mut bridge = cxx_build::bridges(&rust_sources); + bridge .files(cpp_sources) .flag_if_supported("-std=c++17") .flag_if_supported("-DLOCAL_ZLIB") @@ -78,8 +78,12 @@ fn main() { .flag_if_supported("-Wno-format") .flag_if_supported("-Wno-unused-but-set-variable") .flag_if_supported("-Wno-sign-compare") - .flag_if_supported("-Wno-deprecated-copy-with-user-provided-copy") - .compile("jingle_sleigh"); + .flag_if_supported("-Wno-deprecated-copy-with-user-provided-copy"); + + if cfg!(windows) { + bridge.flag_if_supported("-D_WINDOWS"); + } + bridge.compile("jingle_sleigh"); println!("cargo::rerun-if-changed=src/ffi/cpp/"); for src in rust_sources { @@ -99,15 +103,24 @@ fn copy_sources() { copy_cpp_sources(ghidra_zlib_path(), zlib_path()); } -fn copy_cpp_sources,E: AsRef>(inpath: T, outpath: E){ +fn copy_cpp_sources, E: AsRef>(inpath: T, outpath: E) { let _ = fs::create_dir(&outpath); for path in fs::read_dir(inpath).unwrap().flatten() { if let Some(name) = path.file_name().to_str() { - if name.ends_with(".cc") || name.ends_with(".c") || name.ends_with(".hh") || name.ends_with(".h") { + if name.ends_with(".cc") + || name.ends_with(".c") + || name.ends_with(".hh") + || name.ends_with(".h") + { let mut result = PathBuf::from(outpath.as_ref()); result.push(name); copy(path.path().as_path(), result.as_path()).unwrap(); - println!("Copying {} ({} => {})", name, path.path().to_str().unwrap(), result.to_str().unwrap()); + println!( + "Copying {} ({} => {})", + name, + path.path().to_str().unwrap(), + result.to_str().unwrap() + ); } } } @@ -159,4 +172,4 @@ fn ghidra_zlib_path() -> PathBuf { p.push("decompile"); p.push("zlib"); p -} \ No newline at end of file +} diff --git a/jingle_sleigh/src/ffi/cpp/rust_load_image.cpp b/jingle_sleigh/src/ffi/cpp/rust_load_image.cpp index 3d5abe1..15771e7 100644 --- a/jingle_sleigh/src/ffi/cpp/rust_load_image.cpp +++ b/jingle_sleigh/src/ffi/cpp/rust_load_image.cpp @@ -9,7 +9,7 @@ void RustLoadImage::loadFill(ghidra::uint1 *ptr, ghidra::int4 size, const ghidra::Address &addr) { ghidra::VarnodeData vn = {addr.getSpace(), addr.getOffset(), static_cast(size)}; - size_t result = img.load(varnodeToFFI(vn), rust::Slice(ptr, size)); + size_t result = img.load(varnodeToFFI(vn), rust::Slice(ptr, size)); if(result == 0){ ghidra::ostringstream errmsg; errmsg << "Unable to load " << std::dec << size << " bytes at " From f5d70da25b74ef58849c5424fa089d7ac46735ff Mon Sep 17 00:00:00 2001 From: Daniele Linguaglossa Date: Wed, 27 Nov 2024 23:34:13 +0100 Subject: [PATCH 138/146] Fix ldefs (#26) * fix ldef * return error if there are not ldefs * fix clippy --------- Co-authored-by: daniele.linguaglossa --- jingle_sleigh/src/context/builder/mod.rs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/jingle_sleigh/src/context/builder/mod.rs b/jingle_sleigh/src/context/builder/mod.rs index 7aa632b..0e39307 100644 --- a/jingle_sleigh/src/context/builder/mod.rs +++ b/jingle_sleigh/src/context/builder/mod.rs @@ -57,11 +57,15 @@ impl SleighContextBuilder { if !path.is_dir() { return Err(LanguageSpecRead); } - let ldef_path = find_ldef(&path)?; - let defs = parse_ldef(ldef_path.as_path())?; - let defs = defs + let ldef_paths = find_ldef(&path)?; + let defs: Vec<(LanguageDefinition, PathBuf)> = ldef_paths .iter() - .map(|f| (f.clone(), path.to_path_buf())) + .flat_map(|ldef_path| { + let defs: Vec = parse_ldef(ldef_path.as_path()).unwrap(); + defs.iter() + .map(|f| (f.clone(), path.to_path_buf())) + .collect::>() + }) .collect(); Ok(defs) } @@ -83,15 +87,19 @@ impl SleighContextBuilder { } } -fn find_ldef(path: &Path) -> Result { +fn find_ldef(path: &Path) -> Result, JingleSleighError> { + let mut ldefs = vec![]; for entry in (fs::read_dir(path).map_err(|_| LanguageSpecRead)?).flatten() { if let Some(e) = entry.path().extension() { if e == "ldefs" { - return Ok(entry.path().clone()); + ldefs.push(entry.path().clone()); } } } - Err(LanguageSpecRead) + if ldefs.is_empty() { + return Err(LanguageSpecRead); + } + Ok(ldefs) } #[cfg(test)] From f813d7c01cc7441b8fda675481b4de7287618875 Mon Sep 17 00:00:00 2001 From: toolCHAINZ Date: Mon, 2 Dec 2024 12:34:06 +0000 Subject: [PATCH 139/146] Additional CI refactor (#28) * Steal dtolnay's CI configuration --- .github/workflows/jingle.yml | 62 +++++--------- .github/workflows/jingle_sleigh.yml | 82 ++++++++----------- .github/workflows/style.yml | 46 +++++------ jingle/src/context.rs | 4 +- jingle/src/modeling/block.rs | 4 +- jingle/src/modeling/instruction.rs | 2 +- jingle/src/modeling/state/mod.rs | 4 +- jingle/src/translator.rs | 4 +- jingle/src/varnode/display.rs | 2 +- jingle/src/varnode/mod.rs | 2 +- jingle_sleigh/src/context/image/gimli.rs | 4 +- .../src/context/instruction_iterator.rs | 2 +- jingle_sleigh/src/context/loaded.rs | 10 +-- jingle_sleigh/src/ffi/context_ffi.rs | 7 +- jingle_sleigh/src/instruction.rs | 36 +------- jingle_sleigh/src/pcode/display.rs | 4 +- jingle_sleigh/src/space.rs | 1 - 17 files changed, 102 insertions(+), 174 deletions(-) diff --git a/.github/workflows/jingle.yml b/.github/workflows/jingle.yml index 8d7dcf6..bf4f6f8 100644 --- a/.github/workflows/jingle.yml +++ b/.github/workflows/jingle.yml @@ -2,53 +2,31 @@ name: jingle on: push: - branches: - - main - - dev - paths: - - jingle/** - - Cargo.lock - - Cargo.toml pull_request: - paths: - - jingle/** - - Cargo.lock - - Cargo.toml + workflow_dispatch: jobs: - jingle-build-test: - name: Build jingle on Ubuntu - runs-on: ubuntu-latest + pre_ci: + uses: dtolnay/.github/.github/workflows/pre_ci.yml@master + build: + name: ${{matrix.name || format('Rust {0}', matrix.rust)}} + needs: pre_ci + if: needs.pre_ci.outputs.continue + runs-on: ${{matrix.os}}-latest + strategy: + fail-fast: false + matrix: + rust: [nightly, beta, stable] + os: [ubuntu] + env: + RUSTFLAGS: --cfg deny_warnings -Dwarnings + timeout-minutes: 45 steps: - - name: Checkout code - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true - - name: Set up Rust - uses: actions-rs/toolchain@v1 + - uses: dtolnay/rust-toolchain@master with: - toolchain: stable - override: true - - - name: Cache Cargo registry - uses: actions/cache@v3 - with: - path: ~/.cargo/registry - key: ubuntu-cargo-registry-${{ hashFiles('**/Cargo.lock') }} - restore-keys: | - ubuntu-cargo-registry- - - - name: Cache Cargo build - uses: actions/cache@v3 - with: - path: target - key: ubuntu-cargo-build-jingle-${{ hashFiles('jingle/**', 'Cargo.lock') }} - restore-keys: | - ubuntu-cargo-build-jingle- - - - name: Build jingle - run: cargo build --manifest-path jingle/Cargo.toml - -# - name: Test jingle -# run: cargo test --manifest-path jingle/Cargo.toml + toolchain: ${{matrix.rust}} + - run: cargo build --all-features --manifest-path jingle_sleigh/Cargo.toml \ No newline at end of file diff --git a/.github/workflows/jingle_sleigh.yml b/.github/workflows/jingle_sleigh.yml index b431a63..68b2e5f 100644 --- a/.github/workflows/jingle_sleigh.yml +++ b/.github/workflows/jingle_sleigh.yml @@ -1,63 +1,45 @@ name: jingle_sleigh +# Stealing the multi-platform CI configuration from +# https://github.com/dtolnay/cxx/blob/master/.github/workflows/ci.yml +# for testing build using CXX. + on: push: - branches: - - main - - dev - paths: - - jingle_sleigh/** - - Cargo.lock - - Cargo.toml pull_request: - paths: - - jingle_sleigh/** - - Cargo.lock - - Cargo.toml + workflow_dispatch: jobs: - jingle_sleigh-build-test: - name: Build jingle_sleigh on ${{ matrix.os }} - runs-on: ${{ matrix.os }} + pre_ci: + uses: dtolnay/.github/.github/workflows/pre_ci.yml@master + + build: + name: ${{matrix.name || format('Rust {0}', matrix.rust)}} + needs: pre_ci + if: needs.pre_ci.outputs.continue + runs-on: ${{matrix.os}}-latest strategy: + fail-fast: false matrix: - os: [ubuntu-latest, macos-latest, windows-latest] - rust: [stable] - + rust: [nightly, stable] + os: [ubuntu] + include: + - name: Cargo on macOS + rust: nightly + os: macos + - name: Cargo on Windows (msvc) + rust: nightly-x86_64-pc-windows-msvc + os: windows + flags: /EHsc + env: + CXXFLAGS: ${{matrix.flags}} + RUSTFLAGS: --cfg deny_warnings -Dwarnings + timeout-minutes: 45 steps: - - name: Checkout code - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true - - name: Install Dependencies (Windows Only) - if: matrix.os == 'windows-latest' - run: | - choco install -y llvm - - - name: Set up Rust - uses: actions-rs/toolchain@v1 - with: - toolchain: ${{ matrix.rust }} - override: true - - - name: Cache Cargo registry - uses: actions/cache@v3 + - uses: dtolnay/rust-toolchain@master with: - path: ~/.cargo/registry - key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }} - restore-keys: | - ${{ runner.os }}-cargo-registry- - - - name: Cache Cargo build - uses: actions/cache@v3 - with: - path: target - key: ${{ runner.os }}-cargo-build-jingle_sleigh-${{ hashFiles('jingle_sleigh/**', 'Cargo.lock') }} - restore-keys: | - ${{ runner.os }}-cargo-build-jingle_sleigh- - - - name: Build jingle_sleigh - run: cargo build --manifest-path jingle_sleigh/Cargo.toml - -# - name: Test jingle_sleigh -# run: cargo test --manifest-path jingle_sleigh/Cargo.toml + toolchain: ${{matrix.rust}} + - run: cargo build --all-features --manifest-path jingle_sleigh/Cargo.toml \ No newline at end of file diff --git a/.github/workflows/style.yml b/.github/workflows/style.yml index 4de7e40..c353263 100644 --- a/.github/workflows/style.yml +++ b/.github/workflows/style.yml @@ -2,37 +2,35 @@ name: Style on: push: - branches: - - main - - dev - paths: - - '**/*.rs' - - Cargo.toml - - Cargo.lock pull_request: - paths: - - '**/*.rs' - - Cargo.toml - - Cargo.lock + workflow_dispatch: jobs: - lint: - name: Fmt and Clippy - runs-on: ubuntu-latest + pre_ci: + uses: dtolnay/.github/.github/workflows/pre_ci.yml@master + build: + name: ${{matrix.name || format('Rust {0}', matrix.rust)}} + needs: pre_ci + if: needs.pre_ci.outputs.continue + runs-on: ${{matrix.os}}-latest + strategy: + fail-fast: false + matrix: + rust: [ stable ] + os: [ ubuntu ] + env: + RUSTFLAGS: --cfg deny_warnings -Dwarnings + timeout-minutes: 45 steps: - - name: Checkout code - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true - - name: Set up Rust - uses: actions-rs/toolchain@v1 + - uses: dtolnay/rust-toolchain@master with: - toolchain: stable - override: true - - - name: Check formatting with cargo fmt + toolchain: ${{matrix.rust}} + components: clippy, rustfmt + - name: cargo fmt run: cargo fmt --all -- --check - - - name: Check code with cargo clippy + - name: cargo clippy run: cargo clippy --all-targets --all-features -- -D warnings diff --git a/jingle/src/context.rs b/jingle/src/context.rs index 9dff251..ae682c8 100644 --- a/jingle/src/context.rs +++ b/jingle/src/context.rs @@ -38,7 +38,7 @@ impl<'ctx> JingleContext<'ctx> { } } -impl<'ctx> SpaceManager for JingleContext<'ctx> { +impl SpaceManager for JingleContext<'_> { fn get_space_info(&self, idx: usize) -> Option<&SpaceInfo> { self.spaces.get(idx) } @@ -52,7 +52,7 @@ impl<'ctx> SpaceManager for JingleContext<'ctx> { } } -impl<'ctx> RegisterManager for JingleContext<'ctx> { +impl RegisterManager for JingleContext<'_> { fn get_register(&self, name: &str) -> Option { self.registers .iter() diff --git a/jingle/src/modeling/block.rs b/jingle/src/modeling/block.rs index c81366f..f1c5c15 100644 --- a/jingle/src/modeling/block.rs +++ b/jingle/src/modeling/block.rs @@ -24,7 +24,7 @@ pub struct ModeledBlock<'ctx> { outputs: HashSet>, } -impl<'ctx> Display for ModeledBlock<'ctx> { +impl Display for ModeledBlock<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { for x in self.instructions.iter() { writeln!(f, "{:x} {}", x.address, x.disassembly)?; @@ -122,7 +122,7 @@ impl<'ctx> ModeledBlock<'ctx> { } } -impl<'ctx> SpaceManager for ModeledBlock<'ctx> { +impl SpaceManager for ModeledBlock<'_> { fn get_space_info(&self, idx: usize) -> Option<&SpaceInfo> { self.state.get_space_info(idx) } diff --git a/jingle/src/modeling/instruction.rs b/jingle/src/modeling/instruction.rs index ccb73f9..613601a 100644 --- a/jingle/src/modeling/instruction.rs +++ b/jingle/src/modeling/instruction.rs @@ -51,7 +51,7 @@ impl<'ctx> ModeledInstruction<'ctx> { } } -impl<'ctx> SpaceManager for ModeledInstruction<'ctx> { +impl SpaceManager for ModeledInstruction<'_> { fn get_space_info(&self, idx: usize) -> Option<&SpaceInfo> { self.state.get_space_info(idx) } diff --git a/jingle/src/modeling/state/mod.rs b/jingle/src/modeling/state/mod.rs index 53c5330..4c3d13c 100644 --- a/jingle/src/modeling/state/mod.rs +++ b/jingle/src/modeling/state/mod.rs @@ -25,7 +25,7 @@ pub struct State<'ctx> { spaces: Vec>, } -impl<'ctx> SpaceManager for State<'ctx> { +impl SpaceManager for State<'_> { fn get_space_info(&self, idx: usize) -> Option<&SpaceInfo> { self.jingle.get_space_info(idx) } @@ -39,7 +39,7 @@ impl<'ctx> SpaceManager for State<'ctx> { } } -impl<'ctx> RegisterManager for State<'ctx> { +impl RegisterManager for State<'_> { fn get_register(&self, name: &str) -> Option { self.jingle.get_register(name) } diff --git a/jingle/src/translator.rs b/jingle/src/translator.rs index 01116b1..9b81bab 100644 --- a/jingle/src/translator.rs +++ b/jingle/src/translator.rs @@ -47,7 +47,7 @@ impl<'ctx> SleighTranslator<'ctx> { } } -impl<'ctx> SpaceManager for SleighTranslator<'ctx> { +impl SpaceManager for SleighTranslator<'_> { fn get_space_info(&self, idx: usize) -> Option<&SpaceInfo> { self.sleigh.get_space_info(idx) } @@ -61,7 +61,7 @@ impl<'ctx> SpaceManager for SleighTranslator<'ctx> { } } -impl<'ctx> RegisterManager for SleighTranslator<'ctx> { +impl RegisterManager for SleighTranslator<'_> { fn get_register(&self, name: &str) -> Option { self.sleigh.get_register(name) } diff --git a/jingle/src/varnode/display.rs b/jingle/src/varnode/display.rs index af88f6a..adde07e 100644 --- a/jingle/src/varnode/display.rs +++ b/jingle/src/varnode/display.rs @@ -15,7 +15,7 @@ pub enum ResolvedVarNodeDisplay<'ctx> { Indirect(ResolvedIndirectVarNodeDisplay<'ctx>), } -impl<'ctx> Display for ResolvedVarNodeDisplay<'ctx> { +impl Display for ResolvedVarNodeDisplay<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { ResolvedVarNodeDisplay::Direct(d) => d.fmt(f), diff --git a/jingle/src/varnode/mod.rs b/jingle/src/varnode/mod.rs index 79b13a8..59204d1 100644 --- a/jingle/src/varnode/mod.rs +++ b/jingle/src/varnode/mod.rs @@ -25,7 +25,7 @@ pub enum ResolvedVarnode<'ctx> { Indirect(ResolvedIndirectVarNode<'ctx>), } -impl<'ctx> ResolvedVarnode<'ctx> { +impl ResolvedVarnode<'_> { pub fn display( &self, ctx: &T, diff --git a/jingle_sleigh/src/context/image/gimli.rs b/jingle_sleigh/src/context/image/gimli.rs index f8b65f3..a2ac846 100644 --- a/jingle_sleigh/src/context/image/gimli.rs +++ b/jingle_sleigh/src/context/image/gimli.rs @@ -20,7 +20,7 @@ impl<'a> From<&'a OwnedSection> for ImageSection<'a> { } } -impl<'a, 'b> TryFrom> for OwnedSection { +impl TryFrom> for OwnedSection { type Error = JingleSleighError; fn try_from(value: Section) -> Result { @@ -91,7 +91,7 @@ impl ImageProvider for OwnedFile { } } -impl<'a> ImageProvider for File<'a> { +impl ImageProvider for File<'_> { fn load(&self, vn: &VarNode, output: &mut [u8]) -> usize { let mut written = 0; output.fill(0); diff --git a/jingle_sleigh/src/context/instruction_iterator.rs b/jingle_sleigh/src/context/instruction_iterator.rs index 2b2b612..09c5465 100644 --- a/jingle_sleigh/src/context/instruction_iterator.rs +++ b/jingle_sleigh/src/context/instruction_iterator.rs @@ -26,7 +26,7 @@ impl<'a> SleighContextInstructionIterator<'a> { } } -impl<'a> Iterator for SleighContextInstructionIterator<'a> { +impl Iterator for SleighContextInstructionIterator<'_> { type Item = Instruction; fn next(&mut self) -> Option { diff --git a/jingle_sleigh/src/context/loaded.rs b/jingle_sleigh/src/context/loaded.rs index 1c76254..adad049 100644 --- a/jingle_sleigh/src/context/loaded.rs +++ b/jingle_sleigh/src/context/loaded.rs @@ -19,12 +19,12 @@ pub struct LoadedSleighContext<'a> { img: Pin>>, } -impl<'a> Debug for LoadedSleighContext<'a> { +impl Debug for LoadedSleighContext<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { self.sleigh.fmt(f) } } -impl<'a> Deref for LoadedSleighContext<'a> { +impl Deref for LoadedSleighContext<'_> { type Target = SleighContext; fn deref(&self) -> &Self::Target { @@ -32,7 +32,7 @@ impl<'a> Deref for LoadedSleighContext<'a> { } } -impl<'a> DerefMut for LoadedSleighContext<'a> { +impl DerefMut for LoadedSleighContext<'_> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.sleigh } @@ -153,7 +153,7 @@ impl<'a> LoadedSleighContext<'a> { } } -impl<'a> SpaceManager for LoadedSleighContext<'a> { +impl SpaceManager for LoadedSleighContext<'_> { fn get_space_info(&self, idx: usize) -> Option<&SpaceInfo> { self.sleigh.get_space_info(idx) } @@ -167,7 +167,7 @@ impl<'a> SpaceManager for LoadedSleighContext<'a> { } } -impl<'a> RegisterManager for LoadedSleighContext<'a> { +impl RegisterManager for LoadedSleighContext<'_> { fn get_register(&self, name: &str) -> Option { self.sleigh.get_register(name) } diff --git a/jingle_sleigh/src/ffi/context_ffi.rs b/jingle_sleigh/src/ffi/context_ffi.rs index 687ae63..34264a4 100644 --- a/jingle_sleigh/src/ffi/context_ffi.rs +++ b/jingle_sleigh/src/ffi/context_ffi.rs @@ -1,3 +1,8 @@ +// This is necessary due to a change circa rust 1.83.0 that +// flags the lifetime in ImageFFI as needed for elision. +// Could probably be fixed with a change in CXX. +#![allow(clippy::needless_lifetimes)] + use crate::context::image::ImageProvider; use crate::ffi::context_ffi::bridge::makeContext; use crate::ffi::instruction::bridge::VarnodeInfoFFI; @@ -108,7 +113,7 @@ impl<'a> ImageFFI<'a> { } } -unsafe impl<'a> ExternType for ImageFFI<'a> { +unsafe impl ExternType for ImageFFI<'_> { type Id = cxx::type_id!("ImageFFI"); type Kind = cxx::kind::Opaque; } diff --git a/jingle_sleigh/src/instruction.rs b/jingle_sleigh/src/instruction.rs index 907b50e..28ff03b 100644 --- a/jingle_sleigh/src/instruction.rs +++ b/jingle_sleigh/src/instruction.rs @@ -1,12 +1,10 @@ use crate::error::JingleSleighError; pub use crate::ffi::instruction::bridge::Disassembly; use crate::ffi::instruction::bridge::InstructionFFI; -use crate::pcode::display::PcodeOperationDisplay; use crate::pcode::PcodeOperation; use crate::JingleSleighError::EmptyInstruction; -use crate::{OpCode, RegisterManager}; +use crate::OpCode; use serde::{Deserialize, Serialize}; -use std::fmt::{Display, Formatter}; /// A rust representation of a SLEIGH assembly instruction #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] @@ -21,28 +19,7 @@ pub struct Instruction { pub address: u64, } -/// A helper structure allowing displaying an instruction and its semantics -/// without requiring lots of pcode metadata to be stored in the instruction itself -pub struct InstructionDisplay<'a, T: RegisterManager> { - pub disassembly: Disassembly, - pub ops: Vec>, -} - impl Instruction { - pub fn display<'a, T: RegisterManager>( - &'a self, - ctx: &'a T, - ) -> Result, JingleSleighError> { - let mut ops: Vec> = Vec::with_capacity(self.ops.len()); - for x in &self.ops { - ops.push(x.display(ctx)?) - } - Ok(InstructionDisplay { - disassembly: self.disassembly.clone(), - ops, - }) - } - pub fn next_addr(&self) -> u64 { self.address + self.length as u64 } @@ -60,17 +37,6 @@ impl Instruction { .any(|o| o.opcode() == OpCode::CPUI_CALLOTHER) } } - -impl<'a, T: RegisterManager> Display for InstructionDisplay<'a, T> { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - writeln!(f, "{} {}", self.disassembly.mnemonic, self.disassembly.args)?; - for x in &self.ops { - writeln!(f, "{}", x)?; - } - Ok(()) - } -} - impl From for Instruction { fn from(value: InstructionFFI) -> Self { let ops = value.ops.into_iter().map(PcodeOperation::from).collect(); diff --git a/jingle_sleigh/src/pcode/display.rs b/jingle_sleigh/src/pcode/display.rs index 75f611e..5e0c470 100644 --- a/jingle_sleigh/src/pcode/display.rs +++ b/jingle_sleigh/src/pcode/display.rs @@ -7,9 +7,9 @@ pub struct PcodeOperationDisplay<'a, T: RegisterManager> { pub(crate) ctx: &'a T, } -impl<'a, T: RegisterManager> PcodeOperationDisplay<'a, T> {} +impl PcodeOperationDisplay<'_, T> {} -impl<'a, T> Display for PcodeOperationDisplay<'a, T> +impl Display for PcodeOperationDisplay<'_, T> where T: RegisterManager, { diff --git a/jingle_sleigh/src/space.rs b/jingle_sleigh/src/space.rs index 72421af..3bdb0d5 100644 --- a/jingle_sleigh/src/space.rs +++ b/jingle_sleigh/src/space.rs @@ -121,7 +121,6 @@ pub trait RegisterManager: SpaceManager { fn get_register(&self, name: &str) -> Option; /// Given a [`VarNode`], get the name of the corresponding architectural register, if one exists - fn get_register_name(&self, location: &VarNode) -> Option<&str>; /// Get a listing of all register name/[`VarNode`] pairs From 9e867d7321fba1518ddff7e18feaa6c334dd76a3 Mon Sep 17 00:00:00 2001 From: toolCHAINZ Date: Wed, 11 Dec 2024 21:59:14 +0000 Subject: [PATCH 140/146] Add deflate.c to compilation (#29) --- jingle_sleigh/build.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/jingle_sleigh/build.rs b/jingle_sleigh/build.rs index b34c8f3..5a2f9b8 100644 --- a/jingle_sleigh/build.rs +++ b/jingle_sleigh/build.rs @@ -26,6 +26,7 @@ fn main() { let cpp_sources = vec![ "src/ffi/cpp/zlib/inflate.c", + "src/ffi/cpp/zlib/deflate.c", "src/ffi/cpp/zlib/zutil.c", "src/ffi/cpp/zlib/inftrees.c", "src/ffi/cpp/zlib/inffast.c", @@ -51,8 +52,6 @@ fn main() { "src/ffi/cpp/sleigh/xml.cc", "src/ffi/cpp/sleigh/filemanage.cc", "src/ffi/cpp/sleigh/pcodecompile.cc", - "src/ffi/cpp/sleigh/slghscan.cc", - "src/ffi/cpp/sleigh/slghparse.cc", "src/ffi/cpp/context.cpp", "src/ffi/cpp/dummy_load_image.cpp", "src/ffi/cpp/rust_load_image.cpp", From fe182c33dce755e303166408fd5577e06424bf00 Mon Sep 17 00:00:00 2001 From: toolCHAINZ Date: Thu, 12 Dec 2024 19:26:57 +0000 Subject: [PATCH 141/146] Build tweak (#30) * Fix exception warning, reorganize build rs paths * Add zconf for windows build * Re-add flag * Needed more trees I guess --- jingle_sleigh/build.rs | 242 +++++++++++++++++--------- jingle_sleigh/src/ffi/cpp/exception.h | 2 +- 2 files changed, 156 insertions(+), 88 deletions(-) diff --git a/jingle_sleigh/build.rs b/jingle_sleigh/build.rs index 5a2f9b8..bcd0a79 100644 --- a/jingle_sleigh/build.rs +++ b/jingle_sleigh/build.rs @@ -1,6 +1,99 @@ use std::fs; use std::fs::copy; use std::path::{Path, PathBuf}; + +const SLEIGH_SOURCES: &[&str] = &[ + "address.cc", + "compression.cc", + "context.cc", + "globalcontext.cc", + "float.cc", + "marshal.cc", + "opcodes.cc", + "pcoderaw.cc", + "semantics.cc", + "slaformat.cc", + "sleigh.cc", + "sleighbase.cc", + "slghpatexpress.cc", + "slghpattern.cc", + "slghsymbol.cc", + "space.cc", + "translate.cc", + "xml.cc", + "filemanage.cc", + "pcodecompile.cc", +]; + +const SLEIGH_HEADERS: &[&str] = &[ + "address.hh", + "compression.hh", + "context.hh", + "error.hh", + "filemanage.hh", + "float.hh", + "globalcontext.hh", + "loadimage.hh", + "marshal.hh", + "opbehavior.hh", + "opcodes.hh", + "partmap.hh", + "pcodecompile.hh", + "pcoderaw.hh", + "semantics.hh", + "slaformat.hh", + "sleigh.hh", + "sleighbase.hh", + "slghpatexpress.hh", + "slghpattern.hh", + "slghsymbol.hh", + "space.hh", + "translate.hh", + "types.h", + "xml.hh", +]; + +const ZLIB_HEADERS: &[&str] = &[ + "deflate.h", + "gzguts.h", + "inffast.h", + "inffixed.h", + "inflate.h", + "inftrees.h", + "trees.h", + "zconf.h", + "zlib.h", + "zutil.h", +]; + +const ZLIB_SOURCES: &[&str] = &[ + "deflate.c", + "inflate.c", + "zutil.c", + "inftrees.c", + "inffast.c", + "trees.c", + "adler32.c", +]; + +const JINGLE_CPP_SOURCES: &[&str] = &[ + "context.cpp", + "dummy_load_image.cpp", + "rust_load_image.cpp", + "addrspace_handle.cpp", + "addrspace_manager_handle.cpp", + "varnode_translation.cpp", + "jingle_pcode_emitter.cpp", + "jingle_assembly_emitter.cpp", +]; + +const RUST_FFI_BRIDGES: &[&str] = &[ + "addrspace.rs", + "context_ffi.rs", + "instruction.rs", + "opcode.rs", +]; + fn main() { if cfg!(target_os = "macos") { println!("cargo::rustc-link-search=/opt/homebrew/lib") @@ -17,67 +110,35 @@ fn main() { copy_sources(); } - let rust_sources = vec![ - "src/ffi/addrspace.rs", - "src/ffi/context_ffi.rs", - "src/ffi/instruction.rs", - "src/ffi/opcode.rs", - ]; - - let cpp_sources = vec![ - "src/ffi/cpp/zlib/inflate.c", - "src/ffi/cpp/zlib/deflate.c", - "src/ffi/cpp/zlib/zutil.c", - "src/ffi/cpp/zlib/inftrees.c", - "src/ffi/cpp/zlib/inffast.c", - "src/ffi/cpp/zlib/adler32.c", - "src/ffi/cpp/zlib/trees.c", - "src/ffi/cpp/sleigh/address.cc", - "src/ffi/cpp/sleigh/compression.cc", - "src/ffi/cpp/sleigh/context.cc", - "src/ffi/cpp/sleigh/globalcontext.cc", - "src/ffi/cpp/sleigh/float.cc", - "src/ffi/cpp/sleigh/marshal.cc", - "src/ffi/cpp/sleigh/opcodes.cc", - "src/ffi/cpp/sleigh/pcoderaw.cc", - "src/ffi/cpp/sleigh/semantics.cc", - "src/ffi/cpp/sleigh/slaformat.cc", - "src/ffi/cpp/sleigh/sleigh.cc", - "src/ffi/cpp/sleigh/sleighbase.cc", - "src/ffi/cpp/sleigh/slghpatexpress.cc", - "src/ffi/cpp/sleigh/slghpattern.cc", - "src/ffi/cpp/sleigh/slghsymbol.cc", - "src/ffi/cpp/sleigh/space.cc", - "src/ffi/cpp/sleigh/translate.cc", - "src/ffi/cpp/sleigh/xml.cc", - "src/ffi/cpp/sleigh/filemanage.cc", - "src/ffi/cpp/sleigh/pcodecompile.cc", - "src/ffi/cpp/context.cpp", - "src/ffi/cpp/dummy_load_image.cpp", - "src/ffi/cpp/rust_load_image.cpp", - "src/ffi/cpp/addrspace_handle.cpp", - "src/ffi/cpp/addrspace_manager_handle.cpp", - "src/ffi/cpp/varnode_translation.cpp", - "src/ffi/cpp/jingle_pcode_emitter.cpp", - "src/ffi/cpp/jingle_assembly_emitter.cpp", - ]; + let map_path = |p: fn() -> PathBuf| { + move |s: &&str| { + let mut b = p(); + b.push(s); + b + } + }; + + let rust_bridges: Vec = RUST_FFI_BRIDGES.iter().map(map_path(ffi_rs_path)).collect(); + + let jingle_cpp_sources: Vec = JINGLE_CPP_SOURCES + .iter() + .map(map_path(ffi_cpp_path)) + .collect(); + + let sleigh_sources: Vec = SLEIGH_SOURCES.iter().map(map_path(sleigh_path)).collect(); + let zlib_sources: Vec = ZLIB_SOURCES.iter().map(map_path(zlib_path)).collect(); + // This assumes all your C++ bindings are in lib - let mut bridge = cxx_build::bridges(&rust_sources); + let mut bridge = cxx_build::bridges(&rust_bridges); bridge - .files(cpp_sources) + .files(jingle_cpp_sources) + .files(sleigh_sources) + .files(zlib_sources) .flag_if_supported("-std=c++17") .flag_if_supported("-DLOCAL_ZLIB") .flag_if_supported("-DNO_GZIP") .flag_if_supported("-Wno-register") - .flag_if_supported("-Wno-deprecated") - .flag_if_supported("-Wno-unused-const-variable") - .flag_if_supported("-Wno-unused-parameter") - .flag_if_supported("-Wno-unused-function") - .flag_if_supported("-Wno-unneeded-internal-declaration") - .flag_if_supported("-Wno-format") - .flag_if_supported("-Wno-unused-but-set-variable") - .flag_if_supported("-Wno-sign-compare") - .flag_if_supported("-Wno-deprecated-copy-with-user-provided-copy"); + .flag_if_supported("-w"); if cfg!(windows) { bridge.flag_if_supported("-D_WINDOWS"); @@ -85,39 +146,41 @@ fn main() { bridge.compile("jingle_sleigh"); println!("cargo::rerun-if-changed=src/ffi/cpp/"); - for src in rust_sources { - println!("cargo::rerun-if-changed={src}"); + for src in rust_bridges { + println!("cargo::rerun-if-changed={}", src.to_str().unwrap()); } - println!("cargo::rerun-if-changed=src/ffi/addrspace.rs"); - println!("cargo::rerun-if-changed=src/ffi/context_ffi.rs"); - println!("cargo::rerun-if-changed=src/ffi/instruction.rs"); - println!( - "cargo::rerun-if-changed={}", - ghidra_sleigh_path().to_str().unwrap() - ); } fn copy_sources() { - copy_cpp_sources(ghidra_sleigh_path(), sleigh_path()); - copy_cpp_sources(ghidra_zlib_path(), zlib_path()); + copy_cpp_sources( + ghidra_sleigh_path(), + sleigh_path(), + SLEIGH_SOURCES, + SLEIGH_HEADERS, + ); + copy_cpp_sources(ghidra_zlib_path(), zlib_path(), ZLIB_SOURCES, ZLIB_HEADERS); } -fn copy_cpp_sources, E: AsRef>(inpath: T, outpath: E) { +fn copy_cpp_sources, E: AsRef>( + inpath: T, + outpath: E, + sources: &[&str], + headers: &[&str], +) { let _ = fs::create_dir(&outpath); - for path in fs::read_dir(inpath).unwrap().flatten() { - if let Some(name) = path.file_name().to_str() { - if name.ends_with(".cc") - || name.ends_with(".c") - || name.ends_with(".hh") - || name.ends_with(".h") - { + for direntry in fs::read_dir(inpath).unwrap().flatten() { + let path = direntry.path(); + let filename = path.file_name(); + if let Some(filename) = filename { + let filename = filename.to_str().unwrap(); + if sources.contains(&filename) || headers.contains(&filename) { let mut result = PathBuf::from(outpath.as_ref()); - result.push(name); - copy(path.path().as_path(), result.as_path()).unwrap(); + result.push(filename); + copy(direntry.path(), result.as_path()).unwrap(); println!( "Copying {} ({} => {})", - name, - path.path().to_str().unwrap(), + filename, + direntry.path().to_str().unwrap(), result.to_str().unwrap() ); } @@ -125,20 +188,27 @@ fn copy_cpp_sources, E: AsRef>(inpath: T, outpath: E) { } } -fn sleigh_path() -> PathBuf { +fn ffi_rs_path() -> PathBuf { let mut p = PathBuf::new(); p.push("src"); p.push("ffi"); + p +} + +fn ffi_cpp_path() -> PathBuf { + let mut p = ffi_rs_path(); p.push("cpp"); + p +} + +fn sleigh_path() -> PathBuf { + let mut p = ffi_cpp_path(); p.push("sleigh"); p } fn zlib_path() -> PathBuf { - let mut p = PathBuf::new(); - p.push("src"); - p.push("ffi"); - p.push("cpp"); + let mut p = ffi_cpp_path(); p.push("zlib"); p } @@ -150,8 +220,7 @@ fn submod_path() -> PathBuf { } fn ghidra_sleigh_path() -> PathBuf { - let mut p = PathBuf::new(); - p.push(submod_path()); + let mut p = submod_path(); p.push("Ghidra"); p.push("Features"); p.push("Decompiler"); @@ -162,8 +231,7 @@ fn ghidra_sleigh_path() -> PathBuf { } fn ghidra_zlib_path() -> PathBuf { - let mut p = PathBuf::new(); - p.push(submod_path()); + let mut p = submod_path(); p.push("Ghidra"); p.push("Features"); p.push("Decompiler"); diff --git a/jingle_sleigh/src/ffi/cpp/exception.h b/jingle_sleigh/src/ffi/cpp/exception.h index 430ba4f..8151c57 100644 --- a/jingle_sleigh/src/ffi/cpp/exception.h +++ b/jingle_sleigh/src/ffi/cpp/exception.h @@ -16,7 +16,7 @@ namespace rust { } catch (const ghidra::DecoderError &e) { fail(e.explain); } catch (const std::exception &e) { - throw e; + fail(e.what()); } } } From dffcd19e61a885409fb485d2b9efe2f0cdc6a3df Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 13 Dec 2024 22:15:34 +0000 Subject: [PATCH 142/146] Left shift tweak --- jingle/src/modeling/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jingle/src/modeling/mod.rs b/jingle/src/modeling/mod.rs index 69ceb61..0983d8c 100644 --- a/jingle/src/modeling/mod.rs +++ b/jingle/src/modeling/mod.rs @@ -442,10 +442,10 @@ pub(crate) trait TranslationContext<'ctx>: ModelingContext<'ctx> { input1, output, } => { - let bv1 = self.read_and_track(input0.into())?; + let mut bv1 = self.read_and_track(input0.into())?; let mut bv2 = self.read_and_track(input1.into())?; match bv1.get_size().cmp(&bv2.get_size()) { - Ordering::Less => bv2 = bv2.extract(bv1.get_size() - 1, 0), + Ordering::Less => bv1 = bv1.zero_ext(bv2.get_size() - bv1.get_size()), Ordering::Greater => bv2 = bv2.zero_ext(bv1.get_size() - bv2.get_size()), _ => {} } From 44dfadfc5362230de6f3b588151c3618be864df0 Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 16 Dec 2024 12:08:39 +0000 Subject: [PATCH 143/146] Remove unnecessary pin. Add favicon.svg. --- favicon.svg | 1 + jingle_sleigh/src/ffi/context_ffi.rs | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 favicon.svg diff --git a/favicon.svg b/favicon.svg new file mode 100644 index 0000000..419da0b --- /dev/null +++ b/favicon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/jingle_sleigh/src/ffi/context_ffi.rs b/jingle_sleigh/src/ffi/context_ffi.rs index 34264a4..3237757 100644 --- a/jingle_sleigh/src/ffi/context_ffi.rs +++ b/jingle_sleigh/src/ffi/context_ffi.rs @@ -9,7 +9,6 @@ use crate::ffi::instruction::bridge::VarnodeInfoFFI; use crate::VarNode; use bridge::ContextFFI; use cxx::{Exception, ExternType, UniquePtr}; -use std::pin::Pin; use std::sync::Mutex; type ContextGeneratorFp = fn(&str) -> Result, Exception>; @@ -64,7 +63,7 @@ pub(crate) mod bridge { pub(crate) struct ImageFFI<'a> { /// A thing that has bytes at addresses - pub(crate) provider: Pin>, + pub(crate) provider: Box, /// The current virtual base address for the image loaded by this context. pub(crate) base_offset: u64, /// The space that this image is attached to. For now, always the @@ -75,7 +74,7 @@ pub(crate) struct ImageFFI<'a> { impl<'a> ImageFFI<'a> { pub(crate) fn new(provider: T, idx: usize) -> Self { Self { - provider: Box::pin(provider), + provider: Box::new(provider), base_offset: 0, space_index: idx, } From 8c0792159ecce251d6620191bb856936f2b0f281 Mon Sep 17 00:00:00 2001 From: Mark Date: Thu, 23 Jan 2025 14:08:38 +0000 Subject: [PATCH 144/146] Some CLI stuff --- jingle/Cargo.toml | 3 +- jingle/README.md | 39 +++++++++++++++++- jingle/src/main.rs | 66 +++++++++++++++++++----------- jingle/src/modeling/slice.rs | 1 + jingle/src/modeling/state/mod.rs | 8 ++++ jingle/src/modeling/state/space.rs | 6 ++- jingle_sleigh/src/error.rs | 2 +- 7 files changed, 97 insertions(+), 28 deletions(-) diff --git a/jingle/Cargo.toml b/jingle/Cargo.toml index 332eac8..73a7052 100644 --- a/jingle/Cargo.toml +++ b/jingle/Cargo.toml @@ -27,7 +27,8 @@ tracing = "0.1.40" clap = { version = "4.5.14", optional = true, features = ["derive"] } confy = { version = "0.6.1" , optional = true} hex = { version = "0.4.3" , optional = true} +anyhow = { version = "1.0.95", optional = true } [features] default = [] -bin_features = ["dep:clap", "dep:confy", "dep:hex"] +bin_features = ["dep:clap", "dep:confy", "dep:hex", "dep:anyhow"] gimli = ["jingle_sleigh/gimli"] diff --git a/jingle/README.md b/jingle/README.md index 5f7a375..00ea231 100644 --- a/jingle/README.md +++ b/jingle/README.md @@ -1,4 +1,41 @@ # `jingle`: Z3 + SLEIGH `jingle` uses the sleigh bindings provided by `jingle_sleigh` and the excellent -z3 bindings from the `z3` crate to provide SMT modeling of sequences of `PCODE` instructions +z3 bindings from the `z3` crate to provide SMT modeling of sequences of `PCODE` instructions. + +## CLI + +`jingle` exposes a simple CLI tool for disassembling strings of executable bytes and modeling them in logic. + +### Installation + +From this folder: + +```shell +cargo install --path . --features="bin_features" +``` + +This will install `jingle` in your path. Note that + +### Usage + +`jingle` requires that a Ghidra installation be present. + +```shell +Usage: jingle [GHIDRA_PATH] + +Commands: + disassemble Adds files to myapp + lift + model + architectures + help Print this message or the help of the given subcommand(s) + +Arguments: + [GHIDRA_PATH] + +Options: + -h, --help Print help + -V, --version Print version + +``` \ No newline at end of file diff --git a/jingle/src/main.rs b/jingle/src/main.rs index 1f4028d..405a6f5 100644 --- a/jingle/src/main.rs +++ b/jingle/src/main.rs @@ -1,3 +1,4 @@ +use anyhow::Context; use clap::{Parser, Subcommand}; use hex::decode; use jingle::modeling::{ModeledBlock, ModelingContext}; @@ -8,7 +9,7 @@ use jingle_sleigh::{Disassembly, Instruction, JingleSleighError, PcodeOperation, use serde::{Deserialize, Serialize}; use std::path::PathBuf; use z3::ast::Ast; -use z3::{Config, Context, Solver}; +use z3::{Config, Context as Z3Context, Solver}; #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] struct JingleConfig { @@ -73,10 +74,10 @@ enum Commands { Architectures, } -fn main() { +fn main() -> anyhow::Result<()> { let params: JingleParams = JingleParams::parse(); update_config(¶ms); - let config: JingleConfig = confy::load("jingle", None).unwrap(); + let config: JingleConfig = confy::load("jingle", None)?; match params.command { Commands::Disassemble { architecture, @@ -90,15 +91,17 @@ fn main() { architecture, hex_bytes, } => model(&config, architecture, hex_bytes), - Commands::Architectures => list_architectures(&config), + Commands::Architectures => Ok(list_architectures(&config)), } } fn update_config(params: &JingleParams) { let stored_config: JingleConfig = confy::load("jingle", None).unwrap(); - let new_config = JingleConfig::from(params); - if stored_config != new_config { - confy::store("jingle", None, new_config).unwrap() + if params.ghidra_path.is_some() { + let new_config = JingleConfig::from(params); + if stored_config != new_config { + confy::store("jingle", None, new_config).unwrap() + } } } @@ -113,13 +116,20 @@ fn get_instructions( config: &JingleConfig, architecture: String, hex_bytes: String, -) -> (LoadedSleighContext, Vec) { - let sleigh_build = config.sleigh_builder().unwrap(); - let img = decode(hex_bytes).unwrap(); +) -> anyhow::Result<(LoadedSleighContext, Vec)> { + let sleigh_build = config.sleigh_builder().context(format!( + "Unable to parse selected architecture. \n\ + This may indicate that your configured Ghidra path is incorrect: {}", + config.ghidra_path.display() + ))?; + let img = decode(hex_bytes)?; let max_len = img.len(); let mut offset = 0; - let sleigh = sleigh_build.build(&architecture).unwrap(); - let sleigh = sleigh.initialize_with_image(img).unwrap(); + let sleigh = sleigh_build + .build(&architecture) + .context("Unable to build the selected architecture.\n\ + This is either a bug in sleigh or the .sinc file for your architecture is malformed.")?; + let sleigh = sleigh.initialize_with_image(img)?; let mut instrs = vec![]; while offset < max_len { if let Some(instruction) = sleigh.instruction_at(offset as u64) { @@ -130,29 +140,35 @@ fn get_instructions( break; } } - (sleigh, instrs) + Ok((sleigh, instrs)) } -fn disassemble(config: &JingleConfig, architecture: String, hex_bytes: String) { - for instr in get_instructions(config, architecture, hex_bytes).1 { +fn disassemble( + config: &JingleConfig, + architecture: String, + hex_bytes: String, +) -> anyhow::Result<()> { + for instr in get_instructions(config, architecture, hex_bytes)?.1 { println!("{}", instr.disassembly) } + Ok(()) } -fn lift(config: &JingleConfig, architecture: String, hex_bytes: String) { - let (sleigh, instrs) = get_instructions(config, architecture, hex_bytes); +fn lift(config: &JingleConfig, architecture: String, hex_bytes: String) -> anyhow::Result<()> { + let (sleigh, instrs) = get_instructions(config, architecture, hex_bytes)?; for instr in instrs { for x in instr.ops { - let x_disp = x.display(&sleigh).unwrap(); + let x_disp = x.display(&sleigh)?; println!("{}", x_disp) } } + Ok(()) } -fn model(config: &JingleConfig, architecture: String, hex_bytes: String) { - let z3 = Context::new(&Config::new()); +fn model(config: &JingleConfig, architecture: String, hex_bytes: String) -> anyhow::Result<()> { + let z3 = Z3Context::new(&Config::new()); let solver = Solver::new(&z3); - let (sleigh, mut instrs) = get_instructions(config, architecture, hex_bytes); + let (sleigh, mut instrs) = get_instructions(config, architecture, hex_bytes)?; // todo: this is a disgusting hack to let us read a modeled block without requiring the user // to enter a block-terminating instruction. Everything with reading blocks needs to be reworked // at some point. For now, this lets me not break anything else relying on this behavior while @@ -174,8 +190,10 @@ fn model(config: &JingleConfig, architecture: String, hex_bytes: String) { }); let jingle_ctx = JingleContext::new(&z3, &sleigh); - let block = ModeledBlock::read(&jingle_ctx, instrs.into_iter()).unwrap(); + let block = ModeledBlock::read(&jingle_ctx, instrs.into_iter())?; let final_state = jingle_ctx.fresh_state(); - solver.assert(&final_state._eq(block.get_final_state()).unwrap().simplify()); - println!("{}", solver.to_smt2()) + println!("{}", block.get_final_state().fmt_smt_arrays()); + solver.assert(&final_state._eq(block.get_final_state())?.simplify()); + println!("{}", solver.to_smt2()); + Ok(()) } diff --git a/jingle/src/modeling/slice.rs b/jingle/src/modeling/slice.rs index 6dbf046..6649a5d 100644 --- a/jingle/src/modeling/slice.rs +++ b/jingle/src/modeling/slice.rs @@ -50,3 +50,4 @@ impl<'ctx, T: ModelingContext<'ctx>> ModelingContext<'ctx> for &[T] { self.last().unwrap().get_branch_constraint() } } + diff --git a/jingle/src/modeling/state/mod.rs b/jingle/src/modeling/state/mod.rs index 4c3d13c..c9c938c 100644 --- a/jingle/src/modeling/state/mod.rs +++ b/jingle/src/modeling/state/mod.rs @@ -310,4 +310,12 @@ impl<'ctx> State<'ctx> { let eq_terms: Vec<&Bool> = terms.iter().collect(); Ok(Bool::and(self.jingle.z3, eq_terms.as_slice())) } + + pub fn fmt_smt_arrays(&self)-> String{ + let mut lines = vec![]; + for x in &self.spaces { + lines.push(x.fmt_smt_array()) + } + lines.join("\n") + } } diff --git a/jingle/src/modeling/state/space.rs b/jingle/src/modeling/state/space.rs index e75886a..b340ca0 100644 --- a/jingle/src/modeling/state/space.rs +++ b/jingle/src/modeling/state/space.rs @@ -2,7 +2,7 @@ use crate::JingleError::{MismatchedAddressSize, UnexpectedArraySort, ZeroSizedVa use crate::{JingleContext, JingleError}; use jingle_sleigh::{SleighEndianness, SpaceInfo}; use std::ops::Add; -use z3::ast::{Array, BV}; +use z3::ast::{Array, Ast, BV}; use z3::Sort; /// SLEIGH models programs using many spaces. This struct serves as a helper for modeling a single @@ -89,6 +89,10 @@ impl<'ctx> ModeledSpace<'ctx> { self.metadata = write_to_array::<1>(&self.metadata, val, offset, self.endianness); Ok(()) } + + pub(crate) fn fmt_smt_array(&self) -> String { + format!("{:?}", self.data.simplify()) + } } fn read_from_array<'ctx>( diff --git a/jingle_sleigh/src/error.rs b/jingle_sleigh/src/error.rs index 3d6b3ef..c2aacaa 100644 --- a/jingle_sleigh/src/error.rs +++ b/jingle_sleigh/src/error.rs @@ -5,7 +5,7 @@ use thiserror::Error; pub enum JingleSleighError { /// The sleigh compiler was run against a language definition that had some missing files. /// Probably indicates that the path to the language specification was wrong - #[error("missing files needed to init sleigh. Could be sla or ldef or pspec")] + #[error("Unable to parse sleigh language!")] LanguageSpecRead, /// A language specification existed, but was unable to be parsed #[error("failed to parse sleigh language definition")] From 1e79c587cc83e05a791cc8c7fe567394079747f0 Mon Sep 17 00:00:00 2001 From: Mark Date: Thu, 23 Jan 2025 14:17:40 +0000 Subject: [PATCH 145/146] Fix and fmt --- jingle/README.md | 50 ++++++++++++++++++++++++++++++++ jingle/src/main.rs | 9 +++--- jingle/src/modeling/slice.rs | 1 - jingle/src/modeling/state/mod.rs | 4 +-- 4 files changed, 56 insertions(+), 8 deletions(-) diff --git a/jingle/README.md b/jingle/README.md index 00ea231..1405970 100644 --- a/jingle/README.md +++ b/jingle/README.md @@ -21,6 +21,56 @@ This will install `jingle` in your path. Note that `jingle` requires that a Ghidra installation be present. +When you provide it as the first argument to the `jingle` CLI, it +will save that path for future usage. + +Once it has been configured, you can simple run it as follows: + +```shell +jingle disassemble x86:LE:32:default 89fb +jingle lift x86:LE:32:default 89fb +jingle model x86:LE:32:default 89fb +``` + +These three invocations will print disassembly, pcode translation, and +a logical model respectively. None of these, particularly the logical model, +are intended to be used directly from this utility; this is merely for demonstration. +The proper way to use this tool is through the API. + +The above invocations will produce the following output: +```shell +# jingle disassemble x86:LE:32:default 89fb +MOV EBX,EDI +``` + +```shell +# jingle lift x86:LE:32:default 89fb +EBX = COPY EDI +``` + +```shell +# jingle model x86:LE:32:default 89fb +; benchmark generated from rust API +(set-info :status unknown) +(declare-fun register!4 () (Array (_ BitVec 32) (_ BitVec 8))) +(declare-fun register!9 () (Array (_ BitVec 32) (_ BitVec 8))) +(declare-fun ram!3 () (Array (_ BitVec 32) (_ BitVec 8))) +(declare-fun ram!8 () (Array (_ BitVec 32) (_ BitVec 8))) +(declare-fun OTHER!1 () (Array (_ BitVec 64) (_ BitVec 8))) +(declare-fun OTHER!6 () (Array (_ BitVec 64) (_ BitVec 8))) +(assert + (let ((?x77 (store (store register!4 (_ bv12 32) (select register!4 (_ bv28 32))) (_ bv13 32) (select register!4 (_ bv29 32))))) + (let ((?x81 (store (store ?x77 (_ bv14 32) (select register!4 (_ bv30 32))) (_ bv15 32) (select register!4 (_ bv31 32))))) + (let (($x82 (= register!9 ?x81))) + (let (($x63 (= ram!8 ram!3))) + (let (($x62 (= OTHER!6 OTHER!1))) + (and $x62 $x63 $x82))))))) +(check-sat) + +``` + +### Usage string + ```shell Usage: jingle [GHIDRA_PATH] diff --git a/jingle/src/main.rs b/jingle/src/main.rs index 405a6f5..509ffba 100644 --- a/jingle/src/main.rs +++ b/jingle/src/main.rs @@ -125,10 +125,10 @@ fn get_instructions( let img = decode(hex_bytes)?; let max_len = img.len(); let mut offset = 0; - let sleigh = sleigh_build - .build(&architecture) - .context("Unable to build the selected architecture.\n\ - This is either a bug in sleigh or the .sinc file for your architecture is malformed.")?; + let sleigh = sleigh_build.build(&architecture).context( + "Unable to build the selected architecture.\n\ + This is either a bug in sleigh or the .sinc file for your architecture is malformed.", + )?; let sleigh = sleigh.initialize_with_image(img)?; let mut instrs = vec![]; while offset < max_len { @@ -192,7 +192,6 @@ fn model(config: &JingleConfig, architecture: String, hex_bytes: String) -> anyh let jingle_ctx = JingleContext::new(&z3, &sleigh); let block = ModeledBlock::read(&jingle_ctx, instrs.into_iter())?; let final_state = jingle_ctx.fresh_state(); - println!("{}", block.get_final_state().fmt_smt_arrays()); solver.assert(&final_state._eq(block.get_final_state())?.simplify()); println!("{}", solver.to_smt2()); Ok(()) diff --git a/jingle/src/modeling/slice.rs b/jingle/src/modeling/slice.rs index 6649a5d..6dbf046 100644 --- a/jingle/src/modeling/slice.rs +++ b/jingle/src/modeling/slice.rs @@ -50,4 +50,3 @@ impl<'ctx, T: ModelingContext<'ctx>> ModelingContext<'ctx> for &[T] { self.last().unwrap().get_branch_constraint() } } - diff --git a/jingle/src/modeling/state/mod.rs b/jingle/src/modeling/state/mod.rs index c9c938c..72febcd 100644 --- a/jingle/src/modeling/state/mod.rs +++ b/jingle/src/modeling/state/mod.rs @@ -310,8 +310,8 @@ impl<'ctx> State<'ctx> { let eq_terms: Vec<&Bool> = terms.iter().collect(); Ok(Bool::and(self.jingle.z3, eq_terms.as_slice())) } - - pub fn fmt_smt_arrays(&self)-> String{ + + pub fn fmt_smt_arrays(&self) -> String { let mut lines = vec![]; for x in &self.spaces { lines.push(x.fmt_smt_array()) From c91cf53641e3f417d79f97042be220c8c3b283bd Mon Sep 17 00:00:00 2001 From: Mark Date: Thu, 23 Jan 2025 14:26:50 +0000 Subject: [PATCH 146/146] Clippy fix --- jingle/src/main.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/jingle/src/main.rs b/jingle/src/main.rs index 509ffba..35fd4d4 100644 --- a/jingle/src/main.rs +++ b/jingle/src/main.rs @@ -91,7 +91,10 @@ fn main() -> anyhow::Result<()> { architecture, hex_bytes, } => model(&config, architecture, hex_bytes), - Commands::Architectures => Ok(list_architectures(&config)), + Commands::Architectures => { + list_architectures(&config); + Ok(()) + } } }