def parse_EFI_variables(self, fname, rom, authvars, _fw_type=None): if _fw_type in uefi_platform.fw_types: logger().log( "[uefi] Using FW type (NVRAM format): {}".format(_fw_type)) self.set_FWType(_fw_type) else: logger().error( "Unrecognized FW type (NVRAM format) '{}'..".format(_fw_type)) return False logger().log("[uefi] Searching for NVRAM in the binary..") efi_vars_store = self.find_EFI_variable_store(rom) if efi_vars_store: nvram_fname = fname + '.nvram.bin' write_file(nvram_fname, efi_vars_store) nvram_pth = fname + '.nvram.dir' if not os.path.exists(nvram_pth): os.makedirs(nvram_pth) logger().log("[uefi] Extracting EFI Variables in the NVRAM..") efi_vars = uefi_platform.EFI_VAR_DICT[ self._FWType]['func_getefivariables'](efi_vars_store) decode_EFI_variables(efi_vars, nvram_pth) else: logger().error("Did not find NVRAM") return False return True
def decode_rom(self): _uefi = UEFI(self.cs) self.logger.log( "[CHIPSEC] Decoding SPI ROM image from a file '{}'".format( self._rom)) f = read_file(self._rom) if not f: return False (fd_off, fd) = get_spi_flash_descriptor(f) if (-1 == fd_off) or (fd is None): self.logger.error( "Could not find SPI Flash descriptor in the binary '{}'". format(self._rom)) self.logger.log_information( "To decode an image without a flash decriptor try chipsec_util uefi decode" ) return False self.logger.log( "[CHIPSEC] Found SPI Flash descriptor at offset 0x{:X} in the binary '{}'" .format(fd_off, self._rom)) rom = f[fd_off:] # Decoding SPI Flash Regions flregs = get_spi_regions(fd) if flregs is None: self.logger.error("SPI Flash descriptor region is not valid") self.logger.log_information( "To decode an image with an invalid flash decriptor try chipsec_util uefi decode" ) return False _orig_logname = self.logger.LOG_FILE_NAME pth = os.path.join(self.cs.helper.getcwd(), self._rom + ".dir") if not os.path.exists(pth): os.makedirs(pth) for r in flregs: idx = r[0] name = r[1] base = r[3] limit = r[4] notused = r[5] if not notused: region_data = rom[base:limit + 1] fname = os.path.join( pth, '{:d}_{:04X}-{:04X}_{}.bin'.format(idx, base, limit, name)) write_file(fname, region_data) if FLASH_DESCRIPTOR == idx: # Decoding Flash Descriptor self.logger.set_log_file(os.path.join(pth, fname + '.log')) parse_spi_flash_descriptor(self.cs, region_data) elif BIOS == idx: # Decoding EFI Firmware Volumes self.logger.set_log_file(os.path.join(pth, fname + '.log')) decode_uefi_region(_uefi, pth, fname, self._fwtype) self.logger.set_log_file(_orig_logname)
def parse_uefi_region_from_file(_uefi, filename, fwtype, outpath=None, filetype=[]): # Create an output folder to dump EFI module tree if outpath is None: outpath = "{}.dir".format(filename) if not os.path.exists(outpath): os.makedirs(outpath) # Read UEFI image binary to parse rom = read_file(filename) # Parse UEFI image binary and build a tree hierarchy of EFI modules tree = build_efi_model(_uefi, rom, fwtype) # Save entire EFI module hierarchy on a file-system and export into JSON if filetype: tree_json = save_efi_tree_filetype(tree, path=outpath, filetype=filetype) else: tree_json = save_efi_tree(_uefi, tree, path=outpath) write_file( "{}.UEFI.json".format(filename), json.dumps(tree_json, indent=2, separators=(',', ': '), cls=UUIDEncoder))
def var_find(self): _vars = self._uefi.list_EFI_variables() if _vars is None: self.logger.log_warning( 'Could not enumerate UEFI variables (non-UEFI OS?)' ) return is_guid = 0 try: _input_var = str(uuid.UUID(self.name_guid)) is_guid = 1 except ValueError: _input_var = self.name_guid if is_guid: self.logger.log( "[*] Searching for UEFI variable with GUID {{{}}}..".format(_input_var) ) for name in _vars: n = 0 for (off, buf, hdr, data, guid, attrs) in _vars[name]: if _input_var == guid: var_fname = '{}_{}_{}_{:d}.bin'.format(name, guid, get_attr_string(attrs).strip(), n) self.logger.log_good( "Found UEFI variable {}:{}. Dumped to '{}'".format(guid, name, var_fname) ) write_file( var_fname, data ) n += 1 else: self.logger.log( "[*] Searching for UEFI variable with name {}..".format(_input_var) ) name = _input_var if name in list(_vars.keys()): n = 0 for (off, buf, hdr, data, guid, attrs) in _vars[name]: var_fname = '{}_{}_{}_{:d}.bin'.format(name, guid, get_attr_string(attrs).strip(), n) self.logger.log_good( "Found UEFI variable {}:{}. Dumped to '{}'".format(guid, name, var_fname) ) write_file( var_fname, data ) n += 1
def assemble(self): compression = {'none': 0, 'tiano': 1, 'lzma': 2} if get_guid_bin(self.guid) == '': print('*** Error *** Invalid GUID: {}'.format(self.guid)) return if not os.path.isfile(self.raw_file): print('*** Error *** File doesn\'t exist: {}'.format( self.raw_file)) return if self.comp not in compression: print('*** Error *** Unknown compression: {}'.format(self.comp)) return compression_type = compression[self.comp] if self.file_type == 'freeform': raw_image = read_file(self.raw_file) wrap_image = assemble_uefi_raw(raw_image) if compression_type > 0: comp_image = compress_image(self._uefi, wrap_image, compression_type) wrap_image = assemble_uefi_section(comp_image, len(wrap_image), compression_type) uefi_image = assemble_uefi_file(self.guid, wrap_image) write_file(self.efi_file, uefi_image) else: print('*** Error *** Unknow file type: {}'.format(self.file_type)) return self.logger.log( "[CHIPSEC] UEFI file was successfully assembled! Binary file size: {:d}, compressed UEFI file size: {:d}" .format(len(raw_image), len(uefi_image)))
def get_EFI_variable( self, name, guid, filename=None ): var = self.helper.get_EFI_variable( name, guid ) if var: if filename: write_file( filename, var ) if logger().UTIL_TRACE or logger().HAL: logger().log( '[uefi] EFI variable {}:{} :'.format(guid, name) ) print_buffer( bytestostring(var) ) return var
def read_spi_to_file(self, spi_fla, data_byte_count, filename): buf = self.read_spi(spi_fla, data_byte_count) if buf is None: return None if filename is not None: write_file(filename, buf) else: chipsec.logger.print_buffer(buf, 16) return buf
def generate_efilist( self, json_pth ): self.efi_list = {} self.logger.log( "[*] generating a list of EFI executables from firmware image..." ) efi_tree = build_efi_model(self.uefi, self.image, None) matching_modules = search_efi_tree(efi_tree, self.genlist_callback, EFIModuleType.SECTION_EXE, True) self.logger.log( "[*] found {:d} EFI executables in UEFI firmware image '{}'".format(len(self.efi_list), self.image_file) ) self.logger.log( "[*] creating JSON file '{}'...".format(json_pth) ) write_file("{}".format(json_pth), json.dumps(self.efi_list, indent=2, separators=(',', ': '), cls=UUIDEncoder)) return ModuleResult.PASSED
def compress_image( _uefi, image, compression_type ): precomress_file = 'uefi_file.raw.comp' compressed_file = 'uefi_file.raw.comp.gz' write_file(precomress_file, image) compressed_image = _uefi.compress_EFI_binary(precomress_file, compressed_file, compression_type) write_file(compressed_file, compressed_image) os.remove(precomress_file) os.remove(compressed_file) return compressed_image
def parse_sb_db(db, decode_dir): entries = [] dof = 0 nsig = 0 db_size = len(db) if 0 == db_size: return entries # some platforms have 0's in the beginnig, skip all 0 (no known SignatureType starts with 0x00): while (dof + SIGNATURE_LIST_size) < db_size: SignatureType0, SignatureListSize, SignatureHeaderSize, SignatureSize \ = struct.unpack(SIGNATURE_LIST, db[dof:dof +SIGNATURE_LIST_size]) # prevent infinite loop when parsing malformed var if SignatureListSize == 0: logger().log_bad("db parsing failed!") return entries # Determine the signature type SignatureType = EFI_GUID_STR(SignatureType0) sig_parse_f = None sig_size = 0 if (SignatureType in sig_types.keys()): sig_name, sig_parse_f, sig_size, short_name = sig_types[SignatureType] else: logger().log_bad('Unknown signature type {}, skipping signature decode.'.format(SignatureType)) dof += SignatureListSize continue # Extract signature data blobs if (((sig_size > 0) and (sig_size == SignatureSize)) or ((sig_size == 0) and (SignatureSize >= 0x10))): sof = 0 sig_list = db[dof +SIGNATURE_LIST_size +SignatureHeaderSize:dof +SignatureListSize] sig_list_size = len(sig_list) while ((sof + EFI_GUID_SIZE) < sig_list_size): sig_data = sig_list[sof:sof +SignatureSize] owner0 = struct.unpack(EFI_GUID_FMT, sig_data[:EFI_GUID_SIZE])[0] owner = EFI_GUID_STR(owner0) data = sig_data[EFI_GUID_SIZE:] entries.append( data ) sig_file_name = "{}-{}-{:02d}.bin".format(short_name, owner, nsig) sig_file_name = os.path.join(decode_dir, sig_file_name) write_file(sig_file_name, data) if (sig_parse_f is not None): sig_parse_f(data) sof = sof + SignatureSize nsig = nsig + 1 else: err_str = "Wrong SignatureSize for {} type: 0x{:X}." .format(SignatureType, SignatureSize) if (sig_size > 0): err_str = err_str + " Must be 0x{:X}.".format(sig_size) else: err_str = err_str + " Must be >= 0x10." logger().error( err_str ) logger().error('Skipping signature decode for this list.') dof = dof + SignatureListSize return entries
def check_memory( self, _addr, _smi_desc, fn, restore_contents=False ): _ptr = _smi_desc.ptr filler = self.fill_byte*self.fill_size # # Check if contents have changed at physical address passed in GPRs to SMI handler # If changed, SMI handler might have written to that address # self.logger.log( " < checking buffers" ) expected_buf = FILL_BUFFER( self.fill_byte, self.fill_size, _smi_desc.ptr_in_buffer, _smi_desc.ptr, _smi_desc.ptr_offset, _smi_desc.sig, _smi_desc.sig_offset ) buf = self.cs.mem.read_physical_mem( _addr, self.fill_size ) differences = DIFF( expected_buf, buf, self.fill_size ) _changed = (len(differences) > 0) if self.logger.VERBOSE: self.logger.log( "checking contents at PA 0x{:016X}:".format(_addr) ) print_buffer( buf ) self.logger.log( "expected contents:" ) print_buffer( expected_buf ) if _changed: self.logger.log( " contents changed at 0x{:016X} +{}".format(_addr,differences) ) if restore_contents: self.logger.log( " restoring 0x{:X} bytes at 0x{:016X}".format(self.fill_size, _addr) ) self.cs.mem.write_physical_mem( _addr, self.fill_size, expected_buf ) if DUMP_MEMORY_ON_DETECT: _pth_smi = os.path.join( _pth, '{:X}_{}'.format(_smi_desc.smi_code,_smi_desc.name) ) if not os.path.exists( _pth_smi ): os.makedirs( _pth_smi ) _f = os.path.join( _pth_smi, fn + '.dmp' ) self.logger.log( " dumping buffer to '{}'".format(_f) ) write_file( _f, buf ) _changed1 = False expected_buf = filler if _smi_desc.ptr_in_buffer and _ptr is not None: buf1 = self.cs.mem.read_physical_mem( _ptr, self.fill_size ) differences1 = DIFF( expected_buf, buf1, self.fill_size ) _changed1 = (len(differences1) > 0) if self.logger.VERBOSE: self.logger.log( "checking contents at PA 0x{:016X}:".format(_ptr) ) print_buffer( buf1 ) if _changed1: self.logger.log( " contents changed at 0x{:016X} +{}".format(_ptr,differences1) ) if restore_contents: self.logger.log( " restoring 0x{:X} bytes at PA 0x{:016X}".format(self.fill_size, _ptr) ) self.cs.mem.write_physical_mem( _ptr, self.fill_size, expected_buf ) if DUMP_MEMORY_ON_DETECT: _pth_smi = os.path.join( _pth, '{:X}_{}'.format(_smi_desc.smi_code,_smi_desc.name) ) if not os.path.exists( _pth_smi ): os.makedirs( _pth_smi ) _f = os.path.join( _pth_smi, fn + ('_ptr{:X}.dmp'.format(_smi_desc.ptr_offset)) ) self.logger.log( " dumping buffer to '{}'".format(_f) ) write_file( _f, buf1 ) return (_changed or _changed1)
def parse_XROM( self, xrom_base, xrom_dump=False ): xrom_sig = self.cs.mem.read_physical_mem_word( xrom_base ) if xrom_sig != XROM_SIGNATURE: return None xrom_hdr_buf = self.cs.mem.read_physical_mem( xrom_base, PCI_XROM_HEADER_SIZE ) xrom_hdr = PCI_XROM_HEADER( *struct.unpack_from( PCI_XROM_HEADER_FMT, xrom_hdr_buf ) ) if xrom_dump: xrom_fname = 'xrom_%x-%x-%x_%x%x.bin' % (bus, dev, fun, vid, did) xrom_buf = self.cs.mem.read_physical_mem( xrom_base, xrom_size ) # use xrom_hdr.InitSize ? write_file( xrom_fname, xrom_buf ) return xrom_hdr
def parse_XROM( self, xrom, xrom_dump=False ): xrom_sig = self.cs.mem.read_physical_mem_word( xrom.base ) if xrom_sig != XROM_SIGNATURE: return None xrom_hdr_buf = self.cs.mem.read_physical_mem( xrom.base, PCI_XROM_HEADER_SIZE ) xrom_hdr = PCI_XROM_HEADER( *struct.unpack_from( PCI_XROM_HEADER_FMT, xrom_hdr_buf ) ) if xrom_dump: xrom_fname = 'xrom_{:X}-{:X}-{:X}_{:X}{:X}.bin'.format(xrom.bus, xrom.dev, xrom.fun, xrom.vid, xrom.did) xrom_buf = self.cs.mem.read_physical_mem( xrom.base, xrom.size ) # use xrom_hdr.InitSize ? write_file( xrom_fname, xrom_buf ) return xrom_hdr
def decompress_section_data( _uefi, section_dir_path, sec_fs_name, compressed_data, compression_type, remove_files=False ): compressed_name = os.path.join(section_dir_path, "{}.gz".format(sec_fs_name)) uncompressed_name = os.path.join(section_dir_path, sec_fs_name) write_file(compressed_name, compressed_data) uncompressed_image = _uefi.decompress_EFI_binary( compressed_name, uncompressed_name, compression_type ) if remove_files: try: os.remove(compressed_name) if uncompressed_image: os.remove(uncompressed_name) except: pass return uncompressed_image
def mem_read(self): self.logger.log( '[CHIPSEC] Reading buffer from memory: PA = 0x{:016X}, len = 0x{:X}..' .format(self.phys_address, self.buffer_length)) buffer = self.cs.mem.read_physical_mem(self.phys_address, self.buffer_length) if self.file_name: write_file(self.file_name, buffer) self.logger.log("[CHIPSEC] Written 0x{:X} bytes to '{}'".format( len(buffer), self.file_name)) else: print_buffer(bytestostring(buffer))
def remove(self): if get_guid_bin(self.guid) == '': print ('*** Error *** Invalid GUID: {}'.format(self.guid)) return if not os.path.isfile(self.rom_file): print ('*** Error *** File doesn\'t exist: {}'.format(self.rom_file)) return rom_image = read_file(self.rom_file) new_image = modify_uefi_region(rom_image, CMD_UEFI_FILE_REMOVE, self.guid) write_file(self.new_file, new_image)
def read_dma(self): self.logger.log( '[CHIPSEC] Reading buffer from memory: PA = 0x{:016X}, len = 0x{:X}..' .format(self.address, self.width)) buffer = self.cs.igd.gfx_aperture_dma_read_write( self.address, self.width) if self.file_name: write_file(self.file_name, buffer) self.logger.log("[CHIPSEC] Written 0x{:X} bytes to '{}'".format( len(buffer), self.file_name)) else: print_buffer(buffer)
def smi_mmio_range_fuzz(self, thread_id, b, d, f, bar_off, is64bit, bar, new_bar, base, size): # copy all registers from MMIO range to new location in memory # we do that once rather than before every SMI since we return after first change detected self.logger.log("[*] copying BAR 0x{:X} > 0x{:X}".format( base, self.reloc_mmio)) orig_mmio = self.copy_bar(base, self.reloc_mmio, size) if self.logger.VERBOSE: self.cs.mmio.dump_MMIO(base, size) file.write_file('mmio_mem.orig', orig_mmio) for smi_code in range(self.smic_start, self.smic_end + 1): for smi_data in range(self.smid_start, self.smid_end + 1): for ecx in range(self.smif_start, self.smif_end + 1): self.logger.log( "> SMI# {:02X}: data {:02X}, func (ECX) {:X}".format( smi_code, smi_data, ecx)) if FLUSH_OUTPUT_AFTER_SMI: self.logger.flush() # point MMIO range to new location (relocate MMIO range) self.logger.log(" relocating BAR 0x{:X}".format(bar)) if not self.modify_bar(b, d, f, bar_off, is64bit, bar, new_bar): continue # generate SW SMI self._interrupts.send_SW_SMI(thread_id, smi_code, smi_data, _FILL_VALUE_QWORD, self.comm, ecx, _FILL_VALUE_QWORD, _FILL_VALUE_QWORD, _FILL_VALUE_QWORD) # restore original location of MMIO range self.restore_bar(b, d, f, bar_off, is64bit, bar) self.logger.log(" restored BAR with 0x{:X}".format(bar)) # check the contents at the address range used to relocate MMIO BAR buf = self.cs.mem.read_physical_mem(self.reloc_mmio, size) diff = DIFF(orig_mmio, buf, size) self.logger.log(" checking relocated MMIO") if len(diff) > 0: self.logger.log_important( "changes found at 0x{:X} +{}".format( self.reloc_mmio, diff)) if self.logger.VERBOSE: file.write_file('mmio_mem.new', buf) return True return False
def vmem_read(self): self.logger.log( '[CHIPSEC] Reading buffer from memory: VA = 0x{:016X}, len = 0x{:X}.' .format(self.virt_address, self.size)) try: buffer = self._vmem.read_virtual_mem(self.virt_address, self.size) except (TypeError, OSError): self.logger.error('Error mapping VA to PA.') return if self.buf_file: write_file(self.buf_file, buffer) self.logger.log("[CHIPSEC] Written 0x{:X} bytes to '{}'".format( len(buffer), self.buf_file)) else: print_buffer(bytestostring(buffer))
def dump_efi_module(mod, parent, modn, path): fname = FILENAME(mod, parent, modn) mod_path = os.path.join(path, fname) write_file(mod_path, mod.Image[mod.HeaderSize:] if type(mod) == EFI_SECTION else mod.Image) if type(mod) == EFI_SECTION or WRITE_ALL_HASHES: if mod.MD5 : write_file(("{}.md5" .format(mod_path)), mod.MD5) if mod.SHA1 : write_file(("{}.sha1" .format(mod_path)), mod.SHA1) if mod.SHA256: write_file(("{}.sha256".format(mod_path)), mod.SHA256) return mod_path
def insert_after(self): if get_guid_bin(self.guid) == '': print ('*** Error *** Invalid GUID: {}'.format(self.guid)) return if not os.path.isfile(self.rom_file): print ('*** Error *** File doesn\'t exist: {}'.format(self.rom_file)) return if not os.path.isfile(self.efi_file): print ('*** Error *** File doesn\'t exist: {}'.format(self.efi_file)) return rom_image = read_file(self.rom_file) efi_image = read_file(self.efi_file) new_image = modify_uefi_region(rom_image, CMD_UEFI_FILE_INSERT_AFTER, self.guid, efi_image) write_file(self.new_file, new_image)
def decode_EFI_variables( efi_vars, nvram_pth ): # print decoded and sorted EFI variables into a log file print_sorted_EFI_variables( efi_vars ) # write each EFI variable into its own binary file for name in efi_vars.keys(): n = 0 for (off, buf, hdr, data, guid, attrs) in efi_vars[name]: # efi_vars[name] = (off, buf, hdr, data, guid, attrs) attr_str = get_attr_string( attrs ) var_fname = os.path.join( nvram_pth, '{}_{}_{}_{:d}.bin'.format(name, guid, attr_str.strip(), n) ) write_file( var_fname, data ) if name in SECURE_BOOT_KEY_VARIABLES: parse_efivar_file(var_fname, data, SECURE_BOOT_SIG_VAR) elif name == EFI_VAR_NAME_certdb: parse_efivar_file(var_fname, data, AUTH_SIG_VAR) elif name == EFI_VAR_NAME_AuthVarKeyDatabase: parse_efivar_file(var_fname, data, ESAL_SIG_VAR) n = n+1
def parse_auth_var(db, decode_dir): entries = [] dof = 0 nsig = 0 db_size = len(db) # Verify that list makes sense if db_size < AUTH_CERT_DB_LIST_HEAD_size: logger().warn("Cert list empty.") return entries expected_size = struct.unpack(AUTH_CERT_DB_LIST_HEAD, db[dof:dof + AUTH_CERT_DB_LIST_HEAD_size])[0] if db_size != expected_size: logger().error("Expected size of cert list did not match actual size.") return entries dof += AUTH_CERT_DB_LIST_HEAD_size # Loop through all the certs in the list. while dof + AUTH_CERT_DB_DATA_size < db_size: ven_guid0, cert_node_size, name_size, cert_data_size = struct.unpack( AUTH_CERT_DB_DATA, db[dof:dof + AUTH_CERT_DB_DATA_size]) vendor_guid = EFI_GUID_STR(ven_guid0) name_size *= 2 # Name size is actually the number of CHAR16 in the name array tof = dof + AUTH_CERT_DB_DATA_size try: var_name = codecs.decode(db[tof:tof + name_size], 'utf-16') except UnicodeDecodeError: logger().warn("Unable to decode {}".format(db[tof:tof + name_size])) var_name = "chipsec.exceptions!" tof += name_size sig_data = db[tof:tof + cert_data_size] entries.append(sig_data) sig_file_name = '{}-{}-{:02X}.bin'.format(vendor_guid, codecs.encode(var_name), nsig) sig_file_name = os.path.join(decode_dir, sig_file_name) write_file(sig_file_name, sig_data) dof += cert_node_size nsig += 1 return entries
def parse_esal_var(db, decode_dir): entries = [] dof = 0 nsig = 0 db_size = len(db) # Check to see how many signatures exist if db_size < ESAL_SIG_SIZE: logger().log('No signatures present.') return entries # Extract signatures while dof + ESAL_SIG_SIZE <= db_size: key_data = db[dof:dof +ESAL_SIG_SIZE] entries.append(key_data) key_file_name = os.path.join(decode_dir, 'AuthVarKeyDatabase-cert-{:02X}.bin'.format(nsig)) write_file(key_file_name, key_data) dof += ESAL_SIG_SIZE nsig += 1 return entries
def smi_mmio_range_fuzz(self, thread_id, b, d, f, bar_off, is64bit, bar, new_bar, base, size): # copy all registers from MMIO range to new location in memory # we do that once rather than before every SMI since we return after first change detected self.logger.log( "[*] copying BAR 0x%X > 0x%X" % (base,self.reloc_mmio) ) orig_mmio = self.copy_bar(base, self.reloc_mmio, size) if self.logger.VERBOSE: self.cs.mmio.dump_MMIO(base, size) file.write_file('mmio_mem.orig', orig_mmio) for smi_code in xrange(self.smic_start,self.smic_end+1): for smi_data in xrange(self.smid_start,self.smid_end+1): for ecx in xrange(self.smif_start,self.smif_end+1): self.logger.log( "> SMI# %02X: data %02X, func (ECX) %X" % (smi_code,smi_data,ecx) ) if FLUSH_OUTPUT_AFTER_SMI: self.logger.flush() # point MMIO range to new location (relocate MMIO range) self.logger.log( " relocating BAR 0x%X" % bar ) if not self.modify_bar(b, d, f, bar_off, is64bit, bar, new_bar): continue # generate SW SMI self._interrupts.send_SW_SMI(thread_id, smi_code, smi_data, _FILL_VALUE_QWORD, self.comm, ecx, _FILL_VALUE_QWORD, _FILL_VALUE_QWORD, _FILL_VALUE_QWORD) # restore original location of MMIO range self.restore_bar(b, d, f, bar_off, is64bit, bar) self.logger.log( " restored BAR with 0x%X" % bar ) # check the contents at the address range used to relocate MMIO BAR buf = self.cs.mem.read_physical_mem( self.reloc_mmio, size ) diff = DIFF(orig_mmio, buf, size) self.logger.log(" checking relocated MMIO") if len(diff) > 0: self.logger.log_important("changes found at 0x%X +%s" % (self.reloc_mmio, diff)) if self.logger.VERBOSE: file.write_file('mmio_mem.new', buf) return True return False
def run(self, module_argv): self.logger.start_test("EPT Finder") self.read_from_file = len(module_argv) > 0 and module_argv[0] == "file" if self.read_from_file: if len(module_argv) == 3: revision_id = int(module_argv[2], 16) pattern = "%s.dram_*" % module_argv[1] filenames = glob.glob(pattern) for name in filenames: addr = name[len(pattern) - 1:] addr = 0 if addr == "lo" else 0x100000000 if addr == "hi" else int(addr, 16) size = os.stat(name).st_size self.logger.log(" Mapping file to address: 0x%012x size: 0x%012x name: %s" % (addr, size, name)) self.par.append((addr, addr + size, open(name, "rb"))) else: self.usage() return ModuleResult.ERROR else: revision_id = self.cs.msr.read_msr(0, 0x480)[0] self.par = self.get_memory_ranges() if (len(self.par) == 0): self.logger.error("Memory ranges are not defined!") return ModuleResult.ERROR if len(module_argv) == 2 and module_argv[0] == "dump": for (pa, end_pa, source) in self.par: postfix = "lo" if pa == 0x0 else "hi" if pa == 0x100000000 else "0x%08x" % pa filename = "%s.dram_%s" % (module_argv[1], postfix) self.dump_dram(filename, pa, end_pa) return ModuleResult.PASSED self.logger.log( '[*] Searching Extented Page Tables ...') ept_pt_list = self.find_ept_pt({}, 0, 4) self.logger.log( '[*] Found PTs : %d' % len(ept_pt_list)) ept_pd_list = self.find_ept_pt(ept_pt_list, 4, 3) self.logger.log( '[*] Found PDs : %d' % len(ept_pd_list)) ept_pdpt_list = self.find_ept_pt(ept_pd_list, 1, 2) self.logger.log( '[*] Found PDPTs: %d' % len(ept_pdpt_list)) ept_pml4_list = self.find_ept_pt(ept_pdpt_list, 1, 1) self.logger.log( '[*] Found PML4s: %d' % len(ept_pml4_list)) self.logger.log( '[*] -> EPTP: ' + ' '.join(['%08X' % x for x in sorted(ept_pml4_list.keys())])) ept_vmcs_list = self.find_vmcs_by_ept([x for x in ept_pml4_list.keys()], revision_id) self.logger.log( '[*] Found VMCSs: %d' % len(ept_vmcs_list)) self.logger.log( '[*] -> VMCS: ' + ' '.join(['%08X' % x for x in sorted(ept_vmcs_list)])) try: self.path = 'VMs\\' os.makedirs(self.path) except OSError: pass for addr in sorted(ept_vmcs_list): write_file(self.path + 'vmcs_%08x.bin' % addr, self.read_physical_mem(addr)) count = 1 for eptp in sorted(ept_pml4_list.keys()): ept = c_extended_page_tables_from_file(self.cs, self.read_from_file, self.par) ept.prompt = '[VM%d]' % count ept.read_pt_and_show_status(self.path + 'ept_%08x' % eptp, 'Extended', eptp) if not ept.failure: ept.save_configuration(self.path + 'ept_%08x.py' % eptp) count += 1 return ModuleResult.PASSED
def run(self): if len(self.argv) < 3: print DecodeCommand.__doc__ return _uefi = uefi.UEFI( self.cs ) if self.argv[2] == "types": print "\n<fw_type> should be in [ %s ]\n" % ( " | ".join( ["%s" % t for t in uefi.uefi_platform.fw_types] ) ) return rom_file = self.argv[2] fwtype = self.argv[3] if len(self.argv) == 4 else None self.logger.log( "[CHIPSEC] Decoding SPI ROM image from a file '%s'" % rom_file ) t = time.time() f = read_file( rom_file ) (fd_off, fd) = spi_descriptor.get_spi_flash_descriptor( f ) if (-1 == fd_off) or (fd is None): self.logger.error( "Could not find SPI Flash descriptor in the binary '%s'" % rom_file ) return False self.logger.log( "[CHIPSEC] Found SPI Flash descriptor at offset 0x%x in the binary '%s'" % (fd_off, rom_file) ) rom = f[fd_off:] # Decoding Flash Descriptor #self.logger.LOG_COMPLETE_FILE_NAME = os.path.join( pth, 'flash_descriptor.log' ) #parse_spi_flash_descriptor( self.cs, fd ) # Decoding SPI Flash Regions # flregs[r] = (r,SPI_REGION_NAMES[r],flreg,base,limit,notused) flregs = spi_descriptor.get_spi_regions( fd ) if flregs is None: self.logger.error( "SPI Flash descriptor region is not valid" ) return False _orig_logname = self.logger.LOG_FILE_NAME pth = os.path.join( self.cs.helper.getcwd(), rom_file + ".dir" ) if not os.path.exists( pth ): os.makedirs( pth ) for r in flregs: idx = r[0] name = r[1] base = r[3] limit = r[4] notused = r[5] if not notused: region_data = rom[base:limit+1] fname = os.path.join( pth, '%d_%04X-%04X_%s.bin' % (idx, base, limit, name) ) write_file( fname, region_data ) if spi.FLASH_DESCRIPTOR == idx: # Decoding Flash Descriptor self.logger.set_log_file( os.path.join( pth, fname + '.log' ) ) spi_descriptor.parse_spi_flash_descriptor( self.cs, region_data ) elif spi.BIOS == idx: # Decoding EFI Firmware Volumes self.logger.set_log_file( os.path.join( pth, fname + '.log' ) ) spi_uefi.decode_uefi_region(_uefi, pth, fname, fwtype) self.logger.set_log_file( _orig_logname ) self.logger.log( "[CHIPSEC] (decode) time elapsed %.3f" % (time.time()-t) )
def run(self, module_argv): self.logger.start_test("Fuzz UEFI Variable Interface") self.logger.warn( "Are you sure you want to continue fuzzing UEFI variable interface?" ) s = cs_input("Type 'yes' to continue > ") if s != 'yes': return # Default options _NAME = 'FuzzerVarName' _GUID = UUID('414C4694-F4CF-0525-69AF-C99C8596530F') _ATTRIB = 0x07 _SIZE = 0x08 _DATA = struct.pack("B", 0x41) * _SIZE ITERATIONS = 1000 SEED = int(time()) CASE = 1 BOUND_STR = 255 #tested value that can be increased or decreased to fit the limit bounds BOUND_INT = 1000 FUZZ_NAME = True FUZZ_GUID = True FUZZ_ATTRIB = True FUZZ_DATA = True FUZZ_SIZE = True # Init fuzzing primitives name_prim = prim.string(value=_NAME, max_len=BOUND_STR) attrib_prim = prim.dword( value=_ATTRIB) # i think the attrib field is 4 bytes large? data_prim = prim.random_data(value=_DATA, min_length=0, max_length=BOUND_INT) help_text = False if len(module_argv): fz_cli = module_argv[0].lower() if ('all' != fz_cli): FUZZ_NAME = False FUZZ_GUID = False FUZZ_ATTRIB = False FUZZ_DATA = False FUZZ_SIZE = False if ('name' == fz_cli): FUZZ_NAME = True elif ('guid' == fz_cli): FUZZ_GUID = True elif ('attrib' == fz_cli): FUZZ_ATTRIB = True elif ('data' == fz_cli): FUZZ_DATA = True elif ('size' == fz_cli): FUZZ_SIZE = True else: help_text = self.usage() if len(module_argv) > 1: if (module_argv[1].isdigit()): ITERATIONS = int(module_argv[1]) else: help_text = self.usage() if len(module_argv) > 2: if (module_argv[2].isdigit()): SEED = int(module_argv[2]) else: help_text = self.usage() if len(module_argv) > 3: if (module_argv[3].isdigit()): CASE = int(module_argv[3]) else: help_text = self.usage() if not help_text: random.seed(SEED) write_file('SEED.txt', str(SEED)) if not len(module_argv): fz_cli = 'all' self.logger.log('Test : {}'.format(fz_cli)) self.logger.log('Iterations: {:d}'.format(ITERATIONS)) self.logger.log('Seed : {:d}'.format(SEED)) self.logger.log('Test case : {:d}'.format(CASE)) self.logger.log('') for count in range(1, ITERATIONS + CASE): if FUZZ_NAME: _NAME = '' if name_prim.mutate(): _NAME = name_prim.render() else: # if mutate() returns false, we need to reload the primitive name_prim = prim.string(value=_NAME, max_len=BOUND_STR) _NAME = name_prim.render() if FUZZ_GUID: _GUID = uuid4() if FUZZ_ATTRIB: if attrib_prim.mutate(): _ATTRIB = attrib_prim.render() else: attrib_prim = prim.dword(value=_ATTRIB) _ATTRIB = attrib_prim.render() if FUZZ_DATA: if data_prim.mutate(): _DATA = data_prim.render() else: data_prim = prim.random_data(value=_DATA, min_length=0, max_length=BOUND_INT) data_prim.mutate() _DATA = data_prim.render() if FUZZ_SIZE: if _DATA: _SIZE = random.randrange(len(_DATA)) else: _SIZE = random.randrange(1024) if (count < CASE): continue self.logger.log(' Running test #{:d}:'.format(count)) self.logger.flush() status = self._uefi.set_EFI_variable(_NAME, str(_GUID), _DATA, _SIZE, _ATTRIB) self.logger.log(status) status = self._uefi.delete_EFI_variable(_NAME, str(_GUID)) self.logger.log(status) return ModuleResult.PASSED