///|
/// The Import Address Table (data-directory slot 12).
///
/// The lookup table and the IAT normally start with the same hint/name RVAs,
/// but they serve different purposes: the loader overwrites IAT slots with
/// resolved function addresses. A dependency checker needs the slot location
/// and its on-disk value, while a security tool may need to distinguish an
/// unbound image from one carrying pre-bound virtual addresses.
///|
pub(all) struct IatEntry {
library : String
delayed : Bool
slot_rva : Int32
// Raw slot bits as stored on disk. For PE32+ this can have bit 63 set.
raw_value : Int64
symbol : ImportEntry
} derive(@debug.Debug)
///|
/// Read every current IAT slot in descriptor order.
///
/// Static imports use data-directory slot 12, but delay-loaded libraries carry
/// independent IATs inside slot 13. Both are returned and distinguished by
/// `delayed`; reading only the normal IAT silently misses the latter.
pub fn Pe::iat(self : Pe) -> Array[IatEntry] raise PeError {
let out : Array[IatEntry] = []
let wide = self.bits() == 64
for descriptor in self.import_descriptors() {
let library = self.string_at_rva(descriptor.name_rva, 4096)
let lookup_rva = if descriptor.original_thunk != 0 {
descriptor.original_thunk
} else {
descriptor.first_thunk
}
let symbols = self.read_thunks(lookup_rva)
let slots = match self.reader_at_rva(descriptor.first_thunk) {
Some(reader) => reader
None =>
raise PeError::Malformed(
"IAT RVA " +
hex(descriptor.first_thunk) +
" is not backed by file bytes",
0,
)
}
let mut index = 0
for symbol in symbols {
// The ordinal bit makes a PE32 slot look like a value above 2 GiB, so this
// deliberate bit-pattern read must bypass the address-range guard.
let raw_value = if wide {
slots.u64()
} else {
slots.u32_raw().to_int64() & 0xFFFFFFFFL
}
out.push({
library,
delayed: false,
slot_rva: descriptor.first_thunk + index * (if wide { 8 } else { 4 }),
raw_value,
symbol,
})
index = index + 1
}
}
for library in self.delay_imports() {
let iat_rva = match library.iat_rva {
Some(rva) => rva
None =>
raise PeError::Malformed(
"delay-import descriptor for " + library.name + " has no IAT RVA",
0,
)
}
let slots = match self.reader_at_rva(iat_rva) {
Some(reader) => reader
None =>
raise PeError::Malformed(
"delay-IAT RVA " + hex(iat_rva) + " is not backed by file bytes",
0,
)
}
let mut index = 0
for symbol in library.entries {
let raw_value = if wide {
slots.u64()
} else {
slots.u32_raw().to_int64() & 0xFFFFFFFFL
}
out.push({
library: library.name,
delayed: true,
slot_rva: iat_rva + index * (if wide { 8 } else { 4 }),
raw_value,
symbol,
})
index = index + 1
}
}
out
}