예제 #1
0
 def __init__(self, arguments, cdc, sahara, loglevel, printer):
     self.cdc = cdc
     self.sahara = sahara
     self.arguments = arguments
     self.streaming = Streaming(cdc, sahara, loglevel)
     self.printer = printer
     self.__logger.setLevel(loglevel)
     if loglevel == logging.DEBUG:
         logfilename = "log.txt"
         fh = logging.FileHandler(logfilename)
         self.__logger.addHandler(fh)
예제 #2
0
class streaming_client(metaclass=LogBase):
    def __init__(self, arguments, cdc, sahara, loglevel, printer):
        self.cdc = cdc
        self.__logger = self.__logger
        self.sahara = sahara
        self.arguments = arguments
        self.streaming = Streaming(cdc, sahara, loglevel)
        self.printer = printer
        self.__logger.setLevel(loglevel)
        self.error = self.__logger.error
        self.info = self.__logger.info
        if loglevel == logging.DEBUG:
            logfilename = "log.txt"
            fh = logging.FileHandler(logfilename)
            self.__logger.addHandler(fh)

    def disconnect(self):
        self.cdc.close()
        sys.exit(0)

    def check_param(self, parameters):
        error = False
        params = ""
        for parameter in parameters:
            params += parameter + " "
            if parameter not in parameters:
                error = True
        if error:
            if len(parameters) == 1:
                self.printer("Argument " + params + "required.")
            else:
                self.printer("Arguments " + params + "required.")
            return False
        return True

    def print_partitions(self, partitions):
        self.printer("Name            Offset\t\tLength\t\tAttr\t\t\tFlash")
        self.printer(
            "-------------------------------------------------------------")
        for name in partitions:
            partition = partitions[name]
            for i in range(0x10 - len(name)):
                name += " "
            offset = partition[
                "offset"] * self.streaming.settings.num_pages_per_blk * self.streaming.settings.PAGESIZE
            length = partition[
                "length"] * self.streaming.settings.num_pages_per_blk * self.streaming.settings.PAGESIZE
            attr1 = partition["attr1"]
            attr2 = partition["attr2"]
            attr3 = partition["attr3"]
            which_flash = partition["which_flash"]
            self.printer(
                f"{name}\t%08X\t%08X\t{hex(attr1)}/{hex(attr2)}/{hex(attr3)}\t{which_flash}"
                % (offset, length))

    def handle_streaming(self, cmd, options):
        mode = 0
        """
        offset = getint(options["<offset>"])
        length = getint(options["<length>"])
        filename = options["<filename>"]
        self.streaming.streaming_mode=self.streaming.Qualcomm
        self.streaming.memread=self.streaming.qc_memread
        self.streaming.memtofile(offset, length, filename)
        """

        if "<mode>" in options:
            mode = options["<mode>"]
        if self.streaming.connect(mode):
            xflag = 0
            self.streaming.hdlc.receive_reply(5)
            if self.streaming.streaming_mode == self.streaming.Patched:
                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.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.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.error(
                            f"Error: Couldn't detect partition: {partition}\nAvailable partitions:"
                        )
                        self.print_partitions(rpartitions)
            elif cmd == "rs":
                sector = getint(options["<start_sector>"])  # Page
                sectors = getint(options["<sectors>"])
                filename = options["<filename>"]
                self.printer(
                    f"Dumping at Sector {hex(sector)} with Sectorcount {hex(sectors)}..."
                )
                if self.streaming.read_sectors(sector, sectors, filename,
                                               True):
                    self.printer(
                        f"Dumped sector {str(sector)} with sector count {str(sectors)} as {filename}."
                    )
            elif cmd == "rf":
                sector = 0
                sectors = self.streaming.settings.MAXBLOCK * self.streaming.settings.num_pages_per_blk * \
                    self.streaming.settings.sectors_per_page
                filename = options["<filename>"]
                self.printer(
                    f"Dumping Flash from sector 0 to sector {hex(sectors)}...")
                if self.streaming.read_sectors(sector, sectors, filename,
                                               True):
                    self.printer(
                        f"Dumped sector {str(sector)} with sector count {str(sectors)} as {filename}."
                    )
            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.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.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 = getint(options["<offset>"])
                length = getint(options["<length>"])
                filename = options["<filename>"]
                if self.streaming.memtofile(offset, length, filename):
                    self.info(
                        f"Peek data from offset {hex(offset)} and length {hex(length)} was written to {filename}"
                    )
            elif cmd == "peekhex":
                offset = getint(options["<offset>"])
                length = getint(options["<length>"])
                resp = self.streaming.memread(offset, length)
                self.printer("\n")
                self.printer(hexlify(resp))
            elif cmd == "peekqword":
                offset = getint(options["<offset>"])
                resp = self.streaming.memread(offset, 8)
                self.printer("\n")
                self.printer(hex(unpack("<Q", resp[:8])[0]))
            elif cmd == "peekdword":
                offset = getint(options["<offset>"])
                resp = self.streaming.mempeek(offset)
                self.printer("\n")
                self.printer(hex(resp))
            elif cmd == "poke":
                offset = getint(options["<offset>"])
                filename = unhexlify(options["<filename>"])
                try:
                    with open(filename, "rb") as rf:
                        data = rf.read()
                        if self.streaming.memwrite(offset, data):
                            self.info("Poke succeeded.")
                        else:
                            self.error("Poke failed.")
                except Exception as e:
                    self.error(str(e))
            elif cmd == "pokehex":
                offset = getint(options["<offset>"])
                data = unhexlify(options["<data>"])
                if self.streaming.memwrite(offset, data):
                    self.info("Poke succeeded.")
                else:
                    self.error("Poke failed.")
            elif cmd == "pokeqword":
                offset = getint(options["<offset>"])
                data = pack("<Q", getint(options["<data>"]))
                if self.streaming.memwrite(offset, data):
                    self.info("Poke succeeded.")
                else:
                    self.error("Poke failed.")
            elif cmd == "pokedword":
                offset = getint(options["<offset>"])
                data = pack("<I", getint(options["<data>"]))
                if self.streaming.mempoke(offset, data):
                    self.info("Poke succeeded.")
                else:
                    self.error("Poke failed.")
            elif cmd == "reset":
                if self.streaming.reset():
                    self.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.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.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.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.error("Error on dumping qfprom")
            elif cmd == "memcpy":
                if not self.check_param(["<offset>", "<size>"]):
                    return False
                srcoffset = getint(options["<offset>"])
                size = getint(options["<size>"])
                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":
                # resp=self.streaming.send(b"\x7E\x09")
                self.error("Nop command isn't supported by streaming loader")
                return True
            elif cmd == "setbootablestoragedrive":
                self.error(
                    "setbootablestoragedrive command isn't supported by streaming loader"
                )
                return True
            elif cmd == "getstorageinfo":
                self.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>"]
                partitionfilename = ""
                if "--partitionfilename" in options:
                    partitionfilename = options["--partitionfilename"]
                    if not os.path.exists(partitionfilename):
                        self.error(
                            f"Error: Couldn't find partition file: {partitionfilename}"
                        )
                        return False
                if not os.path.exists(filename):
                    self.error(f"Error: Couldn't find file: {filename}")
                    return False
                if partitionfilename == "":
                    rpartitions = self.streaming.get_partitions()
                else:
                    rpartitions = self.streaming.get_partitions(
                        partitionfilename)
                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.error(
                                f"Error: {filename} has {sectors} sectors but partition only has {length}."
                            )
                            return False
                        if self.streaming.modules is not None:
                            self.streaming.modules.writeprepare()
                        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.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.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.writeprepare()
                    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.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.error(
                    "ws command isn't supported by streaming loader")  # todo
                return False
            elif cmd == "wf":
                self.error(
                    "wf command isn't supported by streaming loader")  # todo
                return False
            elif cmd == "e":
                self.error(
                    "e command isn't supported by streaming loader")  # todo
                return False
            elif cmd == "es":
                self.error(
                    "es command isn't supported by streaming loader")  # todo
                return False
            elif cmd == "xml":
                self.error("xml command isn't supported by streaming loader")
                return False
            elif cmd == "rawxml":
                self.error(
                    "rawxml command isn't supported by streaming loader")
                return False
            elif cmd == "send":
                self.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.error("Feature is not supported")
                    return False
                else:
                    return self.streaming.modules.run(mainargs=options,
                                                      command=command)
            else:
                self.error("Unknown/Missing command, a command is required.")
                return False
예제 #3
0
파일: edl.py 프로젝트: Ethern0T/edl
    def run(self):
        if sys.platform == 'win32' or sys.platform == 'win64' or sys.platform == 'winnt':
            proper_driver = self.console_cmd(
                r'reg query HKLM\HARDWARE\DEVICEMAP\SERIALCOMM')
            if re.findall(r'QCUSB', str(proper_driver)):
                self.warning(
                    f'Please first install libusb_win32 driver from Zadig')

        mode = ""
        loop = 0
        vid = int(args["--vid"], 16)
        pid = int(args["--pid"], 16)
        interface = -1
        if vid != -1 and pid != -1:
            portconfig = [[vid, pid, interface]]
        else:
            portconfig = default_ids
        if args["--debugmode"]:
            logfilename = "log.txt"
            if os.path.exists(logfilename):
                os.remove(logfilename)
            fh = logging.FileHandler(logfilename)
            self.__logger.addHandler(fh)
            self.__logger.setLevel(logging.DEBUG)
        else:
            self.__logger.setLevel(logging.INFO)

        self.cdc = UsbClass(portconfig=portconfig,
                            loglevel=self.__logger.level)
        self.sahara = sahara(self.cdc, loglevel=self.__logger.level)

        if args["--loader"] == 'None':
            self.info("Trying with no loader given ...")
            self.sahara.programmer = ""
        else:
            loader = args["--loader"]
            self.info(f"Using loader {loader} ...")
            self.sahara.programmer = loader

        self.info("Waiting for the device")
        resp = None
        self.cdc.timeout = 100
        mode, resp = self.doconnect(loop, mode, resp)
        if resp == -1:
            mode, resp = self.doconnect(loop, mode, resp)
            if resp == -1:
                self.error("USB desync, please rerun command !")
                self.exit()
        # print((mode, resp))
        if mode == "sahara":
            if resp is None:
                if mode == "sahara":
                    print("Sahara in error state, resetting ...")
                    self.sahara.cmd_reset()
                    data = self.cdc.read(5)
                    self.exit()
            elif "mode" in resp:
                mode = resp["mode"]
                if mode == self.sahara.sahara_mode.SAHARA_MODE_MEMORY_DEBUG:
                    if args["memorydump"]:
                        time.sleep(0.5)
                        print("Device is in memory dump mode, dumping memory")
                        self.sahara.debug_mode()
                        self.exit()
                    else:
                        print("Device is in streaming mode, uploading loader")
                        self.cdc.timeout = None
                        sahara_info = self.sahara.streaminginfo()
                        if sahara_info:
                            mode, resp = self.sahara.connect()
                            if mode == "sahara":
                                mode = self.sahara.upload_loader()
                                if "enprg" in self.sahara.programmer.lower():
                                    mode = "load_enandprg"
                                elif "nprg" in self.sahara.programmer.lower():
                                    mode = "load_nandprg"
                                elif mode != "":
                                    mode = "load_" + mode
                                if "load_" in mode:
                                    time.sleep(0.3)
                                else:
                                    print(
                                        "Error, couldn't find suitable enprg/nprg loader :("
                                    )
                                    self.exit()
                else:
                    print("Device is in EDL mode .. continuing.")
                    self.cdc.timeout = None
                    sahara_info = self.sahara.cmd_info()
                    if sahara_info:
                        mode, resp = self.sahara.connect()
                        if mode == "sahara":
                            mode = self.sahara.upload_loader()
                            if mode == "firehose":
                                if "enprg" in self.sahara.programmer.lower():
                                    mode = "enandprg"
                                elif "nprg" in self.sahara.programmer.lower():
                                    mode = "nandprg"
                            if mode != "":
                                if mode != "firehose":
                                    streaming = Streaming(
                                        self.cdc, self.sahara,
                                        self.__logger.level)
                                    if streaming.connect(1):
                                        print(
                                            "Successfully uploaded programmer :)"
                                        )
                                        mode = "nandprg"
                                    else:
                                        print("Device is in an unknown state")
                                        self.exit()
                                else:
                                    print(
                                        "Successfully uploaded programmer :)")
                            else:
                                print("No suitable loader found :(")
                                self.exit()
                    else:
                        print(
                            "Device is in an unknown sahara state, resetting")
                        print("resp={0}".format(resp))
                        self.sahara.cmd_reset()
                        self.exit()
            else:
                print("Device is in an unknown state")
                self.exit()
        else:
            self.sahara.bit64 = True

        if mode == "firehose":
            self.cdc.timeout = None
            fh = firehose_client(args, self.cdc, self.sahara,
                                 self.__logger.level, print)
            cmd = self.parse_cmd(args)
            options = self.parse_option(args)
            if cmd != "":
                fh.handle_firehose(cmd, options)
        elif mode == "nandprg" or mode == "enandprg" or mode == "load_nandprg" or mode == "load_enandprg":
            sc = streaming_client(args, self.cdc, self.sahara,
                                  self.__logger.level, print)
            cmd = self.parse_cmd(args)
            options = self.parse_option(args)
            if "load_" in mode:
                options["<mode>"] = 1
            else:
                options["<mode>"] = 0
            sc.handle_streaming(cmd, options)
        else:
            self.error(
                "Sorry, couldn't talk to Sahara, please reboot the device !")

        self.exit()