From 81c8d0a8ecf49968a17526b067ca42611d1cbbba Mon Sep 17 00:00:00 2001 From: Jean-Marie Mineau Date: Thu, 14 Dec 2023 11:27:43 +0100 Subject: [PATCH] add instruction enum to code item --- androscalpel_serializer/src/items/code.rs | 60 +++++++++-- .../src/items/instructions.rs | 101 ++++++++++++------ 2 files changed, 122 insertions(+), 39 deletions(-) diff --git a/androscalpel_serializer/src/items/code.rs b/androscalpel_serializer/src/items/code.rs index 19bc6c0..2fae98d 100644 --- a/androscalpel_serializer/src/items/code.rs +++ b/androscalpel_serializer/src/items/code.rs @@ -1,7 +1,7 @@ //! Code items use crate as androscalpel_serializer; -use crate::{Error, ReadSeek, Result, Serializable, Sleb128, Uleb128}; +use crate::{Error, Instruction, ReadSeek, Result, Serializable, Sleb128, Uleb128}; use log::debug; use std::io::Write; @@ -16,7 +16,7 @@ pub struct CodeItem { /// 0 if no debug info, else offset to a [`crate::DebugInfoItem`]. pub debug_info_off: u32, // pub insns_size: u32, - pub insns: Vec, + pub insns: Vec, // pub padding: Vec, /// try items must refere to non overlapping range an order from low to hight addresses. pub tries: Vec, @@ -29,7 +29,7 @@ impl CodeItem { } pub fn insns_size_field(&self) -> u32 { - self.insns.len() as u32 + self.insns.iter().map(|ins| ins.size() as u32).sum::() / 2 } pub fn sanity_check(&self) -> Result<()> { @@ -56,7 +56,7 @@ impl CodeItem { /* // Necessary? no in spec and apk in the wild seams to have try blocks spaming outside the // insns array. - if max_addr > self.insns.len() as u32 { + if max_addr > self.insns_size_field() { return Err(Error::InconsistantStruct( "found try_item whose block span outside of the insns array".into(), )); @@ -72,7 +72,7 @@ impl CodeItem { handler.sanity_check()?; for handler in &handler.handlers { // Necessary? no in spec - if handler.addr.0 > self.insns.len() as u32 { + if handler.addr.0 > self.insns_size_field() { return Err(Error::InconsistantStruct( "Found an handler whose address is outside of the insns array".into(), )); @@ -80,7 +80,7 @@ impl CodeItem { } if let Some(Uleb128(addr)) = handler.catch_all_addr { // Necessary? no in spec - if addr > self.insns.len() as u32 { + if addr > self.insns_size_field() { return Err(Error::InconsistantStruct( "Found a catch all handler whose address is outside of the insns array" .into(), @@ -88,6 +88,46 @@ impl CodeItem { } } } + + let mut addresses = vec![]; + for try_ in &self.tries { + addresses.push(try_.start_addr); + addresses.push(try_.start_addr + try_.insn_count as u32); + } + for handler in &self.handlers { + for catch in &handler.list { + for EncodedTypeAddrPair { + addr: Uleb128(addr), + .. + } in &catch.handlers + { + addresses.push(*addr); + } + if let Some(Uleb128(addr)) = catch.catch_all_addr { + addresses.push(addr); + } + } + } + addresses.sort(); + let mut addr = 0; + let mut i = 0; + while i < addresses.len() && addresses[i] == addr { + i += 1; + } + for insn in &self.insns { + addr += insn.size() as u32; + while i < addresses.len() && addresses[i] == addr { + i += 1; + } + } + if i < addresses.len() && addresses[i] < addr { + return Err(Error::InconsistantStruct(format!( + "Found an address in try block (0x{addr:x}) that does not align with an instruction" + ))); + } + + // TODO check goto addresses? pb: op code are not parsed so goto instruction are not known + Ok(()) } } @@ -127,9 +167,13 @@ impl Serializable for CodeItem { let tries_size = u16::deserialize(input)?; let debug_info_off = u32::deserialize(input)?; let insns_size = u32::deserialize(input)?; + let mut insns = vec![]; - for _ in 0..insns_size { - insns.push(u16::deserialize(input)?); + let mut serialized_insns_size = 0; + while serialized_insns_size != insns_size { + let ins = Instruction::deserialize(input)?; + serialized_insns_size += ins.size() as u32; + insns.push(ins); } if tries_size != 0 && insns_size % 2 == 1 { let _ = u16::deserialize(input)?; diff --git a/androscalpel_serializer/src/items/instructions.rs b/androscalpel_serializer/src/items/instructions.rs index 8a8f59e..8425e7c 100644 --- a/androscalpel_serializer/src/items/instructions.rs +++ b/androscalpel_serializer/src/items/instructions.rs @@ -269,7 +269,6 @@ impl Instruction { requires the first byte to be 0 found {v}" ))); } - // TODO: check bytes order let a = i16::deserialize(input)?; Ok(Self::Format20T { op, a }) } @@ -277,7 +276,6 @@ impl Instruction { pub fn deserialize_20bc(input: &mut dyn ReadSeek) -> Result { let op = u8::deserialize(input)?; let a = i8::deserialize(input)?; - // TODO: check bytes order let b = u16::deserialize(input)?; Ok(Self::Format20BC { a, op, b }) } @@ -285,7 +283,6 @@ impl Instruction { pub fn deserialize_22x(input: &mut dyn ReadSeek) -> Result { let op = u8::deserialize(input)?; let va = u8::deserialize(input)?; - // TODO: check bytes order let vb = u16::deserialize(input)?; Ok(Self::Format22X { va, op, vb }) } @@ -293,7 +290,6 @@ impl Instruction { pub fn deserialize_21t(input: &mut dyn ReadSeek) -> Result { let op = u8::deserialize(input)?; let va = u8::deserialize(input)?; - // TODO: check bytes order let b = i16::deserialize(input)?; Ok(Self::Format21T { va, op, b }) } @@ -301,7 +297,6 @@ impl Instruction { pub fn deserialize_21s(input: &mut dyn ReadSeek) -> Result { let op = u8::deserialize(input)?; let va = u8::deserialize(input)?; - // TODO: check bytes order let b = i16::deserialize(input)?; Ok(Self::Format21S { va, op, b }) } @@ -309,7 +304,6 @@ impl Instruction { pub fn deserialize_21h(input: &mut dyn ReadSeek) -> Result { let op = u8::deserialize(input)?; let va = u8::deserialize(input)?; - // TODO: check bytes order let b = i16::deserialize(input)?; Ok(Self::Format21H { va, op, b }) } @@ -317,7 +311,6 @@ impl Instruction { pub fn deserialize_21c(input: &mut dyn ReadSeek) -> Result { let op = u8::deserialize(input)?; let va = u8::deserialize(input)?; - // TODO: check bytes order let b = u16::deserialize(input)?; Ok(Self::Format21C { va, op, b }) } @@ -343,7 +336,6 @@ impl Instruction { let val = u8::deserialize(input)?; let va = val & 0b0000_1111; let vb = (val & 0b1111_0000) >> 4; - // TODO: check bytes order let c = i16::deserialize(input)?; Ok(Self::Format22T { vb, va, op, c }) } @@ -353,7 +345,6 @@ impl Instruction { let val = u8::deserialize(input)?; let va = val & 0b0000_1111; let vb = (val & 0b1111_0000) >> 4; - // TODO: check bytes order let c = i16::deserialize(input)?; Ok(Self::Format22S { vb, va, op, c }) } @@ -363,7 +354,6 @@ impl Instruction { let val = u8::deserialize(input)?; let va = val & 0b0000_1111; let vb = (val & 0b1111_0000) >> 4; - // TODO: check bytes order let c = u16::deserialize(input)?; Ok(Self::Format22C { vb, va, op, c }) } @@ -373,7 +363,6 @@ impl Instruction { let val = u8::deserialize(input)?; let va = val & 0b0000_1111; let vb = (val & 0b1111_0000) >> 4; - // TODO: check bytes order let c = u16::deserialize(input)?; Ok(Self::Format22CS { vb, va, op, c }) } @@ -388,7 +377,6 @@ impl Instruction { requires the first byte to be 0 found {v}" ))); } - // TODO: check the bytes order let [a_l0, a_l1, a_h0, a_h1] = i32::deserialize(input)?.to_be_bytes(); let a = i32::from_be_bytes([a_h0, a_h1, a_l0, a_l1]); Ok(Self::Format30T { op, a }) @@ -404,9 +392,7 @@ impl Instruction { requires the first byte to be 0 found {v}" ))); } - // TODO: check the bytes order let va = u16::deserialize(input)?; - // TODO: check the bytes order let vb = u16::deserialize(input)?; Ok(Self::Format32X { op, va, vb }) } @@ -415,7 +401,6 @@ impl Instruction { let op = u8::deserialize(input)?; let va = u8::deserialize(input)?; let [b_l0, b_l1, b_h0, b_h1] = i32::deserialize(input)?.to_be_bytes(); - // TODO: check the bytes order let b = i32::from_be_bytes([b_h0, b_h1, b_l0, b_l1]); Ok(Self::Format31I { va, op, b }) } @@ -424,7 +409,6 @@ impl Instruction { let op = u8::deserialize(input)?; let va = u8::deserialize(input)?; let [b_l0, b_l1, b_h0, b_h1] = i32::deserialize(input)?.to_be_bytes(); - // TODO: check the bytes order let b = i32::from_be_bytes([b_h0, b_h1, b_l0, b_l1]); Ok(Self::Format31T { va, op, b }) } @@ -433,7 +417,6 @@ impl Instruction { let op = u8::deserialize(input)?; let va = u8::deserialize(input)?; let [b_l0, b_l1, b_h0, b_h1] = u32::deserialize(input)?.to_be_bytes(); - // TODO: check the bytes order let b = u32::from_be_bytes([b_h0, b_h1, b_l0, b_l1]); Ok(Self::Format31C { va, op, b }) } @@ -449,7 +432,6 @@ impl Instruction { requires A to be between 0 and 5, found {a}" ))); } - // TODO: check the bytes order let b = u16::deserialize(input)?; let val = u8::deserialize(input)?; @@ -483,7 +465,6 @@ impl Instruction { requires A to be between 0 and 5, found {a}" ))); } - // TODO: check the bytes order let b = u16::deserialize(input)?; let val = u8::deserialize(input)?; @@ -517,7 +498,6 @@ impl Instruction { requires A to be between 0 and 5, found {a}" ))); } - // TODO: check the bytes order let b = u16::deserialize(input)?; let val = u8::deserialize(input)?; @@ -543,9 +523,7 @@ impl Instruction { pub fn deserialize_3rc(input: &mut dyn ReadSeek) -> Result { let op = u8::deserialize(input)?; let a = u8::deserialize(input)?; - // TODO: check the bytes order let b = u16::deserialize(input)?; - // TODO: check the bytes order let vc = u16::deserialize(input)?; Ok(Self::Format3RC { a, op, b, vc }) } @@ -553,9 +531,7 @@ impl Instruction { pub fn deserialize_3rms(input: &mut dyn ReadSeek) -> Result { let op = u8::deserialize(input)?; let a = u8::deserialize(input)?; - // TODO: check the bytes order let b = u16::deserialize(input)?; - // TODO: check the bytes order let vc = u16::deserialize(input)?; Ok(Self::Format3RMS { a, op, b, vc }) } @@ -563,9 +539,7 @@ impl Instruction { pub fn deserialize_3rmi(input: &mut dyn ReadSeek) -> Result { let op = u8::deserialize(input)?; let a = u8::deserialize(input)?; - // TODO: check the bytes order let b = u16::deserialize(input)?; - // TODO: check the bytes order let vc = u16::deserialize(input)?; Ok(Self::Format3RMI { a, op, b, vc }) } @@ -581,7 +555,6 @@ impl Instruction { requires A to be between 0 and 5, found {a}" ))); } - // TODO: check the bytes order let b = u16::deserialize(input)?; let val = u8::deserialize(input)?; @@ -592,7 +565,6 @@ impl Instruction { let vf = (val & 0b1111_0000) >> 4; let ve = val & 0b0000_1111; - // TODO: check the bytes order let h = u16::deserialize(input)?; Ok(Self::Format45CC { @@ -611,11 +583,8 @@ impl Instruction { pub fn deserialize_4rcc(input: &mut dyn ReadSeek) -> Result { let op = u8::deserialize(input)?; let a = u8::deserialize(input)?; - // TODO: check the bytes order let b = u16::deserialize(input)?; - // TODO: check the bytes order let vc = u16::deserialize(input)?; - // TODO: check the bytes order let h = u16::deserialize(input)?; Ok(Self::Format4RCC { a, op, b, vc, h }) } @@ -2113,6 +2082,76 @@ mod test { } } + #[test] + fn test_parsing_20t() { + for (raw, expected) in [ + ( + vec![0x29, 0x00, 0xd4, 0xfe], + Instruction::Format20T { a: -300, op: 0x29 }, + ), + ( + vec![0x29, 0x00, 0x16, 0x01], + Instruction::Format20T { a: 278, op: 0x29 }, + ), + ] { + assert_eq!(expected.size(), raw.len()); + assert_eq!(expected, Instruction::deserialize_from_slice(&raw).unwrap()); + assert_eq!(raw, expected.serialize_to_vec().unwrap()); + } + } + + #[test] + fn test_parsing_22x() { + for (raw, expected) in [ + ( + vec![0x08, 0x0b, 0x11, 0x00], + Instruction::Format22X { + va: 11, + vb: 17, + op: 0x8, + }, + ), + ( + vec![0x08, 0x03, 0x11, 0x00], + Instruction::Format22X { + va: 3, + vb: 17, + op: 0x8, + }, + ), + ] { + assert_eq!(expected.size(), raw.len()); + assert_eq!(expected, Instruction::deserialize_from_slice(&raw).unwrap()); + assert_eq!(raw, expected.serialize_to_vec().unwrap()); + } + } + + #[test] + fn test_parsing_21h() { + for (raw, expected) in [ + ( + vec![0x15, 0x0b, 0x10, 0x00], + Instruction::Format21H { + va: 11, + b: (1048576 / 65536) as i16, + op: 0x15, + }, + ), + ( + vec![0x15, 0x06, 0x00, 0x80], + Instruction::Format21H { + va: 6, + b: (-2147483648 / 65536) as i16, + op: 0x15, + }, + ), + ] { + assert_eq!(expected.size(), raw.len()); + assert_eq!(expected, Instruction::deserialize_from_slice(&raw).unwrap()); + assert_eq!(raw, expected.serialize_to_vec().unwrap()); + } + } + #[test] fn test_parsing_21c() { let raw = vec![0x22, 0x00, 0x2d, 0x24];