Exemplo n.º 1
0
    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
Exemplo n.º 2
0
    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)
Exemplo n.º 3
0
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))
Exemplo n.º 4
0
    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
Exemplo n.º 5
0
    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)))
Exemplo n.º 6
0
 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
Exemplo n.º 7
0
 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
Exemplo n.º 8
0
 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
Exemplo n.º 9
0
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
Exemplo n.º 10
0
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
Exemplo n.º 11
0
    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)
Exemplo n.º 12
0
 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
Exemplo n.º 13
0
 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
Exemplo n.º 14
0
 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
Exemplo n.º 15
0
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
Exemplo n.º 16
0
 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))
Exemplo n.º 17
0
    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)
Exemplo n.º 18
0
 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)
Exemplo n.º 19
0
    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
Exemplo n.º 20
0
    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))
Exemplo n.º 21
0
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
Exemplo n.º 22
0
    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)
Exemplo n.º 23
0
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
Exemplo n.º 24
0
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
Exemplo n.º 25
0
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
Exemplo n.º 26
0
    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
Exemplo n.º 27
0
    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
Exemplo n.º 28
0
    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) )
Exemplo n.º 29
0
    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