rusty_dex/dex/
header.rs

1//! DEX file header
2//!
3//! This module contains the representation of the header of a DEX file.
4//! The main use of this module is to load and parse each DEX file. When
5//! parsing a DEX file, the module will also verify the Adler32 checksum
6//! contained in the header.
7
8use std::io::Read;
9
10use crate::error::DexError;
11use crate::adler32;
12use crate::dex::reader::DexReader;
13
14/// Representation of the header of a DEX file
15#[derive(Debug)]
16pub struct DexHeader {
17    pub version: [u8; 3],
18    pub checksum: u32,
19    pub signature: [u8; 20],
20    pub file_size: u32,
21    pub header_size: u32,
22    pub endian_tag: u32,
23    pub link_size: u32,
24    pub link_off: u32,
25    pub map_off: u32,
26    pub string_ids_size: u32,
27    pub string_ids_off: u32,
28    pub type_ids_size: u32,
29    pub type_ids_off: u32,
30    pub proto_ids_size: u32,
31    pub proto_ids_off: u32,
32    pub fields_ids_size: u32,
33    pub fields_ids_off: u32,
34    pub method_ids_size: u32,
35    pub method_ids_off: u32,
36    pub class_defs_size: u32,
37    pub class_defs_off: u32,
38    pub data_size: u32,
39    pub data_off: u32
40}
41
42impl DexHeader {
43    /// Reads from the given cursor and builds a `DexHeader`
44    pub fn new(dex_cursor: &mut DexReader) -> Result<DexHeader, DexError> {
45        // DEX version
46        let mut magic = [0; 8];
47        dex_cursor.bytes.read_exact(&mut magic)?;
48        let mut version = [0; 3];
49        version[0] = magic[4];
50        version[1] = magic[5];
51        version[2] = magic[6];
52
53        let checksum = dex_cursor.read_u32()?;
54        adler32::verify_from_bytes(&dex_cursor.bytes, checksum)?;
55
56        let mut signature = [0; 20];
57        dex_cursor.bytes.read_exact(&mut signature)?;
58
59        let file_size = dex_cursor.read_u32()?;
60        let header_size = dex_cursor.read_u32()?;
61        let endian_tag = dex_cursor.read_u32()?;
62
63        let link_size = dex_cursor.read_u32()?;
64        let link_off = dex_cursor.read_u32()?;
65        let map_off = dex_cursor.read_u32()?;
66        let string_ids_size = dex_cursor.read_u32()?;
67        let string_ids_off = dex_cursor.read_u32()?;
68        let type_ids_size = dex_cursor.read_u32()?;
69        let type_ids_off = dex_cursor.read_u32()?;
70        let proto_ids_size = dex_cursor.read_u32()?;
71        let proto_ids_off = dex_cursor.read_u32()?;
72        let fields_ids_size = dex_cursor.read_u32()?;
73        let fields_ids_off = dex_cursor.read_u32()?;
74        let method_ids_size = dex_cursor.read_u32()?;
75        let method_ids_off = dex_cursor.read_u32()?;
76        let class_defs_size = dex_cursor.read_u32()?;
77        let class_defs_off = dex_cursor.read_u32()?;
78        let data_size = dex_cursor.read_u32()?;
79        let data_off = dex_cursor.read_u32()?;
80
81        Ok(DexHeader {
82                version,
83                checksum,
84                signature,
85                file_size,
86                header_size,
87                endian_tag,
88                link_size,
89                link_off,
90                map_off,
91                string_ids_size,
92                string_ids_off,
93                type_ids_size,
94                type_ids_off,
95                proto_ids_size,
96                proto_ids_off,
97                fields_ids_size,
98                fields_ids_off,
99                method_ids_size,
100                method_ids_off,
101                class_defs_size,
102                class_defs_off,
103                data_size,
104                data_off
105        })
106    }
107}
108
109#[cfg(test)]
110mod tests {
111    use super::*;
112
113    const DEX_DATA: [u8; 128] = [
114        0x64, 0x65, 0x78, 0x0a, 0x30, 0x33, 0x35, 0x00,
115        0x81, 0xc4, 0x10, 0x8e, 0x1c, 0xd2, 0x09, 0x16,
116        0x05, 0x09, 0xc2, 0xb6, 0xe6, 0xbf, 0xfb, 0x47,
117        0x1c, 0xda, 0xa3, 0xab, 0xfb, 0x5d, 0xd1, 0x4a,
118        0x10, 0x85, 0x1b, 0x00, 0x70, 0x00, 0x00, 0x00,
119        0x78, 0x56, 0x34, 0x12, 0x00, 0x00, 0x00, 0x00,
120        0x00, 0x00, 0x00, 0x00, 0x34, 0x84, 0x1b, 0x00,
121        0x44, 0x42, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00,
122        0x41, 0x09, 0x00, 0x00, 0x80, 0x09, 0x01, 0x00,
123        0xf6, 0x0d, 0x00, 0x00, 0x84, 0x2e, 0x01, 0x00,
124        0x5d, 0x20, 0x00, 0x00, 0x0c, 0xd6, 0x01, 0x00,
125        0xab, 0x37, 0x00, 0x00, 0xf4, 0xd8, 0x02, 0x00,
126        0xef, 0x05, 0x00, 0x00, 0x4c, 0x96, 0x04, 0x00,
127        0xe4, 0x30, 0x16, 0x00, 0x2c, 0x54, 0x05, 0x00,
128        0xc2, 0x15, 0x12, 0x00, 0xc4, 0x15, 0x12, 0x00,
129        0xf7, 0x15, 0x12, 0x00, 0x36, 0x16, 0x12, 0x00
130    ];
131
132    // #[test]
133    fn test_build() {
134        let mut dex_reader = DexReader::build(DEX_DATA.to_vec()).unwrap();
135        let dex_header = DexHeader::new(&mut dex_reader).unwrap();
136
137        assert_eq!(dex_header.version, [0x30, 0x33, 0x35]);
138        assert_eq!(dex_header.checksum, 0x8e10c481);
139        assert_eq!(dex_header.signature, [0x1c, 0xd2, 0x09, 0x16,
140                                          0x05, 0x09, 0xc2, 0xb6,
141                                          0xe6, 0xbf, 0xfb, 0x47,
142                                          0x1c, 0xda, 0xa3, 0xab,
143                                          0xfb, 0x5d, 0xd1, 0x4a]);
144        assert_eq!(dex_header.file_size,       0x001b8510);
145        assert_eq!(dex_header.header_size,     0x00000070);
146        assert_eq!(dex_header.endian_tag,      0x12345678);
147        assert_eq!(dex_header.link_size,       0x00000000);
148        assert_eq!(dex_header.link_off,        0x00000000);
149        assert_eq!(dex_header.map_off,         0x001b8434);
150        assert_eq!(dex_header.string_ids_size, 0x00004244);
151        assert_eq!(dex_header.string_ids_off,  0x00000070);
152        assert_eq!(dex_header.type_ids_size,   0x00000941);
153        assert_eq!(dex_header.type_ids_off,    0x00010980);
154        assert_eq!(dex_header.proto_ids_size,  0x00000df6);
155        assert_eq!(dex_header.proto_ids_off,   0x00012e84);
156        assert_eq!(dex_header.fields_ids_size, 0x0000205d);
157        assert_eq!(dex_header.fields_ids_off,  0x0001d60c);
158        assert_eq!(dex_header.method_ids_size, 0x000037ab);
159        assert_eq!(dex_header.method_ids_off,  0x0002d8f4);
160        assert_eq!(dex_header.class_defs_size, 0x000005ef);
161        assert_eq!(dex_header.class_defs_off,  0x0004964c);
162        assert_eq!(dex_header.data_size,       0x001630e4);
163        assert_eq!(dex_header.data_off,        0x0005542c);
164    }
165}