Calculates the Authenticode hash of a PE/COFF file
(data: &[u8])
| 9 | |
| 10 | /// Calculates the Authenticode hash of a PE/COFF file |
| 11 | fn authenticode_sha384_hash(data: &[u8]) -> Result<Vec<u8>> { |
| 12 | let lfanew_offset = 0x3c; |
| 13 | let lfanew: u32 = read_le(data, lfanew_offset, "DOS header")?; |
| 14 | |
| 15 | let pe_sig_offset = lfanew as usize; |
| 16 | let pe_sig: u32 = read_le(data, pe_sig_offset, "PE signature offset")?; |
| 17 | if pe_sig != pe::IMAGE_NT_SIGNATURE { |
| 18 | bail!("Invalid PE signature"); |
| 19 | } |
| 20 | |
| 21 | let coff_header_offset = pe_sig_offset + 4; |
| 22 | let optional_header_size = |
| 23 | read_le::<u16>(data, coff_header_offset + 16, "COFF header size")? as usize; |
| 24 | |
| 25 | let optional_header_offset = coff_header_offset + 20; |
| 26 | let magic: u16 = read_le(data, optional_header_offset, "header magic")?; |
| 27 | |
| 28 | let is_pe32_plus = magic == 0x20b; |
| 29 | |
| 30 | let checksum_offset = optional_header_offset + 64; |
| 31 | let checksum_end = checksum_offset + 4; |
| 32 | |
| 33 | let data_dir_offset = optional_header_offset + if is_pe32_plus { 112 } else { 96 }; |
| 34 | let cert_dir_offset = data_dir_offset + (pe::IMAGE_DIRECTORY_ENTRY_SECURITY * 8); |
| 35 | let cert_dir_end = cert_dir_offset + 8; |
| 36 | |
| 37 | let size_of_headers_offset = optional_header_offset + 60; |
| 38 | let size_of_headers = read_le::<u32>(data, size_of_headers_offset, "size_of_headers")? as usize; |
| 39 | |
| 40 | let mut hasher = Sha384::new(); |
| 41 | hasher.update(&data[0..checksum_offset]); |
| 42 | hasher.update(&data[checksum_end..cert_dir_offset]); |
| 43 | hasher.update(&data[cert_dir_end..size_of_headers]); |
| 44 | |
| 45 | let mut sum_of_bytes_hashed = size_of_headers; |
| 46 | |
| 47 | let num_sections_offset = coff_header_offset + 2; |
| 48 | let num_sections = read_le::<u16>(data, num_sections_offset, "number of sections")? as usize; |
| 49 | |
| 50 | let section_table_offset = optional_header_offset + optional_header_size; |
| 51 | let section_size = 40; |
| 52 | |
| 53 | let mut sections = Vec::with_capacity(num_sections); |
| 54 | for i in 0..num_sections { |
| 55 | let section_offset = section_table_offset + (i * section_size); |
| 56 | |
| 57 | let ptr_raw_data_offset = section_offset + 20; |
| 58 | let ptr_raw_data = |
| 59 | read_le::<u32>(data, ptr_raw_data_offset, "pointer_to_raw_data")? as usize; |
| 60 | |
| 61 | let size_raw_data_offset = section_offset + 16; |
| 62 | let size_raw_data = |
| 63 | read_le::<u32>(data, size_raw_data_offset, "size_of_raw_data")? as usize; |
| 64 | |
| 65 | if size_raw_data > 0 { |
| 66 | sections.push((ptr_raw_data, size_raw_data)); |
| 67 | } |
| 68 | } |