def modify_uefi_region(data, command, guid, uefi_file = ''): RgLengthChange = 0 fv = NextFwVolume(data) while fv is not None: FvLengthChange = 0 polarity = bit_set(fv.Attributes, EFI_FVB2_ERASE_POLARITY) if ((fv.Guid == EFI_FIRMWARE_FILE_SYSTEM2_GUID) or (fv.Guid == EFI_FIRMWARE_FILE_SYSTEM_GUID)): fwbin = NextFwFile(fv.Image, fv.Size, fv.HeaderSize, polarity) while fwbin is not None: next_offset = fwbin.Size + fwbin.Offset if (fwbin.Guid == guid): uefi_file_size = (len(uefi_file) + 7) & 0xFFFFFFF8 CurFileOffset = fv.Offset + fwbin.Offset + FvLengthChange NxtFileOffset = fv.Offset + next_offset + FvLengthChange if command == CMD_UEFI_FILE_REMOVE: FvLengthChange -= (next_offset - fwbin.Offset) logger().log( "Removing UEFI file with GUID={} at offset={:08X}, size change: {:d} bytes".format(fwbin.Guid, CurFileOffset, FvLengthChange) ) data = data[:CurFileOffset] + data[NxtFileOffset:] elif command == CMD_UEFI_FILE_INSERT_BEFORE: FvLengthChange += uefi_file_size logger().log( "Inserting UEFI file before file with GUID={} at offset={:08X}, size change: {:d} bytes".format(fwbin.Guid, CurFileOffset, FvLengthChange) ) data = data[:CurFileOffset] + uefi_file.ljust(uefi_file_size, '\xFF') + data[CurFileOffset:] elif command == CMD_UEFI_FILE_INSERT_AFTER: FvLengthChange += uefi_file_size logger().log( "Inserting UEFI file after file with GUID={} at offset={:08X}, size change: {:d} bytes".format(fwbin.Guid, CurFileOffset, FvLengthChange) ) data = data[:NxtFileOffset] + uefi_file.ljust(uefi_file_size, '\xFF') + data[NxtFileOffset:] elif command == CMD_UEFI_FILE_REPLACE: FvLengthChange += uefi_file_size - (next_offset - fwbin.Offset) logger().log( "Replacing UEFI file with GUID={} at offset={:08X}, new size: {:d}, old size: {:d}, size change: {:d} bytes".format(fwbin.Guid, CurFileOffset, len(uefi_file), fwbin.Size, FvLengthChange) ) data = data[:CurFileOffset] + uefi_file.ljust(uefi_file_size, '\xFF') + data[NxtFileOffset:] else: raise Exception('Invalid command') if next_offset - fwbin.Offset >= 24: FvEndOffset = fv.Offset + next_offset + FvLengthChange fwbin = NextFwFile(fv.Image, fv.Size, next_offset, polarity) if FvLengthChange >= 0: data = data[:FvEndOffset] + data[FvEndOffset + FvLengthChange:] else: data = data[:FvEndOffset] + (abs(FvLengthChange) * '\xFF') + data[FvEndOffset:] FvLengthChange = 0 #if FvLengthChange != 0: # logger().log( "Rebuilding Firmware Volume with GUID={} at offset={:08X}".format(FsGuid, FvOffset) ) # FvHeader = data[FvOffset: FvOffset + FvHeaderLength] # FvHeader = FvHeader[:0x20] + struct.pack('<Q', FvLength) + FvHeader[0x28:] # NewChecksum = FvChecksum16(FvHeader[:0x32] + '\x00\x00' + FvHeader[0x34:]) # FvHeader = FvHeader[:0x32] + struct.pack('<H', NewChecksum) + FvHeader[0x34:] # data = data[:FvOffset] + FvHeader + data[FvOffset + FvHeaderLength:] fv = NextFwVolume(data, fv.Offset + fv.Size) return data
def NextFwFile(FvImage, FvLength, fof, polarity): file_header_size = struct.calcsize(EFI_FFS_FILE_HEADER) fof = align(fof, 8) cur_offset = fof res = None update_or_deleted = False while cur_offset + file_header_size < min(FvLength, len(FvImage)): fsize = 0 #if (fof + file_header_size) <= min(FvLength, len(FvImage)): #Check for a blank header if polarity: blank = b"\xff" * file_header_size else: blank = b"\x00" * file_header_size if (blank == FvImage[cur_offset:cur_offset + file_header_size]): #next_offset = fof + 8 cur_offset += 8 continue Name0, IntegrityCheck, Type, Attributes, Size, State = struct.unpack( EFI_FFS_FILE_HEADER, FvImage[cur_offset:cur_offset + file_header_size]) #Get File Header Size if Attributes & FFS_ATTRIB_LARGE_FILE: header_size = struct.calcsize(EFI_FFS_FILE_HEADER2) else: header_size = struct.calcsize(EFI_FFS_FILE_HEADER) #Get File size if Attributes & FFS_ATTRIB_LARGE_FILE and len( FvImage) > fof + struct.calcsize(EFI_FFS_FILE_HEADER2): fsize = struct.unpack( "Q", FvImage[fof + file_header_size:fof + file_header_size + struct.calcsize("Q")])[0] fsize &= 0xFFFFFFFF if fsize == 0 or fsize > FvLength - cur_offset: fsize = get_3b_size(Size) #Validate fsize is a legal value if fsize == 0 or fsize > FvLength - cur_offset: logger().log( "Unable to get correct file size for NextFwFile corrupt header information" ) break #Get next_offset update_or_deleted = (bit_set(State, EFI_FILE_MARKED_FOR_UPDATE, polarity)) or (bit_set( State, EFI_FILE_DELETED, polarity)) if not ((bit_set(State, EFI_FILE_DATA_VALID, polarity)) or update_or_deleted): #else: cur_offset = align(cur_offset + 1, 8) continue Name = UUID(bytes_le=Name0) #TODO need to fix up checksum? fheader = struct.pack(EFI_FFS_FILE_HEADER, Name0, 0, Type, Attributes, Size, 0) hsum = FvChecksum8(fheader) if (Attributes & FFS_ATTRIB_CHECKSUM): fsum = FvChecksum8(FvImage[cur_offset + file_header_size:cur_offset + fsize]) else: fsum = FFS_FIXED_CHECKSUM CalcSum = (hsum | (fsum << 8)) res = EFI_FILE(cur_offset, Name, Type, Attributes, State, IntegrityCheck, fsize, FvImage[cur_offset:cur_offset + fsize], header_size, update_or_deleted, CalcSum) break return res