new tool to explore .apk
This commit is contained in:
parent
92d4ecaa1c
commit
519d0748be
5 changed files with 252 additions and 0 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
|
@ -57,6 +57,13 @@ dependencies = [
|
||||||
"backtrace",
|
"backtrace",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "apk_frauder"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"androscalpel_serializer",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arc-swap"
|
name = "arc-swap"
|
||||||
version = "1.6.0"
|
version = "1.6.0"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
|
|
||||||
members = [
|
members = [
|
||||||
|
"apk_frauder",
|
||||||
"androscalpel_serializer",
|
"androscalpel_serializer",
|
||||||
"androscalpel_serializer_derive",
|
"androscalpel_serializer_derive",
|
||||||
"androscalpel",
|
"androscalpel",
|
||||||
|
|
|
||||||
9
apk_frauder/Cargo.toml
Normal file
9
apk_frauder/Cargo.toml
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
[package]
|
||||||
|
name = "apk_frauder"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
androscalpel_serializer = { version = "0.1.0", path = "../androscalpel_serializer" }
|
||||||
1
apk_frauder/README.md
Normal file
1
apk_frauder/README.md
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
flate2/rust_backend
|
||||||
234
apk_frauder/src/main.rs
Normal file
234
apk_frauder/src/main.rs
Normal file
|
|
@ -0,0 +1,234 @@
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{Read, Seek, SeekFrom, Write};
|
||||||
|
|
||||||
|
use androscalpel_serializer::{ReadSeek, Result, Serializable};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Serializable, Default)]
|
||||||
|
//struct Signature(pub [u8; 4]);
|
||||||
|
struct Signature(pub u32);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
struct Zip64EndCentralDirectory {
|
||||||
|
// signature: Signature
|
||||||
|
// size_zip64_edf_record: u64
|
||||||
|
version_made_by: u16,
|
||||||
|
version_needed_to_extract: u16,
|
||||||
|
number_of_this_disk: u32,
|
||||||
|
disk_number_of_central_directory_start: u32,
|
||||||
|
number_entry_in_central_directory_on_this_disk: u64,
|
||||||
|
number_entry_in_central_directory: u64,
|
||||||
|
size_of_central_directory: u64,
|
||||||
|
offset_central_directory: u64,
|
||||||
|
extensible_data: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Zip64EndCentralDirectory {
|
||||||
|
const SIGNATURE: Signature = Signature(0x06064b50);
|
||||||
|
const MIN_SIZE: usize = 4 + 8 + 2 + 2 + 4 + 4 + 8 + 8 + 8 + 8; // + 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serializable for Zip64EndCentralDirectory {
|
||||||
|
fn serialize(&self, output: &mut dyn Write) -> Result<()> {
|
||||||
|
Self::SIGNATURE.serialize(output)?;
|
||||||
|
((self.size() - 12) as u64).serialize(output)?;
|
||||||
|
self.version_made_by.serialize(output)?;
|
||||||
|
self.version_needed_to_extract.serialize(output)?;
|
||||||
|
self.number_of_this_disk.serialize(output)?;
|
||||||
|
self.disk_number_of_central_directory_start
|
||||||
|
.serialize(output)?;
|
||||||
|
self.number_entry_in_central_directory_on_this_disk
|
||||||
|
.serialize(output)?;
|
||||||
|
self.number_entry_in_central_directory.serialize(output)?;
|
||||||
|
self.size_of_central_directory.serialize(output)?;
|
||||||
|
self.offset_central_directory.serialize(output)?;
|
||||||
|
for d in &self.extensible_data {
|
||||||
|
d.serialize(output)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize(input: &mut dyn ReadSeek) -> Result<Self> {
|
||||||
|
let signature = Signature::deserialize(input)?;
|
||||||
|
assert_eq!(signature, Self::SIGNATURE); // TODO
|
||||||
|
let size_zip64_edf_record = u64::deserialize(input)?;
|
||||||
|
let version_made_by = u16::deserialize(input)?;
|
||||||
|
let version_needed_to_extract = u16::deserialize(input)?;
|
||||||
|
let number_of_this_disk = u32::deserialize(input)?;
|
||||||
|
let disk_number_of_central_directory_start = u32::deserialize(input)?;
|
||||||
|
let number_entry_in_central_directory_on_this_disk = u64::deserialize(input)?;
|
||||||
|
let number_entry_in_central_directory = u64::deserialize(input)?;
|
||||||
|
let size_of_central_directory = u64::deserialize(input)?;
|
||||||
|
let offset_central_directory = u64::deserialize(input)?;
|
||||||
|
let mut extensible_data = vec![];
|
||||||
|
for _ in 0..(size_zip64_edf_record as usize + 12 - Self::MIN_SIZE) {
|
||||||
|
extensible_data.push(u8::deserialize(input)?);
|
||||||
|
}
|
||||||
|
Ok(Self {
|
||||||
|
version_made_by,
|
||||||
|
version_needed_to_extract,
|
||||||
|
number_of_this_disk,
|
||||||
|
disk_number_of_central_directory_start,
|
||||||
|
number_entry_in_central_directory_on_this_disk,
|
||||||
|
number_entry_in_central_directory,
|
||||||
|
size_of_central_directory,
|
||||||
|
offset_central_directory,
|
||||||
|
extensible_data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size(&self) -> usize {
|
||||||
|
Self::MIN_SIZE + self.extensible_data.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Serializable)]
|
||||||
|
struct Zip64EndCentralDirectoryLocator {
|
||||||
|
#[prefix(Self::SIGNATURE.0.to_le_bytes())]
|
||||||
|
disk_number_of_zip64_end_central_directory_start: u32,
|
||||||
|
offset_zip64_end_of_central_directory_record: u64,
|
||||||
|
total_number_of_disks: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Zip64EndCentralDirectoryLocator {
|
||||||
|
const SIGNATURE: Signature = Signature(0x07064b50);
|
||||||
|
const SIZE: usize = 4 + 4 + 8 + 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
struct EndCentralDirectory {
|
||||||
|
//signature: Self::SIGNATURE,
|
||||||
|
disk_number: u16,
|
||||||
|
disk_number_of_central_directory_start: u16,
|
||||||
|
number_of_entries_in_central_directory_on_disk: u16,
|
||||||
|
number_of_entries_in_central_directory: u16,
|
||||||
|
size_central_directory: u32,
|
||||||
|
offset_central_directory: u32,
|
||||||
|
//file_comment_length: u16,
|
||||||
|
comment: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EndCentralDirectory {
|
||||||
|
const SIGNATURE: Signature = Signature(0x06054b50); //Signature([0x06, 0x05, 0x4b, 0x50]);
|
||||||
|
const MIN_SIZE: usize = 4 + 4 * 2 + 2 * 4 + 2; // + 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serializable for EndCentralDirectory {
|
||||||
|
fn serialize(&self, output: &mut dyn Write) -> Result<()> {
|
||||||
|
Self::SIGNATURE.serialize(output)?;
|
||||||
|
self.disk_number.serialize(output)?;
|
||||||
|
self.disk_number_of_central_directory_start
|
||||||
|
.serialize(output)?;
|
||||||
|
self.number_of_entries_in_central_directory_on_disk
|
||||||
|
.serialize(output)?;
|
||||||
|
self.number_of_entries_in_central_directory
|
||||||
|
.serialize(output)?;
|
||||||
|
self.size_central_directory.serialize(output)?;
|
||||||
|
self.offset_central_directory.serialize(output)?;
|
||||||
|
(self.comment.len() as u16).serialize(output)?;
|
||||||
|
for c in &self.comment {
|
||||||
|
c.serialize(output)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize(input: &mut dyn ReadSeek) -> Result<Self> {
|
||||||
|
let signature = Signature::deserialize(input)?;
|
||||||
|
let disk_number = u16::deserialize(input)?;
|
||||||
|
let disk_number_of_central_directory_start = u16::deserialize(input)?;
|
||||||
|
let number_of_entries_in_central_directory_on_disk = u16::deserialize(input)?;
|
||||||
|
let number_of_entries_in_central_directory = u16::deserialize(input)?;
|
||||||
|
let size_central_directory = u32::deserialize(input)?;
|
||||||
|
let offset_central_directory = u32::deserialize(input)?;
|
||||||
|
let file_comment_length = u16::deserialize(input)?;
|
||||||
|
let mut comment = vec![];
|
||||||
|
for _ in 0..file_comment_length {
|
||||||
|
comment.push(u8::deserialize(input)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(signature, Self::SIGNATURE); // TODO
|
||||||
|
Ok(Self {
|
||||||
|
disk_number,
|
||||||
|
disk_number_of_central_directory_start,
|
||||||
|
number_of_entries_in_central_directory_on_disk,
|
||||||
|
number_of_entries_in_central_directory,
|
||||||
|
size_central_directory,
|
||||||
|
offset_central_directory,
|
||||||
|
comment,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size(&self) -> usize {
|
||||||
|
Self::MIN_SIZE + self.comment.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ZipFile<T: Read + Seek> {
|
||||||
|
end_of_central_directory: EndCentralDirectory,
|
||||||
|
end_of_central_directory_off: u64,
|
||||||
|
data: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Read + Seek> ZipFile<T> {
|
||||||
|
fn new(mut reader: T) -> Self {
|
||||||
|
let end_of_central_directory_off =
|
||||||
|
Self::get_end_of_central_directory_offset(&mut reader).unwrap();
|
||||||
|
reader
|
||||||
|
.seek(SeekFrom::Start(end_of_central_directory_off))
|
||||||
|
.unwrap();
|
||||||
|
let end_of_central_directory = EndCentralDirectory::deserialize(&mut reader).unwrap();
|
||||||
|
println!("{end_of_central_directory:#?}");
|
||||||
|
reader
|
||||||
|
.seek(SeekFrom::Start(
|
||||||
|
end_of_central_directory_off - Zip64EndCentralDirectoryLocator::SIZE as u64,
|
||||||
|
))
|
||||||
|
.unwrap();
|
||||||
|
let zip64_ecd_locator = Zip64EndCentralDirectoryLocator::deserialize(&mut reader).ok();
|
||||||
|
if let Some(zip64_ecd_locator) = zip64_ecd_locator {
|
||||||
|
assert_eq!(
|
||||||
|
zip64_ecd_locator.disk_number_of_zip64_end_central_directory_start,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
assert!(zip64_ecd_locator.total_number_of_disks <= 1);
|
||||||
|
println!("Zip64 ECD Locator {:#?}", zip64_ecd_locator);
|
||||||
|
let zip64_edc_record_off =
|
||||||
|
zip64_ecd_locator.offset_zip64_end_of_central_directory_record;
|
||||||
|
reader.seek(SeekFrom::Start(zip64_edc_record_off)).unwrap();
|
||||||
|
let zip64_edc_reccord = Zip64EndCentralDirectory::deserialize(&mut reader).ok();
|
||||||
|
println!("{zip64_edc_reccord:#?}");
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
end_of_central_directory,
|
||||||
|
end_of_central_directory_off,
|
||||||
|
data: reader,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_end_of_central_directory_offset(reader: &mut T) -> Option<u64> {
|
||||||
|
let file_size = reader.seek(SeekFrom::End(0)).unwrap();
|
||||||
|
let mut sig = Signature::default();
|
||||||
|
let mut comment_size = 0;
|
||||||
|
while sig != EndCentralDirectory::SIGNATURE {
|
||||||
|
reader
|
||||||
|
.seek(SeekFrom::End(
|
||||||
|
-(EndCentralDirectory::MIN_SIZE as i64) - comment_size,
|
||||||
|
))
|
||||||
|
.unwrap();
|
||||||
|
sig = Signature::deserialize(reader).unwrap();
|
||||||
|
comment_size += 1;
|
||||||
|
if comment_size > 65536
|
||||||
|
|| comment_size as usize + EndCentralDirectory::MIN_SIZE > file_size as usize
|
||||||
|
{
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
comment_size -= 1;
|
||||||
|
Some(file_size - comment_size as u64 - EndCentralDirectory::MIN_SIZE as u64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
//let file = File::open("app-release.apk").expect("failed to open file");
|
||||||
|
let file = File::open("tst_64.zip").expect("failed to open file");
|
||||||
|
let zip_fime = ZipFile::new(file);
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue