| 46 | } |
| 47 | |
| 48 | pub fn parse_exports(dll_path: &Path) -> Result<Vec<DllExport>, String> { |
| 49 | let data = fs::read(dll_path).map_err(|e| format!("Failed to read DLL: {}", e))?; |
| 50 | |
| 51 | if data.len() < 64 || read_u16(&data, 0) != 0x5A4D { |
| 52 | return Err("Not a valid PE file (bad MZ signature)".into()); |
| 53 | } |
| 54 | |
| 55 | let pe_offset = read_u32(&data, 0x3C) as usize; |
| 56 | if data.len() < pe_offset + 4 || read_u32(&data, pe_offset) != 0x00004550 { |
| 57 | return Err("Not a valid PE file (bad PE signature)".into()); |
| 58 | } |
| 59 | |
| 60 | let magic = read_u16(&data, pe_offset + 24); |
| 61 | let export_dir_rva_offset = match magic { |
| 62 | 0x10b => pe_offset + 24 + 96, // PE32 |
| 63 | 0x20b => pe_offset + 24 + 112, // PE32+ |
| 64 | _ => return Err(format!("Unknown PE optional header magic: 0x{:04x}", magic)), |
| 65 | }; |
| 66 | |
| 67 | let num_sections = read_u16(&data, pe_offset + 6); |
| 68 | let sections = parse_sections(&data, pe_offset, num_sections); |
| 69 | |
| 70 | let export_rva = read_u32(&data, export_dir_rva_offset); |
| 71 | let export_size = read_u32(&data, export_dir_rva_offset + 4); |
| 72 | |
| 73 | if export_rva == 0 || export_size == 0 { |
| 74 | return Ok(vec![]); |
| 75 | } |
| 76 | |
| 77 | let export_offset = |
| 78 | rva_to_offset(§ions, export_rva).ok_or("Cannot resolve export directory RVA")?; |
| 79 | |
| 80 | let num_functions = read_u32(&data, export_offset + 20) as usize; |
| 81 | let num_names = read_u32(&data, export_offset + 24) as usize; |
| 82 | let ordinal_base = read_u32(&data, export_offset + 16) as u16; |
| 83 | |
| 84 | let addr_table_rva = read_u32(&data, export_offset + 28); |
| 85 | let name_ptr_rva = read_u32(&data, export_offset + 32); |
| 86 | let ordinal_table_rva = read_u32(&data, export_offset + 36); |
| 87 | |
| 88 | let addr_table_off = |
| 89 | rva_to_offset(§ions, addr_table_rva).ok_or("Cannot resolve address table RVA")?; |
| 90 | let name_ptr_off = |
| 91 | rva_to_offset(§ions, name_ptr_rva).ok_or("Cannot resolve name pointer RVA")?; |
| 92 | let ordinal_off = |
| 93 | rva_to_offset(§ions, ordinal_table_rva).ok_or("Cannot resolve ordinal table RVA")?; |
| 94 | |
| 95 | let mut name_for_index: Vec<Option<String>> = vec![None; num_functions]; |
| 96 | for i in 0..num_names { |
| 97 | let name_rva = read_u32(&data, name_ptr_off + i * 4); |
| 98 | let ord_index = read_u16(&data, ordinal_off + i * 2) as usize; |
| 99 | if let Some(off) = rva_to_offset(§ions, name_rva) { |
| 100 | if let Some(name) = read_cstring(&data, off) { |
| 101 | if ord_index < num_functions { |
| 102 | name_for_index[ord_index] = Some(name); |
| 103 | } |
| 104 | } |
| 105 | } |