From 31af34d5b89be327780f2a425d0954adcae62b21 Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Tue, 4 Jul 2023 00:00:00 +0000 Subject: [PATCH] read/coff: lower level parsing support for ImportObjectHeader (#556) Add lower level parsing support for ImportObjectHeader and use it in the readobj example. Also some style changes for the import file support. --- crates/examples/src/objdump.rs | 4 +- crates/examples/src/readobj/mod.rs | 1 + crates/examples/src/readobj/pe.rs | 34 + .../testfiles/coff/import_msvc.lib.readobj | 1058 +++++++++++++++++ src/pe.rs | 4 + src/read/coff/import.rs | 148 ++- src/read/mod.rs | 12 +- 7 files changed, 1212 insertions(+), 49 deletions(-) create mode 100644 crates/examples/testfiles/coff/import_msvc.lib.readobj diff --git a/crates/examples/src/objdump.rs b/crates/examples/src/objdump.rs index cfb6d421..45b1da3e 100644 --- a/crates/examples/src/objdump.rs +++ b/crates/examples/src/objdump.rs @@ -22,7 +22,7 @@ pub fn print( writeln!(w)?; writeln!(w, "{}:", String::from_utf8_lossy(member.name()))?; if let Ok(data) = member.data(file) { - if FileKind::parse(data) == Ok(FileKind::CoffImportFile) { + if FileKind::parse(data) == Ok(FileKind::CoffImport) { dump_import(w, e, data)?; } else { dump_object(w, e, data)?; @@ -252,7 +252,7 @@ fn dump_parsed_object(w: &mut W, e: &mut E, file: &object::F } fn dump_import(w: &mut W, e: &mut E, data: &[u8]) -> Result<()> { - let file = match coff::CoffImportFile::parse(data) { + let file = match coff::ImportFile::parse(data) { Ok(import) => import, Err(err) => { writeln!(e, "Failed to parse short import: {}", err)?; diff --git a/crates/examples/src/readobj/mod.rs b/crates/examples/src/readobj/mod.rs index 39a42518..35baf3d0 100644 --- a/crates/examples/src/readobj/mod.rs +++ b/crates/examples/src/readobj/mod.rs @@ -193,6 +193,7 @@ fn print_object(p: &mut Printer<'_>, data: &[u8]) { object::FileKind::Archive => print_archive(p, data), object::FileKind::Coff => pe::print_coff(p, data), object::FileKind::CoffBig => pe::print_coff_big(p, data), + object::FileKind::CoffImport => pe::print_coff_import(p, data), object::FileKind::DyldCache => macho::print_dyld_cache(p, data), object::FileKind::Elf32 => elf::print_elf32(p, data), object::FileKind::Elf64 => elf::print_elf64(p, data), diff --git a/crates/examples/src/readobj/pe.rs b/crates/examples/src/readobj/pe.rs index ac3fa0e5..8744e960 100644 --- a/crates/examples/src/readobj/pe.rs +++ b/crates/examples/src/readobj/pe.rs @@ -38,6 +38,31 @@ pub(super) fn print_coff_big(p: &mut Printer<'_>, data: &[u8]) { } } +pub(super) fn print_coff_import(p: &mut Printer<'_>, data: &[u8]) { + let mut offset = 0; + if let Some(header) = ImportObjectHeader::parse(data, &mut offset).print_err(p) { + writeln!(p.w(), "Format: COFF import").unwrap(); + p.group("ImportObjectHeader", |p| { + p.field_hex("Signature1", header.sig1.get(LE)); + p.field_hex("Signature2", header.sig2.get(LE)); + p.field("Version", header.version.get(LE)); + p.field_enum("Machine", header.machine.get(LE), FLAGS_IMAGE_FILE_MACHINE); + p.field("TimeDateStamp", header.time_date_stamp.get(LE)); + p.field_hex("SizeOfData", header.size_of_data.get(LE)); + p.field("OrdinalOrHint", header.ordinal_or_hint.get(LE)); + p.field_enum("ImportType", header.import_type(), FLAGS_IMAGE_OBJECT_TYPE); + p.field_enum("NameType", header.name_type(), FLAGS_IMAGE_OBJECT_NAME); + if let Some(data) = header.parse_data(data, &mut offset).print_err(p) { + p.field_inline_string("Symbol", data.symbol()); + p.field_inline_string("Dll", data.dll()); + if let Some(export) = data.export() { + p.field_inline_string("Export", export); + } + } + }); + } +} + pub(super) fn print_pe32(p: &mut Printer<'_>, data: &[u8]) { writeln!(p.w(), "Format: PE 32-bit").unwrap(); print_pe::(p, data); @@ -1243,3 +1268,12 @@ const FLAGS_RT: &[Flag] = &flags!( RT_HTML, RT_MANIFEST, ); +const FLAGS_IMAGE_OBJECT_TYPE: &[Flag] = + &flags!(IMPORT_OBJECT_CODE, IMPORT_OBJECT_DATA, IMPORT_OBJECT_CONST); +const FLAGS_IMAGE_OBJECT_NAME: &[Flag] = &flags!( + IMPORT_OBJECT_ORDINAL, + IMPORT_OBJECT_NAME, + IMPORT_OBJECT_NAME_NO_PREFIX, + IMPORT_OBJECT_NAME_UNDECORATE, + IMPORT_OBJECT_NAME_EXPORTAS, +); diff --git a/crates/examples/testfiles/coff/import_msvc.lib.readobj b/crates/examples/testfiles/coff/import_msvc.lib.readobj new file mode 100644 index 00000000..673aba5c --- /dev/null +++ b/crates/examples/testfiles/coff/import_msvc.lib.readobj @@ -0,0 +1,1058 @@ +Format: Archive (Coff) + +Member: test_x64.dll +Format: COFF import +ImportObjectHeader { + Signature1: 0x0 + Signature2: 0xFFFF + Version: 0 + Machine: IMAGE_FILE_MACHINE_AMD64 (0x8664) + TimeDateStamp: 1687268223 + SizeOfData: 0x15 + OrdinalOrHint: 2 + ImportType: IMPORT_OBJECT_CODE (0x0) + NameType: IMPORT_OBJECT_NAME (0x1) + Symbol: "foo_x64" + Dll: "test_x64.dll" +} + +Member: test_x64.dll +Format: COFF import +ImportObjectHeader { + Signature1: 0x0 + Signature2: 0xFFFF + Version: 0 + Machine: IMAGE_FILE_MACHINE_AMD64 (0x8664) + TimeDateStamp: 1687268223 + SizeOfData: 0x15 + OrdinalOrHint: 1 + ImportType: IMPORT_OBJECT_CODE (0x0) + NameType: IMPORT_OBJECT_ORDINAL (0x0) + Symbol: "bar_x64" + Dll: "test_x64.dll" +} + +Member: test_x64.dll +Format: COFF import +ImportObjectHeader { + Signature1: 0x0 + Signature2: 0xFFFF + Version: 0 + Machine: IMAGE_FILE_MACHINE_AMD64 (0x8664) + TimeDateStamp: 1687268223 + SizeOfData: 0x15 + OrdinalOrHint: 1 + ImportType: IMPORT_OBJECT_DATA (0x1) + NameType: IMPORT_OBJECT_NAME (0x1) + Symbol: "FOO_x64" + Dll: "test_x64.dll" +} + +Member: test_x64.dll +Format: COFF import +ImportObjectHeader { + Signature1: 0x0 + Signature2: 0xFFFF + Version: 0 + Machine: IMAGE_FILE_MACHINE_AMD64 (0x8664) + TimeDateStamp: 1687268223 + SizeOfData: 0x15 + OrdinalOrHint: 0 + ImportType: IMPORT_OBJECT_CONST (0x2) + NameType: IMPORT_OBJECT_NAME (0x1) + Symbol: "BAR_x64" + Dll: "test_x64.dll" +} + +Member: test_x64.dll +Format: COFF +ImageFileHeader { + Machine: IMAGE_FILE_MACHINE_AMD64 (0x8664) + NumberOfSections: 3 + TimeDateStamp: 1687268223 + PointerToSymbolTable: 0xDE + NumberOfSymbols: 2 + SizeOfOptionalHeader: 0x0 + Characteristics: 0x0 +} +ImageSectionHeader { + Index: 1 + Name: ".debug$S" + VirtualSize: 0x0 + VirtualAddress: 0x0 + SizeOfRawData: 0x42 + PointerToRawData: 0x8C + PointerToRelocations: 0x0 + PointerToLinenumbers: 0x0 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + Characteristics: 0x42100040 + IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) + IMAGE_SCN_MEM_DISCARDABLE (0x2000000) + IMAGE_SCN_MEM_READ (0x40000000) + IMAGE_SCN_ALIGN_1BYTES (0x100000) +} +ImageSectionHeader { + Index: 2 + Name: ".idata$5" + VirtualSize: 0x0 + VirtualAddress: 0x0 + SizeOfRawData: 0x8 + PointerToRawData: 0xCE + PointerToRelocations: 0x0 + PointerToLinenumbers: 0x0 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + Characteristics: 0xC0400040 + IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) + IMAGE_SCN_MEM_READ (0x40000000) + IMAGE_SCN_MEM_WRITE (0x80000000) + IMAGE_SCN_ALIGN_8BYTES (0x400000) +} +ImageSectionHeader { + Index: 3 + Name: ".idata$4" + VirtualSize: 0x0 + VirtualAddress: 0x0 + SizeOfRawData: 0x8 + PointerToRawData: 0xD6 + PointerToRelocations: 0x0 + PointerToLinenumbers: 0x0 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + Characteristics: 0xC0400040 + IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) + IMAGE_SCN_MEM_READ (0x40000000) + IMAGE_SCN_MEM_WRITE (0x80000000) + IMAGE_SCN_ALIGN_8BYTES (0x400000) +} +ImageSymbol { + Index: 0 + Name: "@comp.id" + Value: 0x1017DD9 + Section: IMAGE_SYM_ABSOLUTE (-1) + Type: 0x0 + BaseType: IMAGE_SYM_TYPE_NULL (0x0) + DerivedType: IMAGE_SYM_DTYPE_NULL (0x0) + StorageClass: IMAGE_SYM_CLASS_STATIC (0x3) + NumberOfAuxSymbols: 0x0 +} +ImageSymbol { + Index: 1 + Name: "test_x64_NULL_THUNK_DATA" + Value: 0x0 + Section: ".idata$5" (0x2) + Type: 0x0 + BaseType: IMAGE_SYM_TYPE_NULL (0x0) + DerivedType: IMAGE_SYM_DTYPE_NULL (0x0) + StorageClass: IMAGE_SYM_CLASS_EXTERNAL (0x2) + NumberOfAuxSymbols: 0x0 +} + +Member: test_x64.dll +Format: COFF +ImageFileHeader { + Machine: IMAGE_FILE_MACHINE_AMD64 (0x8664) + NumberOfSections: 2 + TimeDateStamp: 1687268223 + PointerToSymbolTable: 0xBA + NumberOfSymbols: 2 + SizeOfOptionalHeader: 0x0 + Characteristics: 0x0 +} +ImageSectionHeader { + Index: 1 + Name: ".debug$S" + VirtualSize: 0x0 + VirtualAddress: 0x0 + SizeOfRawData: 0x42 + PointerToRawData: 0x64 + PointerToRelocations: 0x0 + PointerToLinenumbers: 0x0 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + Characteristics: 0x42100040 + IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) + IMAGE_SCN_MEM_DISCARDABLE (0x2000000) + IMAGE_SCN_MEM_READ (0x40000000) + IMAGE_SCN_ALIGN_1BYTES (0x100000) +} +ImageSectionHeader { + Index: 2 + Name: ".idata$3" + VirtualSize: 0x0 + VirtualAddress: 0x0 + SizeOfRawData: 0x14 + PointerToRawData: 0xA6 + PointerToRelocations: 0x0 + PointerToLinenumbers: 0x0 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + Characteristics: 0xC0300040 + IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) + IMAGE_SCN_MEM_READ (0x40000000) + IMAGE_SCN_MEM_WRITE (0x80000000) + IMAGE_SCN_ALIGN_4BYTES (0x300000) +} +ImageSymbol { + Index: 0 + Name: "@comp.id" + Value: 0x1017DD9 + Section: IMAGE_SYM_ABSOLUTE (-1) + Type: 0x0 + BaseType: IMAGE_SYM_TYPE_NULL (0x0) + DerivedType: IMAGE_SYM_DTYPE_NULL (0x0) + StorageClass: IMAGE_SYM_CLASS_STATIC (0x3) + NumberOfAuxSymbols: 0x0 +} +ImageSymbol { + Index: 1 + Name: "__NULL_IMPORT_DESCRIPTOR" + Value: 0x0 + Section: ".idata$3" (0x2) + Type: 0x0 + BaseType: IMAGE_SYM_TYPE_NULL (0x0) + DerivedType: IMAGE_SYM_DTYPE_NULL (0x0) + StorageClass: IMAGE_SYM_CLASS_EXTERNAL (0x2) + NumberOfAuxSymbols: 0x0 +} + +Member: test_x64.dll +Format: COFF +ImageFileHeader { + Machine: IMAGE_FILE_MACHINE_AMD64 (0x8664) + NumberOfSections: 3 + TimeDateStamp: 1687268223 + PointerToSymbolTable: 0x10E + NumberOfSymbols: 8 + SizeOfOptionalHeader: 0x0 + Characteristics: 0x0 +} +ImageSectionHeader { + Index: 1 + Name: ".debug$S" + VirtualSize: 0x0 + VirtualAddress: 0x0 + SizeOfRawData: 0x42 + PointerToRawData: 0x8C + PointerToRelocations: 0x0 + PointerToLinenumbers: 0x0 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + Characteristics: 0x42100040 + IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) + IMAGE_SCN_MEM_DISCARDABLE (0x2000000) + IMAGE_SCN_MEM_READ (0x40000000) + IMAGE_SCN_ALIGN_1BYTES (0x100000) +} +ImageSectionHeader { + Index: 2 + Name: ".idata$2" + VirtualSize: 0x0 + VirtualAddress: 0x0 + SizeOfRawData: 0x14 + PointerToRawData: 0xCE + PointerToRelocations: 0xE2 + PointerToLinenumbers: 0x0 + NumberOfRelocations: 3 + NumberOfLinenumbers: 0 + Characteristics: 0xC0300040 + IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) + IMAGE_SCN_MEM_READ (0x40000000) + IMAGE_SCN_MEM_WRITE (0x80000000) + IMAGE_SCN_ALIGN_4BYTES (0x300000) + ImageRelocation { + VirtualAddress: 0xC + Symbol: ".idata$6" (0x3) + Type: IMAGE_REL_AMD64_ADDR32NB (0x3) + } + ImageRelocation { + VirtualAddress: 0x0 + Symbol: ".idata$4" (0x4) + Type: IMAGE_REL_AMD64_ADDR32NB (0x3) + } + ImageRelocation { + VirtualAddress: 0x10 + Symbol: ".idata$5" (0x5) + Type: IMAGE_REL_AMD64_ADDR32NB (0x3) + } +} +ImageSectionHeader { + Index: 3 + Name: ".idata$6" + VirtualSize: 0x0 + VirtualAddress: 0x0 + SizeOfRawData: 0xE + PointerToRawData: 0x100 + PointerToRelocations: 0xE2 + PointerToLinenumbers: 0x0 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + Characteristics: 0xC0200040 + IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) + IMAGE_SCN_MEM_READ (0x40000000) + IMAGE_SCN_MEM_WRITE (0x80000000) + IMAGE_SCN_ALIGN_2BYTES (0x200000) +} +ImageSymbol { + Index: 0 + Name: "@comp.id" + Value: 0x1017DD9 + Section: IMAGE_SYM_ABSOLUTE (-1) + Type: 0x0 + BaseType: IMAGE_SYM_TYPE_NULL (0x0) + DerivedType: IMAGE_SYM_DTYPE_NULL (0x0) + StorageClass: IMAGE_SYM_CLASS_STATIC (0x3) + NumberOfAuxSymbols: 0x0 +} +ImageSymbol { + Index: 1 + Name: "__IMPORT_DESCRIPTOR_test_x64" + Value: 0x0 + Section: ".idata$2" (0x2) + Type: 0x0 + BaseType: IMAGE_SYM_TYPE_NULL (0x0) + DerivedType: IMAGE_SYM_DTYPE_NULL (0x0) + StorageClass: IMAGE_SYM_CLASS_EXTERNAL (0x2) + NumberOfAuxSymbols: 0x0 +} +ImageSymbol { + Index: 2 + Name: ".idata$2" + Value: 0xC0000040 + Section: ".idata$2" (0x2) + Type: 0x0 + BaseType: IMAGE_SYM_TYPE_NULL (0x0) + DerivedType: IMAGE_SYM_DTYPE_NULL (0x0) + StorageClass: IMAGE_SYM_CLASS_SECTION (0x68) + NumberOfAuxSymbols: 0x0 +} +ImageSymbol { + Index: 3 + Name: ".idata$6" + Value: 0x0 + Section: ".idata$6" (0x3) + Type: 0x0 + BaseType: IMAGE_SYM_TYPE_NULL (0x0) + DerivedType: IMAGE_SYM_DTYPE_NULL (0x0) + StorageClass: IMAGE_SYM_CLASS_STATIC (0x3) + NumberOfAuxSymbols: 0x0 +} +ImageSymbol { + Index: 4 + Name: ".idata$4" + Value: 0xC0000040 + Section: IMAGE_SYM_UNDEFINED (0) + Type: 0x0 + BaseType: IMAGE_SYM_TYPE_NULL (0x0) + DerivedType: IMAGE_SYM_DTYPE_NULL (0x0) + StorageClass: IMAGE_SYM_CLASS_SECTION (0x68) + NumberOfAuxSymbols: 0x0 +} +ImageSymbol { + Index: 5 + Name: ".idata$5" + Value: 0xC0000040 + Section: IMAGE_SYM_UNDEFINED (0) + Type: 0x0 + BaseType: IMAGE_SYM_TYPE_NULL (0x0) + DerivedType: IMAGE_SYM_DTYPE_NULL (0x0) + StorageClass: IMAGE_SYM_CLASS_SECTION (0x68) + NumberOfAuxSymbols: 0x0 +} +ImageSymbol { + Index: 6 + Name: "__NULL_IMPORT_DESCRIPTOR" + Value: 0x0 + Section: IMAGE_SYM_UNDEFINED (0) + Type: 0x0 + BaseType: IMAGE_SYM_TYPE_NULL (0x0) + DerivedType: IMAGE_SYM_DTYPE_NULL (0x0) + StorageClass: IMAGE_SYM_CLASS_EXTERNAL (0x2) + NumberOfAuxSymbols: 0x0 +} +ImageSymbol { + Index: 7 + Name: "test_x64_NULL_THUNK_DATA" + Value: 0x0 + Section: IMAGE_SYM_UNDEFINED (0) + Type: 0x0 + BaseType: IMAGE_SYM_TYPE_NULL (0x0) + DerivedType: IMAGE_SYM_DTYPE_NULL (0x0) + StorageClass: IMAGE_SYM_CLASS_EXTERNAL (0x2) + NumberOfAuxSymbols: 0x0 +} + +Member: test_x86.dll +Format: COFF import +ImportObjectHeader { + Signature1: 0x0 + Signature2: 0xFFFF + Version: 0 + Machine: IMAGE_FILE_MACHINE_I386 (0x14C) + TimeDateStamp: 1687268223 + SizeOfData: 0x16 + OrdinalOrHint: 0 + ImportType: IMPORT_OBJECT_CODE (0x0) + NameType: IMPORT_OBJECT_NAME_NO_PREFIX (0x2) + Symbol: "_foo_x86" + Dll: "test_x86.dll" +} + +Member: test_x86.dll +Format: COFF +ImageFileHeader { + Machine: IMAGE_FILE_MACHINE_I386 (0x14C) + NumberOfSections: 3 + TimeDateStamp: 1687268223 + PointerToSymbolTable: 0xD6 + NumberOfSymbols: 2 + SizeOfOptionalHeader: 0x0 + Characteristics: 0x100 + IMAGE_FILE_32BIT_MACHINE (0x100) +} +ImageSectionHeader { + Index: 1 + Name: ".debug$S" + VirtualSize: 0x0 + VirtualAddress: 0x0 + SizeOfRawData: 0x42 + PointerToRawData: 0x8C + PointerToRelocations: 0x0 + PointerToLinenumbers: 0x0 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + Characteristics: 0x42100040 + IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) + IMAGE_SCN_MEM_DISCARDABLE (0x2000000) + IMAGE_SCN_MEM_READ (0x40000000) + IMAGE_SCN_ALIGN_1BYTES (0x100000) +} +ImageSectionHeader { + Index: 2 + Name: ".idata$5" + VirtualSize: 0x0 + VirtualAddress: 0x0 + SizeOfRawData: 0x4 + PointerToRawData: 0xCE + PointerToRelocations: 0x0 + PointerToLinenumbers: 0x0 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + Characteristics: 0xC0300040 + IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) + IMAGE_SCN_MEM_READ (0x40000000) + IMAGE_SCN_MEM_WRITE (0x80000000) + IMAGE_SCN_ALIGN_4BYTES (0x300000) +} +ImageSectionHeader { + Index: 3 + Name: ".idata$4" + VirtualSize: 0x0 + VirtualAddress: 0x0 + SizeOfRawData: 0x4 + PointerToRawData: 0xD2 + PointerToRelocations: 0x0 + PointerToLinenumbers: 0x0 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + Characteristics: 0xC0300040 + IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) + IMAGE_SCN_MEM_READ (0x40000000) + IMAGE_SCN_MEM_WRITE (0x80000000) + IMAGE_SCN_ALIGN_4BYTES (0x300000) +} +ImageSymbol { + Index: 0 + Name: "@comp.id" + Value: 0x1017DD9 + Section: IMAGE_SYM_ABSOLUTE (-1) + Type: 0x0 + BaseType: IMAGE_SYM_TYPE_NULL (0x0) + DerivedType: IMAGE_SYM_DTYPE_NULL (0x0) + StorageClass: IMAGE_SYM_CLASS_STATIC (0x3) + NumberOfAuxSymbols: 0x0 +} +ImageSymbol { + Index: 1 + Name: "test_x86_NULL_THUNK_DATA" + Value: 0x0 + Section: ".idata$5" (0x2) + Type: 0x0 + BaseType: IMAGE_SYM_TYPE_NULL (0x0) + DerivedType: IMAGE_SYM_DTYPE_NULL (0x0) + StorageClass: IMAGE_SYM_CLASS_EXTERNAL (0x2) + NumberOfAuxSymbols: 0x0 +} + +Member: test_x86.dll +Format: COFF +ImageFileHeader { + Machine: IMAGE_FILE_MACHINE_I386 (0x14C) + NumberOfSections: 2 + TimeDateStamp: 1687268223 + PointerToSymbolTable: 0xBA + NumberOfSymbols: 2 + SizeOfOptionalHeader: 0x0 + Characteristics: 0x100 + IMAGE_FILE_32BIT_MACHINE (0x100) +} +ImageSectionHeader { + Index: 1 + Name: ".debug$S" + VirtualSize: 0x0 + VirtualAddress: 0x0 + SizeOfRawData: 0x42 + PointerToRawData: 0x64 + PointerToRelocations: 0x0 + PointerToLinenumbers: 0x0 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + Characteristics: 0x42100040 + IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) + IMAGE_SCN_MEM_DISCARDABLE (0x2000000) + IMAGE_SCN_MEM_READ (0x40000000) + IMAGE_SCN_ALIGN_1BYTES (0x100000) +} +ImageSectionHeader { + Index: 2 + Name: ".idata$3" + VirtualSize: 0x0 + VirtualAddress: 0x0 + SizeOfRawData: 0x14 + PointerToRawData: 0xA6 + PointerToRelocations: 0x0 + PointerToLinenumbers: 0x0 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + Characteristics: 0xC0300040 + IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) + IMAGE_SCN_MEM_READ (0x40000000) + IMAGE_SCN_MEM_WRITE (0x80000000) + IMAGE_SCN_ALIGN_4BYTES (0x300000) +} +ImageSymbol { + Index: 0 + Name: "@comp.id" + Value: 0x1017DD9 + Section: IMAGE_SYM_ABSOLUTE (-1) + Type: 0x0 + BaseType: IMAGE_SYM_TYPE_NULL (0x0) + DerivedType: IMAGE_SYM_DTYPE_NULL (0x0) + StorageClass: IMAGE_SYM_CLASS_STATIC (0x3) + NumberOfAuxSymbols: 0x0 +} +ImageSymbol { + Index: 1 + Name: "__NULL_IMPORT_DESCRIPTOR" + Value: 0x0 + Section: ".idata$3" (0x2) + Type: 0x0 + BaseType: IMAGE_SYM_TYPE_NULL (0x0) + DerivedType: IMAGE_SYM_DTYPE_NULL (0x0) + StorageClass: IMAGE_SYM_CLASS_EXTERNAL (0x2) + NumberOfAuxSymbols: 0x0 +} + +Member: test_x86.dll +Format: COFF +ImageFileHeader { + Machine: IMAGE_FILE_MACHINE_I386 (0x14C) + NumberOfSections: 3 + TimeDateStamp: 1687268223 + PointerToSymbolTable: 0x10E + NumberOfSymbols: 8 + SizeOfOptionalHeader: 0x0 + Characteristics: 0x100 + IMAGE_FILE_32BIT_MACHINE (0x100) +} +ImageSectionHeader { + Index: 1 + Name: ".debug$S" + VirtualSize: 0x0 + VirtualAddress: 0x0 + SizeOfRawData: 0x42 + PointerToRawData: 0x8C + PointerToRelocations: 0x0 + PointerToLinenumbers: 0x0 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + Characteristics: 0x42100040 + IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) + IMAGE_SCN_MEM_DISCARDABLE (0x2000000) + IMAGE_SCN_MEM_READ (0x40000000) + IMAGE_SCN_ALIGN_1BYTES (0x100000) +} +ImageSectionHeader { + Index: 2 + Name: ".idata$2" + VirtualSize: 0x0 + VirtualAddress: 0x0 + SizeOfRawData: 0x14 + PointerToRawData: 0xCE + PointerToRelocations: 0xE2 + PointerToLinenumbers: 0x0 + NumberOfRelocations: 3 + NumberOfLinenumbers: 0 + Characteristics: 0xC0300040 + IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) + IMAGE_SCN_MEM_READ (0x40000000) + IMAGE_SCN_MEM_WRITE (0x80000000) + IMAGE_SCN_ALIGN_4BYTES (0x300000) + ImageRelocation { + VirtualAddress: 0xC + Symbol: ".idata$6" (0x3) + Type: IMAGE_REL_I386_DIR32NB (0x7) + } + ImageRelocation { + VirtualAddress: 0x0 + Symbol: ".idata$4" (0x4) + Type: IMAGE_REL_I386_DIR32NB (0x7) + } + ImageRelocation { + VirtualAddress: 0x10 + Symbol: ".idata$5" (0x5) + Type: IMAGE_REL_I386_DIR32NB (0x7) + } +} +ImageSectionHeader { + Index: 3 + Name: ".idata$6" + VirtualSize: 0x0 + VirtualAddress: 0x0 + SizeOfRawData: 0xE + PointerToRawData: 0x100 + PointerToRelocations: 0xE2 + PointerToLinenumbers: 0x0 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + Characteristics: 0xC0200040 + IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) + IMAGE_SCN_MEM_READ (0x40000000) + IMAGE_SCN_MEM_WRITE (0x80000000) + IMAGE_SCN_ALIGN_2BYTES (0x200000) +} +ImageSymbol { + Index: 0 + Name: "@comp.id" + Value: 0x1017DD9 + Section: IMAGE_SYM_ABSOLUTE (-1) + Type: 0x0 + BaseType: IMAGE_SYM_TYPE_NULL (0x0) + DerivedType: IMAGE_SYM_DTYPE_NULL (0x0) + StorageClass: IMAGE_SYM_CLASS_STATIC (0x3) + NumberOfAuxSymbols: 0x0 +} +ImageSymbol { + Index: 1 + Name: "__IMPORT_DESCRIPTOR_test_x86" + Value: 0x0 + Section: ".idata$2" (0x2) + Type: 0x0 + BaseType: IMAGE_SYM_TYPE_NULL (0x0) + DerivedType: IMAGE_SYM_DTYPE_NULL (0x0) + StorageClass: IMAGE_SYM_CLASS_EXTERNAL (0x2) + NumberOfAuxSymbols: 0x0 +} +ImageSymbol { + Index: 2 + Name: ".idata$2" + Value: 0xC0000040 + Section: ".idata$2" (0x2) + Type: 0x0 + BaseType: IMAGE_SYM_TYPE_NULL (0x0) + DerivedType: IMAGE_SYM_DTYPE_NULL (0x0) + StorageClass: IMAGE_SYM_CLASS_SECTION (0x68) + NumberOfAuxSymbols: 0x0 +} +ImageSymbol { + Index: 3 + Name: ".idata$6" + Value: 0x0 + Section: ".idata$6" (0x3) + Type: 0x0 + BaseType: IMAGE_SYM_TYPE_NULL (0x0) + DerivedType: IMAGE_SYM_DTYPE_NULL (0x0) + StorageClass: IMAGE_SYM_CLASS_STATIC (0x3) + NumberOfAuxSymbols: 0x0 +} +ImageSymbol { + Index: 4 + Name: ".idata$4" + Value: 0xC0000040 + Section: IMAGE_SYM_UNDEFINED (0) + Type: 0x0 + BaseType: IMAGE_SYM_TYPE_NULL (0x0) + DerivedType: IMAGE_SYM_DTYPE_NULL (0x0) + StorageClass: IMAGE_SYM_CLASS_SECTION (0x68) + NumberOfAuxSymbols: 0x0 +} +ImageSymbol { + Index: 5 + Name: ".idata$5" + Value: 0xC0000040 + Section: IMAGE_SYM_UNDEFINED (0) + Type: 0x0 + BaseType: IMAGE_SYM_TYPE_NULL (0x0) + DerivedType: IMAGE_SYM_DTYPE_NULL (0x0) + StorageClass: IMAGE_SYM_CLASS_SECTION (0x68) + NumberOfAuxSymbols: 0x0 +} +ImageSymbol { + Index: 6 + Name: "__NULL_IMPORT_DESCRIPTOR" + Value: 0x0 + Section: IMAGE_SYM_UNDEFINED (0) + Type: 0x0 + BaseType: IMAGE_SYM_TYPE_NULL (0x0) + DerivedType: IMAGE_SYM_DTYPE_NULL (0x0) + StorageClass: IMAGE_SYM_CLASS_EXTERNAL (0x2) + NumberOfAuxSymbols: 0x0 +} +ImageSymbol { + Index: 7 + Name: "test_x86_NULL_THUNK_DATA" + Value: 0x0 + Section: IMAGE_SYM_UNDEFINED (0) + Type: 0x0 + BaseType: IMAGE_SYM_TYPE_NULL (0x0) + DerivedType: IMAGE_SYM_DTYPE_NULL (0x0) + StorageClass: IMAGE_SYM_CLASS_EXTERNAL (0x2) + NumberOfAuxSymbols: 0x0 +} + +Member: test_arm64ec.dll +Format: COFF import +ImportObjectHeader { + Signature1: 0x0 + Signature2: 0xFFFF + Version: 0 + Machine: 0xA641 + TimeDateStamp: 1687268223 + SizeOfData: 0x2A + OrdinalOrHint: 0 + ImportType: IMPORT_OBJECT_CODE (0x0) + NameType: IMPORT_OBJECT_NAME_EXPORTAS (0x4) + Symbol: "#foo_arm64ec" + Dll: "test_arm64ec.dll" + Export: "foo_arm64ec" +} + +Member: test_arm64ec.dll +Format: COFF +ImageFileHeader { + Machine: IMAGE_FILE_MACHINE_ARM64 (0xAA64) + NumberOfSections: 3 + TimeDateStamp: 1687268223 + PointerToSymbolTable: 0xE2 + NumberOfSymbols: 2 + SizeOfOptionalHeader: 0x0 + Characteristics: 0x0 +} +ImageSectionHeader { + Index: 1 + Name: ".debug$S" + VirtualSize: 0x0 + VirtualAddress: 0x0 + SizeOfRawData: 0x46 + PointerToRawData: 0x8C + PointerToRelocations: 0x0 + PointerToLinenumbers: 0x0 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + Characteristics: 0x42100040 + IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) + IMAGE_SCN_MEM_DISCARDABLE (0x2000000) + IMAGE_SCN_MEM_READ (0x40000000) + IMAGE_SCN_ALIGN_1BYTES (0x100000) +} +ImageSectionHeader { + Index: 2 + Name: ".idata$5" + VirtualSize: 0x0 + VirtualAddress: 0x0 + SizeOfRawData: 0x8 + PointerToRawData: 0xD2 + PointerToRelocations: 0x0 + PointerToLinenumbers: 0x0 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + Characteristics: 0xC0400040 + IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) + IMAGE_SCN_MEM_READ (0x40000000) + IMAGE_SCN_MEM_WRITE (0x80000000) + IMAGE_SCN_ALIGN_8BYTES (0x400000) +} +ImageSectionHeader { + Index: 3 + Name: ".idata$4" + VirtualSize: 0x0 + VirtualAddress: 0x0 + SizeOfRawData: 0x8 + PointerToRawData: 0xDA + PointerToRelocations: 0x0 + PointerToLinenumbers: 0x0 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + Characteristics: 0xC0400040 + IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) + IMAGE_SCN_MEM_READ (0x40000000) + IMAGE_SCN_MEM_WRITE (0x80000000) + IMAGE_SCN_ALIGN_8BYTES (0x400000) +} +ImageSymbol { + Index: 0 + Name: "@comp.id" + Value: 0x1017DD9 + Section: IMAGE_SYM_ABSOLUTE (-1) + Type: 0x0 + BaseType: IMAGE_SYM_TYPE_NULL (0x0) + DerivedType: IMAGE_SYM_DTYPE_NULL (0x0) + StorageClass: IMAGE_SYM_CLASS_STATIC (0x3) + NumberOfAuxSymbols: 0x0 +} +ImageSymbol { + Index: 1 + Name: "test_arm64ec_NULL_THUNK_DATA" + Value: 0x0 + Section: ".idata$5" (0x2) + Type: 0x0 + BaseType: IMAGE_SYM_TYPE_NULL (0x0) + DerivedType: IMAGE_SYM_DTYPE_NULL (0x0) + StorageClass: IMAGE_SYM_CLASS_EXTERNAL (0x2) + NumberOfAuxSymbols: 0x0 +} + +Member: test_arm64ec.dll +Format: COFF +ImageFileHeader { + Machine: IMAGE_FILE_MACHINE_ARM64 (0xAA64) + NumberOfSections: 2 + TimeDateStamp: 1687268223 + PointerToSymbolTable: 0xBE + NumberOfSymbols: 2 + SizeOfOptionalHeader: 0x0 + Characteristics: 0x0 +} +ImageSectionHeader { + Index: 1 + Name: ".debug$S" + VirtualSize: 0x0 + VirtualAddress: 0x0 + SizeOfRawData: 0x46 + PointerToRawData: 0x64 + PointerToRelocations: 0x0 + PointerToLinenumbers: 0x0 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + Characteristics: 0x42100040 + IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) + IMAGE_SCN_MEM_DISCARDABLE (0x2000000) + IMAGE_SCN_MEM_READ (0x40000000) + IMAGE_SCN_ALIGN_1BYTES (0x100000) +} +ImageSectionHeader { + Index: 2 + Name: ".idata$3" + VirtualSize: 0x0 + VirtualAddress: 0x0 + SizeOfRawData: 0x14 + PointerToRawData: 0xAA + PointerToRelocations: 0x0 + PointerToLinenumbers: 0x0 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + Characteristics: 0xC0300040 + IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) + IMAGE_SCN_MEM_READ (0x40000000) + IMAGE_SCN_MEM_WRITE (0x80000000) + IMAGE_SCN_ALIGN_4BYTES (0x300000) +} +ImageSymbol { + Index: 0 + Name: "@comp.id" + Value: 0x1017DD9 + Section: IMAGE_SYM_ABSOLUTE (-1) + Type: 0x0 + BaseType: IMAGE_SYM_TYPE_NULL (0x0) + DerivedType: IMAGE_SYM_DTYPE_NULL (0x0) + StorageClass: IMAGE_SYM_CLASS_STATIC (0x3) + NumberOfAuxSymbols: 0x0 +} +ImageSymbol { + Index: 1 + Name: "__NULL_IMPORT_DESCRIPTOR" + Value: 0x0 + Section: ".idata$3" (0x2) + Type: 0x0 + BaseType: IMAGE_SYM_TYPE_NULL (0x0) + DerivedType: IMAGE_SYM_DTYPE_NULL (0x0) + StorageClass: IMAGE_SYM_CLASS_EXTERNAL (0x2) + NumberOfAuxSymbols: 0x0 +} + +Member: test_arm64ec.dll +Format: COFF +ImageFileHeader { + Machine: IMAGE_FILE_MACHINE_ARM64 (0xAA64) + NumberOfSections: 3 + TimeDateStamp: 1687268223 + PointerToSymbolTable: 0x116 + NumberOfSymbols: 8 + SizeOfOptionalHeader: 0x0 + Characteristics: 0x0 +} +ImageSectionHeader { + Index: 1 + Name: ".debug$S" + VirtualSize: 0x0 + VirtualAddress: 0x0 + SizeOfRawData: 0x46 + PointerToRawData: 0x8C + PointerToRelocations: 0x0 + PointerToLinenumbers: 0x0 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + Characteristics: 0x42100040 + IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) + IMAGE_SCN_MEM_DISCARDABLE (0x2000000) + IMAGE_SCN_MEM_READ (0x40000000) + IMAGE_SCN_ALIGN_1BYTES (0x100000) +} +ImageSectionHeader { + Index: 2 + Name: ".idata$2" + VirtualSize: 0x0 + VirtualAddress: 0x0 + SizeOfRawData: 0x14 + PointerToRawData: 0xD2 + PointerToRelocations: 0xE6 + PointerToLinenumbers: 0x0 + NumberOfRelocations: 3 + NumberOfLinenumbers: 0 + Characteristics: 0xC0300040 + IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) + IMAGE_SCN_MEM_READ (0x40000000) + IMAGE_SCN_MEM_WRITE (0x80000000) + IMAGE_SCN_ALIGN_4BYTES (0x300000) + ImageRelocation { + VirtualAddress: 0xC + Symbol: ".idata$6" (0x3) + Type: IMAGE_REL_ARM64_ADDR32NB (0x2) + } + ImageRelocation { + VirtualAddress: 0x0 + Symbol: ".idata$4" (0x4) + Type: IMAGE_REL_ARM64_ADDR32NB (0x2) + } + ImageRelocation { + VirtualAddress: 0x10 + Symbol: ".idata$5" (0x5) + Type: IMAGE_REL_ARM64_ADDR32NB (0x2) + } +} +ImageSectionHeader { + Index: 3 + Name: ".idata$6" + VirtualSize: 0x0 + VirtualAddress: 0x0 + SizeOfRawData: 0x12 + PointerToRawData: 0x104 + PointerToRelocations: 0xE6 + PointerToLinenumbers: 0x0 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + Characteristics: 0xC0200040 + IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) + IMAGE_SCN_MEM_READ (0x40000000) + IMAGE_SCN_MEM_WRITE (0x80000000) + IMAGE_SCN_ALIGN_2BYTES (0x200000) +} +ImageSymbol { + Index: 0 + Name: "@comp.id" + Value: 0x1017DD9 + Section: IMAGE_SYM_ABSOLUTE (-1) + Type: 0x0 + BaseType: IMAGE_SYM_TYPE_NULL (0x0) + DerivedType: IMAGE_SYM_DTYPE_NULL (0x0) + StorageClass: IMAGE_SYM_CLASS_STATIC (0x3) + NumberOfAuxSymbols: 0x0 +} +ImageSymbol { + Index: 1 + Name: "__IMPORT_DESCRIPTOR_test_arm64ec" + Value: 0x0 + Section: ".idata$2" (0x2) + Type: 0x0 + BaseType: IMAGE_SYM_TYPE_NULL (0x0) + DerivedType: IMAGE_SYM_DTYPE_NULL (0x0) + StorageClass: IMAGE_SYM_CLASS_EXTERNAL (0x2) + NumberOfAuxSymbols: 0x0 +} +ImageSymbol { + Index: 2 + Name: ".idata$2" + Value: 0xC0000040 + Section: ".idata$2" (0x2) + Type: 0x0 + BaseType: IMAGE_SYM_TYPE_NULL (0x0) + DerivedType: IMAGE_SYM_DTYPE_NULL (0x0) + StorageClass: IMAGE_SYM_CLASS_SECTION (0x68) + NumberOfAuxSymbols: 0x0 +} +ImageSymbol { + Index: 3 + Name: ".idata$6" + Value: 0x0 + Section: ".idata$6" (0x3) + Type: 0x0 + BaseType: IMAGE_SYM_TYPE_NULL (0x0) + DerivedType: IMAGE_SYM_DTYPE_NULL (0x0) + StorageClass: IMAGE_SYM_CLASS_STATIC (0x3) + NumberOfAuxSymbols: 0x0 +} +ImageSymbol { + Index: 4 + Name: ".idata$4" + Value: 0xC0000040 + Section: IMAGE_SYM_UNDEFINED (0) + Type: 0x0 + BaseType: IMAGE_SYM_TYPE_NULL (0x0) + DerivedType: IMAGE_SYM_DTYPE_NULL (0x0) + StorageClass: IMAGE_SYM_CLASS_SECTION (0x68) + NumberOfAuxSymbols: 0x0 +} +ImageSymbol { + Index: 5 + Name: ".idata$5" + Value: 0xC0000040 + Section: IMAGE_SYM_UNDEFINED (0) + Type: 0x0 + BaseType: IMAGE_SYM_TYPE_NULL (0x0) + DerivedType: IMAGE_SYM_DTYPE_NULL (0x0) + StorageClass: IMAGE_SYM_CLASS_SECTION (0x68) + NumberOfAuxSymbols: 0x0 +} +ImageSymbol { + Index: 6 + Name: "__NULL_IMPORT_DESCRIPTOR" + Value: 0x0 + Section: IMAGE_SYM_UNDEFINED (0) + Type: 0x0 + BaseType: IMAGE_SYM_TYPE_NULL (0x0) + DerivedType: IMAGE_SYM_DTYPE_NULL (0x0) + StorageClass: IMAGE_SYM_CLASS_EXTERNAL (0x2) + NumberOfAuxSymbols: 0x0 +} +ImageSymbol { + Index: 7 + Name: "test_arm64ec_NULL_THUNK_DATA" + Value: 0x0 + Section: IMAGE_SYM_UNDEFINED (0) + Type: 0x0 + BaseType: IMAGE_SYM_TYPE_NULL (0x0) + DerivedType: IMAGE_SYM_DTYPE_NULL (0x0) + StorageClass: IMAGE_SYM_CLASS_EXTERNAL (0x2) + NumberOfAuxSymbols: 0x0 +} diff --git a/src/pe.rs b/src/pe.rs index bac101ea..f274d227 100644 --- a/src/pe.rs +++ b/src/pe.rs @@ -2873,10 +2873,14 @@ pub struct ImportObjectHeader { pub name_type: U16, } +pub const IMPORT_OBJECT_TYPE_MASK: u16 = 0b11; +pub const IMPORT_OBJECT_TYPE_SHIFT: u16 = 0; pub const IMPORT_OBJECT_CODE: u16 = 0; pub const IMPORT_OBJECT_DATA: u16 = 1; pub const IMPORT_OBJECT_CONST: u16 = 2; +pub const IMPORT_OBJECT_NAME_MASK: u16 = 0b111; +pub const IMPORT_OBJECT_NAME_SHIFT: u16 = 2; /// Import by ordinal pub const IMPORT_OBJECT_ORDINAL: u16 = 0; /// Import name == public symbol name. diff --git a/src/read/coff/import.rs b/src/read/coff/import.rs index a88f38da..d635e759 100644 --- a/src/read/coff/import.rs +++ b/src/read/coff/import.rs @@ -7,31 +7,24 @@ use crate::read::{Architecture, Error, ReadError, ReadRef, Result}; use crate::{pe, ByteString, Bytes, LittleEndian as LE}; /// A Windows short form description of a symbol to import. -/// Used in Windows import libraries. This is not an object file. +/// +/// Used in Windows import libraries to provide a mapping from +/// a symbol name to a DLL export. This is not an object file. #[derive(Debug, Clone)] -pub struct CoffImportFile<'data> { +pub struct ImportFile<'data> { header: &'data pe::ImportObjectHeader, + kind: ImportType, dll: ByteString<'data>, symbol: ByteString<'data>, - kind: ImportType, import: Option>, } -impl<'data> CoffImportFile<'data> { + +impl<'data> ImportFile<'data> { /// Parse it. pub fn parse>(data: R) -> Result { let mut offset = 0; let header = pe::ImportObjectHeader::parse(data, &mut offset)?; - let data_size = header.size_of_data.get(LE); - let mut strings = Bytes( - data.read_bytes(&mut offset, data_size as u64) - .read_error("Invalid COFF import library data size")?, - ); - let symbol = strings - .read_string() - .read_error("Could not read COFF import library symbol name")?; - let dll = strings - .read_string() - .read_error("Could not read COFF import library DLL name")?; + let data = header.parse_data(data, &mut offset)?; // Unmangles a name by removing a `?`, `@` or `_` prefix. fn strip_prefix(s: &[u8]) -> &[u8] { @@ -42,29 +35,26 @@ impl<'data> CoffImportFile<'data> { } Ok(Self { header, - dll: ByteString(dll), - symbol: ByteString(symbol), - kind: match header.name_type.get(LE) & 0b11 { + dll: data.dll, + symbol: data.symbol, + kind: match header.import_type() { pe::IMPORT_OBJECT_CODE => ImportType::Code, pe::IMPORT_OBJECT_DATA => ImportType::Data, pe::IMPORT_OBJECT_CONST => ImportType::Const, - 0b11 => return Err(Error("Invalid COFF import library import type")), - _ => unreachable!("COFF import library ImportType must be a two bit number"), + _ => return Err(Error("Invalid COFF import library import type")), }, - import: match (header.name_type.get(LE) >> 2) & 0b111 { + import: match header.name_type() { pe::IMPORT_OBJECT_ORDINAL => None, - pe::IMPORT_OBJECT_NAME => Some(symbol), - pe::IMPORT_OBJECT_NAME_NO_PREFIX => Some(strip_prefix(symbol)), - pe::IMPORT_OBJECT_NAME_UNDECORATE => { - Some(strip_prefix(symbol).split(|&b| b == b'@').next().unwrap()) - } - pe::IMPORT_OBJECT_NAME_EXPORTAS => Some( - strings - .read_string() - .read_error("Could not read COFF import library export name")?, + pe::IMPORT_OBJECT_NAME => Some(data.symbol()), + pe::IMPORT_OBJECT_NAME_NO_PREFIX => Some(strip_prefix(data.symbol())), + pe::IMPORT_OBJECT_NAME_UNDECORATE => Some( + strip_prefix(data.symbol()) + .split(|&b| b == b'@') + .next() + .unwrap(), ), - 5..=7 => return Err(Error("Unknown COFF import library name type")), - _ => unreachable!("COFF import library name type must be a three bit number"), + pe::IMPORT_OBJECT_NAME_EXPORTAS => data.export(), + _ => return Err(Error("Unknown COFF import library name type")), } .map(ByteString), }) @@ -81,6 +71,11 @@ impl<'data> CoffImportFile<'data> { } } + /// The public symbol name. + pub fn symbol(&self) -> &'data [u8] { + self.symbol.0 + } + /// The name of the DLL to import the symbol from. pub fn dll(&self) -> &'data [u8] { self.dll.0 @@ -98,14 +93,9 @@ impl<'data> CoffImportFile<'data> { pub fn import_type(&self) -> ImportType { self.kind } - - /// The public symbol name - pub fn symbol(&self) -> &'data [u8] { - self.symbol.0 - } } -/// The name or ordinal to import. +/// The name or ordinal to import from a DLL. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ImportName<'data> { /// Import by ordinal. Ordinarily this is a 1-based index. @@ -114,12 +104,12 @@ pub enum ImportName<'data> { Name(&'data [u8]), } -/// The kind of import. +/// The kind of import symbol. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum ImportType { - /// Executable code + /// An executable code symbol. Code, - /// Some data + /// A data symbol. Data, /// A constant value. Const, @@ -132,7 +122,7 @@ impl pe::ImportObjectHeader { /// Directly following this header will be the string data. pub fn parse<'data, R: ReadRef<'data>>(data: R, offset: &mut u64) -> Result<&'data Self> { let header = data - .read::(offset) + .read::(offset) .read_error("Invalid COFF import library header size")?; if header.sig1.get(LE) != 0 || header.sig2.get(LE) != pe::IMPORT_OBJECT_HDR_SIG2 { Err(Error("Invalid COFF import library header")) @@ -142,4 +132,78 @@ impl pe::ImportObjectHeader { Ok(header) } } + + /// Parse the data following the header. + pub fn parse_data<'data, R: ReadRef<'data>>( + &self, + data: R, + offset: &mut u64, + ) -> Result> { + let mut data = Bytes( + data.read_bytes(offset, u64::from(self.size_of_data.get(LE))) + .read_error("Invalid COFF import library data size")?, + ); + let symbol = data + .read_string() + .map(ByteString) + .read_error("Could not read COFF import library symbol name")?; + let dll = data + .read_string() + .map(ByteString) + .read_error("Could not read COFF import library DLL name")?; + let export = if self.name_type() == pe::IMPORT_OBJECT_NAME_EXPORTAS { + data.read_string() + .map(ByteString) + .map(Some) + .read_error("Could not read COFF import library export name")? + } else { + None + }; + Ok(ImportObjectData { + symbol, + dll, + export, + }) + } + + /// The type of import. + /// + /// This is one of the `IMPORT_OBJECT_*` constants. + pub fn import_type(&self) -> u16 { + self.name_type.get(LE) & pe::IMPORT_OBJECT_TYPE_MASK + } + + /// The type of import name. + /// + /// This is one of the `IMPORT_OBJECT_*` constants. + pub fn name_type(&self) -> u16 { + (self.name_type.get(LE) >> pe::IMPORT_OBJECT_NAME_SHIFT) & pe::IMPORT_OBJECT_NAME_MASK + } +} + +/// The data following `ImportObjectHeader`. +#[derive(Debug, Clone)] +pub struct ImportObjectData<'data> { + symbol: ByteString<'data>, + dll: ByteString<'data>, + export: Option>, +} + +impl<'data> ImportObjectData<'data> { + /// The public symbol name. + pub fn symbol(&self) -> &'data [u8] { + self.symbol.0 + } + + /// The name of the DLL to import the symbol from. + pub fn dll(&self) -> &'data [u8] { + self.dll.0 + } + + /// The name exported from the DLL. + /// + /// This is only set if the name is not derived from the symbol name. + pub fn export(&self) -> Option<&'data [u8]> { + self.export.map(|export| export.0) + } } diff --git a/src/read/mod.rs b/src/read/mod.rs index 092536d1..8230d43b 100644 --- a/src/read/mod.rs +++ b/src/read/mod.rs @@ -158,7 +158,7 @@ pub enum FileKind { CoffBig, /// A Windows short import file. #[cfg(feature = "coff")] - CoffImportFile, + CoffImport, /// A dyld cache file containing Mach-O images. #[cfg(feature = "macho")] DyldCache, @@ -235,6 +235,7 @@ impl FileKind { [0x00, b'a', b's', b'm', ..] => FileKind::Wasm, #[cfg(feature = "pe")] [b'M', b'Z', ..] if offset == 0 => { + // offset == 0 restriction is because optional_header_magic only looks at offset 0 match pe::optional_header_magic(data) { Ok(crate::pe::IMAGE_NT_OPTIONAL_HDR32_MAGIC) => { FileKind::Pe32 @@ -256,18 +257,19 @@ impl FileKind { // COFF x86-64 | [0x64, 0x86, ..] => FileKind::Coff, #[cfg(feature = "coff")] + [0x00, 0x00, 0xff, 0xff, 0x00, 0x00, ..] => FileKind::CoffImport, + #[cfg(feature = "coff")] [0x00, 0x00, 0xff, 0xff, 0x02, 0x00, ..] if offset == 0 => { + // offset == 0 restriction is because anon_object_class_id only looks at offset 0 match coff::anon_object_class_id(data) { Ok(crate::pe::ANON_OBJECT_HEADER_BIGOBJ_CLASS_ID) => FileKind::CoffBig, _ => return Err(Error("Unknown anon object file")), } } #[cfg(feature = "xcoff")] - [0x01, 0xDF, ..] => FileKind::Xcoff32, + [0x01, 0xdf, ..] => FileKind::Xcoff32, #[cfg(feature = "xcoff")] - [0x01, 0xF7, ..] => FileKind::Xcoff64, - #[cfg(feature = "coff")] - [0, 0, 0xFF, 0xFF, ..] => FileKind::CoffImportFile, + [0x01, 0xf7, ..] => FileKind::Xcoff64, _ => return Err(Error("Unknown file magic")), }; Ok(kind)