update rust edition of androscalpel
This commit is contained in:
parent
d4ccc73362
commit
218d6bf6fc
20 changed files with 223 additions and 167 deletions
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "androscalpel"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
[lib]
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ use pyo3::prelude::*;
|
|||
|
||||
use crate::hashmap_vectorize;
|
||||
use crate::{
|
||||
dex_id::IdType, value::DexValue, DexString, IdField, IdMethod, IdMethodType, MethodHandle,
|
||||
Result, Visitable, VisitableMut, Visitor, VisitorMut,
|
||||
DexString, IdField, IdMethod, IdMethodType, MethodHandle, Result, Visitable, VisitableMut,
|
||||
Visitor, VisitorMut, dex_id::IdType, value::DexValue,
|
||||
};
|
||||
|
||||
/// Annotation with a visibility
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//! Representation of an apk.
|
||||
|
||||
use anyhow::{anyhow, bail, Context};
|
||||
use anyhow::{Context, anyhow, bail};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fs::File;
|
||||
|
|
@ -11,9 +11,9 @@ use log::{error, info};
|
|||
#[cfg(feature = "python")]
|
||||
use pyo3::{prelude::*, types::PyBytes};
|
||||
|
||||
use crate::Result;
|
||||
use crate::ins::CallSite;
|
||||
use crate::instructions;
|
||||
use crate::Result;
|
||||
use crate::*;
|
||||
use androscalpel_serializer::Instruction as InsFormat;
|
||||
use androscalpel_serializer::*;
|
||||
|
|
@ -1030,7 +1030,9 @@ impl Apk {
|
|||
Format11X { op: 0x27, va } => Instruction::Throw { reg: va },
|
||||
Format10T { op: 0x28, a } => {
|
||||
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 {
|
||||
addr + a as usize
|
||||
|
|
@ -1043,7 +1045,9 @@ impl Apk {
|
|||
}
|
||||
Format20T { op: 0x29, a } => {
|
||||
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 {
|
||||
addr + a as usize
|
||||
|
|
@ -1056,7 +1060,9 @@ impl Apk {
|
|||
}
|
||||
Format30T { op: 0x2a, a } => {
|
||||
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 {
|
||||
addr + a as usize
|
||||
|
|
@ -3053,24 +3059,29 @@ impl Apk {
|
|||
i += 1;
|
||||
dex_name = format!("classes{i}.dex");
|
||||
}
|
||||
if let Some(_version) = crate::utils::is_dex(&mut code)? {
|
||||
let mut data = vec![];
|
||||
std::io::copy(&mut code, &mut data)?;
|
||||
self.add_dex_file(&dex_name, &data, label_ins, cache)
|
||||
} else if crate::utils::is_zip(&mut code)? {
|
||||
let mut tmp_apk = Apk::load_apk(code, label_ins, cache)?;
|
||||
let mut j = 1;
|
||||
let mut tmp_dex_name: String = "classes.dex".into();
|
||||
while let Some(dex_file) = tmp_apk.dex_files.remove(&tmp_dex_name) {
|
||||
self.dex_files.insert(dex_name, dex_file);
|
||||
i += 1;
|
||||
j += 1;
|
||||
dex_name = format!("classes{i}.dex");
|
||||
tmp_dex_name = format!("classes{j}.dex");
|
||||
match crate::utils::is_dex(&mut code)? {
|
||||
Some(_version) => {
|
||||
let mut data = vec![];
|
||||
std::io::copy(&mut code, &mut data)?;
|
||||
self.add_dex_file(&dex_name, &data, label_ins, cache)
|
||||
}
|
||||
_ => {
|
||||
if crate::utils::is_zip(&mut code)? {
|
||||
let mut tmp_apk = Apk::load_apk(code, label_ins, cache)?;
|
||||
let mut j = 1;
|
||||
let mut tmp_dex_name: String = "classes.dex".into();
|
||||
while let Some(dex_file) = tmp_apk.dex_files.remove(&tmp_dex_name) {
|
||||
self.dex_files.insert(dex_name, dex_file);
|
||||
i += 1;
|
||||
j += 1;
|
||||
dex_name = format!("classes{i}.dex");
|
||||
tmp_dex_name = format!("classes{j}.dex");
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
bail!("Could not recognize the type of the input file")
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
bail!("Could not recognize the type of the input file")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ use std::collections::{HashMap, HashSet};
|
|||
use pyo3::prelude::*;
|
||||
|
||||
use crate::{
|
||||
ins::Instruction, DexString, IdField, IdMethod, IdMethodType, IdType, Method, MethodHandle,
|
||||
Result, Visitable, VisitableMut, Visitor, VisitorMut,
|
||||
DexString, IdField, IdMethod, IdMethodType, IdType, Method, MethodHandle, Result, Visitable,
|
||||
VisitableMut, Visitor, VisitorMut, ins::Instruction,
|
||||
};
|
||||
|
||||
// TODO: make this easy to edit/manipulate, maybe move to Method
|
||||
|
|
|
|||
|
|
@ -293,19 +293,24 @@ impl<'a> MethodCFG<'a> {
|
|||
" node_{i} [shape=record,style=filled,fillcolor=lightgrey,label=\"{label}\"];\n\n"
|
||||
);
|
||||
}
|
||||
dot_string +=
|
||||
" node_end [shape=record,style=filled,fillcolor=lightgrey,label=\"{\\< EXIT \\>}\"];\n\n";
|
||||
dot_string += " node_end [shape=record,style=filled,fillcolor=lightgrey,label=\"{\\< EXIT \\>}\"];\n\n";
|
||||
|
||||
for (i, node) in self.nodes.iter().enumerate() {
|
||||
for j in &node.next_nodes {
|
||||
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 {
|
||||
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() {
|
||||
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";
|
||||
|
|
|
|||
|
|
@ -123,7 +123,9 @@ impl MethodCFG<'_> {
|
|||
node_label += reg.to_str();
|
||||
}
|
||||
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";
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@ use std::cmp::{Ord, Ordering, PartialOrd};
|
|||
use std::collections::HashSet;
|
||||
use std::hash::Hash;
|
||||
|
||||
use anyhow::{anyhow, bail, Context};
|
||||
use anyhow::{Context, anyhow, bail};
|
||||
#[cfg(feature = "python")]
|
||||
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};
|
||||
|
||||
/// The type of a method. The shorty is formated as described in
|
||||
|
|
@ -332,15 +332,18 @@ impl IdType {
|
|||
'J' => Some(Self::long()),
|
||||
'F' => Some(Self::float()),
|
||||
'D' => Some(Self::double()),
|
||||
'[' => { array_dimmention += 1; None },
|
||||
'[' => {
|
||||
array_dimmention += 1;
|
||||
None
|
||||
}
|
||||
'L' => {
|
||||
let mut class_name = String::new();
|
||||
for cc in chars.by_ref(){
|
||||
if cc == ';' { break;}
|
||||
else {
|
||||
for cc in chars.by_ref() {
|
||||
if cc == ';' {
|
||||
break;
|
||||
} else {
|
||||
class_name.push(cc);
|
||||
}
|
||||
|
||||
}
|
||||
Some(Self::class(&class_name))
|
||||
}
|
||||
|
|
@ -350,13 +353,13 @@ impl IdType {
|
|||
};
|
||||
if let Some(mut new_type) = new_type {
|
||||
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] {
|
||||
*c = 0x5b;
|
||||
}
|
||||
data[array_dimmention..].copy_from_slice(&new_type.0 .0.data);
|
||||
new_type.0 .0.data = data;
|
||||
new_type.0 .0.utf16_size.0 += array_dimmention as u32;
|
||||
data[array_dimmention..].copy_from_slice(&new_type.0.0.data);
|
||||
new_type.0.0.data = data;
|
||||
new_type.0.0.utf16_size.0 += array_dimmention as u32;
|
||||
}
|
||||
|
||||
lst.push(new_type);
|
||||
|
|
@ -443,8 +446,8 @@ impl IdType {
|
|||
#[cfg_attr(feature = "python", staticmethod)]
|
||||
pub fn array(type_: &IdType) -> Self {
|
||||
let mut ty = type_.clone();
|
||||
ty.0 .0.utf16_size.0 += 1;
|
||||
ty.0 .0.data.insert(0, 0x5b);
|
||||
ty.0.0.utf16_size.0 += 1;
|
||||
ty.0.0.data.insert(0, 0x5b);
|
||||
ty
|
||||
}
|
||||
|
||||
|
|
@ -644,7 +647,7 @@ impl IdType {
|
|||
impl SmaliName for IdType {
|
||||
/// Convert a descriptor to its smali representation.
|
||||
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)
|
||||
}
|
||||
/// Convert a smali representation to its descriptor.
|
||||
|
|
|
|||
|
|
@ -27,27 +27,30 @@ impl<V: VisitorMut> VisitableMut<V> for DexString {
|
|||
|
||||
impl std::fmt::Debug for DexString {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
if let Ok(string) = TryInto::<String>::try_into(self) {
|
||||
f.write_str(&format!(
|
||||
"DexString({}, {:#x})",
|
||||
string, self.0.utf16_size.0
|
||||
))
|
||||
/*
|
||||
f.debug_tuple("DexString")
|
||||
.field(&string)
|
||||
.field(&self.0.utf16_size.0)
|
||||
.finish()
|
||||
*/
|
||||
} else {
|
||||
f.write_str(&format!(
|
||||
"DexString({:?}, {:#x})",
|
||||
self.0.data, self.0.utf16_size.0
|
||||
))
|
||||
/*f.debug_tuple("DexString")
|
||||
.field(&self.0.data)
|
||||
.field(&self.0.utf16_size.0)
|
||||
.finish()
|
||||
*/
|
||||
match TryInto::<String>::try_into(self) {
|
||||
Ok(string) => {
|
||||
f.write_str(&format!(
|
||||
"DexString({}, {:#x})",
|
||||
string, self.0.utf16_size.0
|
||||
))
|
||||
/*
|
||||
f.debug_tuple("DexString")
|
||||
.field(&string)
|
||||
.field(&self.0.utf16_size.0)
|
||||
.finish()
|
||||
*/
|
||||
}
|
||||
_ => {
|
||||
f.write_str(&format!(
|
||||
"DexString({:?}, {:#x})",
|
||||
self.0.data, self.0.utf16_size.0
|
||||
))
|
||||
/*f.debug_tuple("DexString")
|
||||
.field(&self.0.data)
|
||||
.field(&self.0.utf16_size.0)
|
||||
.finish()
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -193,10 +196,11 @@ impl DexString {
|
|||
}
|
||||
|
||||
pub fn __str__(&self) -> String {
|
||||
if let Ok(string) = TryInto::<String>::try_into(self) {
|
||||
string
|
||||
} else {
|
||||
format!("string{:02x?}", self.0.data)
|
||||
match TryInto::<String>::try_into(self) {
|
||||
Ok(string) => string,
|
||||
_ => {
|
||||
format!("string{:02x?}", self.0.data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use std::io;
|
|||
use std::io::{Cursor, Seek, SeekFrom, Write};
|
||||
|
||||
use adler::Adler32;
|
||||
use anyhow::{anyhow, bail, Context};
|
||||
use anyhow::{Context, anyhow, bail};
|
||||
use log::{debug, warn};
|
||||
use sha1::{Digest, Sha1};
|
||||
|
||||
|
|
@ -707,7 +707,7 @@ impl DexWriter {
|
|||
.handlers
|
||||
.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!(
|
||||
"Label {} not found in code of {}, but found try \
|
||||
with this label as catch all",
|
||||
|
|
@ -1524,7 +1524,9 @@ impl DexWriter {
|
|||
(None, Some(field)) => (false, field),
|
||||
_ => bail!(
|
||||
"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() {
|
||||
let annotations_off = self
|
||||
|
|
@ -1558,7 +1560,9 @@ impl DexWriter {
|
|||
(None, Some(method)) => (false, method),
|
||||
_ => bail!(
|
||||
"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() {
|
||||
let annotations_off = self
|
||||
|
|
@ -1587,7 +1591,9 @@ impl DexWriter {
|
|||
(None, Some(method)) => (false, method),
|
||||
_ => bail!(
|
||||
"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() {
|
||||
let annotations_off = self
|
||||
|
|
@ -1763,12 +1769,12 @@ impl DexWriter {
|
|||
debug!("Generate the map_list");
|
||||
// Get the size of a map item
|
||||
let map_item_size = 12; /* = MapItem {
|
||||
type_: MapItemType::HeaderItem,
|
||||
unused: 0,
|
||||
size: 0,
|
||||
offset: 0,
|
||||
}
|
||||
.size(); */
|
||||
type_: MapItemType::HeaderItem,
|
||||
unused: 0,
|
||||
size: 0,
|
||||
offset: 0,
|
||||
}
|
||||
.size(); */
|
||||
// Empty map has a size 4, then we add the size of a MapItem for each element
|
||||
// The size of the map_list must be computed before generating the map list,
|
||||
// as it affect the offset of some sections.
|
||||
|
|
@ -2673,12 +2679,12 @@ impl SectionManager {
|
|||
}
|
||||
let mut map_list_size = 4;
|
||||
let map_item_size = 12; /* = MapItem {
|
||||
type_: MapItemType::HeaderItem,
|
||||
unused: 0,
|
||||
size: 0,
|
||||
offset: 0,
|
||||
}
|
||||
.size(); */
|
||||
type_: MapItemType::HeaderItem,
|
||||
unused: 0,
|
||||
size: 0,
|
||||
offset: 0,
|
||||
}
|
||||
.size(); */
|
||||
for section in Section::VARIANT_LIST {
|
||||
if !section.is_data()
|
||||
&& (self.get_nb_elt(*section) != 0 || section == &Section::MapList)
|
||||
|
|
|
|||
|
|
@ -170,7 +170,9 @@ impl HiddenApiDomain {
|
|||
value += "test-api";
|
||||
}
|
||||
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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use crate::{Apk, IdType, Result};
|
|||
use androscalpel_serializer::{
|
||||
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
|
||||
#[pyfunction]
|
||||
|
|
@ -111,13 +111,18 @@ pub fn replace_dex(
|
|||
.map(PyBytesMethods::as_bytes)
|
||||
.map(Cursor::new)
|
||||
.collect();
|
||||
let additionnal_files: Option<HashMap<_, _>> = additionnal_files.as_ref().map(|additionnal_files|
|
||||
additionnal_files.iter()
|
||||
.map(|(k, v)| (
|
||||
k.clone(),
|
||||
v.as_ref().map(|bytes| bytes.as_bytes()).map(Cursor::new)
|
||||
)).collect()
|
||||
);
|
||||
let additionnal_files: Option<HashMap<_, _>> =
|
||||
additionnal_files.as_ref().map(|additionnal_files| {
|
||||
additionnal_files
|
||||
.iter()
|
||||
.map(|(k, v)| {
|
||||
(
|
||||
k.clone(),
|
||||
v.as_ref().map(|bytes| bytes.as_bytes()).map(Cursor::new),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
});
|
||||
apk_frauder::replace_dex(
|
||||
apk,
|
||||
dst,
|
||||
|
|
|
|||
|
|
@ -13,13 +13,14 @@ use std::time::Instant;
|
|||
fn write_to_report(data: &str) {
|
||||
static REPORT_FILE: Mutex<Option<File>> = Mutex::new(None);
|
||||
let mut report_file = REPORT_FILE.lock().unwrap();
|
||||
let mut report_file = if let Some(report_file) = report_file.deref() {
|
||||
report_file
|
||||
} else {
|
||||
*report_file = Some(
|
||||
File::create(&format!("{}/test_repport.txt", env!("CARGO_MANIFEST_DIR"),)).unwrap(),
|
||||
);
|
||||
report_file.deref().as_ref().unwrap()
|
||||
let mut report_file = match report_file.deref() {
|
||||
Some(report_file) => report_file,
|
||||
_ => {
|
||||
*report_file = Some(
|
||||
File::create(&format!("{}/test_repport.txt", env!("CARGO_MANIFEST_DIR"),)).unwrap(),
|
||||
);
|
||||
report_file.deref().as_ref().unwrap()
|
||||
}
|
||||
};
|
||||
writeln!(report_file, "{data}").unwrap();
|
||||
}
|
||||
|
|
@ -625,13 +626,16 @@ fn test_hidden_api() {
|
|||
(
|
||||
sj::Value::String(apktool_hiddenapi),
|
||||
sj::Value::Null,
|
||||
Some(HiddenApiData {
|
||||
permission,
|
||||
domain,
|
||||
}),
|
||||
) if (permission.to_smali_name() == apktool_hiddenapi) && &domain.to_smali_name() == "" => (),
|
||||
Some(HiddenApiData { permission, domain }),
|
||||
) 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");
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::io::{Read, Seek, SeekFrom};
|
|||
|
||||
use crate::Result;
|
||||
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.
|
||||
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.
|
||||
pub fn is_zip(mut file: impl Read + Seek) -> Result<bool> {
|
||||
let pos = file.stream_position()?;
|
||||
let ecd_off = if let Some(off) = ZipFileReader::get_end_of_central_directory_offset(&mut file) {
|
||||
off
|
||||
} else {
|
||||
return Ok(false);
|
||||
let ecd_off = match ZipFileReader::get_end_of_central_directory_offset(&mut file) {
|
||||
Some(off) => off,
|
||||
_ => {
|
||||
return Ok(false);
|
||||
}
|
||||
};
|
||||
file.seek(SeekFrom::Start(ecd_off))?;
|
||||
let r = if let Ok(sig) = apk_frauder::Signature::deserialize(&mut file) {
|
||||
EndCentralDirectory::SIGNATURE == sig
|
||||
} else {
|
||||
false
|
||||
let r = match apk_frauder::Signature::deserialize(&mut file) {
|
||||
Ok(sig) => EndCentralDirectory::SIGNATURE == sig,
|
||||
_ => false,
|
||||
};
|
||||
file.seek(SeekFrom::Start(pos))?;
|
||||
Ok(r)
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ use std::collections::HashSet;
|
|||
use pyo3::{exceptions::PyTypeError, prelude::*};
|
||||
|
||||
use crate::{
|
||||
dex_id::*, scalar::*, DexAnnotation, DexString, MethodHandle, Result, Visitable, VisitableMut,
|
||||
Visitor, VisitorMut,
|
||||
DexAnnotation, DexString, MethodHandle, Result, Visitable, VisitableMut, Visitor, VisitorMut,
|
||||
dex_id::*, scalar::*,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
//! The visitor trait and common implementations.
|
||||
|
||||
use crate::{
|
||||
ins::Instruction, scalar::*, Apk, CallSite, Class, Code, DexAnnotation, DexAnnotationItem,
|
||||
DexFile, DexString, DexValue, Field, FieldVisibility, HiddenApiData, HiddenApiDomain,
|
||||
HiddenApiPermission, IdEnum, IdField, IdMethod, IdMethodType, IdType, Method, MethodHandle,
|
||||
MethodVisibility, Result,
|
||||
Apk, CallSite, Class, Code, DexAnnotation, DexAnnotationItem, DexFile, DexString, DexValue,
|
||||
Field, FieldVisibility, HiddenApiData, HiddenApiDomain, HiddenApiPermission, IdEnum, IdField,
|
||||
IdMethod, IdMethodType, IdType, Method, MethodHandle, MethodVisibility, Result,
|
||||
ins::Instruction, scalar::*,
|
||||
};
|
||||
use std::collections::HashSet;
|
||||
|
||||
|
|
|
|||
|
|
@ -390,7 +390,9 @@ mod test {
|
|||
fn serialize_u64() {
|
||||
assert_eq!(
|
||||
0x123456789ABCDEF0u64.serialize_to_vec().unwrap(),
|
||||
vec![0xF0u8, 0xDEu8, 0xBCu8, 0x9Au8, 0x78u8, 0x56u8, 0x34u8, 0x12u8]
|
||||
vec![
|
||||
0xF0u8, 0xDEu8, 0xBCu8, 0x9Au8, 0x78u8, 0x56u8, 0x34u8, 0x12u8
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -357,26 +357,34 @@ mod test {
|
|||
/// Test for bug found in <https://github.com/TkTech/mutf8/tree/master>:
|
||||
#[test]
|
||||
fn test_tktech_bad_mutf8() {
|
||||
assert!(TryInto::<String>::try_into(StringDataItem {
|
||||
utf16_size: Uleb128(0),
|
||||
data: vec![0x00]
|
||||
})
|
||||
.is_err());
|
||||
assert!(TryInto::<String>::try_into(StringDataItem {
|
||||
utf16_size: Uleb128(0),
|
||||
data: vec![0xC2]
|
||||
})
|
||||
.is_err());
|
||||
assert!(TryInto::<String>::try_into(StringDataItem {
|
||||
utf16_size: Uleb128(0),
|
||||
data: vec![0xED]
|
||||
})
|
||||
.is_err());
|
||||
assert!(TryInto::<String>::try_into(StringDataItem {
|
||||
utf16_size: Uleb128(0),
|
||||
data: vec![0xE2]
|
||||
})
|
||||
.is_err());
|
||||
assert!(
|
||||
TryInto::<String>::try_into(StringDataItem {
|
||||
utf16_size: Uleb128(0),
|
||||
data: vec![0x00]
|
||||
})
|
||||
.is_err()
|
||||
);
|
||||
assert!(
|
||||
TryInto::<String>::try_into(StringDataItem {
|
||||
utf16_size: Uleb128(0),
|
||||
data: vec![0xC2]
|
||||
})
|
||||
.is_err()
|
||||
);
|
||||
assert!(
|
||||
TryInto::<String>::try_into(StringDataItem {
|
||||
utf16_size: Uleb128(0),
|
||||
data: vec![0xED]
|
||||
})
|
||||
.is_err()
|
||||
);
|
||||
assert!(
|
||||
TryInto::<String>::try_into(StringDataItem {
|
||||
utf16_size: Uleb128(0),
|
||||
data: vec![0xE2]
|
||||
})
|
||||
.is_err()
|
||||
);
|
||||
}
|
||||
|
||||
/// Test from <https://github.com/TkTech/mutf8/tree/master>, test 2 bytes
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use crate as androscalpel_serializer;
|
||||
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;
|
||||
|
||||
|
|
|
|||
|
|
@ -270,7 +270,7 @@ impl<'a> DexFileReader<'a> {
|
|||
MapItemType::HeaderItem if item.offset != 0 || item.size != 1 => {
|
||||
return Err(Error::InconsistantStruct(format!(
|
||||
"Inconsistant Header Mapping info found in map_list: {item:x?}"
|
||||
)))
|
||||
)));
|
||||
}
|
||||
MapItemType::StringIdItem
|
||||
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?}, \
|
||||
header.string_ids_off: 0x{:x}, header.string_ids_size: {}",
|
||||
self.header.string_ids_off, self.header.string_ids_size
|
||||
)))
|
||||
)));
|
||||
}
|
||||
MapItemType::TypeIdItem
|
||||
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?}, \
|
||||
header.type_ids_off: 0x{:x}, header.type_ids_size: {}",
|
||||
self.header.type_ids_off, self.header.type_ids_size
|
||||
)))
|
||||
)));
|
||||
}
|
||||
MapItemType::ProtoIdItem
|
||||
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?}, \
|
||||
header.proto_ids_off: 0x{:x}, header.proto_ids_size: {}",
|
||||
self.header.proto_ids_off, self.header.proto_ids_size
|
||||
)))
|
||||
)));
|
||||
}
|
||||
MapItemType::FieldIdItem
|
||||
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?}, \
|
||||
header.field_ids_off: 0x{:x}, header.field_ids_size: {}",
|
||||
self.header.field_ids_off, self.header.field_ids_size
|
||||
)))
|
||||
)));
|
||||
}
|
||||
MapItemType::MethodIdItem
|
||||
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?}, \
|
||||
header.method_ids_off: 0x{:x}, header.method_ids_size: {}",
|
||||
self.header.method_ids_off, self.header.method_ids_size
|
||||
)))
|
||||
)));
|
||||
}
|
||||
MapItemType::ClassDefItem
|
||||
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?}, \
|
||||
header.class_defs_off: 0x{:x}, 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 => {
|
||||
return Err(Error::InconsistantStruct(format!(
|
||||
"Inconsistant MapList Mapping info found in map_list: {item:x?}, \
|
||||
header.map_list_off: 0x{:x}",
|
||||
self.header.map_off
|
||||
)))
|
||||
)));
|
||||
}
|
||||
/*
|
||||
MapItemType::CallSiteIdItem => todo!(),
|
||||
|
|
|
|||
|
|
@ -977,7 +977,9 @@ mod test {
|
|||
}
|
||||
.serialize_to_vec()
|
||||
.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!(
|
||||
EncodedCatchHandler {
|
||||
|
|
@ -999,7 +1001,9 @@ mod test {
|
|||
}
|
||||
.serialize_to_vec()
|
||||
.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!(
|
||||
EncodedCatchHandler {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue