def ExtractFfs(inputfile: str, Ffs_name: str, outputfile: str, Fv_name: str = None) -> None: if not os.path.exists(inputfile): logger.error("Invalid inputfile, can not open {}.".format(inputfile)) raise Exception("Process Failed: Invalid inputfile!") # 1. Data Prepare with open(inputfile, "rb") as f: whole_data = f.read() FmmtParser = FMMTParser(inputfile, ROOT_TREE) # 2. DataTree Create logger.debug('Parsing inputfile data......') FmmtParser.ParserFromRoot(FmmtParser.WholeFvTree, whole_data) logger.debug('Done!') FmmtParser.WholeFvTree.FindNode(Ffs_name, FmmtParser.WholeFvTree.Findlist) if Fv_name: for item in FmmtParser.WholeFvTree.Findlist: if item.Parent.key != Fv_name and item.Parent.Data.Name != Fv_name: FmmtParser.WholeFvTree.Findlist.remove(item) if FmmtParser.WholeFvTree.Findlist != []: TargetNode = FmmtParser.WholeFvTree.Findlist[0] TargetFv = TargetNode.Parent if TargetFv.Data.Header.Attributes & EFI_FVB2_ERASE_POLARITY: TargetNode.Data.Header.State = c_uint8( ~TargetNode.Data.Header.State) FinalData = struct2stream( TargetNode.Data.Header) + TargetNode.Data.Data with open(outputfile, "wb") as f: f.write(FinalData) logger.debug('Extract ffs data is saved in {}.'.format(outputfile)) else: logger.error('Target Ffs not found!!!')
def DeCompressData(self, GuidTool, Section_Data: bytes, FileName) -> bytes: guidtool = GUIDTools().__getitem__(struct2stream(GuidTool)) if not guidtool.ifexist: logger.error("GuidTool {} is not found when decompressing {} file.\n".format(guidtool.command, FileName)) raise Exception("Process Failed: GuidTool not found!") DecompressedData = guidtool.unpack(Section_Data) return DecompressedData
def Encapsulation(self, rootTree, CompressStatus: bool) -> None: # If current node is Root node, skip it. if rootTree.type == ROOT_TREE or rootTree.type == ROOT_FV_TREE or rootTree.type == ROOT_FFS_TREE or rootTree.type == ROOT_SECTION_TREE: logger.debug('Encapsulated successfully!') # If current node do not have Header, just add Data. elif rootTree.type == BINARY_DATA or rootTree.type == FFS_FREE_SPACE: self.FinalData += rootTree.Data.Data rootTree.Child = [] # If current node do not have Child and ExtHeader, just add its Header and Data. elif rootTree.type == DATA_FV_TREE or rootTree.type == FFS_PAD: self.FinalData += struct2stream(rootTree.Data.Header) + rootTree.Data.Data + rootTree.Data.PadData if rootTree.isFinalChild(): ParTree = rootTree.Parent if ParTree.type != 'ROOT': self.FinalData += ParTree.Data.PadData rootTree.Child = [] # If current node is not Section node and may have Child and ExtHeader, add its Header,ExtHeader. If do not have Child, add its Data. elif rootTree.type == FV_TREE or rootTree.type == FFS_TREE or rootTree.type == SEC_FV_TREE: if rootTree.HasChild(): self.FinalData += struct2stream(rootTree.Data.Header) else: self.FinalData += struct2stream(rootTree.Data.Header) + rootTree.Data.Data + rootTree.Data.PadData if rootTree.isFinalChild(): ParTree = rootTree.Parent if ParTree.type != 'ROOT': self.FinalData += ParTree.Data.PadData # If current node is Section, need to consider its ExtHeader, Child and Compressed Status. elif rootTree.type == SECTION_TREE: # Not compressed section if rootTree.Data.OriData == b'' or (rootTree.Data.OriData != b'' and CompressStatus): if rootTree.HasChild(): if rootTree.Data.ExtHeader: self.FinalData += struct2stream(rootTree.Data.Header) + struct2stream(rootTree.Data.ExtHeader) else: self.FinalData += struct2stream(rootTree.Data.Header) else: Data = rootTree.Data.Data if rootTree.Data.ExtHeader: self.FinalData += struct2stream(rootTree.Data.Header) + struct2stream(rootTree.Data.ExtHeader) + Data + rootTree.Data.PadData else: self.FinalData += struct2stream(rootTree.Data.Header) + Data + rootTree.Data.PadData if rootTree.isFinalChild(): ParTree = rootTree.Parent self.FinalData += ParTree.Data.PadData # If compressed section else: Data = rootTree.Data.OriData rootTree.Child = [] if rootTree.Data.ExtHeader: self.FinalData += struct2stream(rootTree.Data.Header) + struct2stream(rootTree.Data.ExtHeader) + Data + rootTree.Data.PadData else: self.FinalData += struct2stream(rootTree.Data.Header) + Data + rootTree.Data.PadData if rootTree.isFinalChild(): ParTree = rootTree.Parent self.FinalData += ParTree.Data.PadData for Child in rootTree.Child: self.Encapsulation(Child, CompressStatus)
def DeleteFfs(self) -> bool: logger.debug('Start Deleting Process......') Delete_Ffs = self.TargetFfs Delete_Fv = Delete_Ffs.Parent # Calculate free space Add_Free_Space = Delete_Ffs.Data.Size + len(Delete_Ffs.Data.PadData) # If Ffs parent Fv have free space, follow the rules to merge the new free space. if Delete_Fv.Data.Free_Space: # If Fv is a Section fv, free space need to be recalculated to keep align with BlockSize. # Other free space saved in self.Remain_New_Free_Space, will be moved to the 1st level Fv. if Delete_Fv.type == SEC_FV_TREE: Used_Size = Delete_Fv.Data.Size - Delete_Fv.Data.Free_Space - Add_Free_Space BlockSize = Delete_Fv.Data.Header.BlockMap[0].Length New_Free_Space = BlockSize - Used_Size % BlockSize self.Remain_New_Free_Space += Delete_Fv.Data.Free_Space + Add_Free_Space - New_Free_Space Delete_Fv.Child[-1].Data.Data = New_Free_Space * b'\xff' Delete_Fv.Data.Free_Space = New_Free_Space # If Fv is lst level Fv, new free space will be merged with origin free space. else: Used_Size = Delete_Fv.Data.Size - Delete_Fv.Data.Free_Space - Add_Free_Space Delete_Fv.Child[-1].Data.Data += Add_Free_Space * b'\xff' Delete_Fv.Data.Free_Space += Add_Free_Space New_Free_Space = Delete_Fv.Data.Free_Space # If Ffs parent Fv not have free space, will create new free space node to save the free space. else: # If Fv is a Section fv, new free space need to be recalculated to keep align with BlockSize. # Then create a Free spcae node to save the 0xff data, and insert into the Fv. # If have more space left, move to 1st level fv. if Delete_Fv.type == SEC_FV_TREE: Used_Size = Delete_Fv.Data.Size - Add_Free_Space BlockSize = Delete_Fv.Data.Header.BlockMap[0].Length New_Free_Space = BlockSize - Used_Size % BlockSize self.Remain_New_Free_Space += Add_Free_Space - New_Free_Space Add_Free_Space = New_Free_Space # If Fv is lst level Fv, new free space node will be created to save the free space. else: Used_Size = Delete_Fv.Data.Size - Add_Free_Space New_Free_Space = Add_Free_Space New_Free_Space_Info = FfsNode(Add_Free_Space * b'\xff') New_Free_Space_Info.Data = Add_Free_Space * b'\xff' New_Ffs_Tree = BIOSTREE(New_Free_Space_Info.Name) New_Ffs_Tree.type = FFS_FREE_SPACE New_Ffs_Tree.Data = New_Free_Space_Info Delete_Fv.insertChild(New_Ffs_Tree) Delete_Fv.Data.Free_Space = Add_Free_Space Delete_Fv.Child.remove(Delete_Ffs) Delete_Fv.Data.Header.FvLength = Used_Size + New_Free_Space Delete_Fv.Data.ModFvExt() Delete_Fv.Data.ModFvSize() Delete_Fv.Data.ModExtHeaderData() ModifyFvExtData(Delete_Fv) Delete_Fv.Data.ModCheckSum() # Recompress from the Fv node to update all the related node data. self.CompressData(Delete_Fv) self.Status = True logger.debug('Done!') return self.Status
def __getitem__(self, guid): if not self.tooldef: self.LoadingTools() guid_tool = self.tooldef.get(guid) if guid_tool: self.VerifyTools(guid_tool) return guid_tool else: logger.error("{} GuidTool is not defined!".format(guid)) raise Exception("Process Failed: is not defined!")
def LoadingTools(self) -> None: self.SetConfigFile() if os.path.exists(self.tooldef_file): with open(self.tooldef_file, "r") as fd: config_data = fd.readlines() for line in config_data: try: if not line.startswith("#"): guid, short_name, command = line.split() new_format_guid = struct2stream( ModifyGuidFormat(guid.strip())) self.tooldef[new_format_guid] = GUIDTool( guid.strip(), short_name.strip(), command.strip()) except: logger.error("GuidTool load error!") continue else: self.tooldef.update(self.default_tools)
def __init__(self, buffer: bytes) -> None: self.Header = EFI_FFS_FILE_HEADER.from_buffer_copy(buffer) # self.Attributes = unpack("<B", buffer[21:22])[0] if self.Header.FFS_FILE_SIZE != 0 and self.Header.Attributes != 0xff and self.Header.Attributes & 0x01 == 1: logger.error('Error Ffs Header! Ffs {} Header Size and Attributes is not matched!'.format(uuid.UUID(bytes_le=struct2stream(self.Header.Name)))) raise Exception("Process Failed: Error Ffs Header!") if self.Header.FFS_FILE_SIZE == 0 and self.Header.Attributes & 0x01 == 1: self.Header = EFI_FFS_FILE_HEADER2.from_buffer_copy(buffer) self.Name = uuid.UUID(bytes_le=struct2stream(self.Header.Name)) self.UiName = b'' self.Version = b'' self.Size = self.Header.FFS_FILE_SIZE self.HeaderLength = self.Header.HeaderLength self.HOffset = 0 self.DOffset = 0 self.ROffset = 0 self.Data = b'' self.PadData = b'' self.SectionMaxAlignment = SECTION_COMMON_ALIGNMENT # 4-align
def deleteNode(self, deletekey: str) -> None: FindStatus, DeleteTree = self.FindNode(deletekey) if FindStatus: parentTree = DeleteTree.Parent lastTree = DeleteTree.LastRel nextTree = DeleteTree.NextRel if parentTree: index = parentTree.Child.index(DeleteTree) del parentTree.Child[index] if lastTree and nextTree: lastTree.NextRel = nextTree nextTree.LastRel = lastTree elif lastTree: lastTree.NextRel = None elif nextTree: nextTree.LastRel = None return DeleteTree else: logger.error('Could not find the target tree') return None
def unpack(self, buffer: bytes) -> bytes: """ buffer: remove common header uncompress file """ tool = self.command if tool: tmp = tempfile.mkdtemp(dir=os.environ.get('tmp')) ToolInputFile = os.path.join(tmp, "unpack_sec_file") ToolOuputFile = os.path.join(tmp, "unpack_uncompress_sec_file") try: file = open(ToolInputFile, "wb") file.write(buffer) file.close() command = [tool, '-d', '-o', ToolOuputFile, ToolInputFile] ExecuteCommand(command) buf = open(ToolOuputFile, "rb") res_buffer = buf.read() except Exception as msg: logger.error(msg) return "" else: buf.close() if os.path.exists(tmp): shutil.rmtree(tmp) return res_buffer else: logger.error( "Error parsing section: EFI_SECTION_GUID_DEFINED cannot be parsed at this time." ) logger.info("Its GUID is: %s" % self.guid) return ""
def __init__(self, name, buffer: bytes) -> None: self.Header = EFI_FIRMWARE_VOLUME_HEADER.from_buffer_copy(buffer) Map_num = (self.Header.HeaderLength - 56)//8 self.Header = Refine_FV_Header(Map_num).from_buffer_copy(buffer) self.FvId = "FV" + str(name) self.Name = "FV" + str(name) if self.Header.ExtHeaderOffset: self.ExtHeader = EFI_FIRMWARE_VOLUME_EXT_HEADER.from_buffer_copy(buffer[self.Header.ExtHeaderOffset:]) self.Name = uuid.UUID(bytes_le=struct2stream(self.ExtHeader.FvName)) self.ExtEntryOffset = self.Header.ExtHeaderOffset + 20 if self.ExtHeader.ExtHeaderSize != 20: self.ExtEntryExist = 1 self.ExtEntry = EFI_FIRMWARE_VOLUME_EXT_ENTRY.from_buffer_copy(buffer[self.ExtEntryOffset:]) self.ExtTypeExist = 1 if self.ExtEntry.ExtEntryType == 0x01: nums = (self.ExtEntry.ExtEntrySize - 8) // 16 self.ExtEntry = Refine_FV_EXT_ENTRY_OEM_TYPE_Header(nums).from_buffer_copy(buffer[self.ExtEntryOffset:]) elif self.ExtEntry.ExtEntryType == 0x02: nums = self.ExtEntry.ExtEntrySize - 20 self.ExtEntry = Refine_FV_EXT_ENTRY_GUID_TYPE_Header(nums).from_buffer_copy(buffer[self.ExtEntryOffset:]) elif self.ExtEntry.ExtEntryType == 0x03: self.ExtEntry = EFI_FIRMWARE_VOLUME_EXT_ENTRY_USED_SIZE_TYPE.from_buffer_copy(buffer[self.ExtEntryOffset:]) else: self.ExtTypeExist = 0 else: self.ExtEntryExist = 0 self.Size = self.Header.FvLength self.HeaderLength = self.Header.HeaderLength self.HOffset = 0 self.DOffset = 0 self.ROffset = 0 self.Data = b'' if self.Header.Signature != 1213613663: logger.error('Invalid Fv Header! Fv {} signature {} is not "_FVH".'.format(struct2stream(self.Header), self.Header.Signature)) raise Exception("Process Failed: Fv Header Signature!") self.PadData = b'' self.Free_Space = 0 self.ModCheckSum()
def dump(self,layoutdict: dict, layoutlist: list, outputfile: str=None) -> None: logger.info('Binary Layout Info is saved in {} file.'.format(outputfile)) with open(outputfile, "w") as f: for item in layoutlist: f.writelines(item + '\n')
def CompressSectionData(self, TargetTree, pos: int, GuidTool=None) -> None: NewData = b'' temp_save_child = TargetTree.Child if TargetTree.Data: # Update current node data as adding all the header and data of its child node. for item in temp_save_child: if item.type == SECTION_TREE and not item.Data.OriData and item.Data.ExtHeader: NewData += struct2stream(item.Data.Header) + struct2stream( item.Data.ExtHeader ) + item.Data.Data + item.Data.PadData elif item.type == SECTION_TREE and item.Data.OriData and not item.Data.ExtHeader: NewData += struct2stream( item.Data.Header ) + item.Data.OriData + item.Data.PadData elif item.type == SECTION_TREE and item.Data.OriData and item.Data.ExtHeader: NewData += struct2stream(item.Data.Header) + struct2stream( item.Data.ExtHeader ) + item.Data.OriData + item.Data.PadData elif item.type == FFS_FREE_SPACE: NewData += item.Data.Data + item.Data.PadData else: NewData += struct2stream( item.Data.Header) + item.Data.Data + item.Data.PadData # If node is FFS_TREE, update Pad data and Header info. # Remain_New_Free_Space is used for move more free space into lst level Fv. if TargetTree.type == FFS_TREE: New_Pad_Size = GetPadSize(len(NewData), 8) Size_delta = len(NewData) - len(TargetTree.Data.Data) ChangeSize(TargetTree, -Size_delta) Delta_Pad_Size = len(TargetTree.Data.PadData) - New_Pad_Size self.Remain_New_Free_Space += Delta_Pad_Size TargetTree.Data.PadData = b'\xff' * New_Pad_Size TargetTree.Data.ModCheckSum() # If node is FV_TREE, update Pad data and Header info. # Consume Remain_New_Free_Space is used for move more free space into lst level Fv. elif TargetTree.type == FV_TREE or TargetTree.type == SEC_FV_TREE and not pos: if self.Remain_New_Free_Space: if TargetTree.Data.Free_Space: TargetTree.Data.Free_Space += self.Remain_New_Free_Space NewData += self.Remain_New_Free_Space * b'\xff' TargetTree.Child[ -1].Data.Data += self.Remain_New_Free_Space * b'\xff' else: TargetTree.Data.Data += self.Remain_New_Free_Space * b'\xff' New_Free_Space = BIOSTREE('FREE_SPACE') New_Free_Space.type = FFS_FREE_SPACE New_Free_Space.Data = FreeSpaceNode( b'\xff' * self.Remain_New_Free_Space) TargetTree.insertChild(New_Free_Space) self.Remain_New_Free_Space = 0 if TargetTree.type == SEC_FV_TREE: Size_delta = len( NewData) + self.Remain_New_Free_Space - len( TargetTree.Data.Data) TargetTree.Data.Header.FvLength += Size_delta TargetTree.Data.ModFvExt() TargetTree.Data.ModFvSize() TargetTree.Data.ModExtHeaderData() ModifyFvExtData(TargetTree) TargetTree.Data.ModCheckSum() # If node is SECTION_TREE and not guided section, update Pad data and Header info. # Remain_New_Free_Space is used for move more free space into lst level Fv. elif TargetTree.type == SECTION_TREE and TargetTree.Data.Type != 0x02: New_Pad_Size = GetPadSize(len(NewData), 4) Size_delta = len(NewData) - len(TargetTree.Data.Data) ChangeSize(TargetTree, -Size_delta) if TargetTree.NextRel: Delta_Pad_Size = len( TargetTree.Data.PadData) - New_Pad_Size self.Remain_New_Free_Space += Delta_Pad_Size TargetTree.Data.PadData = b'\x00' * New_Pad_Size TargetTree.Data.Data = NewData if GuidTool: guidtool = GUIDTools().__getitem__(struct2stream(GuidTool)) if not guidtool.ifexist: logger.error( "GuidTool {} is not found when decompressing {} file.\n". format(guidtool.command, TargetTree.Parent.Data.Name)) raise Exception("Process Failed: GuidTool not found!") CompressedData = guidtool.pack(TargetTree.Data.Data) if len(CompressedData) < len(TargetTree.Data.OriData): New_Pad_Size = GetPadSize(len(CompressedData), SECTION_COMMON_ALIGNMENT) Size_delta = len(CompressedData) - len(TargetTree.Data.OriData) ChangeSize(TargetTree, -Size_delta) if TargetTree.NextRel: TargetTree.Data.PadData = b'\x00' * New_Pad_Size self.Remain_New_Free_Space = len( TargetTree.Data.OriData) + len( TargetTree.Data.PadData) - len( CompressedData) - New_Pad_Size else: TargetTree.Data.PadData = b'' self.Remain_New_Free_Space = len( TargetTree.Data.OriData) - len(CompressedData) TargetTree.Data.OriData = CompressedData elif len(CompressedData) == len(TargetTree.Data.OriData): TargetTree.Data.OriData = CompressedData elif len(CompressedData) > len(TargetTree.Data.OriData): New_Pad_Size = GetPadSize(len(CompressedData), SECTION_COMMON_ALIGNMENT) self.Remain_New_Free_Space = len( CompressedData) + New_Pad_Size - len( TargetTree.Data.OriData) - len(TargetTree.Data.PadData) self.ModifyTest(TargetTree, self.Remain_New_Free_Space) self.Status = True
def AddNewFfs(inputfile: str, Fv_name: str, newffsfile: str, outputfile: str) -> None: if not os.path.exists(inputfile): logger.error("Invalid inputfile, can not open {}.".format(inputfile)) raise Exception("Process Failed: Invalid inputfile!") if not os.path.exists(newffsfile): logger.error("Invalid ffsfile, can not open {}.".format(newffsfile)) raise Exception("Process Failed: Invalid ffs file!") # 1. Data Prepare with open(inputfile, "rb") as f: whole_data = f.read() FmmtParser = FMMTParser(inputfile, ROOT_TREE) # 2. DataTree Create logger.debug('Parsing inputfile data......') FmmtParser.ParserFromRoot(FmmtParser.WholeFvTree, whole_data) logger.debug('Done!') # Get Target Fv and Target Ffs_Pad FmmtParser.WholeFvTree.FindNode(Fv_name, FmmtParser.WholeFvTree.Findlist) # Create new ffs Tree with open(newffsfile, "rb") as f: new_ffs_data = f.read() NewFmmtParser = FMMTParser(newffsfile, ROOT_FFS_TREE) Status = False # 3. Data Modify if FmmtParser.WholeFvTree.Findlist: for TargetFv in FmmtParser.WholeFvTree.Findlist: TargetFfsPad = TargetFv.Child[-1] logger.debug('Parsing newffsfile data......') if TargetFfsPad.type == FFS_FREE_SPACE: NewFmmtParser.ParserFromRoot(NewFmmtParser.WholeFvTree, new_ffs_data, TargetFfsPad.Data.HOffset) else: NewFmmtParser.ParserFromRoot( NewFmmtParser.WholeFvTree, new_ffs_data, TargetFfsPad.Data.HOffset + TargetFfsPad.Data.Size) logger.debug('Done!') FfsMod = FvHandler(NewFmmtParser.WholeFvTree.Child[0], TargetFfsPad) Status = FfsMod.AddFfs() else: logger.error('Target Fv not found!!!') # 4. Data Encapsulation if Status: logger.debug('Start encapsulating data......') FmmtParser.Encapsulation(FmmtParser.WholeFvTree, False) with open(outputfile, "wb") as f: f.write(FmmtParser.FinalData) logger.debug('Encapsulated data is saved in {}.'.format(outputfile))
def DeleteFfs(inputfile: str, TargetFfs_name: str, outputfile: str, Fv_name: str = None) -> None: if not os.path.exists(inputfile): logger.error("Invalid inputfile, can not open {}.".format(inputfile)) raise Exception("Process Failed: Invalid inputfile!") # 1. Data Prepare with open(inputfile, "rb") as f: whole_data = f.read() FmmtParser = FMMTParser(inputfile, ROOT_TREE) # 2. DataTree Create logger.debug('Parsing inputfile data......') FmmtParser.ParserFromRoot(FmmtParser.WholeFvTree, whole_data) logger.debug('Done!') # 3. Data Modify FmmtParser.WholeFvTree.FindNode(TargetFfs_name, FmmtParser.WholeFvTree.Findlist) # Choose the Specfic DeleteFfs with Fv info if Fv_name: for item in FmmtParser.WholeFvTree.Findlist: if item.Parent.key != Fv_name and item.Parent.Data.Name != Fv_name: FmmtParser.WholeFvTree.Findlist.remove(item) Status = False if FmmtParser.WholeFvTree.Findlist != []: for Delete_Ffs in FmmtParser.WholeFvTree.Findlist: FfsMod = FvHandler(None, Delete_Ffs) Status = FfsMod.DeleteFfs() else: logger.error('Target Ffs not found!!!') # 4. Data Encapsulation if Status: logger.debug('Start encapsulating data......') FmmtParser.Encapsulation(FmmtParser.WholeFvTree, False) with open(outputfile, "wb") as f: f.write(FmmtParser.FinalData) logger.debug('Encapsulated data is saved in {}.'.format(outputfile))
def ModifyTest(self, ParTree, Needed_Space: int) -> None: # If have needed space, will find if there have free space in parent tree, meanwhile update the node data. if Needed_Space > 0: # If current node is a Fv node if ParTree.type == FV_TREE or ParTree.type == SEC_FV_TREE: ParTree.Data.Data = b'' # First check if Fv free space is enough for needed space. # If so, use the current Fv free space; # Else, use all the Free space, and recalculate needed space, continue finding in its parent node. Needed_Space = Needed_Space - ParTree.Data.Free_Space if Needed_Space < 0: ParTree.Child[-1].Data.Data = b'\xff' * (-Needed_Space) ParTree.Data.Free_Space = (-Needed_Space) self.Status = True else: if ParTree.type == FV_TREE: self.Status = False else: BlockSize = ParTree.Data.Header.BlockMap[0].Length New_Add_Len = BlockSize - Needed_Space % BlockSize if New_Add_Len % BlockSize: ParTree.Child[-1].Data.Data = b'\xff' * New_Add_Len ParTree.Data.Free_Space = New_Add_Len Needed_Space += New_Add_Len else: ParTree.Child.remove(ParTree.Child[-1]) ParTree.Data.Free_Space = 0 ParTree.Data.Size += Needed_Space ParTree.Data.Header.Fvlength = ParTree.Data.Size ModifyFvSystemGuid(ParTree) for item in ParTree.Child: if item.type == FFS_FREE_SPACE: ParTree.Data.Data += item.Data.Data + item.Data.PadData else: ParTree.Data.Data += struct2stream( item.Data.Header ) + item.Data.Data + item.Data.PadData ParTree.Data.ModFvExt() ParTree.Data.ModFvSize() ParTree.Data.ModExtHeaderData() ModifyFvExtData(ParTree) ParTree.Data.ModCheckSum() # If current node is a Ffs node elif ParTree.type == FFS_TREE: ParTree.Data.Data = b'' OriHeaderLen = ParTree.Data.HeaderLength # Update its data as adding all the header and data of its child node. for item in ParTree.Child: if item.Data.OriData: if item.Data.ExtHeader: ParTree.Data.Data += struct2stream( item.Data.Header) + struct2stream( item.Data.ExtHeader ) + item.Data.OriData + item.Data.PadData else: ParTree.Data.Data += struct2stream( item.Data.Header ) + item.Data.OriData + item.Data.PadData else: if item.Data.ExtHeader: ParTree.Data.Data += struct2stream( item.Data.Header) + struct2stream( item.Data.ExtHeader ) + item.Data.Data + item.Data.PadData else: ParTree.Data.Data += struct2stream( item.Data.Header ) + item.Data.Data + item.Data.PadData ChangeSize(ParTree, -Needed_Space) ModifyFfsType(ParTree) # Recalculate pad data, update needed space with Delta_Pad_Size. Needed_Space += ParTree.Data.HeaderLength - OriHeaderLen New_Pad_Size = GetPadSize(ParTree.Data.Size, FFS_COMMON_ALIGNMENT) Delta_Pad_Size = New_Pad_Size - len(ParTree.Data.PadData) Needed_Space += Delta_Pad_Size ParTree.Data.PadData = b'\xff' * GetPadSize( ParTree.Data.Size, FFS_COMMON_ALIGNMENT) ParTree.Data.ModCheckSum() # If current node is a Section node elif ParTree.type == SECTION_TREE: OriData = ParTree.Data.Data OriHeaderLen = ParTree.Data.HeaderLength ParTree.Data.Data = b'' # Update its data as adding all the header and data of its child node. for item in ParTree.Child: if item.type == SECTION_TREE and item.Data.ExtHeader and item.Data.Type != 0x02: ParTree.Data.Data += struct2stream( item.Data.Header) + struct2stream( item.Data.ExtHeader ) + item.Data.Data + item.Data.PadData elif item.type == SECTION_TREE and item.Data.ExtHeader and item.Data.Type == 0x02: ParTree.Data.Data += struct2stream( item.Data.Header) + struct2stream( item.Data.ExtHeader ) + item.Data.OriData + item.Data.PadData else: ParTree.Data.Data += struct2stream( item.Data.Header ) + item.Data.Data + item.Data.PadData # If the current section is guided section if ParTree.Data.Type == 0x02: guidtool = GUIDTools().__getitem__( struct2stream( ParTree.Data.ExtHeader.SectionDefinitionGuid)) if not guidtool.ifexist: logger.error( "GuidTool {} is not found when decompressing {} file.\n" .format(guidtool.command, ParTree.Parent.Data.Name)) raise Exception("Process Failed: GuidTool not found!") # Recompress current data, and recalculate the needed space CompressedData = guidtool.pack(ParTree.Data.Data) Needed_Space = len(CompressedData) - len( ParTree.Data.OriData) ParTree.Data.OriData = CompressedData New_Size = ParTree.Data.HeaderLength + len(CompressedData) ParTree.Data.Header.Size[0] = New_Size % (16**2) ParTree.Data.Header.Size[1] = New_Size % (16**4) // (16**2) ParTree.Data.Header.Size[2] = New_Size // (16**4) ParTree.Data.Size = ParTree.Data.Header.SECTION_SIZE ModifySectionType(ParTree) Needed_Space += ParTree.Data.HeaderLength - OriHeaderLen # Update needed space with Delta_Pad_Size if ParTree.NextRel: New_Pad_Size = GetPadSize(ParTree.Data.Size, SECTION_COMMON_ALIGNMENT) Delta_Pad_Size = New_Pad_Size - len( ParTree.Data.PadData) ParTree.Data.PadData = b'\x00' * New_Pad_Size Needed_Space += Delta_Pad_Size else: ParTree.Data.PadData = b'' if Needed_Space < 0: self.Remain_New_Free_Space = len( ParTree.Data.OriData) - len(CompressedData) # If current section is not guided section elif Needed_Space: ChangeSize(ParTree, -Needed_Space) ModifySectionType(ParTree) # Update needed space with Delta_Pad_Size Needed_Space += ParTree.Data.HeaderLength - OriHeaderLen New_Pad_Size = GetPadSize(ParTree.Data.Size, SECTION_COMMON_ALIGNMENT) Delta_Pad_Size = New_Pad_Size - len(ParTree.Data.PadData) Needed_Space += Delta_Pad_Size ParTree.Data.PadData = b'\x00' * New_Pad_Size NewParTree = ParTree.Parent ROOT_TYPE = [ ROOT_FV_TREE, ROOT_FFS_TREE, ROOT_SECTION_TREE, ROOT_TREE ] if NewParTree and NewParTree.type not in ROOT_TYPE: self.ModifyTest(NewParTree, Needed_Space) # If current node have enough space, will recompress all the related node data, return true. else: self.CompressData(ParTree) self.Status = True
def ViewFile(inputfile: str, ROOT_TYPE: str, layoutfile: str = None, outputfile: str = None) -> None: if not os.path.exists(inputfile): logger.error("Invalid inputfile, can not open {}.".format(inputfile)) raise Exception("Process Failed: Invalid inputfile!") # 1. Data Prepare with open(inputfile, "rb") as f: whole_data = f.read() FmmtParser = FMMTParser(inputfile, ROOT_TYPE) # 2. DataTree Create logger.debug('Parsing inputfile data......') FmmtParser.ParserFromRoot(FmmtParser.WholeFvTree, whole_data) logger.debug('Done!') # 3. Log Output InfoDict = FmmtParser.WholeFvTree.ExportTree() logger.debug('BinaryTree created, start parsing BinaryTree data......') FmmtParser.WholeFvTree.parserTree(InfoDict, FmmtParser.BinaryInfo) logger.debug('Done!') GetFormatter("").LogPrint(FmmtParser.BinaryInfo) if layoutfile: if os.path.splitext(layoutfile)[1]: layoutfilename = layoutfile layoutfileformat = os.path.splitext(layoutfile)[1][1:].lower() else: layoutfilename = "Layout_{}{}".format( os.path.basename(inputfile), ".{}".format(layoutfile.lower())) layoutfileformat = layoutfile.lower() GetFormatter(layoutfileformat).dump(InfoDict, FmmtParser.BinaryInfo, layoutfilename) # 4. Data Encapsulation if outputfile: logger.debug('Start encapsulating data......') FmmtParser.Encapsulation(FmmtParser.WholeFvTree, False) with open(outputfile, "wb") as f: f.write(FmmtParser.FinalData) logger.debug('Encapsulated data is saved in {}.'.format(outputfile))
def ReplaceFfs(inputfile: str, Ffs_name: str, newffsfile: str, outputfile: str, Fv_name: str = None) -> None: if not os.path.exists(inputfile): logger.error("Invalid inputfile, can not open {}.".format(inputfile)) raise Exception("Process Failed: Invalid inputfile!") # 1. Data Prepare with open(inputfile, "rb") as f: whole_data = f.read() FmmtParser = FMMTParser(inputfile, ROOT_TREE) # 2. DataTree Create logger.debug('Parsing inputfile data......') FmmtParser.ParserFromRoot(FmmtParser.WholeFvTree, whole_data) logger.debug('Done!') with open(newffsfile, "rb") as f: new_ffs_data = f.read() newFmmtParser = FMMTParser(newffsfile, FV_TREE) logger.debug('Parsing newffsfile data......') newFmmtParser.ParserFromRoot(newFmmtParser.WholeFvTree, new_ffs_data) logger.debug('Done!') Status = False # 3. Data Modify new_ffs = newFmmtParser.WholeFvTree.Child[0] new_ffs.Data.PadData = GetPadSize(new_ffs.Data.Size, FFS_COMMON_ALIGNMENT) * b'\xff' FmmtParser.WholeFvTree.FindNode(Ffs_name, FmmtParser.WholeFvTree.Findlist) if Fv_name: for item in FmmtParser.WholeFvTree.Findlist: if item.Parent.key != Fv_name and item.Parent.Data.Name != Fv_name: FmmtParser.WholeFvTree.Findlist.remove(item) if FmmtParser.WholeFvTree.Findlist != []: for TargetFfs in FmmtParser.WholeFvTree.Findlist: FfsMod = FvHandler(newFmmtParser.WholeFvTree.Child[0], TargetFfs) Status = FfsMod.ReplaceFfs() else: logger.error('Target Ffs not found!!!') # 4. Data Encapsulation if Status: logger.debug('Start encapsulating data......') FmmtParser.Encapsulation(FmmtParser.WholeFvTree, False) with open(outputfile, "wb") as f: f.write(FmmtParser.FinalData) logger.debug('Encapsulated data is saved in {}.'.format(outputfile))
def ReplaceFfs(self) -> bool: logger.debug('Start Replacing Process......') TargetFv = self.TargetFfs.Parent # If the Fv Header Attributes is EFI_FVB2_ERASE_POLARITY, Child Ffs Header State need be reversed. if TargetFv.Data.Header.Attributes & EFI_FVB2_ERASE_POLARITY: self.NewFfs.Data.Header.State = c_uint8( ~self.NewFfs.Data.Header.State) # NewFfs parsing will not calculate the PadSize, thus recalculate. self.NewFfs.Data.PadData = b'\xff' * GetPadSize( self.NewFfs.Data.Size, FFS_COMMON_ALIGNMENT) if self.NewFfs.Data.Size >= self.TargetFfs.Data.Size: Needed_Space = self.NewFfs.Data.Size + len( self.NewFfs.Data.PadData) - self.TargetFfs.Data.Size - len( self.TargetFfs.Data.PadData) # If TargetFv have enough free space, just move part of the free space to NewFfs. if TargetFv.Data.Free_Space >= Needed_Space: # Modify TargetFv Child info and BiosTree. TargetFv.Child[-1].Data.Data = b'\xff' * ( TargetFv.Data.Free_Space - Needed_Space) TargetFv.Data.Free_Space -= Needed_Space Target_index = TargetFv.Child.index(self.TargetFfs) TargetFv.Child.remove(self.TargetFfs) TargetFv.insertChild(self.NewFfs, Target_index) # Modify TargetFv Header and ExtHeader info. TargetFv.Data.ModFvExt() TargetFv.Data.ModFvSize() TargetFv.Data.ModExtHeaderData() ModifyFvExtData(TargetFv) TargetFv.Data.ModCheckSum() # Recompress from the Fv node to update all the related node data. self.CompressData(TargetFv) # return the Status self.Status = True # If TargetFv do not have enough free space, need move part of the free space of TargetFv's parent Fv to TargetFv/NewFfs. else: if TargetFv.type == FV_TREE: self.Status = False else: # Recalculate TargetFv needed space to keep it match the BlockSize setting. Needed_Space -= TargetFv.Data.Free_Space BlockSize = TargetFv.Data.Header.BlockMap[0].Length New_Add_Len = BlockSize - Needed_Space % BlockSize Target_index = TargetFv.Child.index(self.TargetFfs) if New_Add_Len % BlockSize: TargetFv.Child[-1].Data.Data = b'\xff' * New_Add_Len TargetFv.Data.Free_Space = New_Add_Len Needed_Space += New_Add_Len TargetFv.insertChild(self.NewFfs, Target_index) TargetFv.Child.remove(self.TargetFfs) else: TargetFv.Child.remove(self.TargetFfs) TargetFv.Data.Free_Space = 0 TargetFv.insertChild(self.NewFfs) # Encapsulate the Fv Data for update. TargetFv.Data.Data = b'' for item in TargetFv.Child: if item.type == FFS_FREE_SPACE: TargetFv.Data.Data += item.Data.Data + item.Data.PadData else: TargetFv.Data.Data += struct2stream( item.Data.Header ) + item.Data.Data + item.Data.PadData TargetFv.Data.Size += Needed_Space # Modify TargetFv Data Header and ExtHeader info. TargetFv.Data.Header.FvLength = TargetFv.Data.Size TargetFv.Data.ModFvExt() TargetFv.Data.ModFvSize() TargetFv.Data.ModExtHeaderData() ModifyFvExtData(TargetFv) TargetFv.Data.ModCheckSum() # Start free space calculating and moving process. self.ModifyTest(TargetFv.Parent, Needed_Space) else: New_Free_Space = self.TargetFfs.Data.Size - self.NewFfs.Data.Size # If TargetFv already have free space, move the new free space into it. if TargetFv.Data.Free_Space: TargetFv.Child[-1].Data.Data += b'\xff' * New_Free_Space TargetFv.Data.Free_Space += New_Free_Space Target_index = TargetFv.Child.index(self.TargetFfs) TargetFv.Child.remove(self.TargetFfs) TargetFv.insertChild(self.NewFfs, Target_index) self.Status = True # If TargetFv do not have free space, create free space for Fv. else: New_Free_Space_Tree = BIOSTREE('FREE_SPACE') New_Free_Space_Tree.type = FFS_FREE_SPACE New_Free_Space_Tree.Data = FfsNode(b'\xff' * New_Free_Space) TargetFv.Data.Free_Space = New_Free_Space TargetFv.insertChild(New_Free_Space) Target_index = TargetFv.Child.index(self.TargetFfs) TargetFv.Child.remove(self.TargetFfs) TargetFv.insertChild(self.NewFfs, Target_index) self.Status = True # Modify TargetFv Header and ExtHeader info. TargetFv.Data.ModFvExt() TargetFv.Data.ModFvSize() TargetFv.Data.ModExtHeaderData() ModifyFvExtData(TargetFv) TargetFv.Data.ModCheckSum() # Recompress from the Fv node to update all the related node data. self.CompressData(TargetFv) logger.debug('Done!') return self.Status
def VerifyTools(self, guidtool) -> None: """ Verify Tools and Update Tools path. """ path_env = os.environ.get("PATH") path_env_list = path_env.split(os.pathsep) path_env_list.append(os.path.dirname(__file__)) path_env_list = list(set(path_env_list)) cmd = guidtool.command if os.path.isabs(cmd): if not os.path.exists(cmd): if guidtool not in self.default_tools: logger.error( "Tool Not found %s, which causes compress/uncompress process error." % cmd) logger.error( "Please goto edk2 repo in current console, run 'edksetup.bat rebuild' command, and try again.\n" ) else: logger.error( "Tool Not found %s, which causes compress/uncompress process error." % cmd) else: guidtool.ifexist = True else: for syspath in path_env_list: if glob.glob(os.path.join(syspath, cmd + "*")): guidtool.ifexist = True break else: if guidtool not in self.default_tools: logger.error( "Tool Not found %s, which causes compress/uncompress process error." % cmd) logger.error( "Please goto edk2 repo in current console, run 'edksetup.bat rebuild' command, and try again.\n" ) else: logger.error( "Tool Not found %s, which causes compress/uncompress process error." % cmd)
def AddFfs(self) -> bool: logger.debug('Start Adding Process......') # NewFfs parsing will not calculate the PadSize, thus recalculate. self.NewFfs.Data.PadData = b'\xff' * GetPadSize( self.NewFfs.Data.Size, FFS_COMMON_ALIGNMENT) if self.TargetFfs.type == FFS_FREE_SPACE: TargetLen = self.NewFfs.Data.Size + len( self.NewFfs.Data.PadData) - self.TargetFfs.Data.Size - len( self.TargetFfs.Data.PadData) TargetFv = self.TargetFfs.Parent # If the Fv Header Attributes is EFI_FVB2_ERASE_POLARITY, Child Ffs Header State need be reversed. if TargetFv.Data.Header.Attributes & EFI_FVB2_ERASE_POLARITY: self.NewFfs.Data.Header.State = c_uint8( ~self.NewFfs.Data.Header.State) # If TargetFv have enough free space, just move part of the free space to NewFfs, split free space to NewFfs and new free space. if TargetLen < 0: self.Status = True self.TargetFfs.Data.Data = b'\xff' * (-TargetLen) TargetFv.Data.Free_Space = (-TargetLen) TargetFv.Data.ModFvExt() TargetFv.Data.ModExtHeaderData() ModifyFvExtData(TargetFv) TargetFv.Data.ModCheckSum() TargetFv.insertChild(self.NewFfs, -1) ModifyFfsType(self.NewFfs) # Recompress from the Fv node to update all the related node data. self.CompressData(TargetFv) elif TargetLen == 0: self.Status = True TargetFv.Child.remove(self.TargetFfs) TargetFv.insertChild(self.NewFfs) ModifyFfsType(self.NewFfs) # Recompress from the Fv node to update all the related node data. self.CompressData(TargetFv) # If TargetFv do not have enough free space, need move part of the free space of TargetFv's parent Fv to TargetFv/NewFfs. else: if TargetFv.type == FV_TREE: self.Status = False elif TargetFv.type == SEC_FV_TREE: # Recalculate TargetFv needed space to keep it match the BlockSize setting. BlockSize = TargetFv.Data.Header.BlockMap[0].Length New_Add_Len = BlockSize - TargetLen % BlockSize if New_Add_Len % BlockSize: self.TargetFfs.Data.Data = b'\xff' * New_Add_Len self.TargetFfs.Data.Size = New_Add_Len TargetLen += New_Add_Len TargetFv.insertChild(self.NewFfs, -1) TargetFv.Data.Free_Space = New_Add_Len else: TargetFv.Child.remove(self.TargetFfs) TargetFv.insertChild(self.NewFfs) TargetFv.Data.Free_Space = 0 ModifyFfsType(self.NewFfs) ModifyFvSystemGuid(TargetFv) TargetFv.Data.Data = b'' for item in TargetFv.Child: if item.type == FFS_FREE_SPACE: TargetFv.Data.Data += item.Data.Data + item.Data.PadData else: TargetFv.Data.Data += struct2stream( item.Data.Header ) + item.Data.Data + item.Data.PadData # Encapsulate the Fv Data for update. TargetFv.Data.Size += TargetLen TargetFv.Data.Header.FvLength = TargetFv.Data.Size TargetFv.Data.ModFvExt() TargetFv.Data.ModFvSize() TargetFv.Data.ModExtHeaderData() ModifyFvExtData(TargetFv) TargetFv.Data.ModCheckSum() # Start free space calculating and moving process. self.ModifyTest(TargetFv.Parent, TargetLen) else: # If TargetFv do not have free space, need directly move part of the free space of TargetFv's parent Fv to TargetFv/NewFfs. TargetLen = self.NewFfs.Data.Size + len(self.NewFfs.Data.PadData) TargetFv = self.TargetFfs.Parent if TargetFv.Data.Header.Attributes & EFI_FVB2_ERASE_POLARITY: self.NewFfs.Data.Header.State = c_uint8( ~self.NewFfs.Data.Header.State) if TargetFv.type == FV_TREE: self.Status = False elif TargetFv.type == SEC_FV_TREE: BlockSize = TargetFv.Data.Header.BlockMap[0].Length New_Add_Len = BlockSize - TargetLen % BlockSize if New_Add_Len % BlockSize: New_Free_Space = BIOSTREE('FREE_SPACE') New_Free_Space.type = FFS_FREE_SPACE New_Free_Space.Data = FreeSpaceNode(b'\xff' * New_Add_Len) TargetLen += New_Add_Len TargetFv.Data.Free_Space = New_Add_Len TargetFv.insertChild(self.NewFfs) TargetFv.insertChild(New_Free_Space) else: TargetFv.insertChild(self.NewFfs) ModifyFfsType(self.NewFfs) ModifyFvSystemGuid(TargetFv) TargetFv.Data.Data = b'' for item in TargetFv.Child: if item.type == FFS_FREE_SPACE: TargetFv.Data.Data += item.Data.Data + item.Data.PadData else: TargetFv.Data.Data += struct2stream( item.Data.Header ) + item.Data.Data + item.Data.PadData TargetFv.Data.Size += TargetLen TargetFv.Data.Header.FvLength = TargetFv.Data.Size TargetFv.Data.ModFvExt() TargetFv.Data.ModFvSize() TargetFv.Data.ModExtHeaderData() ModifyFvExtData(TargetFv) TargetFv.Data.ModCheckSum() self.ModifyTest(TargetFv.Parent, TargetLen) logger.debug('Done!') return self.Status