diff --git a/androscalpel_serializer/src/core/leb.rs b/androscalpel_serializer/src/core/leb.rs new file mode 100644 index 0000000..75ee847 --- /dev/null +++ b/androscalpel_serializer/src/core/leb.rs @@ -0,0 +1,318 @@ +//! The implementation of serializable for LEB128 types. + +use std::io::Write; + +use crate::{Error, ReadSeek, Result, Serializable}; + +/// Signed LEB128, variable-length +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Sleb128(i32); + +/// Unsigned LEB128, variable-length +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Uleb128(u32); + +/// Unsigned LEB128 plus 1, variable-length +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Uleb128p1(u32); + +impl Sleb128 { + fn get_serialized_bytes(&self) -> Vec { + let Self(mut val) = self; + let mut bytes = vec![]; + loop { + let byte = val as u8 & 0b0111_1111; + val /= 64; + if val == 0 || val == -1 { + bytes.push(byte); + return bytes; + } else { + val /= 2; + } + bytes.push(byte | 0b1000_0000); + } + } +} + +impl Serializable for Sleb128 { + fn serialize(&self, output: &mut dyn Write) -> Result<()> { + output + .write_all(&self.get_serialized_bytes()) + .map_err(|err| { + Error::SerializationError(format!( + "Failed to write serialize Sleb128 to output: {err}" + )) + })?; + Ok(()) + } + + fn deserialize(input: &mut dyn ReadSeek) -> Result { + let mut shift = 0; + let mut uvalue: u64 = 0; + let mut buffer = [0u8; 1]; + for _ in 0..5 { + input.read_exact(&mut buffer).map_err(|_| { + Error::InputTooSmall("Failed to read all bytes for Sleb128 from the input".into()) + })?; + let byte = buffer[0]; + let is_last_byte = byte & 0b1000_0000 == 0; + + if is_last_byte { + uvalue += ((byte & 0b0011_1111) as u64) << shift; + let sign = ((byte & 0b0100_0000) as u64) << shift; + let value = uvalue as i64 - sign as i64; + let value: i32 = value.try_into().map_err(|err| Error::DeserializationError( + format!("Failed to parse the Sleb128 value, the encoded value is supposed to fit in 32 bits: {err}") + ))?; + return Ok(Self(value)); + } else { + uvalue |= ((byte & 0b0111_1111) as u64) << shift; + shift += 7; + } + } + Err(Error::DeserializationError( + "Malfored LEB128 encoding: the value cannot be longer than 5 bytes".into(), + )) + } + + fn size(&self) -> usize { + self.get_serialized_bytes().len() + } +} + +impl Uleb128 { + fn get_serialized_bytes(&self) -> Vec { + let Self(mut val) = self; + let mut bytes = vec![]; + loop { + let byte = val as u8 & 0b0111_1111; + val /= 128; + if val == 0 { + bytes.push(byte); + return bytes; + } + bytes.push(byte | 0b1000_0000); + } + } +} + +impl Serializable for Uleb128 { + fn serialize(&self, output: &mut dyn Write) -> Result<()> { + output + .write_all(&self.get_serialized_bytes()) + .map_err(|err| { + Error::SerializationError(format!( + "Failed to write serialize Uleb128 to output: {err}" + )) + })?; + Ok(()) + } + + fn deserialize(input: &mut dyn ReadSeek) -> Result { + let mut shift = 0; + let mut value: u32 = 0; + let mut buffer = [0u8; 1]; + for _ in 0..5 { + input.read_exact(&mut buffer).map_err(|_| { + Error::InputTooSmall("Failed to read all bytes for Uleb128 from the input".into()) + })?; + let byte = buffer[0]; + let is_last_byte = byte & 0b1000_0000 == 0; + + value += ((byte & 0b0111_1111) as u32) << shift; + if is_last_byte { + return Ok(Self(value)); + } + shift += 7; + } + Err(Error::DeserializationError( + "Malfored LEB128 encoding: the value cannot be longer than 5 bytes".into(), + )) + } + + fn size(&self) -> usize { + self.get_serialized_bytes().len() + } +} + +impl Uleb128p1 { + pub const MINUS_ONE: Uleb128p1 = Uleb128p1(0xFFFFFFFF); +} + +impl Serializable for Uleb128p1 { + fn serialize(&self, output: &mut dyn Write) -> Result<()> { + let Self(val) = self; + Uleb128(val.overflowing_add(1).0).serialize(output) + } + + fn deserialize(input: &mut dyn ReadSeek) -> Result { + let Uleb128(val) = Uleb128::deserialize(input)?; + Ok(Self(val.overflowing_sub(1).0)) + } + + fn size(&self) -> usize { + let Self(val) = self; + Uleb128(val.overflowing_add(1).0).size() + } +} + +impl From for Sleb128 { + fn from(item: i32) -> Self { + Self(item) + } +} + +impl From for Uleb128 { + fn from(item: u32) -> Self { + Self(item) + } +} + +impl From for Uleb128p1 { + fn from(item: u32) -> Self { + Self(item) + } +} + +impl From for i32 { + fn from(item: Sleb128) -> Self { + item.0 + } +} + +impl From for u32 { + fn from(item: Uleb128) -> Self { + item.0 + } +} + +impl From for u32 { + fn from(item: Uleb128p1) -> Self { + item.0 + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn serialize_sleb128() { + assert_eq!(Sleb128(0).serialize_to_vec().unwrap(), vec![0x00u8]); + assert_eq!(Sleb128(1).serialize_to_vec().unwrap(), vec![0x01u8]); + assert_eq!(Sleb128(-1).serialize_to_vec().unwrap(), vec![0x7Fu8]); + assert_eq!( + Sleb128(-128).serialize_to_vec().unwrap(), + vec![0x80u8, 0x7F] + ); + } + + #[test] + fn deserialize_sleb128() { + assert_eq!( + Sleb128::deserialize_from_slice(&[0x00u8]).unwrap(), + Sleb128(0) + ); + assert_eq!( + Sleb128::deserialize_from_slice(&[0x01u8]).unwrap(), + Sleb128(1) + ); + assert_eq!( + Sleb128::deserialize_from_slice(&[0x7Fu8]).unwrap(), + Sleb128(-1) + ); + assert_eq!( + Sleb128::deserialize_from_slice(&[0x80u8, 0x7Fu8]).unwrap(), + Sleb128(-128) + ); + } + + #[test] + fn size_sleb128() { + assert_eq!(Sleb128(0).size(), 1); + assert_eq!(Sleb128(1).size(), 1); + assert_eq!(Sleb128(-1).size(), 1); + assert_eq!(Sleb128(-128).size(), 2); + } + + #[test] + fn serialize_uleb128() { + assert_eq!(Uleb128(0).serialize_to_vec().unwrap(), vec![0x00u8]); + assert_eq!(Uleb128(1).serialize_to_vec().unwrap(), vec![0x01u8]); + assert_eq!(Uleb128(127).serialize_to_vec().unwrap(), vec![0x7Fu8]); + assert_eq!( + Uleb128(16256).serialize_to_vec().unwrap(), + vec![0x80u8, 0x7F] + ); + } + + #[test] + fn deserialize_uleb128() { + assert_eq!( + Uleb128::deserialize_from_slice(&[0x00u8]).unwrap(), + Uleb128(0) + ); + assert_eq!( + Uleb128::deserialize_from_slice(&[0x01u8]).unwrap(), + Uleb128(1) + ); + assert_eq!( + Uleb128::deserialize_from_slice(&[0x7Fu8]).unwrap(), + Uleb128(127) + ); + assert_eq!( + Uleb128::deserialize_from_slice(&[0x80u8, 0x7Fu8]).unwrap(), + Uleb128(16256) + ); + } + + #[test] + fn size_uleb128() { + assert_eq!(Uleb128(0).size(), 1); + assert_eq!(Uleb128(1).size(), 1); + assert_eq!(Uleb128(127).size(), 1); + assert_eq!(Uleb128(16256).size(), 2); + } + + #[test] + fn serialize_uleb128p1() { + assert_eq!( + Uleb128p1::MINUS_ONE.serialize_to_vec().unwrap(), + vec![0x00u8] + ); + assert_eq!(Uleb128p1(0).serialize_to_vec().unwrap(), vec![0x01u8]); + assert_eq!(Uleb128p1(126).serialize_to_vec().unwrap(), vec![0x7Fu8]); + assert_eq!( + Uleb128p1(16255).serialize_to_vec().unwrap(), + vec![0x80u8, 0x7F] + ); + } + + #[test] + fn deserialize_uleb128p1() { + assert_eq!( + Uleb128p1::deserialize_from_slice(&[0x00u8]).unwrap(), + Uleb128p1::MINUS_ONE + ); + assert_eq!( + Uleb128p1::deserialize_from_slice(&[0x01u8]).unwrap(), + Uleb128p1(0) + ); + assert_eq!( + Uleb128p1::deserialize_from_slice(&[0x7Fu8]).unwrap(), + Uleb128p1(126) + ); + assert_eq!( + Uleb128p1::deserialize_from_slice(&[0x80u8, 0x7Fu8]).unwrap(), + Uleb128p1(16255) + ); + } + + #[test] + fn size_uleb128p1() { + assert_eq!(Uleb128p1::MINUS_ONE.size(), 1); + assert_eq!(Uleb128p1(0).size(), 1); + assert_eq!(Uleb128p1(126).size(), 1); + assert_eq!(Uleb128p1(16255).size(), 2); + } +} diff --git a/androscalpel_serializer/src/core.rs b/androscalpel_serializer/src/core/mod.rs similarity index 95% rename from androscalpel_serializer/src/core.rs rename to androscalpel_serializer/src/core/mod.rs index 595cdc1..7db9892 100644 --- a/androscalpel_serializer/src/core.rs +++ b/androscalpel_serializer/src/core/mod.rs @@ -5,10 +5,14 @@ use std::io::{Cursor, Read, Seek, SeekFrom, Write}; pub use androscalpel_serializer_derive::*; +mod leb; +pub use leb::*; + #[derive(Debug, PartialEq, Eq)] pub enum Error { InputTooSmall(String), // TODO: find a better name - SerializeationError(String), + SerializationError(String), + DeserializationError(String), } pub type Result = core::result::Result; @@ -20,7 +24,8 @@ impl std::fmt::Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { Self::InputTooSmall(msg) => write!(f, "Error: {}", msg), - Self::SerializeationError(msg) => write!(f, "Error: {}", msg), + Self::SerializationError(msg) => write!(f, "Error: {}", msg), + Self::DeserializationError(msg) => write!(f, "Error: {}", msg), } } } @@ -85,15 +90,13 @@ impl SerializableUntil for Vec { let mut data = Self::new(); loop { let pos = input.stream_position().map_err(|err| { - Error::SerializeationError(format!("Failled to get position in steam: {err}")) + Error::SerializationError(format!("Failled to get position in steam: {err}")) })?; match U::deserialize(input) { Ok(val) if val == end_val => break Ok(data), Err(err) => break Err(err), Ok(_) => input.seek(SeekFrom::Start(pos)).map_err(|err| { - Error::SerializeationError(format!( - "Failled to get to position in steam: {err}" - )) + Error::SerializationError(format!("Failled to get to position in steam: {err}")) })?, }; data.push(D::deserialize(input)?); @@ -108,7 +111,7 @@ impl SerializableUntil for Vec { impl Serializable for u8 { fn serialize(&self, output: &mut dyn Write) -> Result<()> { output.write_all(&self.to_be_bytes()).map_err(|err| { - Error::SerializeationError(format!("Failed to write serialize u8 to output: {err}")) + Error::SerializationError(format!("Failed to write serialize u8 to output: {err}")) })?; Ok(()) } @@ -129,7 +132,7 @@ impl Serializable for u8 { impl Serializable for i8 { fn serialize(&self, output: &mut dyn Write) -> Result<()> { output.write_all(&self.to_be_bytes()).map_err(|err| { - Error::SerializeationError(format!("Failed to write serialize i8 to output: {err}")) + Error::SerializationError(format!("Failed to write serialize i8 to output: {err}")) })?; Ok(()) } @@ -150,7 +153,7 @@ impl Serializable for i8 { impl Serializable for u16 { fn serialize(&self, output: &mut dyn Write) -> Result<()> { output.write_all(&self.to_be_bytes()).map_err(|err| { - Error::SerializeationError(format!("Failed to write serialize u16 to output: {err}")) + Error::SerializationError(format!("Failed to write serialize u16 to output: {err}")) })?; Ok(()) } @@ -171,7 +174,7 @@ impl Serializable for u16 { impl Serializable for i16 { fn serialize(&self, output: &mut dyn Write) -> Result<()> { output.write_all(&self.to_be_bytes()).map_err(|err| { - Error::SerializeationError(format!("Failed to write serialize i16 to output: {err}")) + Error::SerializationError(format!("Failed to write serialize i16 to output: {err}")) })?; Ok(()) } @@ -192,7 +195,7 @@ impl Serializable for i16 { impl Serializable for u32 { fn serialize(&self, output: &mut dyn Write) -> Result<()> { output.write_all(&self.to_be_bytes()).map_err(|err| { - Error::SerializeationError(format!("Failed to write serialize u32 to output: {err}")) + Error::SerializationError(format!("Failed to write serialize u32 to output: {err}")) })?; Ok(()) } @@ -213,7 +216,7 @@ impl Serializable for u32 { impl Serializable for i32 { fn serialize(&self, output: &mut dyn Write) -> Result<()> { output.write_all(&self.to_be_bytes()).map_err(|err| { - Error::SerializeationError(format!("Failed to write serialize i32 to output: {err}")) + Error::SerializationError(format!("Failed to write serialize i32 to output: {err}")) })?; Ok(()) } @@ -234,7 +237,7 @@ impl Serializable for i32 { impl Serializable for u64 { fn serialize(&self, output: &mut dyn Write) -> Result<()> { output.write_all(&self.to_be_bytes()).map_err(|err| { - Error::SerializeationError(format!("Failed to write serialize u64 to output: {err}")) + Error::SerializationError(format!("Failed to write serialize u64 to output: {err}")) })?; Ok(()) } @@ -255,7 +258,7 @@ impl Serializable for u64 { impl Serializable for i64 { fn serialize(&self, output: &mut dyn Write) -> Result<()> { output.write_all(&self.to_be_bytes()).map_err(|err| { - Error::SerializeationError(format!("Failed to write serialize i64 to output: {err}")) + Error::SerializationError(format!("Failed to write serialize i64 to output: {err}")) })?; Ok(()) } @@ -276,7 +279,7 @@ impl Serializable for i64 { impl Serializable for u128 { fn serialize(&self, output: &mut dyn Write) -> Result<()> { output.write_all(&self.to_be_bytes()).map_err(|err| { - Error::SerializeationError(format!("Failed to write serialize u128 to output: {err}")) + Error::SerializationError(format!("Failed to write serialize u128 to output: {err}")) })?; Ok(()) } @@ -297,7 +300,7 @@ impl Serializable for u128 { impl Serializable for i128 { fn serialize(&self, output: &mut dyn Write) -> Result<()> { output.write_all(&self.to_be_bytes()).map_err(|err| { - Error::SerializeationError(format!("Failed to write serialize i128 to output: {err}")) + Error::SerializationError(format!("Failed to write serialize i128 to output: {err}")) })?; Ok(()) } diff --git a/androscalpel_serializer_derive/src/lib.rs b/androscalpel_serializer_derive/src/lib.rs index a48e5f6..b2ef2da 100644 --- a/androscalpel_serializer_derive/src/lib.rs +++ b/androscalpel_serializer_derive/src/lib.rs @@ -508,7 +508,7 @@ fn get_implem_deserialize(data: &Data, params: &ParamsStruct) -> TokenStream { let prefix = <#prefix_ty as androscalpel_serializer::Serializable>::deserialize(input)?; #(#recurse)* - Err(androscalpel_serializer::Error::SerializeationError(format!( + Err(androscalpel_serializer::Error::SerializationError(format!( "Found prefix {:?} that did not match any variant.", prefix ))) } diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..bab5251 --- /dev/null +++ b/flake.lock @@ -0,0 +1,61 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1689068808, + "narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1692447944, + "narHash": "sha256-fkJGNjEmTPvqBs215EQU4r9ivecV5Qge5cF/QDLVn3U=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "d680ded26da5cf104dd2735a51e88d2d8f487b4d", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..4d10e6f --- /dev/null +++ b/flake.nix @@ -0,0 +1,31 @@ +{ + description = "An android bytecode manipulation library"; + + inputs.flake-utils.url = "github:numtide/flake-utils"; + inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + + outputs = { self, nixpkgs, flake-utils }: + flake-utils.lib.eachDefaultSystem (system: + let + pkgs = nixpkgs.legacyPackages.${system}; + in + { +# packages = { +# androscalpel = { }; +# docker = pkgs.dockerTools.buildImage { +# name = "androscalpel"; +# tag = "latest"; +# copyToRoot = pkgs.buildEnv { +# name = "androscalpel_root_img"; +# paths = [ self.packages.${system}.androscalpel ]; +# pathsToLink = [ "/bin" ]; +# }; +# }; +# default = self.packages.${system}.androscalpel; +# }; + + devShells.default = pkgs.mkShell { + packages = [ pkgs.rustc pkgs.cargo ]; + }; + }); +}