explore files
This commit is contained in:
parent
0794aac016
commit
0d305fbe62
5 changed files with 189 additions and 47 deletions
|
|
@ -12,6 +12,7 @@ pub mod local_file_header;
|
|||
use apk_signing_block::*;
|
||||
use end_of_central_directory::*;
|
||||
use file_header::FileHeader;
|
||||
use local_file_header::LocalFileHeader;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serializable, Default)]
|
||||
pub struct Signature(pub u32);
|
||||
|
|
@ -21,10 +22,39 @@ pub enum Encoding {
|
|||
UTF8,
|
||||
}
|
||||
|
||||
pub mod general_purpose_flags {
|
||||
pub const MASK_ENCRYPTED: u16 = 1 << 0;
|
||||
pub const MASK_COMPRESS_OPTION_1: u16 = 1 << 1;
|
||||
pub const MASK_COMPRESS_OPTION_2: u16 = 1 << 2;
|
||||
pub const MASK_USE_DATA_DESCRIPTOR: u16 = 1 << 3;
|
||||
pub const MASK_STRONG_ENCRYPTION: u16 = 1 << 6;
|
||||
pub const MASK_UTF8_FILENAME: u16 = 1 << 11;
|
||||
pub const MASK_ENCRYPTED_CENTRAL_DIR: u16 = 1 << 13;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct File {
|
||||
pub local_header: LocalFileHeader,
|
||||
pub header: FileHeader,
|
||||
}
|
||||
// TODO: support data descriptor (MASK_USE_DATA_DESCRIPTOR)
|
||||
|
||||
impl File {
|
||||
pub fn get_name(&self) -> String {
|
||||
self.header.get_name()
|
||||
}
|
||||
pub fn get_offset_local_header(&self) -> u64 {
|
||||
self.header.get_offset_local_header()
|
||||
}
|
||||
pub fn get_compressed_size(&self) -> u64 {
|
||||
self.header.get_compressed_size()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ZipFile<T: Read + Seek> {
|
||||
pub end_of_central_directory: EndCentralDirectory,
|
||||
pub zip64_end_of_central_directory: Option<Zip64EndCentralDirectory>,
|
||||
pub files: Vec<FileHeader>,
|
||||
pub files: Vec<File>,
|
||||
pub apk_sign_block: Option<ApkSigningBlock>,
|
||||
pub data: T,
|
||||
}
|
||||
|
|
@ -37,7 +67,6 @@ impl<T: Read + Seek> ZipFile<T> {
|
|||
.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,
|
||||
|
|
@ -50,13 +79,10 @@ impl<T: Read + Seek> ZipFile<T> {
|
|||
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:#?}");
|
||||
zip64_edc_reccord
|
||||
Zip64EndCentralDirectory::deserialize(&mut reader).ok()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
|
@ -73,39 +99,51 @@ impl<T: Read + Seek> ZipFile<T> {
|
|||
};
|
||||
zip_file
|
||||
.data
|
||||
.seek(SeekFrom::Start(zip_file.get_ed_offset()))
|
||||
.seek(SeekFrom::Start(zip_file.get_cd_offset()))
|
||||
.unwrap();
|
||||
|
||||
let mut size_read = 0;
|
||||
let cd_size = zip_file.get_ed_size();
|
||||
let cd_size = zip_file.get_cd_size();
|
||||
while size_read < cd_size {
|
||||
let file_header = FileHeader::deserialize(&mut zip_file.data).unwrap();
|
||||
println!("{file_header:#?}");
|
||||
size_read += file_header.size() as u64;
|
||||
zip_file.files.push(file_header);
|
||||
}
|
||||
assert_eq!(size_read, cd_size);
|
||||
if zip_file.get_ed_offset() > 16 {
|
||||
let header = FileHeader::deserialize(&mut zip_file.data).unwrap();
|
||||
size_read += header.size() as u64;
|
||||
let pos_in_dir = zip_file.data.stream_position().unwrap();
|
||||
if header.general_purpose_flags & general_purpose_flags::MASK_ENCRYPTED_CENTRAL_DIR != 0
|
||||
{
|
||||
panic!("Central directory encryption not supported");
|
||||
}
|
||||
zip_file
|
||||
.data
|
||||
.seek(SeekFrom::Start(zip_file.get_ed_offset() - 16))
|
||||
.seek(SeekFrom::Start(header.get_offset_local_header()))
|
||||
.unwrap();
|
||||
let local_header = LocalFileHeader::deserialize(&mut zip_file.data).unwrap();
|
||||
zip_file.data.seek(SeekFrom::Start(pos_in_dir)).unwrap();
|
||||
zip_file.files.push(File {
|
||||
local_header,
|
||||
header,
|
||||
});
|
||||
}
|
||||
assert_eq!(size_read, cd_size);
|
||||
if zip_file.get_cd_offset() > 16 {
|
||||
zip_file
|
||||
.data
|
||||
.seek(SeekFrom::Start(zip_file.get_cd_offset() - 16))
|
||||
.unwrap();
|
||||
let magic = Magic::deserialize(&mut zip_file.data).unwrap();
|
||||
if magic == ApkSigningBlock::MAGIC {
|
||||
zip_file
|
||||
.data
|
||||
.seek(SeekFrom::Start(zip_file.get_ed_offset() - 16 - 8))
|
||||
.seek(SeekFrom::Start(zip_file.get_cd_offset() - 16 - 8))
|
||||
.unwrap();
|
||||
let block_size = u64::deserialize(&mut zip_file.data).unwrap();
|
||||
zip_file
|
||||
.data
|
||||
.seek(SeekFrom::Start(zip_file.get_ed_offset() - block_size - 8))
|
||||
.seek(SeekFrom::Start(zip_file.get_cd_offset() - block_size - 8))
|
||||
.unwrap();
|
||||
|
||||
zip_file.apk_sign_block = ApkSigningBlock::deserialize(&mut zip_file.data).ok();
|
||||
}
|
||||
}
|
||||
//println!("{:?}", zip_file.apk_sign_block);
|
||||
|
||||
zip_file
|
||||
}
|
||||
|
|
@ -149,7 +187,7 @@ impl<T: Read + Seek> ZipFile<T> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_ed_size(&self) -> u64 {
|
||||
pub fn get_cd_size(&self) -> u64 {
|
||||
if let Some(zip64_end_of_central_directory) = &self.zip64_end_of_central_directory {
|
||||
zip64_end_of_central_directory.size_of_central_directory
|
||||
} else {
|
||||
|
|
@ -157,7 +195,7 @@ impl<T: Read + Seek> ZipFile<T> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_ed_offset(&self) -> u64 {
|
||||
pub fn get_cd_offset(&self) -> u64 {
|
||||
if let Some(zip64_end_of_central_directory) = &self.zip64_end_of_central_directory {
|
||||
zip64_end_of_central_directory.offset_central_directory
|
||||
} else {
|
||||
|
|
@ -197,7 +235,7 @@ impl<T: Read + Seek> ZipFile<T> {
|
|||
/// META-INF/*.DSA
|
||||
/// META-INF/*.RSA
|
||||
/// META-INF/SIG-*
|
||||
pub fn get_jar_sig_files(&self) -> Vec<&FileHeader> {
|
||||
pub fn get_jar_sig_files(&self) -> Vec<&File> {
|
||||
self.files
|
||||
.iter()
|
||||
.filter(|file| {
|
||||
|
|
@ -229,4 +267,49 @@ impl<T: Read + Seek> ZipFile<T> {
|
|||
pub fn is_signed_v2(&self) -> bool {
|
||||
self.apk_sign_block.is_some()
|
||||
}
|
||||
|
||||
pub fn check_holes(&self) {
|
||||
let mut files: Vec<&File> = self.files.iter().collect();
|
||||
files.sort_by_key(|f| f.get_offset_local_header());
|
||||
let mut lst_offset = 0;
|
||||
for file in files.iter() {
|
||||
if file.get_offset_local_header() != lst_offset {
|
||||
println!(
|
||||
"Hole before {} between 0x{:x} and 0x{:x}",
|
||||
file.get_name(),
|
||||
lst_offset,
|
||||
file.get_offset_local_header()
|
||||
);
|
||||
}
|
||||
lst_offset += file.local_header.size() as u64;
|
||||
lst_offset += file.get_compressed_size();
|
||||
}
|
||||
if let Some(apk_sign_block) = &self.apk_sign_block {
|
||||
let apk_sb_off = self.get_cd_offset() - apk_sign_block.size() as u64;
|
||||
if apk_sb_off != lst_offset {
|
||||
println!(
|
||||
"Hole before apk signing block, between 0x{:x} and 0x{:x}",
|
||||
lst_offset, apk_sb_off
|
||||
);
|
||||
}
|
||||
|
||||
lst_offset += apk_sign_block.size() as u64;
|
||||
}
|
||||
if self.get_cd_offset() != lst_offset {
|
||||
println!(
|
||||
"Hole before central directory between 0x{:x} and 0x{:x}",
|
||||
lst_offset,
|
||||
self.get_cd_offset()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_bin(&mut self, offset: u64, size: usize) -> Vec<u8> {
|
||||
self.data.seek(SeekFrom::Start(offset)).unwrap();
|
||||
let mut data = vec![];
|
||||
for _ in 0..size {
|
||||
data.push(u8::deserialize(&mut self.data).unwrap());
|
||||
}
|
||||
data
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue