예제 #1
0
 def handle_streaming(self, cmd, options):
     mode = 0
     if "<mode>" in options:
         mode = options["<mode>"]
     if self.streaming.connect(mode):
         xflag = 0
         self.streaming.nand_init(xflag)
         if cmd == "gpt":
             directory = options["<directory>"]
             if directory is None:
                 directory = ""
             data = self.streaming.read_partition_table()
             sfilename = os.path.join(directory, f"partition.bin")
             if data != b"":
                 with open(sfilename, "wb") as write_handle:
                     write_handle.write(data)
                 self.printer(f"Dumped Partition Table to {sfilename}")
             else:
                 self.LOGGER.error(f"Error on dumping partition table to {sfilename}")
         elif cmd == "printgpt":
             partitions = self.streaming.get_partitions()
             self.print_partitions(partitions)
             self.streaming.nand_post()
         elif cmd == "r":
             partitionname = options["<partitionname>"]
             filename = options["<filename>"]
             filenames = filename.split(",")
             partitions = partitionname.split(",")
             if len(partitions) != len(filenames):
                 self.LOGGER.error("You need to gives as many filenames as given partitions.")
                 return
             i = 0
             rpartitions = self.streaming.get_partitions()
             for partition in partitions:
                 if partition.lower() in rpartitions:
                     spartition = rpartitions[partition]
                     offset = spartition["offset"]
                     length = spartition["length"]
                     # attr1 = spartition["attr1"]
                     # attr2 = spartition["attr2"]
                     # attr3 = spartition["attr3"]
                     partfilename = filenames[i]
                     self.printer(f"Dumping Partition {partition}...")
                     self.streaming.read_raw(offset, length, self.streaming.settings.UD_SIZE_BYTES, partfilename)
                     self.printer(f"Dumped sector {str(offset)} with sector count {str(length)} as {partfilename}.")
                 else:
                     self.LOGGER.error(f"Error: Couldn't detect partition: {partition}\nAvailable partitions:")
                     self.print_partitions(rpartitions)
         elif cmd == "rs":
             start = int(options["<start_sector>"])
             sectors = int(options["<sectors>"])
             filename = options["<filename>"]
             self.printer(f"Dumping Sector {hex(start)} with Sectorcount {hex(sectors)}...")
             block = 131
             page = 0x20
             data, extra = self.streaming.flash_read(block, page, sectors, self.streaming.settings.UD_SIZE_BYTES)
             try:
                 with open(filename, "wb") as write_handle:
                     write_handle.write(data)
                     self.printer(f"Dumped sector {str(start)} with sector count {str(sectors)} as {filename}.")
                     return
             except Exception as error:
                 self.LOGGER.error(f"Couldn't open {filename} for writing: %s" % str(error))
             self.streaming.nand_post()
         elif cmd == "rl":
             directory = options["<directory>"]
             if options["--skip"]:
                 skip = options["--skip"].split(",")
             else:
                 skip = []
             if not os.path.exists(directory):
                 os.mkdir(directory)
             storedir = directory
             if not os.path.exists(storedir):
                 os.mkdir(storedir)
             sfilename = os.path.join(storedir, f"partition.bin")
             partdata = self.streaming.read_partition_table()
             if partdata != -1:
                 with open(sfilename, "wb") as write_handle:
                     write_handle.write(partdata)
             else:
                 self.LOGGER.error(f"Couldn't detect partition header.")
                 return
             partitions = self.streaming.get_partitions()
             for partition in partitions:
                 if partition in skip:
                     continue
                 filename = os.path.join(storedir, partition + ".bin")
                 spartition = partitions[partition]
                 offset = spartition["offset"]
                 length = spartition["length"]
                 # attr1 = spartition["attr1"]
                 # attr2 = spartition["attr2"]
                 # attr3 = spartition["attr3"]
                 partfilename = filename
                 self.LOGGER.info(f"Dumping partition {str(partition)} with block count {str(length)} as " +
                                  f"{filename}.")
                 self.streaming.read_raw(offset, length, self.streaming.settings.UD_SIZE_BYTES, partfilename)
         elif cmd == "peek":
             offset = int(options["<offset>"], 16)
             length = int(options["<length>"], 16)
             filename = options["<filename>"]
             with open(filename, "wb") as wf:
                 while length > 0:
                     size = 0x20000
                     if length < size:
                         size = length
                         data = self.streaming.memread(offset, size)
                         if data != b"":
                             wf.write(data)
                         else:
                             break
                     length -= size
             self.LOGGER.info(
                 f"Peek data from offset {hex(offset)} and length {hex(length)} was written to {filename}")
         elif cmd == "peekhex":
             offset = int(options["<offset>"], 16)
             length = int(options["<length>"], 16)
             resp = self.streaming.memread(offset, length)
             self.printer("\n")
             self.printer(hexlify(resp))
         elif cmd == "peekqword":
             offset = int(options["<offset>"], 16)
             resp = self.streaming.memread(offset, 8)
             self.printer("\n")
             self.printer(hex(unpack("<Q", resp[:8])[0]))
         elif cmd == "peekdword":
             offset = int(options["<offset>"], 16)
             resp = self.streaming.mempeek(offset)
             self.printer("\n")
             self.printer(hex(resp))
         elif cmd == "poke":
             offset = int(options["<offset>"], 16)
             filename = unhexlify(options["<filename>"])
             try:
                 with open(filename, "rb") as rf:
                     data = rf.read()
                     if self.streaming.memwrite(offset, data):
                         self.LOGGER.info("Poke succeeded.")
                     else:
                         self.LOGGER.error("Poke failed.")
             except Exception as e:
                 self.LOGGER.error(str(e))
         elif cmd == "pokehex":
             offset = int(options["<offset>"], 16)
             data = unhexlify(options["<data>"])
             if self.streaming.memwrite(offset, data):
                 self.LOGGER.info("Poke succeeded.")
             else:
                 self.LOGGER.error("Poke failed.")
         elif cmd == "pokeqword":
             offset = int(options["<offset>"], 16)
             data = pack("<Q", int(options["<data>"], 16))
             if self.streaming.memwrite(offset, data):
                 self.LOGGER.info("Poke succeeded.")
             else:
                 self.LOGGER.error("Poke failed.")
         elif cmd == "pokedword":
             offset = int(options["<offset>"], 16)
             data = pack("<I", int(options["<data>"], 16))
             if self.streaming.mempoke(offset, data):
                 self.LOGGER.info("Poke succeeded.")
             else:
                 self.LOGGER.error("Poke failed.")
         elif cmd == "reset":
             if self.streaming.reset():
                 self.LOGGER.info("Reset succeeded.")
         elif cmd == "memtbl":
             filename = options["<filename>"]
             memtbl = self.streaming.settings.memtbl
             data = self.streaming.memread(memtbl[0], memtbl[1])
             if data != b"":
                 with open(filename, "wb") as wf:
                     wf.write(data)
                     self.printer(f"Dumped memtbl at offset {hex(memtbl[0])} as {filename}.")
             else:
                 self.LOGGER.error("Error on dumping memtbl")
         elif cmd == "secureboot":
             value = self.streaming.mempeek(self.streaming.settings.secureboot)
             if value != -1:
                 is_secure = False
                 for area in range(0, 4):
                     sec_boot = (value >> (area * 8)) & 0xFF
                     pk_hashindex = sec_boot & 3
                     oem_pkhash = True if ((sec_boot >> 4) & 1) == 1 else False
                     auth_enabled = True if ((sec_boot >> 5) & 1) == 1 else False
                     use_serial = True if ((sec_boot >> 6) & 1) == 1 else False
                     if auth_enabled:
                         is_secure = True
                     self.printer(f"Sec_Boot{str(area)} PKHash-Index:{str(pk_hashindex)} " +
                                  f"OEM_PKHash: {str(oem_pkhash)} " +
                                  f"Auth_Enabled: {str(auth_enabled)} " +
                                  f"Use_Serial: {str(use_serial)}")
                 if is_secure:
                     self.printer("Secure boot enabled.")
                 else:
                     self.printer("Secure boot disabled.")
             else:
                 self.LOGGER.error("Unknown target chipset")
         elif cmd == "pbl":
             filename = options["<filename>"]
             pbl = self.streaming.settings.pbl
             self.printer("Dumping pbl....")
             data = self.streaming.memread(pbl[0], pbl[1])
             if data != b"":
                 with open(filename, "wb") as wf:
                     wf.write(data)
                     self.printer(f"Dumped pbl at offset {hex(pbl[0])} as {filename}.")
             else:
                 self.LOGGER.error("Error on dumping pbl")
         elif cmd == "qfp":
             filename = options["<filename>"]
             qfp = self.streaming.settings.qfprom
             self.printer("Dumping qfprom....")
             data = self.streaming.memread(qfp[0], qfp[1])
             if data != b"":
                 with open(filename, "wb") as wf:
                     wf.write(data)
                     self.printer(f"Dumped qfprom at offset {hex(qfp[0])} as {filename}.")
             else:
                 self.LOGGER.error("Error on dumping qfprom")
         elif cmd == "memcpy":
             if not self.check_param(["<offset>", "<size>"]):
                 return False
             srcoffset = int(options["<offset>"], 16)
             size = int(options["<size>"], 16)
             dstoffset = srcoffset + size
             if self.streaming.cmd_memcpy(dstoffset, srcoffset, size):
                 self.printer(f"Memcpy from {hex(srcoffset)} to {hex(dstoffset)} succeeded")
                 return True
             else:
                 return False
         ###############################
         elif cmd == "nop":
             self.LOGGER.error("Nop command isn't supported by streaming loader")
             return True
         elif cmd == "setbootablestoragedrive":
             self.LOGGER.error("setbootablestoragedrive command isn't supported by streaming loader")
             return True
         elif cmd == "getstorageinfo":
             self.LOGGER.error("getstorageinfo command isn't supported by streaming loader")
             return True
         elif cmd == "w":
             if not self.check_param(["<partitionname>", "<filename>"]):
                 return False
             partitionname = options["<partitionname>"]
             filename = options["<filename>"]
             if not os.path.exists(filename):
                 self.LOGGER.error(f"Error: Couldn't find file: {filename}")
                 return False
             rpartitions = self.streaming.get_partitions()
             if self.streaming.enter_flash_mode():
                 if partitionname in rpartitions:
                     spartition = rpartitions[partitionname]
                     offset = spartition["offset"]
                     length = spartition["length"]
                     # attr1 = spartition["attr1"]
                     # attr2 = spartition["attr2"]
                     # attr3 = spartition["attr3"]
                     sectors = int(os.stat(
                         filename).st_size / self.streaming.settings.num_pages_per_blk / self.streaming.settings.PAGESIZE)
                     if sectors > length:
                         self.LOGGER.error(
                             f"Error: {filename} has {sectors} sectors but partition only has {length}.")
                         return False
                     if self.streaming.modules is not None:
                         self.streaming.modules.prerun()
                     if self.streaming.write_flash(partitionname, filename):
                         self.printer(f"Wrote {filename} to sector {str(offset)}.")
                         return True
                     else:
                         self.printer(f"Error writing {filename} to sector {str(offset)}.")
                         return False
                 else:
                     self.LOGGER.error(f"Error: Couldn't detect partition: {partitionname}\nAvailable partitions:")
                     self.print_partitions(rpartitions)
             return False
         elif cmd == "wl":
             if not self.check_param(["<directory>"]):
                 return False
             directory = options["<directory>"]
             if options["--skip"]:
                 skip = options["--skip"].split(",")
             else:
                 skip = []
             if not os.path.exists(directory):
                 self.LOGGER.error(f"Error: Couldn't find directory: {directory}")
                 return False
             filenames = []
             if self.streaming.enter_flash_mode():
                 if self.streaming.modules is not None:
                     self.streaming.modules.prerun()
                 rpartitions = self.streaming.get_partitions()
                 for dirName, subdirList, fileList in os.walk(directory):
                     for fname in fileList:
                         filenames.append(os.path.join(dirName, fname))
                         for filename in filenames:
                             for partition in rpartitions:
                                 partname = filename[filename.rfind("/") + 1:]
                                 if ".bin" in partname[-4:]:
                                     partname = partname[:-4]
                                 if partition == partname:
                                     if partition in skip:
                                         continue
                                     spartition = rpartitions[partition]
                                     offset = spartition["offset"]
                                     length = spartition["length"]
                                     # attr1 = spartition["attr1"]
                                     # attr2 = spartition["attr2"]
                                     # attr3 = spartition["attr3"]
                                     sectors = int(os.stat(filename).st_size /
                                                   self.streaming.settings.num_pages_per_blk /
                                                   self.streaming.settings.PAGESIZE)
                                     if sectors > length:
                                         self.LOGGER.error(
                                             f"Error: {filename} has {sectors} sectors but partition only has {length}.")
                                         return False
                                     self.printer(f"Writing {filename} to partition {str(partition)}.")
                                     self.streaming.write_flash(partition, filename)
                     else:
                         self.printer("Couldn't write partition. Either wrong memorytype given or no gpt partition.")
                         return False
             return True
         elif cmd == "ws":
             self.LOGGER.error("ws command isn't supported by streaming loader")  # todo
             return False
         elif cmd == "wf":
             self.LOGGER.error("wf command isn't supported by streaming loader")  # todo
             return False
         elif cmd == "e":
             self.LOGGER.error("e command isn't supported by streaming loader")  # todo
             return False
         elif cmd == "es":
             self.LOGGER.error("es command isn't supported by streaming loader")  # todo
             return False
         elif cmd == "xml":
             self.LOGGER.error("xml command isn't supported by streaming loader")
             return False
         elif cmd == "rawxml":
             self.LOGGER.error("rawxml command isn't supported by streaming loader")
             return False
         elif cmd == "send":
             self.LOGGER.error("send command isn't supported by streaming loader")
             return False
         ###############################
         elif cmd == "server":
             return do_tcp_server(self, options, self.handle_streaming)
         elif cmd == "modules":
             if not self.check_param(["<command>", "<options>"]):
                 return False
             command = options["<command>"]
             options = options["<options>"]
             if self.streaming.modules is None:
                 self.LOGGER.error("Feature is not supported")
                 return False
             else:
                 return self.streaming.modules.run(mainargs=options, command=command)
         else:
             self.LOGGER.error("Unknown/Missing command, a command is required.")
             return False
예제 #2
0
    def handle_firehose(self, cmd, options):
        if cmd == "gpt":
            luns = self.getluns(options)
            directory = options["<directory>"]
            if directory is None:
                directory = ""
            genxml = False
            if "--genxml" in options:
                if options["--genxml"]:
                    genxml = True
            for lun in luns:
                sfilename = os.path.join(directory, f"gpt_main{str(lun)}.bin")
                data, guid_gpt = self.firehose.get_gpt(
                    lun, int(options["--gpt-num-part-entries"]),
                    int(options["--gpt-part-entry-size"]),
                    int(options["--gpt-part-entry-start-lba"]))
                if guid_gpt is None:
                    break
                with open(sfilename, "wb") as write_handle:
                    write_handle.write(data)

                self.printer(f"Dumped GPT from Lun {str(lun)} to {sfilename}")
                sfilename = os.path.join(directory,
                                         f"gpt_backup{str(lun)}.bin")
                with open(sfilename, "wb") as write_handle:
                    write_handle.write(
                        data[self.firehose.cfg.SECTOR_SIZE_IN_BYTES * 2:])
                self.printer(
                    f"Dumped Backup GPT from Lun {str(lun)} to {sfilename}")
                if genxml:
                    guid_gpt.generate_rawprogram(
                        lun, self.firehose.cfg.SECTOR_SIZE_IN_BYTES, directory)
            return True
        elif cmd == "printgpt":
            luns = self.getluns(options)
            for lun in luns:
                data, guid_gpt = self.firehose.get_gpt(
                    lun, int(options["--gpt-num-part-entries"]),
                    int(options["--gpt-part-entry-size"]),
                    int(options["--gpt-part-entry-start-lba"]))
                if guid_gpt is None:
                    break
                self.printer(f"\nParsing Lun {str(lun)}:")
                guid_gpt.print()
            return True
        elif cmd == "r":
            if not self.check_param(["<partitionname>", "<filename>"]):
                return False
            partitionname = options["<partitionname>"]
            filename = options["<filename>"]
            filenames = filename.split(",")
            partitions = partitionname.split(",")
            if len(partitions) != len(filenames):
                self.error(
                    "You need to gives as many filenames as given partitions.")
                return False
            i = 0
            for partition in partitions:
                partfilename = filenames[i]
                i += 1
                res = self.firehose.detect_partition(options, partition)
                if res[0]:
                    lun = res[1]
                    rpartition = res[2]
                    if self.firehose.cmd_read(lun, rpartition.sector,
                                              rpartition.sectors,
                                              partfilename):
                        self.printer(
                            f"Dumped sector {str(rpartition.sector)} with sector count {str(rpartition.sectors)} "
                            + f"as {partfilename}.")
                else:
                    fpartitions = res[1]
                    self.error(
                        f"Error: Couldn't detect partition: {partition}\nAvailable partitions:"
                    )
                    for lun in fpartitions:
                        for rpartition in fpartitions[lun]:
                            if self.cfg.MemoryName == "emmc":
                                self.error("\t" + rpartition)
                            else:
                                self.error(lun + ":\t" + rpartition)
                    return False
            return True
        elif cmd == "rl":
            if not self.check_param(["<directory>"]):
                return False
            directory = options["<directory>"]
            if options["--skip"]:
                skip = options["--skip"].split(",")
            else:
                skip = []
            genxml = False
            if "--genxml" in options:
                if options["--genxml"]:
                    genxml = True
            if not os.path.exists(directory):
                os.mkdir(directory)

            luns = self.getluns(options)

            for lun in luns:
                data, guid_gpt = self.firehose.get_gpt(
                    lun, int(options["--gpt-num-part-entries"]),
                    int(options["--gpt-part-entry-size"]),
                    int(options["--gpt-part-entry-start-lba"]))
                if guid_gpt is None:
                    break
                if len(luns) > 1:
                    storedir = os.path.join(directory, "lun" + str(lun))
                else:
                    storedir = directory
                if not os.path.exists(storedir):
                    os.mkdir(storedir)
                sfilename = os.path.join(storedir, f"gpt_main{str(lun)}.bin")
                with open(sfilename, "wb") as write_handle:
                    write_handle.write(data)

                sfilename = os.path.join(storedir, f"gpt_backup{str(lun)}.bin")
                with open(sfilename, "wb") as write_handle:
                    write_handle.write(
                        data[self.firehose.cfg.SECTOR_SIZE_IN_BYTES * 2:])

                if genxml:
                    guid_gpt.generate_rawprogram(
                        lun, self.firehose.cfg.SECTOR_SIZE_IN_BYTES, storedir)

                for partition in guid_gpt.partentries:
                    partitionname = partition.name
                    if partition.name in skip:
                        continue
                    filename = os.path.join(storedir, partitionname + ".bin")
                    self.info(
                        f"Dumping partition {str(partition.name)} with sector count {str(partition.sectors)} "
                        + f"as {filename}.")
                    if self.firehose.cmd_read(lun, partition.sector,
                                              partition.sectors, filename):
                        self.info(
                            f"Dumped partition {str(partition.name)} with sector count "
                            + f"{str(partition.sectors)} as {filename}.")
            return True
        elif cmd == "rf":
            if not self.check_param(["<filename>"]):
                return False
            filename = options["<filename>"]
            luns = self.getluns(options)
            for lun in luns:
                data, guid_gpt = self.firehose.get_gpt(
                    lun, int(options["--gpt-num-part-entries"]),
                    int(options["--gpt-part-entry-size"]),
                    int(options["--gpt-part-entry-start-lba"]))
                if guid_gpt is None:
                    break
                if len(luns) > 1:
                    sfilename = filename + f"_lun{str(lun)}"
                else:
                    sfilename = filename
                self.printer(
                    f"Dumping sector 0 with sector count {str(guid_gpt.totalsectors)} as {filename}."
                )
                if self.firehose.cmd_read(lun, 0, guid_gpt.totalsectors,
                                          sfilename):
                    self.printer(
                        f"Dumped sector 0 with sector count {str(guid_gpt.totalsectors)} as {filename}."
                    )
            return True
        elif cmd == "pbl":
            if not self.check_param(["<filename>"]):
                return False
            if not self.check_cmd("peek"):
                self.error("Peek command isn't supported by edl loader")
                return False
            else:
                filename = options["<filename>"]
                if self.target_name in infotbl:
                    target_name = infotbl[self.target_name]
                    if len(target_name[0]) > 0:
                        if self.firehose.cmd_peek(target_name[0][0],
                                                  target_name[0][1], filename,
                                                  True):
                            self.printer(
                                f"Dumped pbl at offset {hex(target_name[0][0])} as {filename}."
                            )
                            return True
                    else:
                        self.error("No known pbl offset for this chipset")
                else:
                    self.error("Unknown target chipset")
                self.error("Error on dumping pbl")
            return False
        elif cmd == "qfp":
            if not self.check_param(["<filename>"]):
                return False
            if not self.check_cmd("peek"):
                self.error("Peek command isn't supported by edl loader")
                return False
            else:
                filename = options["<filename>"]
                if self.target_name not in infotbl:
                    self.error("Unknown target chipset")
                else:
                    target_name = infotbl[self.target_name]
                    if len(target_name[1]) > 0:
                        if self.firehose.cmd_peek(target_name[1][0],
                                                  target_name[1][1], filename):
                            self.printer(
                                f"Dumped qfprom at offset {hex(target_name[1][0])} as {filename}."
                            )
                            return True
                    else:
                        self.error("No known qfprom offset for this chipset")
                self.error("Error on dumping qfprom")
            return False
        elif cmd == "secureboot":
            if not self.check_cmd("peek"):
                self.error("Peek command isn't supported by edl loader")
                return False
            else:
                if self.target_name in secureboottbl:
                    self.target_name = secureboottbl[self.target_name]
                    value = unpack("<I",
                                   self.firehose.cmd_peek(self.target_name,
                                                          4))[0]
                    is_secure = False
                    for area in range(0, 4):
                        sec_boot = (value >> (area * 8)) & 0xFF
                        pk_hashindex = sec_boot & 3
                        oem_pkhash = True if ((sec_boot >> 4)
                                              & 1) == 1 else False
                        auth_enabled = True if ((sec_boot >> 5)
                                                & 1) == 1 else False
                        use_serial = True if ((sec_boot >> 6)
                                              & 1) == 1 else False
                        if auth_enabled:
                            is_secure = True
                        self.printer(f"Sec_Boot{str(area)} " +
                                     f"PKHash-Index:{str(pk_hashindex)} " +
                                     f"OEM_PKHash: {str(oem_pkhash)} " +
                                     f"Auth_Enabled: {str(auth_enabled)}" +
                                     f"Use_Serial: {str(use_serial)}")
                    if is_secure:
                        self.printer("Secure boot enabled.")
                    else:
                        self.printer("Secure boot disabled.")
                    return True
                else:
                    self.error("Unknown target chipset")
                    return False
        elif cmd == "memtbl":
            if not self.check_param(["<filename>"]):
                return False
            if not self.check_cmd("peek"):
                self.error("Peek command isn't supported by edl loader")
                return False
            else:
                filename = options["<filename>"]
                if self.target_name in infotbl:
                    self.target_name = infotbl[self.target_name]
                    if len(self.target_name[2]) > 0:
                        if self.firehose.cmd_peek(self.target_name[2][0],
                                                  self.target_name[2][1],
                                                  filename):
                            self.printer(
                                f"Dumped memtbl at offset {hex(self.target_name[2][0])} as {filename}."
                            )
                            return True
                    else:
                        self.error("No known memtbl offset for this chipset")
                else:
                    self.error("Unknown target chipset")
                self.error("Error on dumping memtbl")
            return False
        elif cmd == "footer":
            if not self.check_param(["<filename>"]):
                return False
            luns = self.getluns(options)
            filename = options["<filename>"]
            for lun in luns:
                data, guid_gpt = self.firehose.get_gpt(
                    lun, int(options["--gpt-num-part-entries"]),
                    int(options["--gpt-part-entry-size"]),
                    int(options["--gpt-part-entry-start-lba"]))
                if guid_gpt is None:
                    break
                pnames = [
                    "userdata2", "metadata", "userdata", "reserved1",
                    "reserved2", "reserved3"
                ]
                for partition in guid_gpt.partentries:
                    if partition.name in pnames:
                        self.printer(f"Detected partition: {partition.name}")
                        data = self.firehose.cmd_read_buffer(
                            lun, partition.sector +
                            (partition.sectors -
                             (0x4000 //
                              self.firehose.cfg.SECTOR_SIZE_IN_BYTES)),
                            (0x4000 // self.firehose.cfg.SECTOR_SIZE_IN_BYTES),
                            False)
                        if data == b"":
                            continue
                        val = unpack("<I", data[:4])[0]
                        if (val & 0xFFFFFFF0) == 0xD0B5B1C0:
                            with open(filename, "wb") as write_handle:
                                write_handle.write(data)
                                self.printer(
                                    f"Dumped footer from {partition.name} as {filename}."
                                )
                                return True
            self.error("Error: Couldn't detect footer partition.")
            return False
        elif cmd == "rs":
            if options["--lun"] is not None:
                lun = int(options["--lun"])
            else:
                lun = 0
            if not self.check_param(
                ["<filename>", "<sectors>", "<start_sector>"]):
                return False
            start = int(options["<start_sector>"])
            sectors = int(options["<sectors>"])
            filename = options["<filename>"]
            if self.firehose.cmd_read(lun, start, sectors, filename, True):
                self.printer(
                    f"Dumped sector {str(start)} with sector count {str(sectors)} as {filename}."
                )
                return True
        elif cmd == "peek":
            if not self.check_param(["<offset>", "<length>", "<filename>"]):
                return False
            if not self.check_cmd("peek"):
                self.error("Peek command isn't supported by edl loader")
                return False
            else:
                offset = getint(options["<offset>"])
                length = getint(options["<length>"])
                filename = options["<filename>"]
                self.firehose.cmd_peek(offset, length, filename, True)
                self.info(
                    f"Peek data from offset {hex(offset)} and length {hex(length)} was written to {filename}"
                )
                return True
        elif cmd == "peekhex":
            if not self.check_param(["<offset>", "<length>"]):
                return False
            if not self.check_cmd("peek"):
                self.error("Peek command isn't supported by edl loader")
                return False
            else:
                offset = getint(options["<offset>"])
                length = getint(options["<length>"])
                resp = self.firehose.cmd_peek(offset, length, "", True)
                self.printer("\n")
                self.printer(hexlify(resp))
                return True
        elif cmd == "peekqword":
            if not self.check_param(["<offset>"]):
                return False
            if not self.check_cmd("peek"):
                self.error("Peek command isn't supported by edl loader")
                return False
            else:
                offset = getint(options["<offset>"])
                resp = self.firehose.cmd_peek(offset, 8, "", True)
                self.printer("\n")
                self.printer(hex(unpack("<Q", resp[:8])[0]))
                return True
        elif cmd == "peekdword":
            if not self.check_param(["<offset>"]):
                return False
            if not self.check_cmd("peek"):
                self.error("Peek command isn't supported by edl loader")
                return False
            else:
                offset = getint(options["<offset>"])
                resp = self.firehose.cmd_peek(offset, 4, "", True)
                self.printer("\n")
                self.printer(hex(unpack("<I", resp[:4])[0]))
                return True
        elif cmd == "poke":
            if not self.check_param(["<offset>", "<filename>"]):
                return False
            if not self.check_cmd("poke"):
                self.error("Poke command isn't supported by edl loader")
                return False
            else:
                offset = getint(options["<offset>"])
                filename = options["<filename>"]
                return self.firehose.cmd_poke(offset, "", filename, True)
        elif cmd == "pokehex":
            if not self.check_param(["<offset>", "<data>"]):
                return False
            if not self.check_cmd("poke"):
                self.error("Poke command isn't supported by edl loader")
                return False
            else:
                offset = getint(options["<offset>"])
                data = unhexlify(options["<data>"])
                return self.firehose.cmd_poke(offset, data, "", True)
        elif cmd == "pokeqword":
            if not self.check_param(["<offset>", "<data>"]):
                return False
            if not self.check_cmd("poke"):
                self.error("Poke command isn't supported by edl loader")
                return False
            else:
                offset = getint(options["<offset>"])
                data = pack("<Q", getint(options["<data>"]))
                return self.firehose.cmd_poke(offset, data, "", True)
        elif cmd == "pokedword":
            if not self.check_param(["<offset>", "<data>"]):
                return False
            if not self.check_cmd("poke"):
                self.error("Poke command isn't supported by edl loader")
                return False
            else:
                offset = getint(options["<offset>"])
                data = pack("<I", getint(options["<data>"]))
                return self.firehose.cmd_poke(offset, data, "", True)
        elif cmd == "memcpy":
            if not self.check_param(["<offset>", "<size>"]):
                return False
            if not self.check_cmd("poke"):
                self.printer("Poke command isn't supported by edl loader")
            else:
                srcoffset = getint(options["<offset>"])
                size = getint(options["<size>"])
                dstoffset = srcoffset + size
                if self.firehose.cmd_memcpy(dstoffset, srcoffset, size):
                    self.printer(
                        f"Memcpy from {hex(srcoffset)} to {hex(dstoffset)} succeeded"
                    )
                    return True
                else:
                    return False
        elif cmd == "reset":
            return self.firehose.cmd_reset()
        elif cmd == "nop":
            if not self.check_cmd("nop"):
                self.error("Nop command isn't supported by edl loader")
                return False
            else:
                return self.firehose.cmd_nop()
        elif cmd == "setbootablestoragedrive":
            if not self.check_param(["<lun>"]):
                return False
            if not self.check_cmd("setbootablestoragedrive"):
                self.error(
                    "setbootablestoragedrive command isn't supported by edl loader"
                )
                return False
            else:
                return self.firehose.cmd_setbootablestoragedrive(
                    int(options["<lun>"]))
        elif cmd == "getstorageinfo":
            if not self.check_cmd("getstorageinfo"):
                self.error(
                    "getstorageinfo command isn't supported by edl loader")
                return False
            else:
                return self.firehose.cmd_getstorageinfo_string()
        elif cmd == "w":
            if not self.check_param(["<partitionname>", "<filename>"]):
                return False
            partitionname = options["<partitionname>"]
            filename = options["<filename>"]
            if options["--lun"] is not None:
                lun = int(options["--lun"])
            else:
                lun = 0
            startsector = 0
            if not os.path.exists(filename):
                self.error(f"Error: Couldn't find file: {filename}")
                return False
            if partitionname.lower() == "gpt":
                sectors = os.stat(
                    filename).st_size // self.firehose.cfg.SECTOR_SIZE_IN_BYTES
                res = [True, lun, sectors]
            else:
                res = self.firehose.detect_partition(options, partitionname)
            if res[0]:
                lun = res[1]
                sectors = os.stat(
                    filename).st_size // self.firehose.cfg.SECTOR_SIZE_IN_BYTES
                if (os.stat(filename).st_size %
                        self.firehose.cfg.SECTOR_SIZE_IN_BYTES) > 0:
                    sectors += 1
                if partitionname.lower() != "gpt":
                    partition = res[2]
                    if sectors > partition.sectors:
                        self.error(
                            f"Error: {filename} has {sectors} sectors but partition only has {partition.sectors}."
                        )
                        return False
                    startsector = partition.sector
                if self.firehose.modules is not None:
                    self.firehose.modules.writeprepare()
                if self.firehose.cmd_program(lun, startsector, filename):
                    self.printer(
                        f"Wrote {filename} to sector {str(startsector)}.")
                    return True
                else:
                    self.printer(
                        f"Error writing {filename} to sector {str(startsector)}."
                    )
                    return False
            else:
                if len(res) > 0:
                    fpartitions = res[1]
                    self.error(
                        f"Error: Couldn't detect partition: {partitionname}\nAvailable partitions:"
                    )
                    for lun in fpartitions:
                        for partition in fpartitions[lun]:
                            if self.cfg.MemoryName == "emmc":
                                self.error("\t" + partition)
                            else:
                                self.error(lun + ":\t" + partition)
            return False
        elif cmd == "wl":
            if not self.check_param(["<directory>"]):
                return False
            directory = options["<directory>"]
            if options["--skip"]:
                skip = options["--skip"].split(",")
            else:
                skip = []
            luns = self.getluns(options)

            if not os.path.exists(directory):
                self.error(f"Error: Couldn't find directory: {directory}")
                sys.exit()
            filenames = []
            if self.firehose.modules is not None:
                self.firehose.modules.writeprepare()
            for dirName, subdirList, fileList in os.walk(directory):
                for fname in fileList:
                    filenames.append(os.path.join(dirName, fname))
            for lun in luns:
                data, guid_gpt = self.firehose.get_gpt(
                    lun, int(options["--gpt-num-part-entries"]),
                    int(options["--gpt-part-entry-size"]),
                    int(options["--gpt-part-entry-start-lba"]))
                if guid_gpt is None:
                    break
                if "partentries" in dir(guid_gpt):
                    for filename in filenames:
                        for partition in guid_gpt.partentries:
                            partname = filename[filename.rfind("/") + 1:]
                            if ".bin" in partname[-4:] or ".img" in partname[
                                    -4:] or ".mbn" in partname[-4:]:
                                partname = partname[:-4]
                            if partition.name == partname:
                                if partition.name in skip:
                                    continue
                                sectors = os.stat(
                                    filename
                                ).st_size // self.firehose.cfg.SECTOR_SIZE_IN_BYTES
                                if (os.stat(filename).st_size %
                                        self.firehose.cfg.SECTOR_SIZE_IN_BYTES
                                    ) > 0:
                                    sectors += 1
                                if sectors > partition.sectors:
                                    self.error(
                                        f"Error: {filename} has {sectors} sectors but partition "
                                        + f"only has {partition.sectors}.")
                                    return False
                                self.printer(
                                    f"Writing {filename} to partition {str(partition.name)}."
                                )
                                self.firehose.cmd_program(
                                    lun, partition.sector, filename)
                else:
                    self.printer(
                        "Couldn't write partition. Either wrong memorytype given or no gpt partition."
                    )
                    return False
            return True
        elif cmd == "ws":
            if not self.check_param(["<start_sector>"]):
                return False
            if options["--lun"] is not None:
                lun = int(options["--lun"])
            else:
                lun = 0
            start = int(options["<start_sector>"])
            filename = options["<filename>"]
            if not os.path.exists(filename):
                self.error(f"Error: Couldn't find file: {filename}")
                return False
            if self.firehose.modules is not None:
                self.firehose.modules.writeprepare()
            if self.firehose.cmd_program(lun, start, filename):
                self.printer(f"Wrote {filename} to sector {str(start)}.")
                return True
            else:
                self.error(
                    f"Error on writing {filename} to sector {str(start)}")
                return False
        elif cmd == "wf":
            if not self.check_param(["<filename>"]):
                return False
            if options["--lun"] is not None:
                lun = int(options["--lun"])
            else:
                lun = 0
            start = 0
            filename = options["<filename>"]
            if not os.path.exists(filename):
                self.error(f"Error: Couldn't find file: {filename}")
                return False
            if self.firehose.modules is not None:
                self.firehose.modules.writeprepare()
            if self.firehose.cmd_program(lun, start, filename):
                self.printer(f"Wrote {filename} to sector {str(start)}.")
                return True
            else:
                self.error(
                    f"Error on writing {filename} to sector {str(start)}")
                return False
        elif cmd == "e":
            if not self.check_param(["<partitionname>"]):
                return False
            luns = self.getluns(options)
            partitionname = options["<partitionname>"]
            for lun in luns:
                data, guid_gpt = self.firehose.get_gpt(
                    lun, int(options["--gpt-num-part-entries"]),
                    int(options["--gpt-part-entry-size"]),
                    int(options["--gpt-part-entry-start-lba"]))
                if guid_gpt is None:
                    break
                if self.firehose.modules is not None:
                    self.firehose.modules.writeprepare()
                if "partentries" in dir(guid_gpt):
                    for partition in guid_gpt.partentries:
                        if partition.name == partitionname:
                            self.firehose.cmd_erase(lun, partition.sector,
                                                    partition.sectors)
                            self.printer(
                                f"Erased {partitionname} starting at sector {str(partition.sector)} "
                                +
                                f"with sector count {str(partition.sectors)}.")
                            return True
                else:
                    self.printer(
                        "Couldn't erase partition. Either wrong memorytype given or no gpt partition."
                    )
                    return False
            self.error(f"Error: Couldn't detect partition: {partitionname}")
            return False
        elif cmd == "ep":
            if not self.check_param(["<partitionname>", "<sectors>"]):
                return False
            luns = self.getluns(options)
            partitionname = options["<partitionname>"]
            sectors = int(options["<sectors>"])

            for lun in luns:
                data, guid_gpt = self.firehose.get_gpt(
                    lun, int(options["--gpt-num-part-entries"]),
                    int(options["--gpt-part-entry-size"]),
                    int(options["--gpt-part-entry-start-lba"]))
                if guid_gpt is None:
                    break
                if self.firehose.modules is not None:
                    self.firehose.modules.writeprepare()
                if "partentries" in dir(guid_gpt):
                    for partition in guid_gpt.partentries:
                        if partition.name == partitionname:
                            self.firehose.cmd_erase(lun, partition.sector,
                                                    sectors)
                            self.printer(
                                f"Erased {partitionname} starting at sector {str(partition.sector)} "
                                + f"with sector count {str(sectors)}.")
                            return True
                else:
                    self.printer(
                        "Couldn't erase partition. Either wrong memorytype given or no gpt partition."
                    )
                    return False
            self.error(f"Error: Couldn't detect partition: {partitionname}")
            return False
        elif cmd == "es":
            if not self.check_param(["<start_sector>", "<sectors>"]):
                return False
            if options["--lun"] is not None:
                lun = int(options["--lun"])
            else:
                lun = 0
            start = int(options["<start_sector>"])
            sectors = int(options["<sectors>"])
            if self.firehose.modules is not None:
                self.firehose.modules.writeprepare()
            if self.firehose.cmd_erase(lun, start, sectors):
                self.printer(
                    f"Erased sector {str(start)} with sector count {str(sectors)}."
                )
                return True
            return False
        elif cmd == "xml":
            if not self.check_param(["<xmlfile>"]):
                return False
            return self.firehose.cmd_xml(options["<xmlfile>"])
        elif cmd == "rawxml":
            if not self.check_param(["<xmlstring>"]):
                return False
            return self.firehose.cmd_rawxml(options["<xmlstring>"])
        elif cmd == "send":
            if not self.check_param(["<command>"]):
                return False
            command = options["<command>"]
            resp = self.firehose.cmd_send(command, True)
            self.printer("\n")
            self.printer(resp)
            return True
        elif cmd == "server":
            return do_tcp_server(self, options, self.handle_firehose)
        elif cmd == "modules":
            if not self.check_param(["<command>", "<options>"]):
                return False
            mcommand = options["<command>"]
            moptions = options["<options>"]
            if self.firehose.modules is None:
                self.error("Feature is not supported")
                return False
            else:
                return self.firehose.modules.run(command=mcommand,
                                                 args=moptions)
        elif cmd == "qfil":
            self.info("[qfil] raw programming...")
            rawprogram = options["<rawprogram>"].split(",")
            imagedir = options["<imagedir>"]
            patch = options["<patch>"].split(",")
            for xml in rawprogram:
                filename = os.path.join(imagedir, xml)
                if os.path.exists(filename):
                    self.info("[qfil] programming %s" % xml)
                    fl = open(filename, "r")
                    for evt, elem in ET.iterparse(fl, events=["end"]):
                        if elem.tag == "program":
                            if elem.get("filename", ""):
                                filename = os.path.join(
                                    imagedir, elem.get("filename"))
                                if not os.path.isfile(filename):
                                    self.error("%s doesn't exist!" % filename)
                                    continue
                                partition_number = int(
                                    elem.get("physical_partition_number"))
                                num_disk_sectors = self.firehose.getlunsize(
                                    partition_number)
                                start_sector = elem.get("start_sector")
                                if "NUM_DISK_SECTORS" in start_sector:
                                    start_sector = start_sector.replace(
                                        "NUM_DISK_SECTORS",
                                        str(num_disk_sectors))
                                if "-" in start_sector or "*" in start_sector or "/" in start_sector or \
                                        "+" in start_sector:
                                    start_sector = start_sector.replace(
                                        ".", "")
                                    start_sector = eval(start_sector)
                                self.info(
                                    f"[qfil] programming {filename} to partition({partition_number})"
                                    + f"@sector({start_sector})...")

                                self.firehose.cmd_program(
                                    int(partition_number), int(start_sector),
                                    filename)
                else:
                    self.warning(f"File : {filename} not found.")
            self.info("[qfil] raw programming ok.")

            self.info("[qfil] patching...")
            for xml in patch:
                filename = os.path.join(imagedir, xml)
                self.info("[qfil] patching with %s" % xml)
                if os.path.exists(filename):
                    fl = open(filename, "r")
                    for evt, elem in ET.iterparse(fl, events=["end"]):
                        if elem.tag == "patch":
                            filename = elem.get("filename")
                            if filename != "DISK":
                                continue
                            start_sector = elem.get("start_sector")
                            size_in_bytes = elem.get("size_in_bytes")
                            self.info(
                                f"[qfil] patching {filename} sector({start_sector}), size={size_in_bytes}"
                                .format(filename=filename,
                                        start_sector=start_sector,
                                        size_in_bytes=size_in_bytes))
                            content = ElementTree.tostring(elem).decode(
                                "utf-8")
                            CMD = "<?xml version=\"1.0\" ?><data>\n {content} </data>".format(
                                content=content)
                            print(CMD)
                            self.firehose.xmlsend(CMD)
                else:
                    self.warning(f"File : {filename} not found.")
            self.info("[qfil] patching ok")
            bootable = self.find_bootable_partition(rawprogram)
            if bootable != -1:
                if self.firehose.cmd_setbootablestoragedrive(bootable):
                    self.info(
                        "[qfil] partition({partition}) is now bootable\n".
                        format(partition=bootable))
                else:
                    self.info(
                        "[qfil] set partition({partition}) as bootable failed\n"
                        .format(partition=bootable))

        else:
            self.error("Unknown/Missing command, a command is required.")
            return False
예제 #3
0
    def handle_firehose(self, cmd, options):
        if cmd == "gpt":
            luns = self.getluns(options)
            directory = options["<directory>"]
            if directory is None:
                directory = ""
            genxml = False
            if "--genxml" in options:
                if options["--genxml"]:
                    genxml = True
            for lun in luns:
                sfilename = os.path.join(directory, f"gpt_main{str(lun)}.bin")
                data, guid_gpt = self.firehose.get_gpt(
                    lun, int(options["--gpt-num-part-entries"]),
                    int(options["--gpt-part-entry-size"]),
                    int(options["--gpt-part-entry-start-lba"]))
                if guid_gpt is None:
                    break
                with open(sfilename, "wb") as write_handle:
                    write_handle.write(data)

                self.printer(f"Dumped GPT from Lun {str(lun)} to {sfilename}")
                sfilename = os.path.join(directory,
                                         f"gpt_backup{str(lun)}.bin")
                with open(sfilename, "wb") as write_handle:
                    write_handle.write(
                        data[self.firehose.cfg.SECTOR_SIZE_IN_BYTES * 2:])
                self.printer(
                    f"Dumped Backup GPT from Lun {str(lun)} to {sfilename}")
                if genxml:
                    guid_gpt.generate_rawprogram(
                        lun, self.firehose.cfg.SECTOR_SIZE_IN_BYTES, directory)
            return True
        elif cmd == "printgpt":
            luns = self.getluns(options)
            for lun in luns:
                data, guid_gpt = self.firehose.get_gpt(
                    lun, int(options["--gpt-num-part-entries"]),
                    int(options["--gpt-part-entry-size"]),
                    int(options["--gpt-part-entry-start-lba"]))
                if guid_gpt is None:
                    break
                self.printer(f"\nParsing Lun {str(lun)}:")
                guid_gpt.print()
            return True
        elif cmd == "r":
            if not self.check_param(["<partitionname>", "<filename>"]):
                return False
            partitionname = options["<partitionname>"]
            filename = options["<filename>"]
            filenames = filename.split(",")
            partitions = partitionname.split(",")
            if len(partitions) != len(filenames):
                self.LOGGER.error(
                    "You need to gives as many filenames as given partitions.")
                return False
            i = 0
            for partition in partitions:
                partfilename = filenames[i]
                i += 1
                res = self.firehose.detect_partition(options, partition)
                if res[0]:
                    lun = res[1]
                    rpartition = res[2]
                    self.firehose.cmd_read(lun, rpartition.sector,
                                           rpartition.sectors, partfilename)
                    self.printer(
                        f"Dumped sector {str(rpartition.sector)} with sector count {str(rpartition.sectors)} " + \
                        f"as {partfilename}.")
                else:
                    fpartitions = res[1]
                    self.LOGGER.error(
                        f"Error: Couldn't detect partition: {partition}\nAvailable partitions:"
                    )
                    for lun in fpartitions:
                        for rpartition in fpartitions[lun]:
                            if options["--memory"].lower() == "emmc":
                                self.LOGGER.error("\t" + rpartition)
                            else:
                                self.LOGGER.error(lun + ":\t" + rpartition)
                    return False
            return True
        elif cmd == "rl":
            if not self.check_param(["<directory>"]):
                return False
            directory = options["<directory>"]
            if options["--skip"]:
                skip = options["--skip"].split(",")
            else:
                skip = []
            genxml = False
            if "--genxml" in options:
                if options["--genxml"]:
                    genxml = True
            if not os.path.exists(directory):
                os.mkdir(directory)

            luns = self.getluns(options)

            for lun in luns:
                data, guid_gpt = self.firehose.get_gpt(
                    lun, int(options["--gpt-num-part-entries"]),
                    int(options["--gpt-part-entry-size"]),
                    int(options["--gpt-part-entry-start-lba"]))
                if guid_gpt is None:
                    break
                if len(luns) > 1:
                    storedir = os.path.join(directory, "lun" + str(lun))
                else:
                    storedir = directory
                if not os.path.exists(storedir):
                    os.mkdir(storedir)
                sfilename = os.path.join(storedir, f"gpt_main{str(lun)}.bin")
                with open(sfilename, "wb") as write_handle:
                    write_handle.write(data)

                sfilename = os.path.join(storedir, f"gpt_backup{str(lun)}.bin")
                with open(sfilename, "wb") as write_handle:
                    write_handle.write(
                        data[self.firehose.cfg.SECTOR_SIZE_IN_BYTES * 2:])

                if genxml:
                    guid_gpt.generate_rawprogram(
                        lun, self.firehose.cfg.SECTOR_SIZE_IN_BYTES, storedir)

                for partition in guid_gpt.partentries:
                    partitionname = partition.name
                    if partition.name in skip:
                        continue
                    filename = os.path.join(storedir, partitionname + ".bin")
                    self.LOGGER.info(
                        f"Dumping partition {str(partition.name)} with sector count {str(partition.sectors)} "
                        + f"as {filename}.")
                    self.firehose.cmd_read(lun, partition.sector,
                                           partition.sectors, filename)
            return True
        elif cmd == "rf":
            if not self.check_param(["<filename>"]):
                return False
            filename = options["<filename>"]
            luns = self.getluns(options)
            for lun in luns:
                data, guid_gpt = self.firehose.get_gpt(
                    lun, int(options["--gpt-num-part-entries"]),
                    int(options["--gpt-part-entry-size"]),
                    int(options["--gpt-part-entry-start-lba"]))
                if guid_gpt is None:
                    break
                if len(luns) > 1:
                    sfilename = f"lun{str(lun)}_" + filename
                else:
                    sfilename = filename
                self.printer(
                    f"Dumping sector 0 with sector count {str(guid_gpt.totalsectors)} as {filename}."
                )
                self.firehose.cmd_read(lun, 0, guid_gpt.totalsectors,
                                       sfilename)
                self.printer(
                    f"Dumped sector 0 with sector count {str(guid_gpt.totalsectors)} as {filename}."
                )
            return True
        elif cmd == "pbl":
            if not self.check_param(["<filename>"]):
                return False
            if not self.check_cmd("peek"):
                self.LOGGER.error("Peek command isn't supported by edl loader")
                return False
            else:
                filename = options["<filename>"]
                if self.target_name in infotbl:
                    target_name = infotbl[self.target_name]
                    if len(target_name[0]) > 0:
                        if self.firehose.cmd_peek(target_name[0][0],
                                                  target_name[0][1], filename,
                                                  True):
                            self.printer(
                                f"Dumped pbl at offset {hex(target_name[0][0])} as {filename}."
                            )
                            return True
                    else:
                        self.LOGGER.error(
                            "No known pbl offset for this chipset")
                else:
                    self.LOGGER.error("Unknown target chipset")
                self.LOGGER.error("Error on dumping pbl")
            return False
        elif cmd == "qfp":
            if not self.check_param(["<filename>"]):
                return False
            if not self.check_cmd("peek"):
                self.LOGGER.error("Peek command isn't supported by edl loader")
                return False
            else:
                filename = options["<filename>"]
                if self.target_name in infotbl:
                    target_name = infotbl[self.target_name]
                    if len(target_name[1]) > 0:
                        if self.firehose.cmd_peek(target_name[1][0],
                                                  target_name[1][1], filename):
                            self.printer(
                                f"Dumped qfprom at offset {hex(target_name[1][0])} as {filename}."
                            )
                            return True
                    else:
                        self.LOGGER.error(
                            "No known qfprom offset for this chipset")
                else:
                    self.LOGGER.error("Unknown target chipset")
                self.LOGGER.error("Error on dumping qfprom")
            return False
        elif cmd == "secureboot":
            if not self.check_cmd("peek"):
                self.LOGGER.error("Peek command isn't supported by edl loader")
                return False
            else:
                if self.target_name in secureboottbl:
                    self.target_name = secureboottbl[self.target_name]
                    value = unpack("<I",
                                   self.firehose.cmd_peek(self.target_name,
                                                          4))[0]
                    is_secure = False
                    for area in range(0, 4):
                        sec_boot = (value >> (area * 8)) & 0xFF
                        pk_hashindex = sec_boot & 3
                        oem_pkhash = True if ((sec_boot >> 4)
                                              & 1) == 1 else False
                        auth_enabled = True if ((sec_boot >> 5)
                                                & 1) == 1 else False
                        use_serial = True if ((sec_boot >> 6)
                                              & 1) == 1 else False
                        if auth_enabled:
                            is_secure = True
                        self.printer(f"Sec_Boot{str(area)} " +
                                     f"PKHash-Index:{str(pk_hashindex)} " +
                                     f"OEM_PKHash: {str(oem_pkhash)} " +
                                     f"Auth_Enabled: {str(auth_enabled)}" +
                                     f"Use_Serial: {str(use_serial)}")
                    if is_secure:
                        self.printer("Secure boot enabled.")
                    else:
                        self.printer("Secure boot disabled.")
                    return True
                else:
                    self.LOGGER.error("Unknown target chipset")
                    return False
        elif cmd == "memtbl":
            if not self.check_param(["<filename>"]):
                return False
            if not self.check_cmd("peek"):
                self.LOGGER.error("Peek command isn't supported by edl loader")
                return False
            else:
                filename = options["<filename>"]
                if self.target_name in infotbl:
                    self.target_name = infotbl[self.target_name]
                    if len(self.target_name[2]) > 0:
                        if self.firehose.cmd_peek(self.target_name[2][0],
                                                  self.target_name[2][1],
                                                  filename):
                            self.printer(
                                f"Dumped memtbl at offset {hex(self.target_name[2][0])} as {filename}."
                            )
                            return True
                    else:
                        self.LOGGER.error(
                            "No known memtbl offset for this chipset")
                else:
                    self.LOGGER.error("Unknown target chipset")
                self.LOGGER.error("Error on dumping memtbl")
            return False
        elif cmd == "footer":
            if not self.check_param(["<filename>"]):
                return False
            luns = self.getluns(options)
            filename = options["<filename>"]
            for lun in luns:
                data, guid_gpt = self.firehose.get_gpt(
                    lun, int(options["--gpt-num-part-entries"]),
                    int(options["--gpt-part-entry-size"]),
                    int(options["--gpt-part-entry-start-lba"]))
                if guid_gpt is None:
                    break
                pnames = [
                    "userdata2", "metadata", "userdata", "reserved1",
                    "reserved2", "reserved3"
                ]
                for partition in guid_gpt.partentries:
                    if partition.name in pnames:
                        self.printer(f"Detected partition: {partition.name}")
                        data = self.firehose.cmd_read_buffer(
                            lun, partition.sector +
                            (partition.sectors -
                             (0x4000 //
                              self.firehose.cfg.SECTOR_SIZE_IN_BYTES)),
                            (0x4000 // self.firehose.cfg.SECTOR_SIZE_IN_BYTES),
                            False)
                        if data == b"":
                            continue
                        val = unpack("<I", data[:4])[0]
                        if (val & 0xFFFFFFF0) == 0xD0B5B1C0:
                            with open(filename, "wb") as write_handle:
                                write_handle.write(data)
                                self.printer(
                                    f"Dumped footer from {partition.name} as {filename}."
                                )
                                return True
            self.LOGGER.error("Error: Couldn't detect footer partition.")
            return False
        elif cmd == "rs":
            if options["--lun"] != 'None':
                lun = int(options["--lun"])
            else:
                lun = 0
            if not self.check_param(
                ["<filename>", "<sectors>", "<start_sector>"]):
                return False
            start = int(options["<start_sector>"])
            sectors = int(options["<sectors>"])
            filename = options["<filename>"]
            data = self.firehose.cmd_read_buffer(lun, start, sectors, False)
            try:
                with open(filename, "wb") as write_handle:
                    write_handle.write(data)
                    self.printer(
                        f"Dumped sector {str(start)} with sector count {str(sectors)} as {filename}."
                    )
                    return True
            except Exception as error:
                self.LOGGER.error(
                    f"Error: Couldn't open {filename} for writing: %s" %
                    str(error))
            return False
        elif cmd == "peek":
            if not self.check_param(["<offset>", "<length>", "<filename>"]):
                return False
            if not self.check_cmd("peek"):
                self.LOGGER.error("Peek command isn't supported by edl loader")
                return False
            else:
                offset = int(options["<offset>"], 16)
                length = int(options["<length>"], 16)
                filename = options["<filename>"]
                self.firehose.cmd_peek(offset, length, filename, True)
                self.LOGGER.info(
                    f"Peek data from offset {hex(offset)} and length {hex(length)} was written to {filename}"
                )
                return True
        elif cmd == "peekhex":
            if not self.check_param(["<offset>", "<length>"]):
                return False
            if not self.check_cmd("peek"):
                self.LOGGER.error("Peek command isn't supported by edl loader")
                return False
            else:
                offset = int(options["<offset>"], 16)
                length = int(options["<length>"], 16)
                resp = self.firehose.cmd_peek(offset, length, "", True)
                self.printer("\n")
                self.printer(hexlify(resp))
                return True
        elif cmd == "peekqword":
            if not self.check_param(["<offset>"]):
                return False
            if not self.check_cmd("peek"):
                self.LOGGER.error("Peek command isn't supported by edl loader")
                return False
            else:
                offset = int(options["<offset>"], 16)
                resp = self.firehose.cmd_peek(offset, 8, "", True)
                self.printer("\n")
                self.printer(hex(unpack("<Q", resp[:8])[0]))
                return True
        elif cmd == "peekdword":
            if not self.check_param(["<offset>"]):
                return False
            if not self.check_cmd("peek"):
                self.LOGGER.error("Peek command isn't supported by edl loader")
                return False
            else:
                offset = int(options["<offset>"], 16)
                resp = self.firehose.cmd_peek(offset, 4, "", True)
                self.printer("\n")
                self.printer(hex(unpack("<I", resp[:4])[0]))
                return True
        elif cmd == "poke":
            if not self.check_param(["<offset>", "<filename>"]):
                return False
            if not self.check_cmd("poke"):
                self.LOGGER.error("Poke command isn't supported by edl loader")
                return False
            else:
                offset = int(options["<offset>"], 16)
                filename = options["<filename>"]
                return self.firehose.cmd_poke(offset, "", filename, True)
        elif cmd == "pokehex":
            if not self.check_param(["<offset>", "<data>"]):
                return False
            if not self.check_cmd("poke"):
                self.LOGGER.error("Poke command isn't supported by edl loader")
                return False
            else:
                offset = int(options["<offset>"], 16)
                data = unhexlify(options["<data>"])
                return self.firehose.cmd_poke(offset, data, "", True)
        elif cmd == "pokeqword":
            if not self.check_param(["<offset>", "<data>"]):
                return False
            if not self.check_cmd("poke"):
                self.LOGGER.error("Poke command isn't supported by edl loader")
                return False
            else:
                offset = int(options["<offset>"], 16)
                data = pack("<Q", int(options["<data>"], 16))
                return self.firehose.cmd_poke(offset, data, "", True)
        elif cmd == "pokedword":
            if not self.check_param(["<offset>", "<data>"]):
                return False
            if not self.check_cmd("poke"):
                self.LOGGER.error("Poke command isn't supported by edl loader")
                return False
            else:
                offset = int(options["<offset>"], 16)
                data = pack("<I", int(options["<data>"], 16))
                return self.firehose.cmd_poke(offset, data, "", True)
        elif cmd == "memcpy":
            if not self.check_param(["<offset>", "<size>"]):
                return False
            if not self.check_cmd("poke"):
                self.printer("Poke command isn't supported by edl loader")
            else:
                srcoffset = int(options["<offset>"], 16)
                size = int(options["<size>"], 16)
                dstoffset = srcoffset + size
                if self.firehose.cmd_memcpy(dstoffset, srcoffset, size):
                    self.printer(
                        f"Memcpy from {hex(srcoffset)} to {hex(dstoffset)} succeeded"
                    )
                    return True
                else:
                    return False
        elif cmd == "reset":
            return self.firehose.cmd_reset()
        elif cmd == "nop":
            if not self.check_cmd("nop"):
                self.LOGGER.error("Nop command isn't supported by edl loader")
                return False
            else:
                return self.firehose.cmd_nop()
        elif cmd == "setbootablestoragedrive":
            if not self.check_param(["<lun>"]):
                return False
            if not self.check_cmd("setbootablestoragedrive"):
                self.LOGGER.error(
                    "setbootablestoragedrive command isn't supported by edl loader"
                )
                return False
            else:
                return self.firehose.cmd_setbootablestoragedrive(
                    int(options["<lun>"]))
        elif cmd == "getstorageinfo":
            if not self.check_cmd("getstorageinfo"):
                self.LOGGER.error(
                    "getstorageinfo command isn't supported by edl loader")
                return False
            else:
                return self.firehose.cmd_getstorageinfo()
        elif cmd == "w":
            if not self.check_param(["<partitionname>", "<filename>"]):
                return False
            partitionname = options["<partitionname>"]
            filename = options["<filename>"]
            if not os.path.exists(filename):
                self.LOGGER.error(f"Error: Couldn't find file: {filename}")
                return False
            res = self.firehose.detect_partition(options, partitionname)
            if res[0]:
                lun = res[1]
                partition = res[2]
                sectors = os.stat(
                    filename).st_size // self.firehose.cfg.SECTOR_SIZE_IN_BYTES
                if (os.stat(filename).st_size %
                        self.firehose.cfg.SECTOR_SIZE_IN_BYTES) > 0:
                    sectors += 1
                if sectors > partition.sectors:
                    self.LOGGER.error(
                        f"Error: {filename} has {sectors} sectors but partition only has {partition.sectors}."
                    )
                    return False
                if self.firehose.modules is not None:
                    self.firehose.modules.prerun()
                if self.firehose.cmd_program(lun, partition.sector, filename):
                    self.printer(
                        f"Wrote {filename} to sector {str(partition.sector)}.")
                    return True
                else:
                    self.printer(
                        f"Error writing {filename} to sector {str(partition.sector)}."
                    )
                    return False
            else:
                fpartitions = res[1]
                self.LOGGER.error(
                    f"Error: Couldn't detect partition: {partitionname}\nAvailable partitions:"
                )
                for lun in fpartitions:
                    for partition in fpartitions[lun]:
                        if options["--memory"].lower() == "emmc":
                            self.LOGGER.error("\t" + partition)
                        else:
                            self.LOGGER.error(lun + ":\t" + partition)
            return False
        elif cmd == "wl":
            if not self.check_param(["<directory>"]):
                return False
            directory = options["<directory>"]
            if options["--skip"]:
                skip = options["--skip"].split(",")
            else:
                skip = []
            luns = self.getluns(options)

            if not os.path.exists(directory):
                self.LOGGER.error(
                    f"Error: Couldn't find directory: {directory}")
                sys.exit()
            filenames = []
            if self.firehose.modules is not None:
                self.firehose.modules.prerun()
            for dirName, subdirList, fileList in os.walk(directory):
                for fname in fileList:
                    filenames.append(os.path.join(dirName, fname))
            for lun in luns:
                data, guid_gpt = self.firehose.get_gpt(
                    lun, int(options["--gpt-num-part-entries"]),
                    int(options["--gpt-part-entry-size"]),
                    int(options["--gpt-part-entry-start-lba"]))
                if guid_gpt is None:
                    break
                if "partentries" in dir(guid_gpt):
                    for filename in filenames:
                        for partition in guid_gpt.partentries:
                            partname = filename[filename.rfind("/") + 1:]
                            if ".bin" in partname[-4:]:
                                partname = partname[:-4]
                            if partition.name == partname:
                                if partition.name in skip:
                                    continue
                                sectors = os.stat(
                                    filename
                                ).st_size // self.firehose.cfg.SECTOR_SIZE_IN_BYTES
                                if (os.stat(filename).st_size %
                                        self.firehose.cfg.SECTOR_SIZE_IN_BYTES
                                    ) > 0:
                                    sectors += 1
                                if sectors > partition.sectors:
                                    self.LOGGER.error(
                                        f"Error: {filename} has {sectors} sectors but partition "
                                        + f"only has {partition.sectors}.")
                                    return False
                                self.printer(
                                    f"Writing {filename} to partition {str(partition.name)}."
                                )
                                self.firehose.cmd_program(
                                    lun, partition.sector, filename)
                else:
                    self.printer(
                        "Couldn't write partition. Either wrong memorytype given or no gpt partition."
                    )
                    return False
            return True
        elif cmd == "ws":
            if not self.check_param(["<start_sector>"]):
                return False
            if options["--lun"] is None:
                lun = 0
            else:
                lun = int(options["--lun"])
            start = int(options["<start_sector>"])
            filename = options["<filename>"]
            if not os.path.exists(filename):
                self.LOGGER.error(f"Error: Couldn't find file: {filename}")
                return False
            if self.firehose.modules is not None:
                self.firehose.modules.prerun()
            if self.firehose.cmd_program(lun, start, filename):
                self.printer(f"Wrote {filename} to sector {str(start)}.")
                return True
            else:
                self.LOGGER.error(
                    f"Error on writing {filename} to sector {str(start)}")
                return False
        elif cmd == "wf":
            if not self.check_param(["<filename>"]):
                return False
            if options["--lun"] is None:
                lun = 0
            else:
                lun = int(options["--lun"])
            start = 0
            filename = options["<filename>"]
            if not os.path.exists(filename):
                self.LOGGER.error(f"Error: Couldn't find file: {filename}")
                return False
            if self.firehose.modules is not None:
                self.firehose.modules.prerun()
            if self.firehose.cmd_program(lun, start, filename):
                self.printer(f"Wrote {filename} to sector {str(start)}.")
                return True
            else:
                self.LOGGER.error(
                    f"Error on writing {filename} to sector {str(start)}")
                return False
        elif cmd == "e":
            if not self.check_param(["<partitionname>"]):
                return False
            luns = self.getluns(options)
            partitionname = options["<partitionname>"]
            for lun in luns:
                data, guid_gpt = self.firehose.get_gpt(
                    lun, int(options["--gpt-num-part-entries"]),
                    int(options["--gpt-part-entry-size"]),
                    int(options["--gpt-part-entry-start-lba"]))
                if guid_gpt is None:
                    break
                if self.firehose.modules is not None:
                    self.firehose.modules.prerun()
                if "partentries" in dir(guid_gpt):
                    for partition in guid_gpt.partentries:
                        if partition.name == partitionname:
                            self.firehose.cmd_erase(lun, partition.sector,
                                                    partition.sectors)
                            self.printer(
                                f"Erased {partitionname} starting at sector {str(partition.sector)} with sector count "
                                + f"{str(partition.sectors)}.")
                            return True
                else:
                    self.printer(
                        "Couldn't erase partition. Either wrong memorytype given or no gpt partition."
                    )
                    return False
            self.LOGGER.error(
                f"Error: Couldn't detect partition: {partitionname}")
            return False
        elif cmd == "es":
            if not self.check_param(["<start_sector>", "<sectors>"]):
                return False
            if options["--lun"] is None:
                lun = 0
            else:
                lun = int(options["--lun"])
            start = int(options["<start_sector>"])
            sectors = int(options["<sectors>"])
            if self.firehose.modules is not None:
                self.firehose.modules.prerun()
            if self.firehose.cmd_erase(lun, start, sectors):
                self.printer(
                    f"Erased sector {str(start)} with sector count {str(sectors)}."
                )
                return True
            return False
        elif cmd == "xml":
            if not self.check_param(["<xmlfile>"]):
                return False
            return self.firehose.cmd_xml(options["<xmlfile>"])
        elif cmd == "rawxml":
            if not self.check_param(["<xmlstring>"]):
                return False
            return self.firehose.cmd_rawxml(options["<xmlstring>"])
        elif cmd == "send":
            if not self.check_param(["<command>"]):
                return False
            command = options["<command>"]
            resp = self.firehose.cmd_send(command, True)
            self.printer("\n")
            self.printer(resp)
            return True
        elif cmd == "server":
            return do_tcp_server(self, options, self.handle_firehose)
        elif cmd == "modules":
            if not self.check_param(["<command>", "<options>"]):
                return False
            mcommand = options["<command>"]
            moptions = options["<options>"]
            if self.firehose.modules is None:
                self.LOGGER.error("Feature is not supported")
                return False
            else:
                return self.firehose.modules.run(command=mcommand,
                                                 args=moptions)
        else:
            self.LOGGER.error(
                "Unknown/Missing command, a command is required.")
            return False