diff --git a/Cargo.lock b/Cargo.lock index 84c38ef..7e1599f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,11 +21,13 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" name = "androscalpel" version = "0.1.0" dependencies = [ + "adler", "androscalpel_serializer", "anyhow", "log", "pyo3 0.20.0", "pyo3-log", + "sha1", ] [[package]] @@ -88,6 +90,15 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "cc" version = "1.0.83" @@ -103,6 +114,45 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cpufeatures" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "gimli" version = "0.28.1" @@ -132,9 +182,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.147" +version = "0.2.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" [[package]] name = "lock_api" @@ -381,6 +431,17 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "smallvec" version = "1.11.0" @@ -404,6 +465,12 @@ version = "0.12.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d0e916b1148c8e263850e1ebcbd046f333e0683c724876bb0da63ea4373dc8a" +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + [[package]] name = "unicode-ident" version = "1.0.11" @@ -416,6 +483,12 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce" +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + [[package]] name = "winapi" version = "0.3.9" diff --git a/androscalpel/Cargo.toml b/androscalpel/Cargo.toml index 08d42d9..1cc2e8a 100644 --- a/androscalpel/Cargo.toml +++ b/androscalpel/Cargo.toml @@ -9,8 +9,10 @@ name = "androscalpel" crate-type = ["cdylib"] [dependencies] +adler = "1.0.2" androscalpel_serializer = { version = "0.1.0", path = "../androscalpel_serializer" } anyhow = { version = "1.0.75", features = ["backtrace"] } log = "0.4.20" pyo3 = { version = "0.20.0", features = ["anyhow"] } pyo3-log = "0.8.3" +sha1 = "0.10.6" diff --git a/androscalpel/src/dex_writer.rs b/androscalpel/src/dex_writer.rs index 7865997..1286fcf 100644 --- a/androscalpel/src/dex_writer.rs +++ b/androscalpel/src/dex_writer.rs @@ -1,11 +1,13 @@ //! The structure that generate a .dex from classes. use std::collections::{HashMap, HashSet, VecDeque}; -use std::io::{Cursor, Write}; - -use log::debug; +use std::io; +use std::io::{Cursor, Seek, SeekFrom, Write}; +use adler::Adler32; use anyhow::{anyhow, bail, Context}; +use log::debug; +use sha1::{Digest, Sha1}; use crate::Result; use crate::*; @@ -1898,7 +1900,7 @@ impl DexWriter { annotation_off + 1 } else { 0 - }, // TODO: link + }, // linked in link_annotations() }); } @@ -2422,57 +2424,58 @@ impl DexWriter { self.link_annotations(); debug!("Serialize the dex file"); + let mut buffer = Cursor::new(Vec::::new()); // TODO: compute checksum, hash, ect - self.header.serialize(writer)?; + self.header.serialize(&mut buffer)?; // StringIdItem section let mut string_off = self.section_manager.get_offset(Section::StringDataItem); for string in self.string_data_list.iter() { let str_id = StringIdItem { string_data_off: string_off, }; - str_id.serialize(writer)?; + str_id.serialize(&mut buffer)?; string_off += string.size() as u32; } // TypeId section for ty in &self.type_ids_list { - ty.serialize(writer)?; + ty.serialize(&mut buffer)?; } // ProtoId section for proto in &self.proto_ids_list { - proto.serialize(writer)?; + proto.serialize(&mut buffer)?; } // FieldIdItem section for field_id in &self.field_ids_list { - field_id.serialize(writer)?; + field_id.serialize(&mut buffer)?; } // MethodIdItem section for method_id in &self.method_ids_list { - method_id.serialize(writer)?; + method_id.serialize(&mut buffer)?; } // ClassDefItem section for class_def in &self.class_defs_list { - class_def.serialize(writer)?; + class_def.serialize(&mut buffer)?; } // CallSiteIdItem, data are inserted as encoded array item later for call_site_id in &self.call_site_ids { - call_site_id.serialize(writer)?; + call_site_id.serialize(&mut buffer)?; } // MethodHandleItem section for handle in &self.method_handles { - handle.serialize(writer)?; + handle.serialize(&mut buffer)?; } // MapList - self.map_list.serialize(writer)?; + self.map_list.serialize(&mut buffer)?; // TypeList, let mut offset = 0; // the sections are always aligned until the type_lists for (list, _) in &self.type_lists_with_offset { while offset % 4 != 0 { offset += 1; - 0u8.serialize(writer)?; + 0u8.serialize(&mut buffer)?; } offset += list.size(); - list.serialize(writer)?; + list.serialize(&mut buffer)?; } // The next section requires alignment to 4 while offset % 4 != 0 { @@ -2482,41 +2485,61 @@ impl DexWriter { } // AnnotationSetRefList section for list in &self.annotation_set_lists { - list.serialize(writer)?; + list.serialize(&mut buffer)?; } // AnnotationSetItem section for set in &self.annotation_set_items { - set.serialize(writer)?; + set.serialize(&mut buffer)?; } // ClassDataItem section for data in &self.class_data_list { - data.serialize(writer)?; + data.serialize(&mut buffer)?; } // CodeItem section for code_item in &self.code_items { - code_item.serialize(writer)? + code_item.serialize(&mut buffer)? } for string in &self.string_data_list { - string.serialize(writer)?; + string.serialize(&mut buffer)?; } // DebugInfoItem section for debug_info in &self.debug_info_items { - debug_info.serialize(writer)?; + debug_info.serialize(&mut buffer)?; } // AnnotationItem section for annot in &self.annotation_items { - annot.serialize(writer)?; + annot.serialize(&mut buffer)?; } // EncodedArrayItem section for array in &self.encoded_array_items { - array.serialize(writer)?; + array.serialize(&mut buffer)?; } // AnnotationsDirectoryItem section for dir in &self.annotations_directory_items { - dir.serialize(writer)?; + dir.serialize(&mut buffer)?; } // TODO: HiddenapiClassDataItem, + // compute signature + buffer.seek(SeekFrom::Start(8 + 4 + 20))?; + let mut hasher = Sha1::new(); + io::copy(&mut buffer, &mut hasher)?; + self.header.signature = hasher.finalize().into(); + buffer.rewind()?; + self.header.serialize(&mut buffer)?; + + // Compute checksum + //buffer.seek(SeekFrom::Start(8 + 4))?; + let mut adler = Adler32::new(); + adler.write_slice(&buffer.get_ref()[8 + 4..]); + self.header.checksum = adler.checksum(); + buffer.rewind()?; + self.header.serialize(&mut buffer)?; + + // copy buffer to output + buffer.rewind()?; + io::copy(&mut buffer, writer)?; + Ok(()) }