update rust edition of androscalpel

This commit is contained in:
Jean-Marie Mineau 2025-04-18 11:12:11 +02:00
parent d4ccc73362
commit 218d6bf6fc
Signed by: histausse
GPG key ID: B66AEEDA9B645AD2
20 changed files with 223 additions and 167 deletions

View file

@ -1,7 +1,7 @@
[package] [package]
name = "androscalpel" name = "androscalpel"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2024"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib] [lib]

View file

@ -7,8 +7,8 @@ use pyo3::prelude::*;
use crate::hashmap_vectorize; use crate::hashmap_vectorize;
use crate::{ use crate::{
dex_id::IdType, value::DexValue, DexString, IdField, IdMethod, IdMethodType, MethodHandle, DexString, IdField, IdMethod, IdMethodType, MethodHandle, Result, Visitable, VisitableMut,
Result, Visitable, VisitableMut, Visitor, VisitorMut, Visitor, VisitorMut, dex_id::IdType, value::DexValue,
}; };
/// Annotation with a visibility /// Annotation with a visibility

View file

@ -1,6 +1,6 @@
//! Representation of an apk. //! Representation of an apk.
use anyhow::{anyhow, bail, Context}; use anyhow::{Context, anyhow, bail};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::fs::File; use std::fs::File;
@ -11,9 +11,9 @@ use log::{error, info};
#[cfg(feature = "python")] #[cfg(feature = "python")]
use pyo3::{prelude::*, types::PyBytes}; use pyo3::{prelude::*, types::PyBytes};
use crate::Result;
use crate::ins::CallSite; use crate::ins::CallSite;
use crate::instructions; use crate::instructions;
use crate::Result;
use crate::*; use crate::*;
use androscalpel_serializer::Instruction as InsFormat; use androscalpel_serializer::Instruction as InsFormat;
use androscalpel_serializer::*; use androscalpel_serializer::*;
@ -1030,7 +1030,9 @@ impl Apk {
Format11X { op: 0x27, va } => Instruction::Throw { reg: va }, Format11X { op: 0x27, va } => Instruction::Throw { reg: va },
Format10T { op: 0x28, a } => { Format10T { op: 0x28, a } => {
if a < 0 && (-(a as i64)) as usize > addr { if a < 0 && (-(a as i64)) as usize > addr {
bail!("Found goto {a} at 0x{addr:0x}: the destination is invalid (negative addresse)"); bail!(
"Found goto {a} at 0x{addr:0x}: the destination is invalid (negative addresse)"
);
} }
let dest_addr = if a > 0 { let dest_addr = if a > 0 {
addr + a as usize addr + a as usize
@ -1043,7 +1045,9 @@ impl Apk {
} }
Format20T { op: 0x29, a } => { Format20T { op: 0x29, a } => {
if a < 0 && (-(a as i64)) as usize > addr { if a < 0 && (-(a as i64)) as usize > addr {
bail!("Found goto {a} at 0x{addr:0x}: the destination is invalid (negative addresse)"); bail!(
"Found goto {a} at 0x{addr:0x}: the destination is invalid (negative addresse)"
);
} }
let dest_addr = if a > 0 { let dest_addr = if a > 0 {
addr + a as usize addr + a as usize
@ -1056,7 +1060,9 @@ impl Apk {
} }
Format30T { op: 0x2a, a } => { Format30T { op: 0x2a, a } => {
if a < 0 && (-(a as i64)) as usize > addr { if a < 0 && (-(a as i64)) as usize > addr {
bail!("Found goto {a} at 0x{addr:0x}: the destination is invalid (negative addresse)"); bail!(
"Found goto {a} at 0x{addr:0x}: the destination is invalid (negative addresse)"
);
} }
let dest_addr = if a > 0 { let dest_addr = if a > 0 {
addr + a as usize addr + a as usize
@ -3053,11 +3059,14 @@ impl Apk {
i += 1; i += 1;
dex_name = format!("classes{i}.dex"); dex_name = format!("classes{i}.dex");
} }
if let Some(_version) = crate::utils::is_dex(&mut code)? { match crate::utils::is_dex(&mut code)? {
Some(_version) => {
let mut data = vec![]; let mut data = vec![];
std::io::copy(&mut code, &mut data)?; std::io::copy(&mut code, &mut data)?;
self.add_dex_file(&dex_name, &data, label_ins, cache) self.add_dex_file(&dex_name, &data, label_ins, cache)
} else if crate::utils::is_zip(&mut code)? { }
_ => {
if crate::utils::is_zip(&mut code)? {
let mut tmp_apk = Apk::load_apk(code, label_ins, cache)?; let mut tmp_apk = Apk::load_apk(code, label_ins, cache)?;
let mut j = 1; let mut j = 1;
let mut tmp_dex_name: String = "classes.dex".into(); let mut tmp_dex_name: String = "classes.dex".into();
@ -3073,6 +3082,8 @@ impl Apk {
bail!("Could not recognize the type of the input file") bail!("Could not recognize the type of the input file")
} }
} }
}
}
/// Add the content of a dex file to the apk. /// Add the content of a dex file to the apk.
/// ///

View file

@ -9,8 +9,8 @@ use std::collections::{HashMap, HashSet};
use pyo3::prelude::*; use pyo3::prelude::*;
use crate::{ use crate::{
ins::Instruction, DexString, IdField, IdMethod, IdMethodType, IdType, Method, MethodHandle, DexString, IdField, IdMethod, IdMethodType, IdType, Method, MethodHandle, Result, Visitable,
Result, Visitable, VisitableMut, Visitor, VisitorMut, VisitableMut, Visitor, VisitorMut, ins::Instruction,
}; };
// TODO: make this easy to edit/manipulate, maybe move to Method // TODO: make this easy to edit/manipulate, maybe move to Method

View file

@ -293,19 +293,24 @@ impl<'a> MethodCFG<'a> {
" node_{i} [shape=record,style=filled,fillcolor=lightgrey,label=\"{label}\"];\n\n" " node_{i} [shape=record,style=filled,fillcolor=lightgrey,label=\"{label}\"];\n\n"
); );
} }
dot_string += dot_string += " node_end [shape=record,style=filled,fillcolor=lightgrey,label=\"{\\< EXIT \\>}\"];\n\n";
" node_end [shape=record,style=filled,fillcolor=lightgrey,label=\"{\\< EXIT \\>}\"];\n\n";
for (i, node) in self.nodes.iter().enumerate() { for (i, node) in self.nodes.iter().enumerate() {
for j in &node.next_nodes { for j in &node.next_nodes {
if *j == i + 1 { if *j == i + 1 {
dot_string += &format!(" node_{i}:s -> node_{j}:n [style=\"solid,bold\",color=black,weight=100,constraint=true];\n"); dot_string += &format!(
" node_{i}:s -> node_{j}:n [style=\"solid,bold\",color=black,weight=100,constraint=true];\n"
);
} else { } else {
dot_string += &format!(" node_{i}:s -> node_{j}:n [style=\"solid,bold\",color=black,weight=10,constraint=true];\n"); dot_string += &format!(
" node_{i}:s -> node_{j}:n [style=\"solid,bold\",color=black,weight=10,constraint=true];\n"
);
} }
} }
if node.next_nodes.is_empty() { if node.next_nodes.is_empty() {
dot_string += &format!(" node_{i}:s -> node_end:n [style=\"solid,bold\",color=black,weight=10,constraint=true];\n"); dot_string += &format!(
" node_{i}:s -> node_end:n [style=\"solid,bold\",color=black,weight=10,constraint=true];\n"
);
} }
} }
dot_string += "}\n"; dot_string += "}\n";

View file

@ -123,7 +123,9 @@ impl MethodCFG<'_> {
node_label += reg.to_str(); node_label += reg.to_str();
} }
node_label += "|"; node_label += "|";
dot_string += &format!(" node_{label} [shape=record,style=filled,fillcolor=lightgrey,label=\"{node_label}\"];\n"); dot_string += &format!(
" node_{label} [shape=record,style=filled,fillcolor=lightgrey,label=\"{node_label}\"];\n"
);
} }
dot_string += "}\n"; dot_string += "}\n";

View file

@ -5,11 +5,11 @@ use std::cmp::{Ord, Ordering, PartialOrd};
use std::collections::HashSet; use std::collections::HashSet;
use std::hash::Hash; use std::hash::Hash;
use anyhow::{anyhow, bail, Context}; use anyhow::{Context, anyhow, bail};
#[cfg(feature = "python")] #[cfg(feature = "python")]
use pyo3::prelude::*; use pyo3::prelude::*;
use crate::{scalar::*, DexString, DexValue, Result, Visitable, VisitableMut, Visitor, VisitorMut}; use crate::{DexString, DexValue, Result, Visitable, VisitableMut, Visitor, VisitorMut, scalar::*};
use androscalpel_serializer::{StringDataItem, Uleb128}; use androscalpel_serializer::{StringDataItem, Uleb128};
/// The type of a method. The shorty is formated as described in /// The type of a method. The shorty is formated as described in
@ -332,15 +332,18 @@ impl IdType {
'J' => Some(Self::long()), 'J' => Some(Self::long()),
'F' => Some(Self::float()), 'F' => Some(Self::float()),
'D' => Some(Self::double()), 'D' => Some(Self::double()),
'[' => { array_dimmention += 1; None }, '[' => {
array_dimmention += 1;
None
}
'L' => { 'L' => {
let mut class_name = String::new(); let mut class_name = String::new();
for cc in chars.by_ref(){ for cc in chars.by_ref() {
if cc == ';' { break;} if cc == ';' {
else { break;
} else {
class_name.push(cc); class_name.push(cc);
} }
} }
Some(Self::class(&class_name)) Some(Self::class(&class_name))
} }
@ -350,13 +353,13 @@ impl IdType {
}; };
if let Some(mut new_type) = new_type { if let Some(mut new_type) = new_type {
if array_dimmention != 0 { if array_dimmention != 0 {
let mut data = vec![0u8; array_dimmention + new_type.0 .0.data.len()]; let mut data = vec![0u8; array_dimmention + new_type.0.0.data.len()];
for c in &mut data[..array_dimmention] { for c in &mut data[..array_dimmention] {
*c = 0x5b; *c = 0x5b;
} }
data[array_dimmention..].copy_from_slice(&new_type.0 .0.data); data[array_dimmention..].copy_from_slice(&new_type.0.0.data);
new_type.0 .0.data = data; new_type.0.0.data = data;
new_type.0 .0.utf16_size.0 += array_dimmention as u32; new_type.0.0.utf16_size.0 += array_dimmention as u32;
} }
lst.push(new_type); lst.push(new_type);
@ -443,8 +446,8 @@ impl IdType {
#[cfg_attr(feature = "python", staticmethod)] #[cfg_attr(feature = "python", staticmethod)]
pub fn array(type_: &IdType) -> Self { pub fn array(type_: &IdType) -> Self {
let mut ty = type_.clone(); let mut ty = type_.clone();
ty.0 .0.utf16_size.0 += 1; ty.0.0.utf16_size.0 += 1;
ty.0 .0.data.insert(0, 0x5b); ty.0.0.data.insert(0, 0x5b);
ty ty
} }
@ -644,7 +647,7 @@ impl IdType {
impl SmaliName for IdType { impl SmaliName for IdType {
/// Convert a descriptor to its smali representation. /// Convert a descriptor to its smali representation.
fn try_to_smali(&self) -> Result<String> { fn try_to_smali(&self) -> Result<String> {
let r = (&self.0 .0).try_into()?; // Anyhow conversion stuff let r = (&self.0.0).try_into()?; // Anyhow conversion stuff
Ok(r) Ok(r)
} }
/// Convert a smali representation to its descriptor. /// Convert a smali representation to its descriptor.

View file

@ -27,7 +27,8 @@ impl<V: VisitorMut> VisitableMut<V> for DexString {
impl std::fmt::Debug for DexString { impl std::fmt::Debug for DexString {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
if let Ok(string) = TryInto::<String>::try_into(self) { match TryInto::<String>::try_into(self) {
Ok(string) => {
f.write_str(&format!( f.write_str(&format!(
"DexString({}, {:#x})", "DexString({}, {:#x})",
string, self.0.utf16_size.0 string, self.0.utf16_size.0
@ -38,7 +39,8 @@ impl std::fmt::Debug for DexString {
.field(&self.0.utf16_size.0) .field(&self.0.utf16_size.0)
.finish() .finish()
*/ */
} else { }
_ => {
f.write_str(&format!( f.write_str(&format!(
"DexString({:?}, {:#x})", "DexString({:?}, {:#x})",
self.0.data, self.0.utf16_size.0 self.0.data, self.0.utf16_size.0
@ -50,6 +52,7 @@ impl std::fmt::Debug for DexString {
*/ */
} }
} }
}
} }
impl Serialize for DexString { impl Serialize for DexString {
@ -193,12 +196,13 @@ impl DexString {
} }
pub fn __str__(&self) -> String { pub fn __str__(&self) -> String {
if let Ok(string) = TryInto::<String>::try_into(self) { match TryInto::<String>::try_into(self) {
string Ok(string) => string,
} else { _ => {
format!("string{:02x?}", self.0.data) format!("string{:02x?}", self.0.data)
} }
} }
}
pub fn __repr__(&self) -> String { pub fn __repr__(&self) -> String {
format!("{:?}", self) format!("{:?}", self)

View file

@ -5,7 +5,7 @@ use std::io;
use std::io::{Cursor, Seek, SeekFrom, Write}; use std::io::{Cursor, Seek, SeekFrom, Write};
use adler::Adler32; use adler::Adler32;
use anyhow::{anyhow, bail, Context}; use anyhow::{Context, anyhow, bail};
use log::{debug, warn}; use log::{debug, warn};
use sha1::{Digest, Sha1}; use sha1::{Digest, Sha1};
@ -707,7 +707,7 @@ impl DexWriter {
.handlers .handlers
.push(EncodedTypeAddrPair { type_idx, addr }); .push(EncodedTypeAddrPair { type_idx, addr });
} }
if let Some(ref label) = default_handler { if let Some(label) = default_handler {
let catch_all_addr = *label_addrs.get(label).ok_or(anyhow!( let catch_all_addr = *label_addrs.get(label).ok_or(anyhow!(
"Label {} not found in code of {}, but found try \ "Label {} not found in code of {}, but found try \
with this label as catch all", with this label as catch all",
@ -1524,7 +1524,9 @@ impl DexWriter {
(None, Some(field)) => (false, field), (None, Some(field)) => (false, field),
_ => bail!( _ => bail!(
"Unexpected configuration: field {} is both a static and a instance field in {}", "Unexpected configuration: field {} is both a static and a instance field in {}",
field_id.__repr__(), class_id.__repr__()), field_id.__repr__(),
class_id.__repr__()
),
}; };
if !field.annotations.is_empty() { if !field.annotations.is_empty() {
let annotations_off = self let annotations_off = self
@ -1558,7 +1560,9 @@ impl DexWriter {
(None, Some(method)) => (false, method), (None, Some(method)) => (false, method),
_ => bail!( _ => bail!(
"Unexpected configuration: method {} is both a direct and a virtual method in {}", "Unexpected configuration: method {} is both a direct and a virtual method in {}",
method_id.__repr__(), class_id.__repr__()), method_id.__repr__(),
class_id.__repr__()
),
}; };
if !method.annotations.is_empty() { if !method.annotations.is_empty() {
let annotations_off = self let annotations_off = self
@ -1587,7 +1591,9 @@ impl DexWriter {
(None, Some(method)) => (false, method), (None, Some(method)) => (false, method),
_ => bail!( _ => bail!(
"Unexpected configuration: method {} is both a direct and a virtual method in {}", "Unexpected configuration: method {} is both a direct and a virtual method in {}",
method_id.__repr__(), class_id.__repr__()), method_id.__repr__(),
class_id.__repr__()
),
}; };
if !method.parameters_annotations.is_empty() { if !method.parameters_annotations.is_empty() {
let annotations_off = self let annotations_off = self

View file

@ -170,7 +170,9 @@ impl HiddenApiDomain {
value += "test-api"; value += "test-api";
} }
if self.unknown_flags != 0 { if self.unknown_flags != 0 {
warn!("This attribut has an unknown hiddenapi domain set, this will not be display for compatibility with apktool"); warn!(
"This attribut has an unknown hiddenapi domain set, this will not be display for compatibility with apktool"
);
} }
value value
} }

View file

@ -12,7 +12,7 @@ use crate::{Apk, IdType, Result};
use androscalpel_serializer::{ use androscalpel_serializer::{
DexFileReader, HeaderItem, Serializable, Sleb128, Uleb128, Uleb128p1, DexFileReader, HeaderItem, Serializable, Sleb128, Uleb128, Uleb128p1,
}; };
use apk_frauder::{end_of_central_directory::EndCentralDirectory, ZipFileReader}; use apk_frauder::{ZipFileReader, end_of_central_directory::EndCentralDirectory};
/// Convert an integer to the uleb128 byte encoding /// Convert an integer to the uleb128 byte encoding
#[pyfunction] #[pyfunction]
@ -111,13 +111,18 @@ pub fn replace_dex(
.map(PyBytesMethods::as_bytes) .map(PyBytesMethods::as_bytes)
.map(Cursor::new) .map(Cursor::new)
.collect(); .collect();
let additionnal_files: Option<HashMap<_, _>> = additionnal_files.as_ref().map(|additionnal_files| let additionnal_files: Option<HashMap<_, _>> =
additionnal_files.iter() additionnal_files.as_ref().map(|additionnal_files| {
.map(|(k, v)| ( additionnal_files
.iter()
.map(|(k, v)| {
(
k.clone(), k.clone(),
v.as_ref().map(|bytes| bytes.as_bytes()).map(Cursor::new) v.as_ref().map(|bytes| bytes.as_bytes()).map(Cursor::new),
)).collect() )
); })
.collect()
});
apk_frauder::replace_dex( apk_frauder::replace_dex(
apk, apk,
dst, dst,

View file

@ -13,13 +13,14 @@ use std::time::Instant;
fn write_to_report(data: &str) { fn write_to_report(data: &str) {
static REPORT_FILE: Mutex<Option<File>> = Mutex::new(None); static REPORT_FILE: Mutex<Option<File>> = Mutex::new(None);
let mut report_file = REPORT_FILE.lock().unwrap(); let mut report_file = REPORT_FILE.lock().unwrap();
let mut report_file = if let Some(report_file) = report_file.deref() { let mut report_file = match report_file.deref() {
report_file Some(report_file) => report_file,
} else { _ => {
*report_file = Some( *report_file = Some(
File::create(&format!("{}/test_repport.txt", env!("CARGO_MANIFEST_DIR"),)).unwrap(), File::create(&format!("{}/test_repport.txt", env!("CARGO_MANIFEST_DIR"),)).unwrap(),
); );
report_file.deref().as_ref().unwrap() report_file.deref().as_ref().unwrap()
}
}; };
writeln!(report_file, "{data}").unwrap(); writeln!(report_file, "{data}").unwrap();
} }
@ -625,13 +626,16 @@ fn test_hidden_api() {
( (
sj::Value::String(apktool_hiddenapi), sj::Value::String(apktool_hiddenapi),
sj::Value::Null, sj::Value::Null,
Some(HiddenApiData { Some(HiddenApiData { permission, domain }),
permission, ) if (permission.to_smali_name() == apktool_hiddenapi)
domain, && &domain.to_smali_name() == "" =>
}), {
) if (permission.to_smali_name() == apktool_hiddenapi) && &domain.to_smali_name() == "" => (), ()
}
_ => panic!("Expected {apktool_hiddenapi:?} and {apktool_hiddenapi_domain:?}, found {parsed_api:?} in {name}"), _ => panic!(
"Expected {apktool_hiddenapi:?} and {apktool_hiddenapi_domain:?}, found {parsed_api:?} in {name}"
),
} }
} }
let apktool_result = File::open(&apktool_result).expect("core-oj-33_hiddenapi.json not found"); let apktool_result = File::open(&apktool_result).expect("core-oj-33_hiddenapi.json not found");

View file

@ -2,7 +2,7 @@ use std::io::{Read, Seek, SeekFrom};
use crate::Result; use crate::Result;
use androscalpel_serializer::{HeaderItem, Serializable}; use androscalpel_serializer::{HeaderItem, Serializable};
use apk_frauder::{end_of_central_directory::EndCentralDirectory, ZipFileReader}; use apk_frauder::{ZipFileReader, end_of_central_directory::EndCentralDirectory};
/// Test if a file is as .dex file an return the dex version if it is, else return None. /// Test if a file is as .dex file an return the dex version if it is, else return None.
pub fn is_dex(file: &mut (impl Read + Seek)) -> Result<Option<usize>> { pub fn is_dex(file: &mut (impl Read + Seek)) -> Result<Option<usize>> {
@ -18,16 +18,16 @@ pub fn is_dex(file: &mut (impl Read + Seek)) -> Result<Option<usize>> {
/// Test if a file is a zip file. /// Test if a file is a zip file.
pub fn is_zip(mut file: impl Read + Seek) -> Result<bool> { pub fn is_zip(mut file: impl Read + Seek) -> Result<bool> {
let pos = file.stream_position()?; let pos = file.stream_position()?;
let ecd_off = if let Some(off) = ZipFileReader::get_end_of_central_directory_offset(&mut file) { let ecd_off = match ZipFileReader::get_end_of_central_directory_offset(&mut file) {
off Some(off) => off,
} else { _ => {
return Ok(false); return Ok(false);
}
}; };
file.seek(SeekFrom::Start(ecd_off))?; file.seek(SeekFrom::Start(ecd_off))?;
let r = if let Ok(sig) = apk_frauder::Signature::deserialize(&mut file) { let r = match apk_frauder::Signature::deserialize(&mut file) {
EndCentralDirectory::SIGNATURE == sig Ok(sig) => EndCentralDirectory::SIGNATURE == sig,
} else { _ => false,
false
}; };
file.seek(SeekFrom::Start(pos))?; file.seek(SeekFrom::Start(pos))?;
Ok(r) Ok(r)

View file

@ -7,8 +7,8 @@ use std::collections::HashSet;
use pyo3::{exceptions::PyTypeError, prelude::*}; use pyo3::{exceptions::PyTypeError, prelude::*};
use crate::{ use crate::{
dex_id::*, scalar::*, DexAnnotation, DexString, MethodHandle, Result, Visitable, VisitableMut, DexAnnotation, DexString, MethodHandle, Result, Visitable, VisitableMut, Visitor, VisitorMut,
Visitor, VisitorMut, dex_id::*, scalar::*,
}; };
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]

View file

@ -1,10 +1,10 @@
//! The visitor trait and common implementations. //! The visitor trait and common implementations.
use crate::{ use crate::{
ins::Instruction, scalar::*, Apk, CallSite, Class, Code, DexAnnotation, DexAnnotationItem, Apk, CallSite, Class, Code, DexAnnotation, DexAnnotationItem, DexFile, DexString, DexValue,
DexFile, DexString, DexValue, Field, FieldVisibility, HiddenApiData, HiddenApiDomain, Field, FieldVisibility, HiddenApiData, HiddenApiDomain, HiddenApiPermission, IdEnum, IdField,
HiddenApiPermission, IdEnum, IdField, IdMethod, IdMethodType, IdType, Method, MethodHandle, IdMethod, IdMethodType, IdType, Method, MethodHandle, MethodVisibility, Result,
MethodVisibility, Result, ins::Instruction, scalar::*,
}; };
use std::collections::HashSet; use std::collections::HashSet;

View file

@ -390,7 +390,9 @@ mod test {
fn serialize_u64() { fn serialize_u64() {
assert_eq!( assert_eq!(
0x123456789ABCDEF0u64.serialize_to_vec().unwrap(), 0x123456789ABCDEF0u64.serialize_to_vec().unwrap(),
vec![0xF0u8, 0xDEu8, 0xBCu8, 0x9Au8, 0x78u8, 0x56u8, 0x34u8, 0x12u8] vec![
0xF0u8, 0xDEu8, 0xBCu8, 0x9Au8, 0x78u8, 0x56u8, 0x34u8, 0x12u8
]
); );
} }

View file

@ -357,26 +357,34 @@ mod test {
/// Test for bug found in <https://github.com/TkTech/mutf8/tree/master>: /// Test for bug found in <https://github.com/TkTech/mutf8/tree/master>:
#[test] #[test]
fn test_tktech_bad_mutf8() { fn test_tktech_bad_mutf8() {
assert!(TryInto::<String>::try_into(StringDataItem { assert!(
TryInto::<String>::try_into(StringDataItem {
utf16_size: Uleb128(0), utf16_size: Uleb128(0),
data: vec![0x00] data: vec![0x00]
}) })
.is_err()); .is_err()
assert!(TryInto::<String>::try_into(StringDataItem { );
assert!(
TryInto::<String>::try_into(StringDataItem {
utf16_size: Uleb128(0), utf16_size: Uleb128(0),
data: vec![0xC2] data: vec![0xC2]
}) })
.is_err()); .is_err()
assert!(TryInto::<String>::try_into(StringDataItem { );
assert!(
TryInto::<String>::try_into(StringDataItem {
utf16_size: Uleb128(0), utf16_size: Uleb128(0),
data: vec![0xED] data: vec![0xED]
}) })
.is_err()); .is_err()
assert!(TryInto::<String>::try_into(StringDataItem { );
assert!(
TryInto::<String>::try_into(StringDataItem {
utf16_size: Uleb128(0), utf16_size: Uleb128(0),
data: vec![0xE2] data: vec![0xE2]
}) })
.is_err()); .is_err()
);
} }
/// Test from <https://github.com/TkTech/mutf8/tree/master>, test 2 bytes /// Test from <https://github.com/TkTech/mutf8/tree/master>, test 2 bytes

View file

@ -2,7 +2,7 @@
use crate as androscalpel_serializer; use crate as androscalpel_serializer;
use crate::{ use crate::{
Error, ReadSeek, Result, Serializable, SerializableUntil, Sleb128, Uleb128, Uleb128p1, NO_INDEX, Error, NO_INDEX, ReadSeek, Result, Serializable, SerializableUntil, Sleb128, Uleb128, Uleb128p1,
}; };
use std::io::Write; use std::io::Write;

View file

@ -270,7 +270,7 @@ impl<'a> DexFileReader<'a> {
MapItemType::HeaderItem if item.offset != 0 || item.size != 1 => { MapItemType::HeaderItem if item.offset != 0 || item.size != 1 => {
return Err(Error::InconsistantStruct(format!( return Err(Error::InconsistantStruct(format!(
"Inconsistant Header Mapping info found in map_list: {item:x?}" "Inconsistant Header Mapping info found in map_list: {item:x?}"
))) )));
} }
MapItemType::StringIdItem MapItemType::StringIdItem
if item.offset != self.header.string_ids_off if item.offset != self.header.string_ids_off
@ -280,7 +280,7 @@ impl<'a> DexFileReader<'a> {
"Inconsistant MapList Mapping info found in map_list: {item:x?}, \ "Inconsistant MapList Mapping info found in map_list: {item:x?}, \
header.string_ids_off: 0x{:x}, header.string_ids_size: {}", header.string_ids_off: 0x{:x}, header.string_ids_size: {}",
self.header.string_ids_off, self.header.string_ids_size self.header.string_ids_off, self.header.string_ids_size
))) )));
} }
MapItemType::TypeIdItem MapItemType::TypeIdItem
if item.offset != self.header.type_ids_off if item.offset != self.header.type_ids_off
@ -290,7 +290,7 @@ impl<'a> DexFileReader<'a> {
"Inconsistant MapList Mapping info found in map_list: {item:x?}, \ "Inconsistant MapList Mapping info found in map_list: {item:x?}, \
header.type_ids_off: 0x{:x}, header.type_ids_size: {}", header.type_ids_off: 0x{:x}, header.type_ids_size: {}",
self.header.type_ids_off, self.header.type_ids_size self.header.type_ids_off, self.header.type_ids_size
))) )));
} }
MapItemType::ProtoIdItem MapItemType::ProtoIdItem
if item.offset != self.header.proto_ids_off if item.offset != self.header.proto_ids_off
@ -300,7 +300,7 @@ impl<'a> DexFileReader<'a> {
"Inconsistant MapList Mapping info found in map_list: {item:x?}, \ "Inconsistant MapList Mapping info found in map_list: {item:x?}, \
header.proto_ids_off: 0x{:x}, header.proto_ids_size: {}", header.proto_ids_off: 0x{:x}, header.proto_ids_size: {}",
self.header.proto_ids_off, self.header.proto_ids_size self.header.proto_ids_off, self.header.proto_ids_size
))) )));
} }
MapItemType::FieldIdItem MapItemType::FieldIdItem
if item.offset != self.header.field_ids_off if item.offset != self.header.field_ids_off
@ -310,7 +310,7 @@ impl<'a> DexFileReader<'a> {
"Inconsistant MapList Mapping info found in map_list: {item:x?}, \ "Inconsistant MapList Mapping info found in map_list: {item:x?}, \
header.field_ids_off: 0x{:x}, header.field_ids_size: {}", header.field_ids_off: 0x{:x}, header.field_ids_size: {}",
self.header.field_ids_off, self.header.field_ids_size self.header.field_ids_off, self.header.field_ids_size
))) )));
} }
MapItemType::MethodIdItem MapItemType::MethodIdItem
if item.offset != self.header.method_ids_off if item.offset != self.header.method_ids_off
@ -320,7 +320,7 @@ impl<'a> DexFileReader<'a> {
"Inconsistant MapList Mapping info found in map_list: {item:x?}, \ "Inconsistant MapList Mapping info found in map_list: {item:x?}, \
header.method_ids_off: 0x{:x}, header.method_ids_size: {}", header.method_ids_off: 0x{:x}, header.method_ids_size: {}",
self.header.method_ids_off, self.header.method_ids_size self.header.method_ids_off, self.header.method_ids_size
))) )));
} }
MapItemType::ClassDefItem MapItemType::ClassDefItem
if item.offset != self.header.class_defs_off if item.offset != self.header.class_defs_off
@ -330,14 +330,14 @@ impl<'a> DexFileReader<'a> {
"Inconsistant MapList Mapping info found in map_list: {item:x?}, \ "Inconsistant MapList Mapping info found in map_list: {item:x?}, \
header.class_defs_off: 0x{:x}, header.class_defs_size: {}", header.class_defs_off: 0x{:x}, header.class_defs_size: {}",
self.header.class_defs_off, self.header.class_defs_size self.header.class_defs_off, self.header.class_defs_size
))) )));
} }
MapItemType::MapList if item.offset != self.header.map_off || item.size != 1 => { MapItemType::MapList if item.offset != self.header.map_off || item.size != 1 => {
return Err(Error::InconsistantStruct(format!( return Err(Error::InconsistantStruct(format!(
"Inconsistant MapList Mapping info found in map_list: {item:x?}, \ "Inconsistant MapList Mapping info found in map_list: {item:x?}, \
header.map_list_off: 0x{:x}", header.map_list_off: 0x{:x}",
self.header.map_off self.header.map_off
))) )));
} }
/* /*
MapItemType::CallSiteIdItem => todo!(), MapItemType::CallSiteIdItem => todo!(),

View file

@ -977,7 +977,9 @@ mod test {
} }
.serialize_to_vec() .serialize_to_vec()
.unwrap(), .unwrap(),
vec![0x03, 0xb4, 0x01, 0x80, 0x02, 0xc7, 0x08, 0x8e, 0x02, 0xd9, 0x09, 0x87, 0x02,] vec![
0x03, 0xb4, 0x01, 0x80, 0x02, 0xc7, 0x08, 0x8e, 0x02, 0xd9, 0x09, 0x87, 0x02,
]
); );
assert_eq!( assert_eq!(
EncodedCatchHandler { EncodedCatchHandler {
@ -999,7 +1001,9 @@ mod test {
} }
.serialize_to_vec() .serialize_to_vec()
.unwrap(), .unwrap(),
vec![0x03, 0xe9, 0x46, 0x56, 0xc7, 0x08, 0x8e, 0x02, 0xd9, 0x09, 0x87, 0x02,] vec![
0x03, 0xe9, 0x46, 0x56, 0xc7, 0x08, 0x8e, 0x02, 0xd9, 0x09, 0x87, 0x02,
]
); );
assert_eq!( assert_eq!(
EncodedCatchHandler { EncodedCatchHandler {