///|
pub fn PEImage::load_config(self : Self) -> LoadConfigInfo? raise PeError {
let directory = match self.directory(10) {
Some(directory) if directory.virtual_address != 0UL && directory.size > 0 =>
directory
_ => return None
}
let offset = self.rva_to_offset(directory.virtual_address)
let mut available = directory.size
let file_available = self.data.length() - offset
if available > file_available {
available = file_available
}
if available < 4 {
raise PeError(offset, "load-config directory is truncated")
}
let declared_size = checked_int(
read_u32(self.data, offset),
offset,
"load-config structure size",
)
if declared_size >= 4 && declared_size < available {
available = declared_size
}
let timestamp = read_u32_field(self.data, offset, available, 4)
let global_flags_clear = read_u32_field(self.data, offset, available, 12)
let global_flags_set = read_u32_field(self.data, offset, available, 16)
let (
cookie_offset,
se_table_offset,
se_count_offset,
guard_check_offset,
guard_dispatch_offset,
guard_table_offset,
guard_count_offset,
guard_flags_offset,
) = if self.is_64_bit() {
(88, 96, 104, 112, 120, 128, 136, 144)
} else {
(60, 64, 68, 72, 76, 80, 84, 88)
}
Some({
structure_size: declared_size,
timestamp: match timestamp {
Some(value) => value
None => 0
},
global_flags_clear,
global_flags_set,
security_cookie: read_pointer_field(
self.data,
offset,
available,
cookie_offset,
self.is_64_bit(),
),
se_handler_table: read_pointer_field(
self.data,
offset,
available,
se_table_offset,
self.is_64_bit(),
),
se_handler_count: read_pointer_count_field(
self.data,
offset,
available,
se_count_offset,
self.is_64_bit(),
),
guard_cf_check_pointer: read_pointer_field(
self.data,
offset,
available,
guard_check_offset,
self.is_64_bit(),
),
guard_cf_dispatch_pointer: read_pointer_field(
self.data,
offset,
available,
guard_dispatch_offset,
self.is_64_bit(),
),
guard_cf_function_table: read_pointer_field(
self.data,
offset,
available,
guard_table_offset,
self.is_64_bit(),
),
guard_cf_function_count: read_pointer_count_field(
self.data,
offset,
available,
guard_count_offset,
self.is_64_bit(),
),
guard_flags: read_u32_field(
self.data,
offset,
available,
guard_flags_offset,
),
})
}
///|
fn read_u32_field(
data : Bytes,
start : Int32,
available : Int32,
relative_offset : Int32,
) -> Int32? {
if relative_offset + 4 > available {
return None
}
let result = Some(
checked_int(
read_u32(data, start + relative_offset),
start + relative_offset,
"load-config field",
),
) catch {
PeError(_, _) => None
}
result
}
///|
fn read_pointer_field(
data : Bytes,
start : Int32,
available : Int32,
relative_offset : Int32,
is_64_bit : Bool,
) -> UInt64? {
let width = if is_64_bit { 8 } else { 4 }
if relative_offset + width > available {
return None
}
try {
if is_64_bit {
Some(read_u64(data, start + relative_offset))
} else {
Some(read_u32(data, start + relative_offset))
}
} catch {
PeError(_, _) => None
}
}
///|
fn read_pointer_count_field(
data : Bytes,
start : Int32,
available : Int32,
relative_offset : Int32,
is_64_bit : Bool,
) -> Int32? {
let value = read_pointer_field(
data, start, available, relative_offset, is_64_bit,
)
match value {
Some(count) if count <= 0x7fffffffUL => Some(count.to_int())
_ => None
}
}