def parse_delay_import_table(dd, sections, optional_header, data, offsets): if not dd or "delay_import_table" not in dd: return None, offsets base_rva, table_len = dd["delay_import_table"]["virtual_address"], dd["delay_import_table"]["length"] if not base_rva or not table_len: return None, offsets base = rva_to_offset(base_rva, sections) if not base or base + table_len > len(data): return None, offsets vals = {} entry_len = struct.calcsize(delay_import_table_str) current_offset = base while current_offset - base < table_len and current_offset + entry_len < len(data): val_data = struct.unpack(delay_import_table_str, data[current_offset:current_offset+entry_len]) check = 0 for v in val_data: if v != 0: check = 1; break if not check: break import_entry = {} for offset, elem in enumerate(delay_import_table_spec): import_entry[elem[0]] = val_data[offset] name_rva = import_entry["name_rva"] if not name_rva: continue name, offsets = rva_string_lookup(name_rva, sections, optional_header["image_base"], data, offsets) lookup_table_rva = import_entry["delay_import_name_table"] lookup_table_offset = rva_to_offset(lookup_table_rva, sections) function_names, offsets = parse_import_lookup_table(lookup_table_offset, lookup_table_rva, optional_header, sections, data, offsets) address_table_rva = import_entry["delay_import_address_table"] address_table_offset = rva_to_offset(address_table_rva, sections) #Delay imports only have addresses in the file at the lookup table. The address table is populated on demand in the image. addresses, offsets = parse_import_address_table(lookup_table_offset, address_table_rva, optional_header, sections, data, offsets) import_entry["function_names"] = function_names import_entry["addresses"] = addresses if name: vals[name] = import_entry else: vals[current_offset] = import_entry offsets = build_delay_offset_strings(import_entry, current_offset, name, offsets) current_offset += entry_len return vals, offsets
def rva_string_lookup(rva, sections, image_base, data, offsets): if not rva: return None, offsets f_offset = rva_to_offset(rva, sections, image_base) if not f_offset: return None, offsets string_end = data[f_offset:].find("\x00") offsets[f_offset] = [{"len":string_end, "string":"Import Name"}] return data[f_offset:f_offset+string_end], offsets
def parse_base_relocations(dd, sections, data, offsets): if not dd or "base_relocation_table" not in dd: return None, offsets base, table_len = dd["base_relocation_table"]["virtual_address"], dd["base_relocation_table"]["length"] if base == 0 and table_len == 0: return None, offsets entry_len = struct.calcsize(base_relocation_block_str) base = rva_to_offset(base, sections) if not base: return None, offsets offset = base relocations = [] while offset - base < table_len and offset+entry_len < len(data): val_data = struct.unpack(base_relocation_block_str, data[offset:offset+entry_len]) block = {} for n, elem in enumerate(base_relocation_block_spec): block[elem[0]] = val_data[n] o = offset for elem in base_relocation_block_spec: length = elem[1] s = "%s: %s (%s)"%(elem[0], block[elem[0]], elem[2]) offsets[o].append({"len":length, "string":s}) o += length rels = [] s = block["block_size"] offset += entry_len s -= entry_len num_entries = s / struct.calcsize(base_relocation_str) rlen = struct.calcsize(base_relocation_str) for i in xrange(num_entries): if offset + rlen >= len(data): break type_offset = struct.unpack(base_relocation_str, data[offset:offset+rlen]) type_val = (type_offset[0] & 0b1111000000000000) >> 12 offset_val = type_offset[0] & 0b0000111111111111 rels.append((type_val, offset_val)) offsets[offset].append({"len":rlen, "string":"Type: %s, Offset: %s"%(type_val, offset_val)}) offset += rlen block["relocations"] = rels relocations.append(block) return relocations, offsets
def parse_exports_directory_table(dd, sections, optional_header, data, offsets): if not dd or "export_table" not in dd: return None, offsets base_rva, table_len = dd["export_table"]["virtual_address"], dd["export_table"]["length"] if base_rva == 0 and table_len == 0: return None, offsets str_len = struct.calcsize(exports_directory_table_str) base = rva_to_offset(base_rva, sections) if not base or base + str_len >= len(data): return None, offsets vals = {} val_data = struct.unpack(exports_directory_table_str, data[base:base+str_len]) for n, elem in enumerate(exports_directory_table_spec): vals[elem[0]] = val_data[n] build_exports_offset_strings(vals, base, offsets) base_rva = vals["export_address_table_rva"] base = rva_to_offset(base_rva, sections) entry_len = struct.calcsize(exports_address_table_str) addresses = [] for i in xrange(vals["address_table_entries"]): if not base or base + entry_len >= len(data): break address = struct.unpack(exports_address_table_str, data[base:base+entry_len]) addresses.append(address[0]) base += entry_len base_rva = vals["name_pointer_rva"] base = rva_to_offset(base_rva, sections) if not base: return None, offsets entry_len = struct.calcsize(exports_name_pointer_table_str) export_names = [] for i in xrange(vals["number_of_name_pointers"]): if base + entry_len >= len(data): break name_ptr = struct.unpack(exports_name_pointer_table_str, data[base:base+entry_len]) name, offsets = rva_string_lookup(name_ptr[0], sections, optional_header["image_base"], data, offsets) base += entry_len if name: export_names.append(name) base_rva = vals["ordinal_table_rva"] base = rva_to_offset(base_rva, sections) entry_len = struct.calcsize(exports_ordinal_table_str) ords = [] for i in xrange(vals["number_of_name_pointers"]): if not base or base + entry_len >= len(data): break ord = struct.unpack(exports_ordinal_table_str, data[base:base+entry_len]) ords.append(ord[0]) base += entry_len exports = {} for n, o in zip(export_names, ords): if o < len(addresses): exports[n] = {"ord":o, "address":addresses[o]} vals["export_names"] = exports return vals, offsets