From ee7cf4d325d91d1474ce2e2cff941daa9c85753c Mon Sep 17 00:00:00 2001 From: Jean-Marie Mineau Date: Thu, 14 Dec 2023 02:15:39 +0100 Subject: [PATCH] add serializer for instruction format --- .gitignore | 1 + androscalpel_serializer/src/items/code.rs | 44 + .../src/items/instructions.rs | 2142 +++++++++++++++++ androscalpel_serializer/src/items/mod.rs | 2 + 4 files changed, 2189 insertions(+) create mode 100644 androscalpel_serializer/src/items/instructions.rs diff --git a/.gitignore b/.gitignore index b2c469e..1d79fd0 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ /venv_maturin /venv_test /test.apk +/androguard_test.py diff --git a/androscalpel_serializer/src/items/code.rs b/androscalpel_serializer/src/items/code.rs index 78990a6..19bc6c0 100644 --- a/androscalpel_serializer/src/items/code.rs +++ b/androscalpel_serializer/src/items/code.rs @@ -1005,4 +1005,48 @@ mod test { EncodedCatchHandler::deserialize_from_slice(&[0x01, 0xc7, 0x08, 0xee, 0x01,]).unwrap() ); } + + const _INSN_RAW_1: &[u8] = &[ + 0x70, 0x10, 0x8b, 0x84, 0x05, 0x00, 0x22, 0x00, 0x2d, 0x24, 0x70, 0x10, 0x51, 0x87, 0x00, + 0x00, 0x5b, 0x50, 0x54, 0x06, 0x5b, 0x57, 0x58, 0x06, 0x22, 0x00, 0x84, 0x05, 0x70, 0x10, + 0x09, 0x1c, 0x00, 0x00, 0x5b, 0x50, 0x56, 0x06, 0x54, 0x77, 0xcc, 0x09, 0x71, 0x20, 0xed, + 0x18, 0x76, 0x00, 0x0c, 0x07, 0x5b, 0x57, 0x55, 0x06, 0x71, 0x10, 0xb9, 0x17, 0x06, 0x00, + 0x0c, 0x06, 0x5b, 0x56, 0x57, 0x06, 0x22, 0x06, 0x1e, 0x24, 0x70, 0x10, 0xa1, 0x86, 0x06, + 0x00, 0x54, 0x70, 0x01, 0x08, 0x1f, 0x00, 0x7a, 0x04, 0x6e, 0x10, 0x8e, 0x84, 0x00, 0x00, + 0x54, 0x00, 0x04, 0x08, 0x6e, 0x10, 0x2a, 0x04, 0x00, 0x00, 0x0c, 0x00, 0x71, 0x10, 0xbc, + 0x86, 0x00, 0x00, 0x0c, 0x00, 0x39, 0x08, 0x16, 0x00, 0x72, 0x10, 0x8d, 0x87, 0x00, 0x00, + 0x0c, 0x07, 0x72, 0x10, 0x6c, 0x87, 0x07, 0x00, 0x0a, 0x08, 0x38, 0x08, 0x58, 0x00, 0x72, + 0x10, 0x6d, 0x87, 0x07, 0x00, 0x0c, 0x08, 0x1f, 0x08, 0x87, 0x23, 0x6e, 0x20, 0xa5, 0x86, + 0x86, 0x00, 0x28, 0xf1, 0x6e, 0x10, 0xf3, 0x19, 0x08, 0x00, 0x0c, 0x01, 0x71, 0x30, 0x73, + 0x17, 0x17, 0x00, 0x0c, 0x07, 0x28, 0x02, 0x12, 0x07, 0x22, 0x01, 0x1e, 0x24, 0x70, 0x10, + 0xa1, 0x86, 0x01, 0x00, 0x72, 0x10, 0x8d, 0x87, 0x00, 0x00, 0x0c, 0x00, 0x72, 0x10, 0x6c, + 0x87, 0x00, 0x00, 0x0a, 0x02, 0x38, 0x02, 0x17, 0x00, 0x72, 0x10, 0x6d, 0x87, 0x00, 0x00, + 0x0c, 0x02, 0x1f, 0x02, 0x87, 0x23, 0x6e, 0x20, 0xb5, 0x84, 0x72, 0x00, 0x0a, 0x03, 0x38, + 0x03, 0x03, 0x00, 0x28, 0xee, 0x6e, 0x20, 0x8f, 0x16, 0x25, 0x00, 0x0c, 0x02, 0x6e, 0x20, + 0xa5, 0x86, 0x21, 0x00, 0x28, 0xe6, 0x6e, 0x20, 0xf2, 0x19, 0x18, 0x00, 0x0c, 0x07, 0x72, + 0x10, 0x8d, 0x87, 0x07, 0x00, 0x0c, 0x07, 0x72, 0x10, 0x6c, 0x87, 0x07, 0x00, 0x0a, 0x08, + 0x38, 0x08, 0x12, 0x00, 0x72, 0x10, 0x6d, 0x87, 0x07, 0x00, 0x0c, 0x08, 0x1f, 0x08, 0xd4, + 0x04, 0x1f, 0x08, 0x7d, 0x05, 0x72, 0x10, 0xf3, 0x1b, 0x08, 0x00, 0x0c, 0x08, 0x6e, 0x20, + 0xa5, 0x86, 0x86, 0x00, 0x28, 0xeb, 0x22, 0x07, 0x1e, 0x24, 0x70, 0x10, 0xa1, 0x86, 0x07, + 0x00, 0x6e, 0x10, 0xaf, 0x86, 0x06, 0x00, 0x0c, 0x06, 0x72, 0x10, 0x6c, 0x87, 0x06, 0x00, + 0x0a, 0x08, 0x38, 0x08, 0x57, 0x00, 0x72, 0x10, 0x6d, 0x87, 0x06, 0x00, 0x0c, 0x08, 0x1f, + 0x08, 0x87, 0x23, 0x1a, 0x00, 0xb5, 0x0d, 0x6e, 0x20, 0xb5, 0x84, 0x08, 0x00, 0x0a, 0x00, + 0x39, 0x00, 0x45, 0x00, 0x1a, 0x00, 0xd0, 0x0d, 0x6e, 0x20, 0xb5, 0x84, 0x08, 0x00, 0x0a, + 0x00, 0x38, 0x00, 0x03, 0x00, 0x28, 0x3b, 0x62, 0x00, 0xe2, 0x00, 0x1a, 0x01, 0x49, 0xc0, + 0x6e, 0x20, 0xb5, 0x84, 0x01, 0x00, 0x0a, 0x00, 0x38, 0x00, 0x03, 0x00, 0x28, 0x1a, 0x54, + 0x50, 0x55, 0x06, 0x6e, 0x20, 0xee, 0x18, 0x80, 0x00, 0x0c, 0x00, 0x62, 0x01, 0xb6, 0x00, + 0x6e, 0x20, 0xc4, 0x18, 0x10, 0x00, 0x0c, 0x00, 0x1f, 0x00, 0x9c, 0x2e, 0x12, 0x01, 0x38, + 0x00, 0x0f, 0x00, 0x21, 0x02, 0x01, 0x13, 0x35, 0x23, 0x0b, 0x00, 0x44, 0x04, 0x00, 0x03, + 0x39, 0x04, 0x04, 0x00, 0x12, 0x11, 0x28, 0x04, 0xd8, 0x03, 0x03, 0x01, 0x28, 0xf6, 0x38, + 0x01, 0xba, 0xff, 0x6e, 0x20, 0xa5, 0x86, 0x87, 0x00, 0x28, 0xb5, 0x0d, 0x06, 0x22, 0x07, + 0x1e, 0x05, 0x71, 0x10, 0xff, 0x48, 0x06, 0x00, 0x0c, 0x06, 0x70, 0x20, 0xc2, 0x1a, 0x67, + 0x00, 0x27, 0x07, 0x6e, 0x20, 0xa5, 0x86, 0x87, 0x00, 0x28, 0xa6, 0x5b, 0x57, 0x53, 0x06, + 0x0e, 0x00, 0x0d, 0x06, 0x22, 0x07, 0x47, 0x04, 0x70, 0x20, 0x84, 0x18, 0x67, 0x00, 0x27, + 0x07, 0x0d, 0x06, 0x22, 0x07, 0x1e, 0x05, 0x70, 0x20, 0xc2, 0x1a, 0x67, 0x00, 0x27, 0x07, + 0x0d, 0x06, 0x22, 0x07, 0x1e, 0x05, 0x71, 0x10, 0xff, 0x48, 0x06, 0x00, 0x0c, 0x06, 0x70, + 0x20, 0xc2, 0x1a, 0x67, 0x00, 0x27, 0x07, + ]; + + //#[test] + //fn test_insn_parsing() {} } diff --git a/androscalpel_serializer/src/items/instructions.rs b/androscalpel_serializer/src/items/instructions.rs new file mode 100644 index 0000000..8a8f59e --- /dev/null +++ b/androscalpel_serializer/src/items/instructions.rs @@ -0,0 +1,2142 @@ +//! The instructions in a code item. + +//use crate as androscalpel_serializer; +use crate::{Error, ReadSeek, Result, Serializable}; +//use log::debug; +use std::io::{SeekFrom, Write}; + +/// An instruction, following the formats described at +/// +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum Instruction { + Format10X { + op: u8, + }, + /// va and vb are in fact u4 values + Format12X { + vb: u8, + va: u8, + op: u8, + }, + /// va and b are in fact u4 values + Format11N { + b: i8, + va: u8, + op: u8, + }, + Format11X { + va: u8, + op: u8, + }, + Format10T { + a: i8, + op: u8, + }, + Format20T { + op: u8, + a: i16, + }, + Format20BC { + a: i8, + op: u8, + b: u16, + }, + Format22X { + va: u8, + op: u8, + vb: u16, + }, + Format21T { + va: u8, + op: u8, + b: i16, + }, + Format21S { + va: u8, + op: u8, + b: i16, + }, + /// b is a a signed hat, ie, the 16 hight order bits of a i32 or i64 value + Format21H { + va: u8, + op: u8, + b: i16, + }, + Format21C { + va: u8, + op: u8, + b: u16, + }, + Format23X { + va: u8, + op: u8, + vc: u8, + vb: u8, + }, + Format22B { + va: u8, + op: u8, + c: i8, + vb: u8, + }, + /// vb and vb are in fact u4 values + Format22T { + vb: u8, + va: u8, + op: u8, + c: i16, + }, + /// vb and vb are in fact u4 values + Format22S { + vb: u8, + va: u8, + op: u8, + c: i16, + }, + /// vb and vb are in fact u4 values + Format22C { + vb: u8, + va: u8, + op: u8, + c: u16, + }, + /// vb and vb are in fact u4 values + Format22CS { + vb: u8, + va: u8, + op: u8, + c: u16, + }, + Format30T { + op: u8, + a: i32, + }, + Format32X { + op: u8, + va: u16, + vb: u16, + }, + /// b can also be a f32 + Format31I { + va: u8, + op: u8, + b: i32, + }, + Format31T { + va: u8, + op: u8, + b: i32, + }, + Format31C { + va: u8, + op: u8, + b: u32, + }, + /// a, vg, vf, ve, vd and vc are in fact u4 values + Format35C { + a: u8, + vg: u8, + op: u8, + b: u16, + vf: u8, + ve: u8, + vd: u8, + vc: u8, + }, + /// a, vg, vf, ve, vd and vc are in fact u4 values + Format35MS { + a: u8, + vg: u8, + op: u8, + b: u16, + vf: u8, + ve: u8, + vd: u8, + vc: u8, + }, + /// a, vg, vf, ve, vd and vc are in fact u4 values + Format35MI { + a: u8, + vg: u8, + op: u8, + b: u16, + vf: u8, + ve: u8, + vd: u8, + vc: u8, + }, + Format3RC { + a: u8, + op: u8, + b: u16, + vc: u16, + }, + Format3RMS { + a: u8, + op: u8, + b: u16, + vc: u16, + }, + Format3RMI { + a: u8, + op: u8, + b: u16, + vc: u16, + }, + /// a, vg, vf, ve, vd and vc are in fact u4 values + Format45CC { + a: u8, + vg: u8, + op: u8, + b: u16, + vf: u8, + ve: u8, + vd: u8, + vc: u8, + h: u16, + }, + Format4RCC { + a: u8, + op: u8, + b: u16, + vc: u16, + h: u16, + }, + /// B can also be a f64... + Format51L { + va: u8, + op: u8, + b: i64, + }, +} + +impl Instruction { + pub fn deserialize_10x(input: &mut dyn ReadSeek) -> Result { + let op = u8::deserialize(input)?; + let v = u8::deserialize(input)?; + if v != 0 { + // TODO: is it enforced on actual android system? + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '10x' (00|op) \ + requires the first byte to be 0 found {v}" + ))); + } + Ok(Self::Format10X { op }) + } + + pub fn deserialize_12x(input: &mut dyn ReadSeek) -> Result { + let op = u8::deserialize(input)?; + let val = u8::deserialize(input)?; + let vb = (val & 0b1111_0000) >> 4; + let va = val & 0b0000_1111; + Ok(Self::Format12X { vb, va, op }) + } + + pub fn deserialize_11n(input: &mut dyn ReadSeek) -> Result { + let op = u8::deserialize(input)?; + let val = u8::deserialize(input)?; + let b = (val & 0b1111_0000) >> 4; + let b = if b & 0b0000_1000 != 0 { + // Sign extention + b | 0b1111_0000 + } else { + b + }; + let b = i8::from_be_bytes([b]); + let va = val & 0b0000_1111; + Ok(Self::Format11N { b, va, op }) + } + + pub fn deserialize_11x(input: &mut dyn ReadSeek) -> Result { + let op = u8::deserialize(input)?; + let va = u8::deserialize(input)?; + Ok(Self::Format11X { va, op }) + } + + pub fn deserialize_10t(input: &mut dyn ReadSeek) -> Result { + let op = u8::deserialize(input)?; + let a = i8::deserialize(input)?; + Ok(Self::Format10T { a, op }) + } + + pub fn deserialize_20t(input: &mut dyn ReadSeek) -> Result { + let op = u8::deserialize(input)?; + let v = u8::deserialize(input)?; + if v != 0 { + // TODO: is it enforced on actual android system? + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '20t' (00|op AAAA) \ + requires the first byte to be 0 found {v}" + ))); + } + // TODO: check bytes order + let a = i16::deserialize(input)?; + Ok(Self::Format20T { op, a }) + } + + 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 }) + } + + 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 }) + } + + 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 }) + } + + 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 }) + } + + 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 }) + } + + 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 }) + } + + pub fn deserialize_23x(input: &mut dyn ReadSeek) -> Result { + let op = u8::deserialize(input)?; + let va = u8::deserialize(input)?; + let vb = u8::deserialize(input)?; + let vc = u8::deserialize(input)?; + Ok(Self::Format23X { va, op, vc, vb }) + } + + pub fn deserialize_22b(input: &mut dyn ReadSeek) -> Result { + let op = u8::deserialize(input)?; + let va = u8::deserialize(input)?; + let vb = u8::deserialize(input)?; + let c = i8::deserialize(input)?; + Ok(Self::Format22B { va, op, c, vb }) + } + + pub fn deserialize_22t(input: &mut dyn ReadSeek) -> Result { + let op = u8::deserialize(input)?; + 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 }) + } + + pub fn deserialize_22s(input: &mut dyn ReadSeek) -> Result { + let op = u8::deserialize(input)?; + 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 }) + } + + pub fn deserialize_22c(input: &mut dyn ReadSeek) -> Result { + let op = u8::deserialize(input)?; + 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 }) + } + + pub fn deserialize_22cs(input: &mut dyn ReadSeek) -> Result { + let op = u8::deserialize(input)?; + 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 }) + } + + pub fn deserialize_30t(input: &mut dyn ReadSeek) -> Result { + let op = u8::deserialize(input)?; + let v = u8::deserialize(input)?; + if v != 0 { + // TODO: is it enforced on actual android system? + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '30t' (00|op AAAA AAAA) \ + 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 }) + } + + pub fn deserialize_32x(input: &mut dyn ReadSeek) -> Result { + let op = u8::deserialize(input)?; + let v = u8::deserialize(input)?; + if v != 0 { + // TODO: is it enforced on actual android system? + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '32x' (00|op AAAA BBBB) \ + 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 }) + } + + pub fn deserialize_31i(input: &mut dyn ReadSeek) -> Result { + 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 }) + } + + pub fn deserialize_31t(input: &mut dyn ReadSeek) -> Result { + 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 }) + } + + pub fn deserialize_31c(input: &mut dyn ReadSeek) -> Result { + 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 }) + } + + pub fn deserialize_35c(input: &mut dyn ReadSeek) -> Result { + let op = u8::deserialize(input)?; + let val = u8::deserialize(input)?; + let a = (val & 0b1111_0000) >> 4; + let vg = val & 0b0000_1111; + if a > 5 { + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '35c' (A|G|op BBBB F|E|D|C) \ + 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)?; + let vd = (val & 0b1111_0000) >> 4; + let vc = val & 0b0000_1111; + + let val = u8::deserialize(input)?; + let vf = (val & 0b1111_0000) >> 4; + let ve = val & 0b0000_1111; + + Ok(Self::Format35C { + a, + vg, + op, + b, + vf, + ve, + vd, + vc, + }) + } + + pub fn deserialize_35ms(input: &mut dyn ReadSeek) -> Result { + let op = u8::deserialize(input)?; + let val = u8::deserialize(input)?; + let a = (val & 0b1111_0000) >> 4; + let vg = val & 0b0000_1111; + if a > 5 { + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '35ms' (A|G|op BBBB F|E|D|C) \ + 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)?; + let vd = (val & 0b1111_0000) >> 4; + let vc = val & 0b0000_1111; + + let val = u8::deserialize(input)?; + let vf = (val & 0b1111_0000) >> 4; + let ve = val & 0b0000_1111; + + Ok(Self::Format35MS { + a, + vg, + op, + b, + vf, + ve, + vd, + vc, + }) + } + + pub fn deserialize_35mi(input: &mut dyn ReadSeek) -> Result { + let op = u8::deserialize(input)?; + let val = u8::deserialize(input)?; + let a = (val & 0b1111_0000) >> 4; + let vg = val & 0b0000_1111; + if a > 5 { + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '35mi' (A|G|op BBBB F|E|D|C) \ + 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)?; + let vd = (val & 0b1111_0000) >> 4; + let vc = val & 0b0000_1111; + + let val = u8::deserialize(input)?; + let vf = (val & 0b1111_0000) >> 4; + let ve = val & 0b0000_1111; + + Ok(Self::Format35MI { + a, + vg, + op, + b, + vf, + ve, + vd, + vc, + }) + } + + 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 }) + } + + 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 }) + } + + 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 }) + } + + pub fn deserialize_45cc(input: &mut dyn ReadSeek) -> Result { + let op = u8::deserialize(input)?; + let val = u8::deserialize(input)?; + let a = (val & 0b1111_0000) >> 4; + let vg = val & 0b0000_1111; + if a > 5 { + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '45cc' (A|G|op BBBB F|E|D|C HHHH) \ + 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)?; + let vd = (val & 0b1111_0000) >> 4; + let vc = val & 0b0000_1111; + + let val = u8::deserialize(input)?; + let vf = (val & 0b1111_0000) >> 4; + let ve = val & 0b0000_1111; + + // TODO: check the bytes order + let h = u16::deserialize(input)?; + + Ok(Self::Format45CC { + a, + vg, + op, + b, + vf, + ve, + vd, + vc, + h, + }) + } + + 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 }) + } + + pub fn deserialize_51l(input: &mut dyn ReadSeek) -> Result { + let op = u8::deserialize(input)?; + let va = u8::deserialize(input)?; + let b = i64::deserialize(input)?; + Ok(Self::Format51L { va, op, b }) + } +} + +impl Serializable for Instruction { + fn serialize(&self, output: &mut dyn Write) -> Result<()> { + match self { + Self::Format10X { op } => { + op.serialize(output)?; + 0u8.serialize(output) + } + Self::Format12X { vb, va, op } => { + if vb & 0b1111_0000 != 0 { + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '12x' (B|A|op) \ + requires B to be between 0 and 15, found {vb}" + ))); + } + if va & 0b1111_0000 != 0 { + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '12x' (B|A|op) \ + requires A to be between 0 and 15, found {va}" + ))); + } + let val: u8 = (vb << 4) | va; + op.serialize(output)?; + val.serialize(output) + } + Self::Format11N { b, va, op } => { + if *b < -8 || *b > 7 { + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '11n' (B|A|op) \ + requires B to be between -8 and 7, found {b}" + ))); + } + let b = b.to_be_bytes()[0] & 0b0000_1111; + if va & 0b1111_0000 != 0 { + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '11n' (B|A|op) \ + requires A to be between 0 and 15, found {va}" + ))); + } + let val: u8 = (b << 4) | va; + op.serialize(output)?; + val.serialize(output) + } + Self::Format11X { va, op } => { + op.serialize(output)?; + va.serialize(output) + } + Self::Format10T { a, op } => { + op.serialize(output)?; + a.serialize(output) + } + Self::Format20T { op, a } => { + op.serialize(output)?; + 0u8.serialize(output)?; + a.serialize(output) + } + Self::Format20BC { a, op, b } => { + op.serialize(output)?; + a.serialize(output)?; + b.serialize(output) + } + Self::Format22X { va, op, vb } => { + op.serialize(output)?; + va.serialize(output)?; + vb.serialize(output) + } + Self::Format21T { va, op, b } => { + op.serialize(output)?; + va.serialize(output)?; + b.serialize(output) + } + Self::Format21S { va, op, b } => { + op.serialize(output)?; + va.serialize(output)?; + b.serialize(output) + } + Self::Format21H { va, op, b } => { + op.serialize(output)?; + va.serialize(output)?; + b.serialize(output) + } + Self::Format21C { va, op, b } => { + op.serialize(output)?; + va.serialize(output)?; + b.serialize(output) + } + Self::Format23X { va, op, vc, vb } => { + op.serialize(output)?; + va.serialize(output)?; + vb.serialize(output)?; + vc.serialize(output) + } + Self::Format22B { va, op, c, vb } => { + op.serialize(output)?; + va.serialize(output)?; + vb.serialize(output)?; + c.serialize(output) + } + Self::Format22T { vb, va, op, c } => { + if vb & 0b1111_0000 != 0 { + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '22t' (B|A|op CCCC) \ + requires B to be between 0 and 15, found {vb}" + ))); + } + if va & 0b1111_0000 != 0 { + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '22t' (B|A|op CCCC) \ + requires A to be between 0 and 15, found {va}" + ))); + } + let val: u8 = (vb << 4) | va; + op.serialize(output)?; + val.serialize(output)?; + c.serialize(output) + } + Self::Format22S { vb, va, op, c } => { + if vb & 0b1111_0000 != 0 { + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '22s' (B|A|op CCCC) \ + requires B to be between 0 and 15, found {vb}" + ))); + } + if va & 0b1111_0000 != 0 { + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '22s' (B|A|op CCCC) \ + requires A to be between 0 and 15, found {va}" + ))); + } + let val: u8 = (vb << 4) | va; + op.serialize(output)?; + val.serialize(output)?; + c.serialize(output) + } + + Self::Format22C { vb, va, op, c } => { + if vb & 0b1111_0000 != 0 { + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '22c' (B|A|op CCCC) \ + requires B to be between 0 and 15, found {vb}" + ))); + } + if va & 0b1111_0000 != 0 { + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '22c' (B|A|op CCCC) \ + requires A to be between 0 and 15, found {va}" + ))); + } + let val: u8 = (vb << 4) | va; + op.serialize(output)?; + val.serialize(output)?; + c.serialize(output) + } + Self::Format22CS { vb, va, op, c } => { + if vb & 0b1111_0000 != 0 { + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '22cs' (B|A|op CCCC) \ + requires B to be between 0 and 15, found {vb}" + ))); + } + if va & 0b1111_0000 != 0 { + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '22cs' (B|A|op CCCC) \ + requires A to be between 0 and 15, found {va}" + ))); + } + let val: u8 = (vb << 4) | va; + op.serialize(output)?; + val.serialize(output)?; + c.serialize(output) + } + Self::Format30T { op, a } => { + op.serialize(output)?; + 0u8.serialize(output)?; + let [a_h0, a_h1, a_l0, a_l1] = a.to_be_bytes(); + // TODO: check the bytes order + u32::from_be_bytes([a_l0, a_l1, a_h0, a_h1]).serialize(output) + } + Self::Format32X { op, va, vb } => { + op.serialize(output)?; + 0u8.serialize(output)?; + va.serialize(output)?; + vb.serialize(output) + } + Self::Format31I { va, op, b } => { + op.serialize(output)?; + va.serialize(output)?; + let [b_h0, b_h1, b_l0, b_l1] = b.to_be_bytes(); + // TODO: check the bytes order + u32::from_be_bytes([b_l0, b_l1, b_h0, b_h1]).serialize(output) + } + Self::Format31T { va, op, b } => { + op.serialize(output)?; + va.serialize(output)?; + let [b_h0, b_h1, b_l0, b_l1] = b.to_be_bytes(); + // TODO: check the bytes order + u32::from_be_bytes([b_l0, b_l1, b_h0, b_h1]).serialize(output) + } + Self::Format31C { va, op, b } => { + op.serialize(output)?; + va.serialize(output)?; + let [b_h0, b_h1, b_l0, b_l1] = b.to_be_bytes(); + // TODO: check the bytes order + u32::from_be_bytes([b_l0, b_l1, b_h0, b_h1]).serialize(output) + } + Self::Format35C { + a, + vg, + op, + b, + vf, + ve, + vd, + vc, + } => { + if *a > 5 { + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '35c' (A|G|op BBBB F|E|D|C) \ + requires A to be between 0 and 5, found {a}" + ))); + } + if vg & 0b1111_0000 != 0 { + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '35c' (A|G|op BBBB F|E|D|C) \ + requires G to be between 0 and 15, found {vg}" + ))); + } + if vf & 0b1111_0000 != 0 { + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '35c' (A|G|op BBBB F|E|D|C) \ + requires F to be between 0 and 15, found {vf}" + ))); + } + if ve & 0b1111_0000 != 0 { + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '35c' (A|G|op BBBB F|E|D|C) \ + requires E to be between 0 and 15, found {ve}" + ))); + } + if vd & 0b1111_0000 != 0 { + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '35c' (A|G|op BBBB F|E|D|C) \ + requires D to be between 0 and 15, found {vd}" + ))); + } + if vc & 0b1111_0000 != 0 { + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '35c' (A|G|op BBBB F|E|D|C) \ + requires C to be between 0 and 15, found {vc}" + ))); + } + op.serialize(output)?; + let val = (a << 4) | vg; + val.serialize(output)?; + b.serialize(output)?; + let val = (vd << 4) | vc; + val.serialize(output)?; + let val = (vf << 4) | ve; + val.serialize(output) + } + Self::Format35MS { + a, + vg, + op, + b, + vf, + ve, + vd, + vc, + } => { + if *a > 5 { + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '35ms' (A|G|op BBBB F|E|D|C) \ + requires A to be between 0 and 5, found {a}" + ))); + } + if vg & 0b1111_0000 != 0 { + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '35ms' (A|G|op BBBB F|E|D|C) \ + requires G to be between 0 and 15, found {vg}" + ))); + } + if vf & 0b1111_0000 != 0 { + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '35ms' (A|G|op BBBB F|E|D|C) \ + requires F to be between 0 and 15, found {vf}" + ))); + } + if ve & 0b1111_0000 != 0 { + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '35ms' (A|G|op BBBB F|E|D|C) \ + requires E to be between 0 and 15, found {ve}" + ))); + } + if vd & 0b1111_0000 != 0 { + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '35ms' (A|G|op BBBB F|E|D|C) \ + requires D to be between 0 and 15, found {vd}" + ))); + } + if vc & 0b1111_0000 != 0 { + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '35ms' (A|G|op BBBB F|E|D|C) \ + requires C to be between 0 and 15, found {vc}" + ))); + } + let val = (a << 4) | vg; + op.serialize(output)?; + val.serialize(output)?; + b.serialize(output)?; + let val = (vd << 4) | vc; + val.serialize(output)?; + let val = (vf << 4) | ve; + val.serialize(output) + } + Self::Format35MI { + a, + vg, + op, + b, + vf, + ve, + vd, + vc, + } => { + if *a > 5 { + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '35mi' (A|G|op BBBB F|E|D|C) \ + requires A to be between 0 and 5, found {a}" + ))); + } + if vg & 0b1111_0000 != 0 { + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '35mi' (A|G|op BBBB F|E|D|C) \ + requires G to be between 0 and 15, found {vg}" + ))); + } + if vf & 0b1111_0000 != 0 { + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '35mi' (A|G|op BBBB F|E|D|C) \ + requires F to be between 0 and 15, found {vf}" + ))); + } + if ve & 0b1111_0000 != 0 { + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '35mi' (A|G|op BBBB F|E|D|C) \ + requires E to be between 0 and 15, found {ve}" + ))); + } + if vd & 0b1111_0000 != 0 { + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '35mi' (A|G|op BBBB F|E|D|C) \ + requires D to be between 0 and 15, found {vd}" + ))); + } + if vc & 0b1111_0000 != 0 { + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '35mi' (A|G|op BBBB F|E|D|C) \ + requires C to be between 0 and 15, found {vc}" + ))); + } + op.serialize(output)?; + let val = (a << 4) | vg; + val.serialize(output)?; + b.serialize(output)?; + let val = (vd << 4) | vc; + val.serialize(output)?; + let val = (vf << 4) | ve; + val.serialize(output) + } + Self::Format3RC { a, op, b, vc } => { + op.serialize(output)?; + a.serialize(output)?; + b.serialize(output)?; + vc.serialize(output) + } + Self::Format3RMS { a, op, b, vc } => { + op.serialize(output)?; + a.serialize(output)?; + b.serialize(output)?; + vc.serialize(output) + } + Self::Format3RMI { a, op, b, vc } => { + op.serialize(output)?; + a.serialize(output)?; + b.serialize(output)?; + vc.serialize(output) + } + Self::Format45CC { + a, + vg, + op, + b, + vf, + ve, + vd, + vc, + h, + } => { + if *a > 5 { + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '45cc' (A|G|op BBBB F|E|D|C) \ + requires A to be between 0 and 5, found {a}" + ))); + } + if vg & 0b1111_0000 != 0 { + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '45cc' (A|G|op BBBB F|E|D|C) \ + requires G to be between 0 and 15, found {vg}" + ))); + } + if vf & 0b1111_0000 != 0 { + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '45cc' (A|G|op BBBB F|E|D|C) \ + requires F to be between 0 and 15, found {vf}" + ))); + } + if ve & 0b1111_0000 != 0 { + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '45cc' (A|G|op BBBB F|E|D|C) \ + requires E to be between 0 and 15, found {ve}" + ))); + } + if vd & 0b1111_0000 != 0 { + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '45cc' (A|G|op BBBB F|E|D|C) \ + requires D to be between 0 and 15, found {vd}" + ))); + } + if vc & 0b1111_0000 != 0 { + return Err(Error::InconsistantStruct(format!( + "Dalvik instruction format '45cc' (A|G|op BBBB F|E|D|C) \ + requires C to be between 0 and 15, found {vc}" + ))); + } + op.serialize(output)?; + let val = (a << 4) | vg; + val.serialize(output)?; + b.serialize(output)?; + let val = (vd << 4) | vc; + val.serialize(output)?; + let val = (vf << 4) | ve; + val.serialize(output)?; + h.serialize(output) + } + Self::Format4RCC { a, op, b, vc, h } => { + op.serialize(output)?; + a.serialize(output)?; + b.serialize(output)?; + vc.serialize(output)?; + h.serialize(output) + } + Self::Format51L { va, op, b } => { + op.serialize(output)?; + va.serialize(output)?; + b.serialize(output) + } + } + } + + fn deserialize(input: &mut dyn ReadSeek) -> Result { + let pos = input.stream_position().map_err(|err| { + Error::SerializationError(format!("Failled to get position in steam: {err}")) + })?; + let op = u8::deserialize(input)?; + let _ = u8::deserialize(input)?; + input.seek(SeekFrom::Start(pos)).map_err(|err| { + Error::SerializationError(format!("Failled to get to position in steam: {err}")) + })?; + + match op { + 0x00 => Self::deserialize_10x(input), + 0x01 => Self::deserialize_12x(input), + 0x02 => Self::deserialize_22x(input), + 0x03 => Self::deserialize_32x(input), + 0x04 => Self::deserialize_12x(input), + 0x05 => Self::deserialize_22x(input), + 0x06 => Self::deserialize_32x(input), + 0x07 => Self::deserialize_12x(input), + 0x08 => Self::deserialize_22x(input), + 0x09 => Self::deserialize_32x(input), + 0x0a => Self::deserialize_11x(input), + 0x0b => Self::deserialize_11x(input), + 0x0c => Self::deserialize_11x(input), + 0x0d => Self::deserialize_11x(input), + 0x0e => Self::deserialize_10x(input), + 0x0f => Self::deserialize_11x(input), + 0x10 => Self::deserialize_11x(input), + 0x11 => Self::deserialize_11x(input), + 0x12 => Self::deserialize_11n(input), + 0x13 => Self::deserialize_21s(input), + 0x14 => Self::deserialize_31i(input), + 0x15 => Self::deserialize_21h(input), + 0x16 => Self::deserialize_21s(input), + 0x17 => Self::deserialize_31i(input), + 0x18 => Self::deserialize_51l(input), + 0x19 => Self::deserialize_21h(input), + 0x1a => Self::deserialize_21c(input), + 0x1b => Self::deserialize_31c(input), + 0x1c => Self::deserialize_21c(input), + 0x1d => Self::deserialize_11x(input), + 0x1e => Self::deserialize_11x(input), + 0x1f => Self::deserialize_21c(input), + 0x20 => Self::deserialize_22c(input), + 0x21 => Self::deserialize_12x(input), + 0x22 => Self::deserialize_21c(input), + 0x23 => Self::deserialize_22c(input), + 0x24 => Self::deserialize_35c(input), + 0x25 => Self::deserialize_3rc(input), + 0x26 => Self::deserialize_31t(input), + 0x27 => Self::deserialize_11x(input), + 0x28 => Self::deserialize_10t(input), + 0x29 => Self::deserialize_20t(input), + 0x2a => Self::deserialize_30t(input), + 0x2b => Self::deserialize_31t(input), + 0x2c => Self::deserialize_31t(input), + 0x2d..=0x31 => Self::deserialize_23x(input), + 0x32..=0x37 => Self::deserialize_22t(input), + 0x38..=0x3d => Self::deserialize_21t(input), + 0x3e..=0x43 => Self::deserialize_10x(input), + 0x44..=0x51 => Self::deserialize_23x(input), + 0x52..=0x5f => Self::deserialize_22c(input), + 0x60..=0x6d => Self::deserialize_21c(input), + 0x6e..=0x72 => Self::deserialize_35c(input), + 0x73 => Self::deserialize_10x(input), + 0x74..=0x78 => Self::deserialize_3rc(input), + 0x79..=0x7a => Self::deserialize_10x(input), + 0x7b..=0x8f => Self::deserialize_12x(input), + 0x90..=0xaf => Self::deserialize_23x(input), + 0xb0..=0xcf => Self::deserialize_12x(input), + 0xd0..=0xd7 => Self::deserialize_22s(input), + 0xd8..=0xe2 => Self::deserialize_22b(input), + 0xe3..=0xf9 => Self::deserialize_10x(input), + 0xfa => Self::deserialize_45cc(input), + 0xfb => Self::deserialize_4rcc(input), + 0xfc => Self::deserialize_35c(input), + 0xfd => Self::deserialize_3rc(input), + 0xfe => Self::deserialize_21c(input), + 0xff => Self::deserialize_21c(input), + } + } + + fn size(&self) -> usize { + match self { + Self::Format10X { .. } => 2, + Self::Format12X { .. } => 2, + Self::Format11N { .. } => 2, + Self::Format11X { .. } => 2, + Self::Format10T { .. } => 2, + Self::Format20T { .. } => 4, + Self::Format20BC { .. } => 4, + Self::Format22X { .. } => 4, + Self::Format21T { .. } => 4, + Self::Format21S { .. } => 4, + Self::Format21H { .. } => 4, + Self::Format21C { .. } => 4, + Self::Format23X { .. } => 4, + Self::Format22B { .. } => 4, + Self::Format22T { .. } => 4, + Self::Format22S { .. } => 4, + Self::Format22C { .. } => 4, + Self::Format22CS { .. } => 4, + Self::Format30T { .. } => 6, + Self::Format32X { .. } => 6, + Self::Format31I { .. } => 6, + Self::Format31T { .. } => 6, + Self::Format31C { .. } => 6, + Self::Format35C { .. } => 6, + Self::Format35MS { .. } => 6, + Self::Format35MI { .. } => 6, + Self::Format3RC { .. } => 6, + Self::Format3RMS { .. } => 6, + Self::Format3RMI { .. } => 6, + Self::Format45CC { .. } => 8, + Self::Format4RCC { .. } => 8, + Self::Format51L { .. } => 10, + } + } +} + +#[cfg(test)] +mod test { + use super::*; + use std::io::Cursor; + + const INSN_RAW_1: &[u8] = &[ + 0x70, 0x10, 0x8b, 0x84, 0x05, 0x00, 0x22, 0x00, 0x2d, 0x24, 0x70, 0x10, 0x51, 0x87, 0x00, + 0x00, 0x5b, 0x50, 0x54, 0x06, 0x5b, 0x57, 0x58, 0x06, 0x22, 0x00, 0x84, 0x05, 0x70, 0x10, + 0x09, 0x1c, 0x00, 0x00, 0x5b, 0x50, 0x56, 0x06, 0x54, 0x77, 0xcc, 0x09, 0x71, 0x20, 0xed, + 0x18, 0x76, 0x00, 0x0c, 0x07, 0x5b, 0x57, 0x55, 0x06, 0x71, 0x10, 0xb9, 0x17, 0x06, 0x00, + 0x0c, 0x06, 0x5b, 0x56, 0x57, 0x06, 0x22, 0x06, 0x1e, 0x24, 0x70, 0x10, 0xa1, 0x86, 0x06, + 0x00, 0x54, 0x70, 0x01, 0x08, 0x1f, 0x00, 0x7a, 0x04, 0x6e, 0x10, 0x8e, 0x84, 0x00, 0x00, + 0x54, 0x00, 0x04, 0x08, 0x6e, 0x10, 0x2a, 0x04, 0x00, 0x00, 0x0c, 0x00, 0x71, 0x10, 0xbc, + 0x86, 0x00, 0x00, 0x0c, 0x00, 0x39, 0x08, 0x16, 0x00, 0x72, 0x10, 0x8d, 0x87, 0x00, 0x00, + 0x0c, 0x07, 0x72, 0x10, 0x6c, 0x87, 0x07, 0x00, 0x0a, 0x08, 0x38, 0x08, 0x58, 0x00, 0x72, + 0x10, 0x6d, 0x87, 0x07, 0x00, 0x0c, 0x08, 0x1f, 0x08, 0x87, 0x23, 0x6e, 0x20, 0xa5, 0x86, + 0x86, 0x00, 0x28, 0xf1, 0x6e, 0x10, 0xf3, 0x19, 0x08, 0x00, 0x0c, 0x01, 0x71, 0x30, 0x73, + 0x17, 0x17, 0x00, 0x0c, 0x07, 0x28, 0x02, 0x12, 0x07, 0x22, 0x01, 0x1e, 0x24, 0x70, 0x10, + 0xa1, 0x86, 0x01, 0x00, 0x72, 0x10, 0x8d, 0x87, 0x00, 0x00, 0x0c, 0x00, 0x72, 0x10, 0x6c, + 0x87, 0x00, 0x00, 0x0a, 0x02, 0x38, 0x02, 0x17, 0x00, 0x72, 0x10, 0x6d, 0x87, 0x00, 0x00, + 0x0c, 0x02, 0x1f, 0x02, 0x87, 0x23, 0x6e, 0x20, 0xb5, 0x84, 0x72, 0x00, 0x0a, 0x03, 0x38, + 0x03, 0x03, 0x00, 0x28, 0xee, 0x6e, 0x20, 0x8f, 0x16, 0x25, 0x00, 0x0c, 0x02, 0x6e, 0x20, + 0xa5, 0x86, 0x21, 0x00, 0x28, 0xe6, 0x6e, 0x20, 0xf2, 0x19, 0x18, 0x00, 0x0c, 0x07, 0x72, + 0x10, 0x8d, 0x87, 0x07, 0x00, 0x0c, 0x07, 0x72, 0x10, 0x6c, 0x87, 0x07, 0x00, 0x0a, 0x08, + 0x38, 0x08, 0x12, 0x00, 0x72, 0x10, 0x6d, 0x87, 0x07, 0x00, 0x0c, 0x08, 0x1f, 0x08, 0xd4, + 0x04, 0x1f, 0x08, 0x7d, 0x05, 0x72, 0x10, 0xf3, 0x1b, 0x08, 0x00, 0x0c, 0x08, 0x6e, 0x20, + 0xa5, 0x86, 0x86, 0x00, 0x28, 0xeb, 0x22, 0x07, 0x1e, 0x24, 0x70, 0x10, 0xa1, 0x86, 0x07, + 0x00, 0x6e, 0x10, 0xaf, 0x86, 0x06, 0x00, 0x0c, 0x06, 0x72, 0x10, 0x6c, 0x87, 0x06, 0x00, + 0x0a, 0x08, 0x38, 0x08, 0x57, 0x00, 0x72, 0x10, 0x6d, 0x87, 0x06, 0x00, 0x0c, 0x08, 0x1f, + 0x08, 0x87, 0x23, 0x1a, 0x00, 0xb5, 0x0d, 0x6e, 0x20, 0xb5, 0x84, 0x08, 0x00, 0x0a, 0x00, + 0x39, 0x00, 0x45, 0x00, 0x1a, 0x00, 0xd0, 0x0d, 0x6e, 0x20, 0xb5, 0x84, 0x08, 0x00, 0x0a, + 0x00, 0x38, 0x00, 0x03, 0x00, 0x28, 0x3b, 0x62, 0x00, 0xe2, 0x00, 0x1a, 0x01, 0x49, 0xc0, + 0x6e, 0x20, 0xb5, 0x84, 0x01, 0x00, 0x0a, 0x00, 0x38, 0x00, 0x03, 0x00, 0x28, 0x1a, 0x54, + 0x50, 0x55, 0x06, 0x6e, 0x20, 0xee, 0x18, 0x80, 0x00, 0x0c, 0x00, 0x62, 0x01, 0xb6, 0x00, + 0x6e, 0x20, 0xc4, 0x18, 0x10, 0x00, 0x0c, 0x00, 0x1f, 0x00, 0x9c, 0x2e, 0x12, 0x01, 0x38, + 0x00, 0x0f, 0x00, 0x21, 0x02, 0x01, 0x13, 0x35, 0x23, 0x0b, 0x00, 0x44, 0x04, 0x00, 0x03, + 0x39, 0x04, 0x04, 0x00, 0x12, 0x11, 0x28, 0x04, 0xd8, 0x03, 0x03, 0x01, 0x28, 0xf6, 0x38, + 0x01, 0xba, 0xff, 0x6e, 0x20, 0xa5, 0x86, 0x87, 0x00, 0x28, 0xb5, 0x0d, 0x06, 0x22, 0x07, + 0x1e, 0x05, 0x71, 0x10, 0xff, 0x48, 0x06, 0x00, 0x0c, 0x06, 0x70, 0x20, 0xc2, 0x1a, 0x67, + 0x00, 0x27, 0x07, 0x6e, 0x20, 0xa5, 0x86, 0x87, 0x00, 0x28, 0xa6, 0x5b, 0x57, 0x53, 0x06, + 0x0e, 0x00, 0x0d, 0x06, 0x22, 0x07, 0x47, 0x04, 0x70, 0x20, 0x84, 0x18, 0x67, 0x00, 0x27, + 0x07, 0x0d, 0x06, 0x22, 0x07, 0x1e, 0x05, 0x70, 0x20, 0xc2, 0x1a, 0x67, 0x00, 0x27, 0x07, + 0x0d, 0x06, 0x22, 0x07, 0x1e, 0x05, 0x71, 0x10, 0xff, 0x48, 0x06, 0x00, 0x0c, 0x06, 0x70, + 0x20, 0xc2, 0x1a, 0x67, 0x00, 0x27, 0x07, + ]; + const INSN_VAL_1: &[Instruction] = &[ + Instruction::Format35C { + a: 1, + b: 33931, + vc: 5, + vd: 0, + ve: 0, + vf: 0, + vg: 0, + op: 0x70, + }, + Instruction::Format21C { + va: 0, + b: 9261, + op: 0x22, + }, + Instruction::Format35C { + a: 1, + b: 34641, + vc: 0, + vd: 0, + ve: 0, + vf: 0, + vg: 0, + op: 0x70, + }, + Instruction::Format22C { + va: 0, + vb: 5, + c: 1620, + op: 0x5b, + }, + Instruction::Format22C { + va: 7, + vb: 5, + c: 1624, + op: 0x5b, + }, + Instruction::Format21C { + va: 0, + b: 1412, + op: 0x22, + }, + Instruction::Format35C { + a: 1, + b: 7177, + vc: 0, + vd: 0, + ve: 0, + vf: 0, + vg: 0, + op: 0x70, + }, + Instruction::Format22C { + va: 0, + vb: 5, + c: 1622, + op: 0x5b, + }, + Instruction::Format22C { + va: 7, + vb: 7, + c: 2508, + op: 0x54, + }, + Instruction::Format35C { + a: 2, + b: 6381, + vc: 6, + vd: 7, + ve: 0, + vf: 0, + vg: 0, + op: 0x71, + }, + Instruction::Format11X { va: 7, op: 0xc }, + Instruction::Format22C { + va: 7, + vb: 5, + c: 1621, + op: 0x5b, + }, + Instruction::Format35C { + a: 1, + b: 6073, + vc: 6, + vd: 0, + ve: 0, + vf: 0, + vg: 0, + op: 0x71, + }, + Instruction::Format11X { va: 6, op: 0xc }, + Instruction::Format22C { + va: 6, + vb: 5, + c: 1623, + op: 0x5b, + }, + Instruction::Format21C { + va: 6, + b: 9246, + op: 0x22, + }, + Instruction::Format35C { + a: 1, + b: 34465, + vc: 6, + vd: 0, + ve: 0, + vf: 0, + vg: 0, + op: 0x70, + }, + Instruction::Format22C { + va: 0, + vb: 7, + c: 2049, + op: 0x54, + }, + Instruction::Format21C { + va: 0, + b: 1146, + op: 0x1f, + }, + Instruction::Format35C { + a: 1, + b: 33934, + vc: 0, + vd: 0, + ve: 0, + vf: 0, + vg: 0, + op: 0x6e, + }, + Instruction::Format22C { + va: 0, + vb: 0, + c: 2052, + op: 0x54, + }, + Instruction::Format35C { + a: 1, + b: 1066, + vc: 0, + vd: 0, + ve: 0, + vf: 0, + vg: 0, + op: 0x6e, + }, + Instruction::Format11X { va: 0, op: 0xc }, + Instruction::Format35C { + a: 1, + b: 34492, + vc: 0, + vd: 0, + ve: 0, + vf: 0, + vg: 0, + op: 0x71, + }, + Instruction::Format11X { va: 0, op: 0xc }, + Instruction::Format21T { + va: 8, + b: 22, + op: 0x39, + }, + Instruction::Format35C { + a: 1, + b: 34701, + vc: 0, + vd: 0, + ve: 0, + vf: 0, + vg: 0, + op: 0x72, + }, + Instruction::Format11X { va: 7, op: 0xc }, + Instruction::Format35C { + a: 1, + b: 34668, + vc: 7, + vd: 0, + ve: 0, + vf: 0, + vg: 0, + op: 0x72, + }, + Instruction::Format11X { va: 8, op: 0xa }, + Instruction::Format21T { + va: 8, + b: 88, + op: 0x38, + }, + Instruction::Format35C { + a: 1, + b: 34669, + vc: 7, + vd: 0, + ve: 0, + vf: 0, + vg: 0, + op: 0x72, + }, + Instruction::Format11X { va: 8, op: 0xc }, + Instruction::Format21C { + va: 8, + b: 9095, + op: 0x1f, + }, + Instruction::Format35C { + a: 2, + b: 34469, + vc: 6, + vd: 8, + ve: 0, + vf: 0, + vg: 0, + op: 0x6e, + }, + Instruction::Format10T { a: -15, op: 0x28 }, + Instruction::Format35C { + a: 1, + b: 6643, + vc: 8, + vd: 0, + ve: 0, + vf: 0, + vg: 0, + op: 0x6e, + }, + Instruction::Format11X { va: 1, op: 0xc }, + Instruction::Format35C { + a: 3, + b: 6003, + vc: 7, + vd: 1, + ve: 0, + vf: 0, + vg: 0, + op: 0x71, + }, + Instruction::Format11X { va: 7, op: 0xc }, + Instruction::Format10T { a: 2, op: 0x28 }, + Instruction::Format11N { + va: 7, + b: 0, + op: 0x12, + }, + Instruction::Format21C { + va: 1, + b: 9246, + op: 0x22, + }, + Instruction::Format35C { + a: 1, + b: 34465, + vc: 1, + vd: 0, + ve: 0, + vf: 0, + vg: 0, + op: 0x70, + }, + Instruction::Format35C { + a: 1, + b: 34701, + vc: 0, + vd: 0, + ve: 0, + vf: 0, + vg: 0, + op: 0x72, + }, + Instruction::Format11X { va: 0, op: 0xc }, + Instruction::Format35C { + a: 1, + b: 34668, + vc: 0, + vd: 0, + ve: 0, + vf: 0, + vg: 0, + op: 0x72, + }, + Instruction::Format11X { va: 2, op: 0xa }, + Instruction::Format21T { + va: 2, + b: 23, + op: 0x38, + }, + Instruction::Format35C { + a: 1, + b: 34669, + vc: 0, + vd: 0, + ve: 0, + vf: 0, + vg: 0, + op: 0x72, + }, + Instruction::Format11X { va: 2, op: 0xc }, + Instruction::Format21C { + va: 2, + b: 9095, + op: 0x1f, + }, + Instruction::Format35C { + a: 2, + b: 33973, + vc: 2, + vd: 7, + ve: 0, + vf: 0, + vg: 0, + op: 0x6e, + }, + Instruction::Format11X { va: 3, op: 0xa }, + Instruction::Format21T { + va: 3, + b: 3, + op: 0x38, + }, + Instruction::Format10T { a: -18, op: 0x28 }, + Instruction::Format35C { + a: 2, + b: 5775, + vc: 5, + vd: 2, + ve: 0, + vf: 0, + vg: 0, + op: 0x6e, + }, + Instruction::Format11X { va: 2, op: 0xc }, + Instruction::Format35C { + a: 2, + b: 34469, + vc: 1, + vd: 2, + ve: 0, + vf: 0, + vg: 0, + op: 0x6e, + }, + Instruction::Format10T { a: -26, op: 0x28 }, + Instruction::Format35C { + a: 2, + b: 6642, + vc: 8, + vd: 1, + ve: 0, + vf: 0, + vg: 0, + op: 0x6e, + }, + Instruction::Format11X { va: 7, op: 0xc }, + Instruction::Format35C { + a: 1, + b: 34701, + vc: 7, + vd: 0, + ve: 0, + vf: 0, + vg: 0, + op: 0x72, + }, + Instruction::Format11X { va: 7, op: 0xc }, + Instruction::Format35C { + a: 1, + b: 34668, + vc: 7, + vd: 0, + ve: 0, + vf: 0, + vg: 0, + op: 0x72, + }, + Instruction::Format11X { va: 8, op: 0xa }, + Instruction::Format21T { + va: 8, + b: 18, + op: 0x38, + }, + Instruction::Format35C { + a: 1, + b: 34669, + vc: 7, + vd: 0, + ve: 0, + vf: 0, + vg: 0, + op: 0x72, + }, + Instruction::Format11X { va: 8, op: 0xc }, + Instruction::Format21C { + va: 8, + b: 1236, + op: 0x1f, + }, + Instruction::Format21C { + va: 8, + b: 1405, + op: 0x1f, + }, + Instruction::Format35C { + a: 1, + b: 7155, + vc: 8, + vd: 0, + ve: 0, + vf: 0, + vg: 0, + op: 0x72, + }, + Instruction::Format11X { va: 8, op: 0xc }, + Instruction::Format35C { + a: 2, + b: 34469, + vc: 6, + vd: 8, + ve: 0, + vf: 0, + vg: 0, + op: 0x6e, + }, + Instruction::Format10T { a: -21, op: 0x28 }, + Instruction::Format21C { + va: 7, + b: 9246, + op: 0x22, + }, + Instruction::Format35C { + a: 1, + b: 34465, + vc: 7, + vd: 0, + ve: 0, + vf: 0, + vg: 0, + op: 0x70, + }, + Instruction::Format35C { + a: 1, + b: 34479, + vc: 6, + vd: 0, + ve: 0, + vf: 0, + vg: 0, + op: 0x6e, + }, + Instruction::Format11X { va: 6, op: 0xc }, + Instruction::Format35C { + a: 1, + b: 34668, + vc: 6, + vd: 0, + ve: 0, + vf: 0, + vg: 0, + op: 0x72, + }, + Instruction::Format11X { va: 8, op: 0xa }, + Instruction::Format21T { + va: 8, + b: 87, + op: 0x38, + }, + Instruction::Format35C { + a: 1, + b: 34669, + vc: 6, + vd: 0, + ve: 0, + vf: 0, + vg: 0, + op: 0x72, + }, + Instruction::Format11X { va: 8, op: 0xc }, + Instruction::Format21C { + va: 8, + b: 9095, + op: 0x1f, + }, + Instruction::Format21C { + va: 0, + b: 3509, + op: 0x1a, + }, + Instruction::Format35C { + a: 2, + b: 33973, + vc: 8, + vd: 0, + ve: 0, + vf: 0, + vg: 0, + op: 0x6e, + }, + Instruction::Format11X { va: 0, op: 0xa }, + Instruction::Format21T { + va: 0, + b: 69, + op: 0x39, + }, + Instruction::Format21C { + va: 0, + b: 3536, + op: 0x1a, + }, + Instruction::Format35C { + a: 2, + b: 33973, + vc: 8, + vd: 0, + ve: 0, + vf: 0, + vg: 0, + op: 0x6e, + }, + Instruction::Format11X { va: 0, op: 0xa }, + Instruction::Format21T { + va: 0, + b: 3, + op: 0x38, + }, + Instruction::Format10T { a: 59, op: 0x28 }, + Instruction::Format21C { + va: 0, + b: 226, + op: 0x62, + }, + Instruction::Format21C { + va: 1, + b: 49225, + op: 0x1a, + }, + Instruction::Format35C { + a: 2, + b: 33973, + vc: 1, + vd: 0, + ve: 0, + vf: 0, + vg: 0, + op: 0x6e, + }, + Instruction::Format11X { va: 0, op: 0xa }, + Instruction::Format21T { + va: 0, + b: 3, + op: 0x38, + }, + Instruction::Format10T { a: 26, op: 0x28 }, + Instruction::Format22C { + va: 0, + vb: 5, + c: 1621, + op: 0x54, + }, + Instruction::Format35C { + a: 2, + b: 6382, + vc: 0, + vd: 8, + ve: 0, + vf: 0, + vg: 0, + op: 0x6e, + }, + Instruction::Format11X { va: 0, op: 0xc }, + Instruction::Format21C { + va: 1, + b: 182, + op: 0x62, + }, + Instruction::Format35C { + a: 2, + b: 6340, + vc: 0, + vd: 1, + ve: 0, + vf: 0, + vg: 0, + op: 0x6e, + }, + Instruction::Format11X { va: 0, op: 0xc }, + Instruction::Format21C { + va: 0, + b: 11932, + op: 0x1f, + }, + Instruction::Format11N { + va: 1, + b: 0, + op: 0x12, + }, + Instruction::Format21T { + va: 0, + b: 15, + op: 0x38, + }, + Instruction::Format12X { + va: 2, + vb: 0, + op: 0x21, + }, + Instruction::Format12X { + va: 3, + vb: 1, + op: 0x1, + }, + Instruction::Format22T { + va: 3, + vb: 2, + c: 11, + op: 0x35, + }, + Instruction::Format23X { + va: 4, + vb: 0, + vc: 3, + op: 0x44, + }, + Instruction::Format21T { + va: 4, + b: 4, + op: 0x39, + }, + Instruction::Format11N { + va: 1, + b: 1, + op: 0x12, + }, + Instruction::Format10T { a: 4, op: 0x28 }, + Instruction::Format22B { + va: 3, + vb: 3, + c: 1, + op: 0xd8, + }, + Instruction::Format10T { a: -10, op: 0x28 }, + Instruction::Format21T { + va: 1, + b: -70, + op: 0x38, + }, + Instruction::Format35C { + a: 2, + b: 34469, + vc: 7, + vd: 8, + ve: 0, + vf: 0, + vg: 0, + op: 0x6e, + }, + Instruction::Format10T { a: -75, op: 0x28 }, + Instruction::Format11X { va: 6, op: 0xd }, + Instruction::Format21C { + va: 7, + b: 1310, + op: 0x22, + }, + Instruction::Format35C { + a: 1, + b: 18687, + vc: 6, + vd: 0, + ve: 0, + vf: 0, + vg: 0, + op: 0x71, + }, + Instruction::Format11X { va: 6, op: 0xc }, + Instruction::Format35C { + a: 2, + b: 6850, + vc: 7, + vd: 6, + ve: 0, + vf: 0, + vg: 0, + op: 0x70, + }, + Instruction::Format11X { va: 7, op: 0x27 }, + Instruction::Format35C { + a: 2, + b: 34469, + vc: 7, + vd: 8, + ve: 0, + vf: 0, + vg: 0, + op: 0x6e, + }, + Instruction::Format10T { a: -90, op: 0x28 }, + Instruction::Format22C { + va: 7, + vb: 5, + c: 1619, + op: 0x5b, + }, + Instruction::Format10X { op: 0xe }, + Instruction::Format11X { va: 6, op: 0xd }, + Instruction::Format21C { + va: 7, + b: 1095, + op: 0x22, + }, + Instruction::Format35C { + a: 2, + b: 6276, + vc: 7, + vd: 6, + ve: 0, + vf: 0, + vg: 0, + op: 0x70, + }, + Instruction::Format11X { va: 7, op: 0x27 }, + Instruction::Format11X { va: 6, op: 0xd }, + Instruction::Format21C { + va: 7, + b: 1310, + op: 0x22, + }, + Instruction::Format35C { + a: 2, + b: 6850, + vc: 7, + vd: 6, + ve: 0, + vf: 0, + vg: 0, + op: 0x70, + }, + Instruction::Format11X { va: 7, op: 0x27 }, + Instruction::Format11X { va: 6, op: 0xd }, + Instruction::Format21C { + va: 7, + b: 1310, + op: 0x22, + }, + Instruction::Format35C { + a: 1, + b: 18687, + vc: 6, + vd: 0, + ve: 0, + vf: 0, + vg: 0, + op: 0x71, + }, + Instruction::Format11X { va: 6, op: 0xc }, + Instruction::Format35C { + a: 2, + b: 6850, + vc: 7, + vd: 6, + ve: 0, + vf: 0, + vg: 0, + op: 0x70, + }, + Instruction::Format11X { va: 7, op: 0x27 }, + ]; + + #[test] + fn test_insn_parsing() { + // TODO: comute n on the fly + let n = INSN_VAL_1.len(); + let mut instructions = vec![]; + let mut buffer = Cursor::new(INSN_RAW_1); + for _ in 0..n { + instructions.push(Instruction::deserialize(&mut buffer).unwrap()); + } + assert_eq!(instructions, INSN_VAL_1); + let mut output = Cursor::new(Vec::::new()); + for ins in INSN_VAL_1 { + ins.serialize(&mut output).unwrap(); + } + assert_eq!(output.into_inner(), INSN_RAW_1); + assert_eq!( + INSN_RAW_1.len(), + INSN_VAL_1.iter().map(|ins| ins.size()).sum() + ); + } + + #[test] + fn test_parsing_35c() { + for (raw, expected) in [ + ( + vec![0x70, 0x10, 0x8b, 0x84, 0x05, 0x00], + Instruction::Format35C { + a: 1, + vg: 0, + op: 0x70, + b: 0x848b, + vf: 0, + ve: 0, + vd: 0, + vc: 5, + }, + ), + ( + vec![0x70, 0x10, 0x51, 0x87, 0x00, 0x00], + Instruction::Format35C { + a: 1, + vg: 0, + op: 0x70, + b: 0x8751, + vf: 0, + ve: 0, + vd: 0, + vc: 0, + }, + ), + ] { + 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_51l() { + for (raw, expected) in [ + ( + vec![0x18, 0x0c, 0x18, 0x2d, 0x44, 0x54, 0xfb, 0x21, 0xf9, 0x3f], + Instruction::Format51L { + va: 12, + b: 0x3ff921fb54442d18, + op: 0x18, + }, + ), + ( + vec![0x18, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00], + Instruction::Format51L { + va: 13, + b: 0x200000000, + op: 0x18, + }, + ), + ( + vec![0x18, 0x05, 0x80, 0x3f, 0xe0, 0x0f, 0xf8, 0x03, 0xfe, 0xff], + Instruction::Format51L { + va: 5, + b: -558586000294016, + op: 0x18, + }, + ), + ] { + 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]; + let expected = Instruction::Format21C { + va: 0, + op: 0x22, + b: 0x242d, + }; + 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_22c() { + let raw = vec![0x5b, 0x50, 0x54, 0x06]; + let expected = Instruction::Format22C { + va: 0, + op: 0x5b, + vb: 5, + c: 0x654, + }; + assert_eq!(expected.size(), raw.len()); + assert_eq!(expected, Instruction::deserialize_from_slice(&raw).unwrap()); + assert_eq!(raw, expected.serialize_to_vec().unwrap()); + } +} diff --git a/androscalpel_serializer/src/items/mod.rs b/androscalpel_serializer/src/items/mod.rs index 82fb4cf..1d3d843 100644 --- a/androscalpel_serializer/src/items/mod.rs +++ b/androscalpel_serializer/src/items/mod.rs @@ -9,12 +9,14 @@ pub mod class; pub mod code; pub mod header; pub mod hiddenapi; +pub mod instructions; pub mod map; pub use class::*; pub use code::*; pub use header::*; pub use hiddenapi::*; +pub use instructions::*; pub use map::*; ///