Add streaming mode

This commit is contained in:
Bjoern Kerler 2020-12-22 22:19:37 +01:00
parent 1eb773f553
commit 036bc63efd
38 changed files with 5769 additions and 4268 deletions

0
Config/nvitems.xml Normal file → Executable file
View file

View file

@ -173,6 +173,7 @@ sochw = {
}
infotbl = {
#BOOT_ROM_BASE_PHYS ,SECURITY_CONTROL_BASE_PHYS,
"QDF2432": [[], [0x01900000, 0x100000], []],
"QCA6290": [[],[0x01e20000,0x1000],[]],
"QCA6390": [[],[0x01e20000,0x1000],[]],
@ -188,17 +189,19 @@ infotbl = {
"APQ8056": [[0x100000, 0x18000], [0x000A0000, 0x6FFF], [0x200000, 0x24000]],
"APQ8076": [[0x100000, 0x18000], [0x000A0000, 0x6FFF], [0x200000, 0x24000]],
"APQ8084": [[0xFC010000, 0x18000], [0xFC4B8000, 0x60F0], [0x200000, 0x24000]],
"APQ8092": [[0xFC010000, 0x18000], [0xFC4B8000, 0x60F0], [0x200000, 0x24000]],
"APQ8092": [[0xFC010000, 0x18000], [0xE0DB8000, 0x60F0], [0x200000, 0x24000]],
"APQ8098": [[0x300000, 0x3c000], [0x780000, 0x10000], []],
"MSM7227A": [[], [], []],
"MSM8210": [[], [], []],
"MSM8210": [[], [0xFC4B8000,0x6FFF], []],
"MSM8212": [[], [], []],
"MSM8610": [[], [0xFC4B8000,0x6FFF], []],
"MSM8905": [[0x100000, 0x18000], [0x00058000, 0x1000], [0x200000, 0x24000]],
"MSM8909": [[0x100000, 0x18000], [0x00058000, 0x1000], [0x200000, 0x24000]],
"MSM8916": [[0x100000, 0x18000], [0x0005C000, 0x1000], [0x200000, 0x24000]],
"MSM8917": [[0x100000, 0x18000], [0x000A0000, 0x6FFF], [0x200000, 0x24000]],
"MSM8920": [[0x100000, 0x18000], [0x000A0000, 0x6FFF], [0x200000, 0x24000]],
"MSM8926": [[], [], []],
"MSM8226": [[], [0xFC4B8000,0x6FFF], []],
"MSM8926": [[], [0xFC4B8000,0x6FFF], []],
"MSM8928": [[], [], []],
"MSM8929": [[0x100000, 0x18000], [0x00058000, 0x1000], [0x200000, 0x24000]],
"MSM8930": [[0x100000, 0x18000], [0x700000, 0x1000], []],
@ -206,9 +209,10 @@ infotbl = {
"MSM8937": [[0x100000, 0x18000], [0x000A0000, 0x6FFF], [0x200000, 0x24000]],
"MSM8939": [[0x100000, 0x18000], [0x00058000, 0x1000], [0x200000, 0x24000]],
"MSM8940": [[0x100000, 0x18000], [0x000A0000, 0x6FFF], [0x200000, 0x24000]],
"MSM8952": [[0x100000, 0x18000], [0x00058000, 0x1000], [0x200000, 0x24000]],
"MSM8952": [[0x100000, 0x18000], [0x00058000, 0x6000], [0x200000, 0x24000]],
"MSM8953": [[0x100000, 0x18000], [0xA0000, 0x1000], [0x200000, 0x24000]],
"MSM8956": [[0x100000, 0x18000], [0x000A0000, 0x6FFF], [0x200000, 0x24000]],
"MSM8962": [[0x100000, 0x18000], [0xFC4B8000, 0x6FFF], [0x200000, 0x24000]],
"MSM8974": [[0xFC010000, 0x18000], [0xFC4B8000, 0x60F0], [0x200000, 0x24000]],
"MSM8974Pro": [[0xFC010000, 0x18000], [0xFC4B8000, 0x60F0], [0x200000, 0x24000]],
"MSM8974AB": [[0xFC010000, 0x18000], [0xFC4B8000, 0x60F0], [0x200000, 0x24000]],
@ -223,6 +227,14 @@ infotbl = {
"MSM8998": [[0x300000, 0x3c000], [0x780000, 0x10000], []],
"MSM9206": [[0x100000, 0x18000], [0x000A0000, 0x6FFF], [0x200000, 0x24000]],
"MSM9207": [[0x100000, 0x18000], [0x000A0000, 0x6FFF], [0x200000, 0x24000]],
"MDM9x25": [[0xFC010000, 0x18000], [0xFC4B8000, 0x6000], [0x200000, 0x24000]],
"MDM9x35": [[0xFC010000, 0x18000], [0xFC4B8000, 0x6000], [0x200000, 0x24000]],
"MDM9x40": [[0x100000, 0x18000], [0x00058000, 0x6000], [0x200000, 0x24000]],
"MDM9x45": [[0x100000, 0x18000], [0x00058000, 0x6000], [0x200000, 0x24000]],
"MDM9x50": [[0x100000, 0x18000], [0x000A0000, 0x6FFF], [0x200000, 0x24000]],
"MDM9x55": [[0x100000, 0x18000], [0x000A0000, 0x6FFF], [0x200000, 0x24000]],
"MDM9x60": [[0x100000, 0x18000], [0x000A0000, 0x6FFF], [0x200000, 0x24000]],
"MDM9x65": [[0x100000, 0x18000], [0x000A0000, 0x6FFF], [0x200000, 0x24000]],
"MDM9250": [[0x100000, 0x18000], [0x000A0000, 0x6FFF], [0x200000, 0x24000]],
"MDM9350": [[0x100000, 0x18000], [0x000A0000, 0x6FFF], [0x200000, 0x24000]],
"MSM9607": [[0x100000, 0x18000], [0x000A0000, 0x6FFF], [0x200000, 0x24000]],
@ -315,8 +327,16 @@ secureboottbl = {
"MDM9250": 0x000a01d0,
"MDM9350": 0x000a01d0,
"MDM9607": 0x000a01d0,
"MDM9x25": 0xFC4B6028,
"MDM9x30": 0xFC4B6028,
"MDM9x35": 0xFC4B6028,
"MDM9x40": 0x00058098,
"MDM9x45": 0x00058098,
"MDM9650": 0x000a01d0,
"MDM9x50": 0x000a01d0,
"MDM9x55": 0x000a01d0,
"MDM9x60": 0x000a01d0,
"MDM9x65": 0x000a01d0,
"SDM429": 0x000a01d0,
"SDM439": 0x000a01d0,
"SDM450": 0x000a01d0,

0
Drivers/50-android.rules Normal file → Executable file
View file

0
Drivers/51-edl.rules Normal file → Executable file
View file

View file

@ -1,4 +1,5 @@
import socket
from binascii import hexlify
class tcpclient():
def __init__(self, port):
@ -11,22 +12,16 @@ class tcpclient():
try:
for command in commands:
self.sock.sendall(bytes(command, 'utf-8'))
amount_received = 0
amount_expected = 3
while amount_received < amount_expected:
data = self.sock.recv(4096)
if data == b"":
break
amount_received += len(data)
# print("received %s" % data)
data = data.decode('utf-8').split("\n")
if data[0] == "<ACK>":
print(data[1])
else:
if len(data)>1:
print("Error: " + data[1])
else:
print("Unknown error !")
data=""
while not "<ACK>" in data and not "<NAK>" in data:
tmp = self.sock.recv(4096)
if tmp == b"":
continue
try:
data += tmp.decode('utf-8')
except:
data += hexlify(tmp)
print(data)
finally:
print("closing socket")
self.sock.close()

0
Example/benchmark.xml Normal file → Executable file
View file

View file

@ -21,8 +21,9 @@ class client():
def main():
exp=client()
exp.commands = [
"send:True,nop",
#"peek:0x00100000,0x8,qfp.bin"
"send:nop",
"r:boot,boot.img",
"peek:0x00100000,0x8,qfp.bin"
#"pokehex:0x1402C2CC,1f2003d5",
#"peek:0x14084840,0xC00,uart.bin"
]

View file

@ -0,0 +1,97 @@
class generic():
def __init__(self, fh, serial, args, logger):
self.fh=fh
self.log=logger
self.serial=serial
self.args=args
def oem_unlock(self,enable):
res = self.fh.detect_partition(self.args, "config")
if res[0] == True:
lun = res[1]
rpartition = res[2]
offsettopatch = 0x7FFFF
sector = rpartition.sector + (offsettopatch // self.fh.cfg.SECTOR_SIZE_IN_BYTES)
offset = offsettopatch % self.fh.cfg.SECTOR_SIZE_IN_BYTES
if enable:
value = 0x1
else:
value = 0x0
size_in_bytes = 1
if self.fh.cmd_patch(lun, sector, offset, value, size_in_bytes, True):
print(
f"Patched sector {str(rpartition.sector)}, offset {str(offset)} with value {value}, size in bytes {size_in_bytes}.")
else:
print(
f"Error on writing sector {str(rpartition.sector)}, offset {str(offset)} with value {value}, size in bytes {size_in_bytes}.")
else:
"""
#define DEVICE_MAGIC "ANDROID-BOOT!"
#define DEVICE_MAGIC_SIZE 13
#define MAX_PANEL_ID_LEN 64
#define MAX_VERSION_LEN 64
#if VBOOT_MOTA
struct device_info
{
unsigned char magic[DEVICE_MAGIC_SIZE];
bool is_unlocked;
bool is_tampered;
bool is_verified;
bool charger_screen_enabled;
char display_panel[MAX_PANEL_ID_LEN];
char bootloader_version[MAX_VERSION_LEN];
char radio_version[MAX_VERSION_LEN];
bool is_unlock_critical;
};
#else
struct device_info
{
unsigned char magic[DEVICE_MAGIC_SIZE];
bool is_unlocked; #0x10
bool is_tampered; #0x14
bool charger_screen_enabled; #0x18
char display_panel[MAX_PANEL_ID_LEN];
char bootloader_version[MAX_VERSION_LEN];
char radio_version[MAX_VERSION_LEN];
bool verity_mode; // 1 = enforcing, 0 = logging
bool is_unlock_critical;
};
#endif
"""
res = self.fh.detect_partition(self.args, "devinfo")
if res[0] == True:
lun = res[1]
rpartition = res[2]
offsettopatch1 = 0x10 # is_unlocked
offsettopatch2 = 0x18 # is_critical_unlocked
offsettopatch3 = 0x7FFE10 # zte
offsettopatch4 = 0x7FFE18 # zte
sector1, offset1 = self.fh.calc_offset(rpartition.sector, offsettopatch1)
sector2, offset2 = self.fh.calc_offset(rpartition.sector, offsettopatch2)
sector3, offset3 = self.fh.calc_offset(rpartition.sector, offsettopatch3)
sector4, offset4 = self.fh.calc_offset(rpartition.sector, offsettopatch4)
value = 0x1
size_in_bytes = 1
if self.fh.cmd_patch(lun, sector1, offset1, 0x1, size_in_bytes, True):
if self.fh.cmd_patch(lun, sector2, offset2, 0x1, size_in_bytes, True):
print(
f"Patched sector {str(rpartition.sector)}, offset {str(offset1)} with value {value}, size in bytes {size_in_bytes}.")
data = self.fh.cmd_read_buffer(lun, rpartition.sector, rpartition.sectors)
if (len(data) > 0x7FFE20) and data[0x7FFE00:0x7FFE10] == b"ANDROID-BOOT!\x00\x00\x00":
if self.fh.cmd_patch(lun, sector3, offset3, value, size_in_bytes, True):
if self.fh.cmd_patch(lun, sector4, offset4, value, size_in_bytes, True):
print(
f"Patched sector {str(rpartition.sector)}, offset {str(offset1)} with value {value}, size in bytes {size_in_bytes}.")
return True
print(
f"Error on writing sector {str(rpartition.sector)}, offset {str(offset1)} with value {value}, size in bytes {size_in_bytes}.")
return False
else:
fpartitions = res[1]
self.log.error(f"Error: Couldn't detect partition: \"devinfo\"\nAvailable partitions:")
for lun in fpartitions:
for rpartition in fpartitions[lun]:
if self.args["--memory"].lower() == "emmc":
self.log.error("\t" + rpartition)
else:
self.log.error(lun + ":\t" + rpartition)

View file

@ -1,107 +1,66 @@
try:
from Library.Modules.oneplus import oneplus
from Library.Modules.generic import generic
except Exception as e:
pass
class modules():
def __init__(self,fh,serial,supported_functions,log,devicemodel):
self.fh=fh
self.serial=serial
self.supported_functions=supported_functions
def __init__(self, fh, serial, supported_functions, log, devicemodel, args):
self.fh = fh
self.args = args
self.serial = serial
self.supported_functions = supported_functions
self.log = log
self.options={}
self.devicemodel=devicemodel
self.ops=None
self.options = {}
self.devicemodel = devicemodel
self.generic = None
try:
self.ops = oneplus(fh=self.fh, projid=self.devicemodel, serial=self.serial,supported_functions=self.supported_functions)
self.generic = generic(fh=self.fh, serial=self.serial, args=self.args, logger=self.log)
except Exception as e:
pass
self.ops = None
try:
self.ops = oneplus(fh=self.fh, projid=self.devicemodel, serial=self.serial,
supported_functions=self.supported_functions)
except Exception as e:
pass
def addpatch(self):
if self.ops!=None:
if self.ops is not None:
return self.ops.addpatch()
return ""
def addprogram(self):
if self.ops!=None:
if self.ops is not None:
return self.ops.addprogram()
return ""
def prerun(self):
if self.ops!=None:
if self.ops is not None:
return self.ops.run()
return True
def run(self,mainargs,command,args):
args=args.split(",")
options={}
def run(self, command, args):
args = args.split(",")
options = {}
for i in range(len(args)):
if "=" in args[i]:
option=args[i].split("=")
if len(option)>1:
options[option[0]]=option[1]
option = args[i].split("=")
if len(option) > 1:
options[option[0]] = option[1]
else:
options[args[i]]=True
if command=="ops":
if self.devicemodel!=None and self.ops!=None:
enable=False
partition = "param"
if "enable" in options:
enable = True
elif "disable" in options:
enable = False
else:
self.log.error("Unknown mode given. Available are: enable, disable.")
exit(0)
res = self.fh.detect_partition(mainargs, partition)
if res[0] == True:
lun = res[1]
rpartition = res[2]
paramdata = self.fh.cmd_read_buffer(lun, rpartition.sector, rpartition.sectors, False)
if paramdata == b"":
self.log.error("Error on reading param partition.")
exit(1)
paramdata = self.ops.enable_ops(paramdata, enable)
self.ops.run()
if self.fh.cmd_program_buffer(lun, rpartition.sector, paramdata, False):
print("Successfully set mode")
else:
self.log.error("Error on writing param partition")
else:
fpartitions = res[1]
self.log.error(f"Error: Couldn't detect partition: {partition}\nAvailable partitions:")
for lun in fpartitions:
for rpartition in fpartitions[lun]:
if mainargs["--memory"].lower() == "emmc":
self.log.error("\t" + rpartition)
else:
self.log.error(lun + ":\t" + rpartition)
options[args[i]] = True
if command=="":
print("Valid commands are:\noemunlock\n")
return False
if self.generic is not None and command == "oemunlock":
if "enable" in options:
enable = True
elif "disable" in options:
enable = False
else:
self.log.error("A devicemodel is needed for this command")
exit(0)
elif command=="oemunlock":
partition = "config"
res=self.fh.detect_partition(mainargs, partition)
if res[0]==True:
lun=res[1]
rpartition=res[2]
offsettopatch=0x7FFFF
sector=rpartition.sector + (offsettopatch//self.fh.cfg.SECTOR_SIZE_IN_BYTES)
offset=offsettopatch%self.fh.cfg.SECTOR_SIZE_IN_BYTES
value=0x1
size_in_bytes=1
if self.fh.cmd_patch(lun, sector, offset, value, size_in_bytes, True):
print(f"Patched sector {str(rpartition.sector)}, offset {str(offset)} with value {value}, size in bytes {size_in_bytes}.")
else:
print(f"Error on writing sector {str(rpartition.sector)}, offset {str(offset)} with value {value}, size in bytes {size_in_bytes}.")
else:
fpartitions=res[1]
self.log.error(f"Error: Couldn't detect partition: {partition}\nAvailable partitions:")
for lun in fpartitions:
for rpartition in fpartitions[lun]:
if mainargs["--memory"].lower() == "emmc":
self.log.error("\t" + rpartition)
else:
self.log.error(lun + ":\t" + rpartition)
exit(0)
self.log.error("Unknown mode given. Available are: enable, disable.")
return False
return self.generic.oem_unlock(enable)
return False

View file

@ -1,142 +1,142 @@
#!/usr/bin/env python3
import os
import sys
from capstone import *
from keystone import *
from binascii import unhexlify
import argparse
def asm(code,cpu,mode,bigendian):
def asm(code, cpu, mode, bigendian):
if bigendian:
little=KS_MODE_BIG_ENDIAN #big-endian mode
little = KS_MODE_BIG_ENDIAN # big-endian mode
else:
little=KS_MODE_LITTLE_ENDIAN #little-endian mode (default mode)
print("CPU: %s, MODE: %s" % (cpu,mode))
ks=None
if cpu=="arm":
#ARM architecture (including Thumb, Thumb-2)
if mode=="arm":
ks = Ks(KS_ARCH_ARM, KS_MODE_ARM+little) #ARM mode
elif mode=="thumb":
ks = Ks(KS_ARCH_ARM, KS_MODE_THUMB+little) #THUMB mode (including Thumb-2)
elif mode=="mclass":
ks = Ks(KS_ARCH_ARM, KS_MODE_THUMB+KS_MODE_MCLASS+little)
elif mode=="v8":
ks = Ks(KS_ARCH_ARM, KS_MODE_ARM+KS_MODE_V8+little)
elif cpu=="arm64":
#ARM-64, also called AArch64
ks = Ks(KS_ARCH_ARM64, little) #ARM mode
elif cpu=="mips":
#Mips architecture
if mode=="micro":
ks = Ks(KS_ARCH_MIPS, KS_MODE_MICRO+little) #MicroMips mode
elif mode=="3":
ks = Ks(KS_ARCH_MIPS, KS_MODE_MIPS3+little) #Mips III ISA
elif mode=="32R6":
ks = Ks(KS_ARCH_MIPS, KS_MODE_MIPS32R6+little) #Mips32r6 ISA
elif mode=="32":
ks = Ks(KS_ARCH_MIPS, KS_MODE_MIPS32+little) #Mips32 ISA
elif mode=="64":
ks = Ks(KS_ARCH_MIPS, KS_MODE_MIPS64+little) #Mips64 ISA
elif cpu=="x86":
#X86 architecture (including x86 & x86-64)
if mode=="16":
ks = Ks(KS_ARCH_X86,KS_MODE_16+little) #16-bit mode
elif mode=="32":
ks = Ks(KS_ARCH_X86,KS_MODE_32+little) #32-bit mode
elif mode=="64":
ks = Ks(KS_ARCH_X86,KS_MODE_64+little) #64-bit mode
elif cpu=="ppc":
#PowerPC architecture (currently unsupported)
if mode=="32":
ks = Ks(KS_ARCH_PPC,KS_MODE_PPC32+little) #32-bit mode
elif mode=="64":
ks = Ks(KS_ARCH_PPC,KS_MODE_PPC64+little) #64-bit mode
elif mode=="qpx":
ks = Ks(KS_ARCH_PPC,KS_MODE_QPX+little) #Quad Processing eXtensions mode
elif cpu=="sparc":
#Sparc architecture
if mode=="32":
ks = Ks(KS_ARCH_SPARC,KS_MODE_SPARC32+little) #32-bit mode
elif mode=="64":
ks = Ks(KS_ARCH_SPARC,KS_MODE_SPARC64+little) #64-bit mode
elif mode=="v9":
ks = Ks(KS_ARCH_SPARC,KS_MODE_V9+little) #SparcV9 mode
elif cpu=="systemz":
ks = Ks(KS_ARCH_SYSTEMZ,KS_MODE_BIG_ENDIAN) #SystemZ architecture (S390X)
elif cpu=="hexagon":
ks = Ks(KS_ARCH_HEXAGON,KS_MODE_LITTLE_ENDIAN)#QDSP6 Hexagon Qualcomm
if (ks==None):
little = KS_MODE_LITTLE_ENDIAN # little-endian mode (default mode)
print("CPU: %s, MODE: %s" % (cpu, mode))
ks = None
if cpu == "arm":
# ARM architecture (including Thumb, Thumb-2)
if mode == "arm":
ks = Ks(KS_ARCH_ARM, KS_MODE_ARM + little) # ARM mode
elif mode == "thumb":
ks = Ks(KS_ARCH_ARM, KS_MODE_THUMB + little) # THUMB mode (including Thumb-2)
elif mode == "mclass":
ks = Ks(KS_ARCH_ARM, KS_MODE_THUMB + little)
elif mode == "v8":
ks = Ks(KS_ARCH_ARM, KS_MODE_ARM + KS_MODE_V8 + little)
elif cpu == "arm64":
# ARM-64, also called AArch64
ks = Ks(KS_ARCH_ARM64, little) # ARM mode
elif cpu == "mips":
# Mips architecture
if mode == "micro":
ks = Ks(KS_ARCH_MIPS, KS_MODE_MICRO + little) # MicroMips mode
elif mode == "3":
ks = Ks(KS_ARCH_MIPS, KS_MODE_MIPS3 + little) # Mips III ISA
elif mode == "32R6":
ks = Ks(KS_ARCH_MIPS, KS_MODE_MIPS32R6 + little) # Mips32r6 ISA
elif mode == "32":
ks = Ks(KS_ARCH_MIPS, KS_MODE_MIPS32 + little) # Mips32 ISA
elif mode == "64":
ks = Ks(KS_ARCH_MIPS, KS_MODE_MIPS64 + little) # Mips64 ISA
elif cpu == "x86":
# X86 architecture (including x86 & x86-64)
if mode == "16":
ks = Ks(KS_ARCH_X86, KS_MODE_16 + little) # 16-bit mode
elif mode == "32":
ks = Ks(KS_ARCH_X86, KS_MODE_32 + little) # 32-bit mode
elif mode == "64":
ks = Ks(KS_ARCH_X86, KS_MODE_64 + little) # 64-bit mode
elif cpu == "ppc":
# PowerPC architecture (currently unsupported)
if mode == "32":
ks = Ks(KS_ARCH_PPC, KS_MODE_PPC32 + little) # 32-bit mode
elif mode == "64":
ks = Ks(KS_ARCH_PPC, KS_MODE_PPC64 + little) # 64-bit mode
elif mode == "qpx":
ks = Ks(KS_ARCH_PPC, KS_MODE_QPX + little) # Quad Processing eXtensions mode
elif cpu == "sparc":
# Sparc architecture
if mode == "32":
ks = Ks(KS_ARCH_SPARC, KS_MODE_SPARC32 + little) # 32-bit mode
elif mode == "64":
ks = Ks(KS_ARCH_SPARC, KS_MODE_SPARC64 + little) # 64-bit mode
elif mode == "v9":
ks = Ks(KS_ARCH_SPARC, KS_MODE_V9 + little) # SparcV9 mode
elif cpu == "systemz":
ks = Ks(KS_ARCH_SYSTEMZ, KS_MODE_BIG_ENDIAN) # SystemZ architecture (S390X)
elif cpu == "hexagon":
ks = Ks(KS_ARCH_HEXAGON, KS_MODE_LITTLE_ENDIAN) # QDSP6 Hexagon Qualcomm
if ks is None:
print("CPU and/or Mode not supported!")
exit(0)
encoding, count = ks.asm(code)
return encoding
def disasm(code, cpu, mode, bigendian, size):
cs=None
if bigendian:
little=CS_MODE_BIG_ENDIAN #big-endian mode
else:
little=CS_MODE_LITTLE_ENDIAN #little-endian mode (default mode)
if cpu=="arm":
if mode=="arm":
cs = Cs(CS_ARCH_ARM,CS_MODE_ARM+little) #ARM mode
elif mode=="thumb":
cs = Cs(CS_ARCH_ARM,CS_MODE_THUMB+little) #THUMB mode (including Thumb-2)
elif mode=="mclass":
cs = Cs(CS_ARCH_ARM,CS_MODE_THUMB+CS_MODE_MCLASS+little) #ARM Cortex-M
elif mode=="v8":
cs = Cs(CS_ARCH_ARM,CS_MODE_ARM+CS_MODE_V8+little) #ARMv8 A32 encodings for ARM
elif cpu=="arm64":
cs = Cs(CS_ARCH_ARM64,CS_MODE_ARM+little)
elif cpu=="mips":
if mode=="micro":
cs = Cs(CS_ARCH_MIPS,CS_MODE_MICRO+little) #MicroMips mode
elif mode=="32":
cs = Cs(CS_ARCH_MIPS,CS_MODE_MIPS32+little) #Mips III ISA
elif mode=="64":
cs = Cs(CS_ARCH_MIPS,CS_MODE_MIPS64+little) #Mips III ISA
elif mode=="32R6-Micro":
cs = Cs(CS_ARCH_MIPS,CS_MODE_MIPS32R6 + CS_MODE_MICRO +little) #Mips32r6 ISA
elif mode=="32R6":
cs = Cs(CS_ARCH_MIPS,CS_MODE_MIPS32R6 +little) #General Purpose Registers are 64bit wide
elif cpu=="x86":
#X86 architecture (including x86 & x86-64)
if mode=="16":
cs = Cs(CS_ARCH_X86,CS_MODE_16+little) #16-bit mode
elif mode=="32":
cs = Cs(CS_ARCH_X86,CS_MODE_32+little) #32-bit mode
elif mode=="64":
cs = Cs(CS_ARCH_X86,CS_MODE_64+little) #64-bit mode
elif cpu=="ppc":
#PowerPC architecture (currently unsupported)
if mode=="64":
cs = Cs(CS_ARCH_PPC,CS_MODE_P64+little) #64-bit mode
elif cpu=="sparc":
#Sparc architecture
if mode=="None":
cs = Cs(CS_ARCH_SPARC,CS_MODE_BIG_ENDIAN) #32-bit mode
elif mode=="v9":
cs = Cs(CS_ARCH_SPARC,CS_MODE_BIG_ENDIAN+CS_MODE_V9) #SparcV9 mode
elif cpu=="systemz":
cs = Cs(CS_ARCH_SYSZ,0) #SystemZ architecture (S390X)
elif cpu=="xcore":
cs = Cs(CS_ARCH_XCORE,0) #XCore architecture
if (cs==None):
def disasm(code, cpu, mode, bigendian, size):
cs = None
if bigendian:
little = CS_MODE_BIG_ENDIAN # big-endian mode
else:
little = CS_MODE_LITTLE_ENDIAN # little-endian mode (default mode)
if cpu == "arm":
if mode == "arm":
cs = Cs(CS_ARCH_ARM, CS_MODE_ARM + little) # ARM mode
elif mode == "thumb":
cs = Cs(CS_ARCH_ARM, CS_MODE_THUMB + little) # THUMB mode (including Thumb-2)
elif mode == "mclass":
cs = Cs(CS_ARCH_ARM, CS_MODE_THUMB + CS_MODE_MCLASS + little) # ARM Cortex-M
elif mode == "v8":
cs = Cs(CS_ARCH_ARM, CS_MODE_ARM + CS_MODE_V8 + little) # ARMv8 A32 encodings for ARM
elif cpu == "arm64":
cs = Cs(CS_ARCH_ARM64, CS_MODE_ARM + little)
elif cpu == "mips":
if mode == "micro":
cs = Cs(CS_ARCH_MIPS, CS_MODE_MICRO + little) # MicroMips mode
elif mode == "32":
cs = Cs(CS_ARCH_MIPS, CS_MODE_MIPS32 + little) # Mips III ISA
elif mode == "64":
cs = Cs(CS_ARCH_MIPS, CS_MODE_MIPS64 + little) # Mips III ISA
elif mode == "32R6-Micro":
cs = Cs(CS_ARCH_MIPS, CS_MODE_MIPS32R6 + CS_MODE_MICRO + little) # Mips32r6 ISA
elif mode == "32R6":
cs = Cs(CS_ARCH_MIPS, CS_MODE_MIPS32R6 + little) # General Purpose Registers are 64bit wide
elif cpu == "x86":
# X86 architecture (including x86 & x86-64)
if mode == "16":
cs = Cs(CS_ARCH_X86, CS_MODE_16 + little) # 16-bit mode
elif mode == "32":
cs = Cs(CS_ARCH_X86, CS_MODE_32 + little) # 32-bit mode
elif mode == "64":
cs = Cs(CS_ARCH_X86, CS_MODE_64 + little) # 64-bit mode
elif cpu == "ppc":
# PowerPC architecture (currently unsupported)
if mode == "64":
cs = Cs(CS_ARCH_PPC, little) # 64-bit mode
elif cpu == "sparc":
# Sparc architecture
if mode == "None":
cs = Cs(CS_ARCH_SPARC, CS_MODE_BIG_ENDIAN) # 32-bit mode
elif mode == "v9":
cs = Cs(CS_ARCH_SPARC, CS_MODE_BIG_ENDIAN + CS_MODE_V9) # SparcV9 mode
elif cpu == "systemz":
cs = Cs(CS_ARCH_SYSZ, 0) # SystemZ architecture (S390X)
elif cpu == "xcore":
cs = Cs(CS_ARCH_XCORE, 0) # XCore architecture
if cs is not None:
print("CPU and/or mode not supported!")
exit(0)
instr = []
for i in cs.disasm(code, size):
# print("0x%x:\t%s\t%s" % (i.address, i.mnemonic, i.op_str))
instr.append("%s\t%s" % (i.mnemonic, i.op_str))
return instr
def main():
parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,
description='Disasm/Asm Tool (c) B. Kerler 2018')
@ -154,20 +154,22 @@ def main():
'--cstyle', '-cstyle',
help='Print in c style',
action="store_true")
parser.add_argument(
'--bigendian', '-bigendian',
help='Big endian',
action="store_true")
parser.add_argument(
'--disasm', '-disasm',
help='Disasm: arm[arm,thumb,mclass,v8],arm64[arm],mips[micro,3,32R6,GP64],x86[16,32,64],ppc[64],sparc[32,64,v9],systemz,xcore',
help='Disasm: arm[arm,thumb,mclass,v8],arm64[arm],mips[micro,3,32R6,GP64],x86[16,32,64],ppc[64],sparc[32,64,'
'v9],systemz,xcore',
default='')
parser.add_argument(
'--asm', '-asm',
help='Asm: arm[arm,thumb,mclass,v8],arm64[arm],mips[micro,32,64,32R6,32R6-Micro],x86[16,32,64],ppc[32,64,qpx],sparc[None,v9],systemz,hexagon',
help='Asm: arm[arm,thumb,mclass,v8],arm64[arm],mips[micro,32,64,32R6,32R6-Micro],x86[16,32,64],ppc[32,64,'
'qpx],sparc[None,v9],systemz,hexagon',
default='')
parser.add_argument(
@ -181,40 +183,40 @@ def main():
print("[asmtools] Usage: -asm cpu,mode or -disasm cpu,mode")
exit(0)
if (args.infile == '' and args.inp==''):
if args.infile == '' and args.inp == '':
print("[asmtools] I must have an infile to work on (-in)")
exit(0)
if args.asm!="":
cpu,mode=args.asm.split(",")
if args.asm != "":
cpu, mode = args.asm.split(",")
else:
cpu,mode=args.disasm.split(",")
if args.inp!="":
args.inp=args.inp.replace("\\n","\n")
if args.asm!="":
aa=asm(args.inp,cpu,mode,args.bigendian)
cpu, mode = args.disasm.split(",")
if args.inp != "":
args.inp = args.inp.replace("\\n", "\n")
if args.asm != "":
aa = asm(args.inp, cpu, mode, args.bigendian)
else:
aa=disasm(unhexlify(args.inp),cpu,mode,args.bigendian,len(args.inp))
aa = disasm(unhexlify(args.inp), cpu, mode, args.bigendian, len(args.inp))
else:
with open (args.infile,"rb") as rf:
code=rf.read()
if args.asm!="":
aa=asm(code,cpu,mode,args.bigendian)
with open(args.infile, "rb") as rf:
code = rf.read()
if args.asm != "":
aa = asm(code, cpu, mode, args.bigendian)
else:
aa=disasm(code,cpu,mode,args.bigendian,len(code))
aa = disasm(code, cpu, mode, args.bigendian, len(code))
if args.outfile != "":
with open(args.outfile,"wb") as wf:
if args.asm!="":
ba=bytearray()
with open(args.outfile, "wb") as wf:
if args.asm != "":
ba = bytearray()
for i in aa:
ba.append(i)
wf.write(ba)
else:
wf.write(aa)
else:
if args.asm!="":
if args.asm != "":
sc = ""
count = 0
out = ""
@ -238,4 +240,5 @@ def main():
print(disasm(bytes(segment),len(segment)))
'''
main()

View file

@ -1,50 +1,63 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#(c) B.Kerler 2018-2019
# (c) B.Kerler 2018-2019
import hashlib
from Crypto.Cipher import AES
from Crypto.Util import Counter
from Crypto.Hash import CMAC
from Crypto.Util.number import long_to_bytes, bytes_to_long
from binascii import hexlify,unhexlify
from binascii import hexlify, unhexlify
class PKCS1BaseException(Exception):
pass
class DecryptionError(PKCS1BaseException):
pass
class MessageTooLong(PKCS1BaseException):
pass
class WrongLength(PKCS1BaseException):
pass
class MessageTooShort(PKCS1BaseException):
pass
class InvalidSignature(PKCS1BaseException):
pass
class RSAModulusTooShort(PKCS1BaseException):
pass
class IntegerTooLarge(PKCS1BaseException):
pass
class MessageRepresentativeOutOfRange(PKCS1BaseException):
pass
class CiphertextRepresentativeOutOfRange(PKCS1BaseException):
pass
class SignatureRepresentativeOutOfRange(PKCS1BaseException):
pass
class EncodingError(PKCS1BaseException):
pass
class InvalidInputException(Exception):
def __init__(self, msg):
self.msg = msg
@ -52,27 +65,17 @@ class InvalidInputException(Exception):
def __str__(self):
return str(self.msg)
class InvalidTagException(Exception):
def __str__(self):
return 'The authentication tag is invalid.'
class cryptutils:
class aes:
# GF(2^128) defined by 1 + a + a^2 + a^7 + a^128
# Please note the MSB is x0 and LSB is x127
def gf_2_128_mul(self, x, y):
assert x < (1 << 128)
assert y < (1 << 128)
res = 0
for i in range(127, -1, -1):
res ^= x * ((y >> i) & 1) # branchless
x = (x >> 1) ^ ((x & 1) * 0xE1000000000000000000000000000000)
assert res < 1 << 128
return res
class AES_GCM:
# Galois/Counter Mode with AES-128 and 96-bit IV
'''
"""
Example:
master_key = 0x0ADAABC70895E008147A48C27791F654 #54F69177C2487A1408E09508C7ABDA0A
init_value = 0x2883B4173F9A838437C1CD86CCFAA5ED #EDA5FACC86CDC13784839A3F17B48328
@ -106,10 +109,23 @@ class cryptutils:
b"\xA0\x62\x9E\xF9\xF4\xE7\xE8\x65"
my_gcm = AES_GCM(master_key)
decrypted = my_gcm.decrypt(init_value, ciphertext, auth_tag)
'''
"""
def __init__(self, master_key):
self.change_key(master_key)
# GF(2^128) defined by 1 + a + a^2 + a^7 + a^128
# Please note the MSB is x0 and LSB is x127
def gf_2_128_mul(self, x, y):
assert x < (1 << 128)
assert y < (1 << 128)
res = 0
for i in range(127, -1, -1):
res ^= x * ((y >> i) & 1) # branchless
x = (x >> 1) ^ ((x & 1) * 0xE1000000000000000000000000000000)
assert res < 1 << 128
return res
def change_key(self, master_key):
if master_key >= (1 << 128):
raise InvalidInputException('Master key should be 128-bit')
@ -231,9 +247,9 @@ class cryptutils:
return plaintext
def aes_gcm(self,ciphertext,nounce,aes_key, hdr, tag_auth, decrypt=True):
def aes_gcm(self, ciphertext, nounce, aes_key, hdr, tag_auth, decrypt=True):
cipher = AES.new(aes_key, AES.MODE_GCM, nounce)
if hdr!=None:
if hdr is not None:
cipher.update(hdr)
if decrypt:
plaintext = cipher.decrypt(ciphertext)
@ -242,24 +258,24 @@ class cryptutils:
return plaintext
except ValueError:
return None
return None
def aes_cbc(self,key,iv,data,decrypt=True):
def aes_cbc(self, key, iv, data, decrypt=True):
if decrypt:
return AES.new(key, AES.MODE_CBC, IV=iv).decrypt(data)
else:
return AES.new(key, AES.MODE_CBC, IV=iv).encrypt(data)
def aes_ecb(self,key,data,decrypt=True):
def aes_ecb(self, key, data, decrypt=True):
if decrypt:
return AES.new(key, AES.MODE_ECB).decrypt(data)
else:
return AES.new(key, AES.MODE_ECB).encrypt(data)
def aes_ctr(self,key,counter,enc_data,decrypt=True):
def aes_ctr(self, key, counter, enc_data, decrypt=True):
ctr = Counter.new(128, initial_value=counter)
# Create the AES cipher object and decrypt the ciphertext, basically this here is just aes ctr 256 :)
cipher = AES.new(key, AES.MODE_CTR, counter=ctr)
data = b""
if decrypt:
data = cipher.decrypt(enc_data)
else:
@ -279,30 +295,29 @@ class cryptutils:
ciphertext = cipher.encrypt(data)
return ciphertext
def aes_cmac_verify(key,plain,compare):
def aes_cmac_verify(self, key, plain, compare):
ctx = CMAC.new(key, ciphermod=AES)
ctx.update(plain)
result=ctx.hexdigest()
if result!=compare:
result = ctx.hexdigest()
if result != compare:
print("AES-CMAC failed !")
else:
print("AES-CMAC ok !")
class rsa: # RFC8017
def __init__(self, hashtype="SHA256"):
hh=hash()
if hashtype == "SHA1":
self.hash = hh.sha1
self.hash = hashlib.sha1
self.digestLen = 0x14
elif hashtype == "SHA256":
self.hash = hh.sha256
self.hash = hashlib.sha256
self.digestLen = 0x20
def pss_test(self):
N = "a2ba40ee07e3b2bd2f02ce227f36a195024486e49c19cb41bbbdfbba98b22b0e577c2eeaffa20d883a76e65e394c69d4b3c05a1e8fadda27edb2a42bc000fe888b9b32c22d15add0cd76b3e7936e19955b220dd17d4ea904b1ec102b2e4de7751222aa99151024c7cb41cc5ea21d00eeb41f7c800834d2c6e06bce3bce7ea9a5"
e = "010001"
D = "050e2c3e38d886110288dfc68a9533e7e12e27d2aa56d2cdb3fb6efa990bcff29e1d2987fb711962860e7391b1ce01ebadb9e812d2fbdfaf25df4ae26110a6d7a26f0b810f54875e17dd5c9fb6d641761245b81e79f8c88f0e55a6dcd5f133abd35f8f4ec80adf1bf86277a582894cb6ebcd2162f1c7534f1f4947b129151b71"
MSG = "859eef2fd78aca00308bdc471193bf55bf9d78db8f8a672b484634f3c9c26e6478ae10260fe0dd8c082e53a5293af2173cd50c6d5d354febf78b26021c25c02712e78cd4694c9f469777e451e7f8e9e04cd3739c6bbfedae487fb55644e9ca74ff77a53cb729802f6ed4a5ffa8ba159890fc"
MSG = "859eef2fd78aca00308bdc471193bf55bf9d78db8f8a672b484634f3c9c26e6478ae10260fe0dd8c082e53a5293af2173cd50c6d5d354febf78b26021c25c02712e78cd4694c9f469777e451e7f8e9e04cd3739c6bbfedae487fb55644e9ca74ff77a53cb729802f6ed4a5ffa8ba159890fc "
salt = "e3b5d5d002c1bce50c2b65ef88a188d83bce7e61"
N = int(N, 16)
@ -318,9 +333,9 @@ class cryptutils:
print("Test failed.")
def i2osp(self, x, x_len):
'''Converts the integer x to its big-endian representation of length
"""Converts the integer x to its big-endian representation of length
x_len.
'''
"""
if x > 256 ** x_len:
raise IntegerTooLarge
h = hex(x)[2:]
@ -331,20 +346,20 @@ class cryptutils:
x = unhexlify(h)
return b'\x00' * int(x_len - len(x)) + x
def os2ip(self,x):
'''Converts the byte string x representing an integer reprented using the
def os2ip(self, x):
"""Converts the byte string x representing an integer reprented using the
big-endian convient to an integer.
'''
"""
h = hexlify(x)
return int(h, 16)
#def os2ip(self, X):
# def os2ip(self, X):
# return int.from_bytes(X, byteorder='big')
def mgf1(self, input, length):
counter = 0
output = b''
while (len(output) < length):
while len(output) < length:
C = self.i2osp(counter, 4)
output += self.hash(input + C)
counter += 1
@ -355,7 +370,7 @@ class cryptutils:
return
raise TypeError('%s should be an integer, not %s' % (name, var.__class__))
def sign(self,tosign,D,N,emBits=1024):
def sign(self, tosign, D, N, emBits=1024):
self.assert_int(tosign, 'message')
self.assert_int(D, 'D')
self.assert_int(N, 'n')
@ -364,8 +379,8 @@ class cryptutils:
raise ValueError('Only non-negative numbers are supported')
if tosign > N:
tosign1=divmod(tosign,N)[1]
signature=pow(tosign1,D,N)
tosign1 = divmod(tosign, N)[1]
signature = pow(tosign1, D, N)
raise OverflowError("The message %i is too long for n=%i" % (tosign, N))
signature = pow(tosign, D, N)
@ -373,30 +388,30 @@ class cryptutils:
return hexsign
def pss_sign(self, D, N, msghash, salt, emBits=1024):
if isinstance(D,str):
D=unhexlify(D)
D=self.os2ip(D)
if isinstance(N,str):
N=unhexlify(N)
N=self.os2ip(N)
slen=len(salt)
if isinstance(D, str):
D = unhexlify(D)
D = self.os2ip(D)
if isinstance(N, str):
N = unhexlify(N)
N = self.os2ip(N)
slen = len(salt)
emLen = self.ceil_div(emBits, 8)
inBlock = b"\x00" * 8 + msghash + salt
hash = self.hash(inBlock)
PSlen=emLen - self.digestLen - slen - 1 - 1
hhash = self.hash(inBlock)
PSlen = emLen - self.digestLen - slen - 1 - 1
DB = (PSlen * b"\x00") + b"\x01" + salt
rlen = emLen - len(hash) - 1
dbMask = self.mgf1(hash, rlen)
rlen = emLen - len(hhash) - 1
dbMask = self.mgf1(hhash, rlen)
maskedDB = bytearray()
for i in range(0, len(dbMask)):
maskedDB.append(dbMask[i] ^ DB[i])
maskedDB[0]=maskedDB[0]&0x7F
EM = maskedDB + hash + b"\xbc"
tosign=self.os2ip(EM)
#EM=hexlify(EM).decode('utf-8')
#tosign = int(EM,16)
return self.sign(tosign,D,N,emBits)
#6B1EAA2042A5C8DA8B1B4A8320111A70A0CBA65233D1C6E418EF8156E82A8F96BD843F047FF25AB9702A6582C8387298753E628F23448B4580E09CBD2A483C623B888F47C4BD2C5EFF09013C6DFF67DB59BAB3037F0BEE05D5660264D28CC6251631FE75CE106D931A04FA032FEA31259715CE0FAB1AE0E2F8130807AF4019A61B9C060ECE59104F22156FEE8108F17DC80D7C2F8397AFB9780994F7C5A0652F93D1B48010B0B248AB9711235787D797FBA4D10A29BCF09628585D405640A866B15EE9D7526A2703E72A19811EF447F6E5C43F915B3808EBC79EA4BCF78903DBDE32E47E239CFB5F2B5986D0CBBFBE6BACDC29B2ADE006D23D0B90775B1AE4DD
maskedDB[0] = maskedDB[0] & 0x7F
EM = maskedDB + hhash + b"\xbc"
tosign = self.os2ip(EM)
# EM=hexlify(EM).decode('utf-8')
# tosign = int(EM,16)
return self.sign(tosign, D, N, emBits)
# 6B1EAA2042A5C8DA8B1B4A8320111A70A0CBA65233D1C6E418EF8156E82A8F96BD843F047FF25AB9702A6582C8387298753E628F23448B4580E09CBD2A483C623B888F47C4BD2C5EFF09013C6DFF67DB59BAB3037F0BEE05D5660264D28CC6251631FE75CE106D931A04FA032FEA31259715CE0FAB1AE0E2F8130807AF4019A61B9C060ECE59104F22156FEE8108F17DC80D7C2F8397AFB9780994F7C5A0652F93D1B48010B0B248AB9711235787D797FBA4D10A29BCF09628585D405640A866B15EE9D7526A2703E72A19811EF447F6E5C43F915B3808EBC79EA4BCF78903DBDE32E47E239CFB5F2B5986D0CBBFBE6BACDC29B2ADE006D23D0B90775B1AE4DD
def ceil_div(self, a, b):
(q, r) = divmod(a, b)
@ -413,8 +428,8 @@ class cryptutils:
sig = self.os2ip(signature)
EM = pow(sig, e, N)
#EM = unhexlify(hex(EM)[2:])
EM=self.i2osp(EM,emBits//8)
# EM = unhexlify(hex(EM)[2:])
EM = self.i2osp(EM, emBits // 8)
emLen = len(signature)
@ -422,16 +437,15 @@ class cryptutils:
if valBC != 0xbc:
print("[rsa_pss] : 0xbc check failed")
return False
hash = EM[emLen - self.digestLen - 1:-1]
mhash = EM[emLen - self.digestLen - 1:-1]
maskedDB = EM[:emLen - self.digestLen - 1]
lmask=~(0xFF >> (8 * emLen + 1 - emBits))
if EM[0]&lmask:
lmask = ~(0xFF >> (8 * emLen + 1 - emBits))
if EM[0] & lmask:
print("[rsa_pss] : lmask check failed")
return False
dbMask = self.mgf1(hash, emLen - self.digestLen - 1)
dbMask = self.mgf1(mhash, emLen - self.digestLen - 1)
DB = bytearray()
for i in range(0, len(dbMask)):
@ -448,22 +462,21 @@ class cryptutils:
print("[rsa_pss] : 0x01 check failed")
return False
if salt != None:
if salt is not None:
inBlock = b"\x00" * 8 + msghash + salt
mhash = self.hash(inBlock)
if mhash == hash:
if mhash == mhash:
return True
else:
return False
else:
salt=TS[-self.digestLen:]
salt = TS[-self.digestLen:]
inBlock = b"\x00" * 8 + msghash + salt
mhash = self.hash(inBlock)
if mhash == hash:
if mhash == mhash:
return True
else:
return False
return maskedDB
class hash():
def __init__(self, hashtype="SHA256"):
@ -484,4 +497,4 @@ class cryptutils:
return hashlib.sha256(msg).digest()
def md5(self, msg):
return hashlib.md5(msg).digest()
return hashlib.md5(msg).digest()

View file

@ -3,6 +3,7 @@ import platform
import time
from Library.utils import *
from Library.gpt import gpt
try:
from Library.Modules.init import modules
except Exception as e:
@ -52,8 +53,9 @@ class qualcomm_firehose:
MaxXMLSizeInBytes = 4096
bit64 = True
def __init__(self, cdc, xml, cfg, log, devicemodel, serial, skipresponse,luns):
def __init__(self, cdc, xml, cfg, log, devicemodel, serial, skipresponse, luns, args):
self.cdc = cdc
self.args = args
self.xml = xml
self.cfg = cfg
self.pk = None
@ -61,8 +63,9 @@ class qualcomm_firehose:
self.serial = serial
self.devicemodel = devicemodel
self.skipresponse = skipresponse
self.log=log
self.luns=luns
self.log = log
self.luns = luns
self.supported_functions = []
if self.cfg.MemoryName == "UFS":
self.cfg.SECTOR_SIZE_IN_BYTES = 4096
@ -72,8 +75,8 @@ class qualcomm_firehose:
lunname = "Lun" + str(lun)
fpartitions[lunname] = []
data, guid_gpt = self.get_gpt(lun, int(arguments["--gpt-num-part-entries"]),
int(arguments["--gpt-part-entry-size"]),
int(arguments["--gpt-part-entry-start-lba"]))
int(arguments["--gpt-part-entry-size"]),
int(arguments["--gpt-part-entry-start-lba"]))
if guid_gpt is None:
break
else:
@ -93,7 +96,7 @@ class qualcomm_firehose:
return True
def xmlsend(self, data, skipresponse=False):
self.cdc.write(bytes(data,'utf-8'), self.cfg.MaxXMLSizeInBytes)
self.cdc.write(bytes(data, 'utf-8'), self.cfg.MaxXMLSizeInBytes)
rdata = bytearray()
counter = 0
timeout = 3
@ -108,23 +111,23 @@ class qualcomm_firehose:
time.sleep(0.3)
if counter > timeout:
break
rdata+=tmp
rdata += tmp
except Exception as e:
self.log.error(e)
return [False, resp, data]
try:
if b"raw hex token" in rdata:
rdata=rdata
rdata = rdata
try:
resp = self.xml.getresponse(rdata)
except:
rdata = bytes(self.log.decoder(rdata),'utf-8')
rdata = bytes(self.log.decoder(rdata), 'utf-8')
resp = self.xml.getresponse(rdata)
status = self.getstatus(resp)
except Exception as e:
status = True
self.log.debug(str(e))
self.log.debug("Error on getting xml response:" + rdata)
self.log.debug("Error on getting xml response:" + rdata.decode('utf-8'))
return [status, {"value": "NAK"}, rdata]
else:
status = True
@ -135,8 +138,8 @@ class qualcomm_firehose:
val = self.xmlsend(data)
try:
v = None
while (v != b''):
v = self.cdc.read()
while v != b'':
v = self.cdc.read(self.cfg.MaxXMLSizeInBytes)
if v != b'':
resp = self.xml.getlog(v)[0]
else:
@ -173,7 +176,8 @@ class qualcomm_firehose:
return False
def cmd_getsha256digest(self, physical_partition_number, start_sector, num_partition_sectors):
data = f"<?xml version=\"1.0\" ?><data><getsha256digest SECTOR_SIZE_IN_BYTES=\"{self.cfg.SECTOR_SIZE_IN_BYTES}\"" + \
data = f"<?xml version=\"1.0\" ?><data><getsha256digest" + \
f" SECTOR_SIZE_IN_BYTES=\"{self.cfg.SECTOR_SIZE_IN_BYTES}\"" + \
f" num_partition_sectors=\"{num_partition_sectors}\"" + \
f" physical_partition_number=\"{physical_partition_number}\"" + \
f" start_sector=\"{start_sector}\"/>\n</data>"
@ -215,9 +219,10 @@ class qualcomm_firehose:
return True
def cmd_patch(self, physical_partition_number, start_sector, byte_offset, value, size_in_bytes, display=True):
'''
<patch SECTOR_SIZE_IN_BYTES="512" byte_offset="16" filename="DISK" physical_partition_number="0" size_in_bytes="4" start_sector="NUM_DISK_SECTORS-1." value="0" what="Zero Out Header CRC in Backup Header."/>
'''
"""
<patch SECTOR_SIZE_IN_BYTES="512" byte_offset="16" filename="DISK" physical_partition_number="0"
size_in_bytes="4" start_sector="NUM_DISK_SECTORS-1." value="0" what="Zero Out Header CRC in Backup Header."/>
"""
data = f"<?xml version=\"1.0\" ?><data>\n" + \
f"<patch SECTOR_SIZE_IN_BYTES=\"{self.cfg.SECTOR_SIZE_IN_BYTES}\"" + \
@ -228,11 +233,11 @@ class qualcomm_firehose:
f" start_sector=\"{start_sector}\" " + \
f" value=\"{value}\" "
if self.modules is not None:
data+=self.modules.addpatch()
data += self.modules.addpatch()
data += f"/>\n</data>"
rsp = self.xmlsend(data)
if rsp[0] == True:
if rsp[0]:
if display:
self.log.info(f"Patch:\n--------------------\n")
self.log.info(rsp[1])
@ -241,11 +246,10 @@ class qualcomm_firehose:
self.log.error(f"Error:{rsp}")
return False
def cmd_program(self, physical_partition_number, start_sector, filename, display=True):
size = os.stat(filename).st_size
fsize=os.stat(filename).st_size
fname=os.path.basename(filename)
fsize = os.stat(filename).st_size
fname = os.path.basename(filename)
with open(filename, "rb") as rf:
# Make sure we fill data up to the sector size
num_partition_sectors = size // self.cfg.SECTOR_SIZE_IN_BYTES
@ -253,7 +257,8 @@ class qualcomm_firehose:
num_partition_sectors += 1
if display:
self.log.info(
f"\nWriting {fname} to physical partition {str(physical_partition_number)}, sector {str(start_sector)}, sectors {str(num_partition_sectors)}")
f"\nWriting {fname} to physical partition {str(physical_partition_number)}, " + \
f"sector {str(start_sector)}, sectors {str(num_partition_sectors)}")
data = f"<?xml version=\"1.0\" ?><data>\n" + \
f"<program SECTOR_SIZE_IN_BYTES=\"{self.cfg.SECTOR_SIZE_IN_BYTES}\"" + \
f" num_partition_sectors=\"{num_partition_sectors}\"" + \
@ -274,22 +279,24 @@ class qualcomm_firehose:
total = self.cfg.SECTOR_SIZE_IN_BYTES * num_partition_sectors
old = 0
while fsize > 0:
wlen=self.cfg.MaxPayloadSizeToTargetInBytes//self.cfg.SECTOR_SIZE_IN_BYTES*self.cfg.SECTOR_SIZE_IN_BYTES
if fsize<wlen:
wlen=fsize
wlen = self.cfg.MaxPayloadSizeToTargetInBytes // self.cfg.SECTOR_SIZE_IN_BYTES * \
self.cfg.SECTOR_SIZE_IN_BYTES
if fsize < wlen:
wlen = fsize
wdata = rf.read(wlen)
bytesToWrite -= wlen
fsize-=wlen
fsize -= wlen
pos += wlen
if (wlen % self.cfg.SECTOR_SIZE_IN_BYTES) != 0:
filllen = (wlen // self.cfg.SECTOR_SIZE_IN_BYTES * self.cfg.SECTOR_SIZE_IN_BYTES) + self.cfg.SECTOR_SIZE_IN_BYTES
if wlen % self.cfg.SECTOR_SIZE_IN_BYTES != 0:
filllen = (wlen // self.cfg.SECTOR_SIZE_IN_BYTES * self.cfg.SECTOR_SIZE_IN_BYTES) + \
self.cfg.SECTOR_SIZE_IN_BYTES
wdata += b"\x00" * (filllen - wlen)
wlen = len(wdata)
self.cdc.write(wdata, wlen)
prog = int(float(pos) / float(total) * float(100))
if (prog > old):
if prog > old:
if display:
print_progress(prog, 100, prefix='Progress:', suffix='Complete', bar_length=50)
@ -315,18 +322,17 @@ class qualcomm_firehose:
else:
self.log.error(f"Error:{rsp}")
return False
return False
def cmd_program_buffer(self, physical_partition_number, start_sector, wfdata, display=True):
size=len(wfdata)
size = len(wfdata)
# Make sure we fill data up to the sector size
num_partition_sectors = size // self.cfg.SECTOR_SIZE_IN_BYTES
if (size % self.cfg.SECTOR_SIZE_IN_BYTES) != 0:
num_partition_sectors += 1
if display:
self.log.info(
f"\nWriting to physical partition {str(physical_partition_number)}, sector {str(start_sector)}, sectors {str(num_partition_sectors)}")
self.log.info(f"\nWriting to physical partition {str(physical_partition_number)}, " +
f"sector {str(start_sector)}, sectors {str(num_partition_sectors)}")
data = f"<?xml version=\"1.0\" ?><data>\n" + \
f"<program SECTOR_SIZE_IN_BYTES=\"{self.cfg.SECTOR_SIZE_IN_BYTES}\"" + \
f" num_partition_sectors=\"{num_partition_sectors}\"" + \
@ -334,7 +340,7 @@ class qualcomm_firehose:
f" start_sector=\"{start_sector}\" "
if self.modules is not None:
data+=self.modules.addprogram()
data += self.modules.addprogram()
data += f"/>\n</data>"
rsp = self.xmlsend(data)
@ -346,24 +352,26 @@ class qualcomm_firehose:
bytesToWrite = self.cfg.SECTOR_SIZE_IN_BYTES * num_partition_sectors
total = self.cfg.SECTOR_SIZE_IN_BYTES * num_partition_sectors
old = 0
fpos=0
fsize=len(wfdata)
fpos = 0
fsize = len(wfdata)
while fsize > 0:
wlen = self.cfg.MaxPayloadSizeToTargetInBytes // self.cfg.SECTOR_SIZE_IN_BYTES * self.cfg.SECTOR_SIZE_IN_BYTES
wlen = self.cfg.MaxPayloadSizeToTargetInBytes // self.cfg.SECTOR_SIZE_IN_BYTES * \
self.cfg.SECTOR_SIZE_IN_BYTES
if fsize < wlen:
wlen = fsize
wdata = wfdata[fpos:fpos+wlen]
wdata = wfdata[fpos:fpos + wlen]
bytesToWrite -= wlen
fsize -= wlen
pos += wlen
fpos += wlen
if (wlen % self.cfg.SECTOR_SIZE_IN_BYTES) != 0:
filllen = (wlen // self.cfg.SECTOR_SIZE_IN_BYTES * self.cfg.SECTOR_SIZE_IN_BYTES) + self.cfg.SECTOR_SIZE_IN_BYTES
filllen = (wlen // self.cfg.SECTOR_SIZE_IN_BYTES * self.cfg.SECTOR_SIZE_IN_BYTES) + \
self.cfg.SECTOR_SIZE_IN_BYTES
wdata += b"\x00" * (filllen - wlen)
wlen = len(wdata)
self.cdc.write(wdata, wlen)
prog = int(float(pos) / float(total) * float(100))
if (prog > old):
if prog > old:
if display:
print_progress(prog, 100, prefix='Progress:', suffix='Complete', bar_length=50)
@ -386,12 +394,11 @@ class qualcomm_firehose:
else:
self.log.error(f"Error:{rsp}")
return False
return False
def cmd_erase(self, physical_partition_number, start_sector, num_partition_sectors, display=True):
if display:
self.log.info(
f"\nErasing from physical partition {str(physical_partition_number)}, sector {str(start_sector)}, sectors {str(num_partition_sectors)}")
self.log.info(f"\nErasing from physical partition {str(physical_partition_number)}, " +
f"sector {str(start_sector)}, sectors {str(num_partition_sectors)}")
data = f"<?xml version=\"1.0\" ?><data>\n" + \
f"<program SECTOR_SIZE_IN_BYTES=\"{self.cfg.SECTOR_SIZE_IN_BYTES}\"" + \
f" num_partition_sectors=\"{num_partition_sectors}\"" + \
@ -399,7 +406,7 @@ class qualcomm_firehose:
f" start_sector=\"{start_sector}\" "
if self.modules is not None:
data+=self.modules.addprogram()
data += self.modules.addprogram()
data += f"/>\n</data>"
rsp = self.xmlsend(data)
@ -408,17 +415,17 @@ class qualcomm_firehose:
prog = 0
if display:
print_progress(prog, 100, prefix='Progress:', suffix='Complete', bar_length=50)
if (rsp[0]) == True:
if rsp[0]:
bytesToWrite = self.cfg.SECTOR_SIZE_IN_BYTES * num_partition_sectors
total = self.cfg.SECTOR_SIZE_IN_BYTES * num_partition_sectors
old = 0
while (bytesToWrite > 0):
while bytesToWrite > 0:
wlen = self.cfg.MaxPayloadSizeToTargetInBytes
if bytesToWrite < wlen:
wlen = bytesToWrite
self.cdc.write(empty[0:wlen], self.cfg.MaxPayloadSizeToTargetInBytes)
prog = int(float(pos) / float(total) * float(100))
if (prog > old):
if prog > old:
if display:
print_progress(prog, 100, prefix='Progress:', suffix='Complete', bar_length=50)
bytesToWrite -= wlen
@ -441,19 +448,20 @@ class qualcomm_firehose:
else:
self.log.error(f"Error:{rsp}")
return False
return False
return False
def cmd_read(self, physical_partition_number, start_sector, num_partition_sectors, filename, display=True):
if display:
self.log.info(
f"\nReading from physical partition {str(physical_partition_number)}, sector {str(start_sector)}, sectors {str(num_partition_sectors)}")
f"\nReading from physical partition {str(physical_partition_number)}, sector {str(start_sector)}" + \
f", sectors {str(num_partition_sectors)}")
with open(filename, "wb") as wr:
#wr = asyncwriter(wf)
# wr = asyncwriter(wf)
data = f"<?xml version=\"1.0\" ?><data><read SECTOR_SIZE_IN_BYTES=\"{self.cfg.SECTOR_SIZE_IN_BYTES}\"" + \
f" num_partition_sectors=\"{num_partition_sectors}\"" + \
f" physical_partition_number=\"{physical_partition_number}\"" + \
f" start_sector=\"{start_sector}\"/>\n</data>"
rsp = self.xmlsend(data,self.skipresponse)
rsp = self.xmlsend(data, self.skipresponse)
if rsp[0]:
if "value" in rsp[1]:
if rsp[1]["value"] == "NAK":
@ -474,7 +482,7 @@ class qualcomm_firehose:
wr.write(tmp)
if display:
prog = int(float(dataread) / float(total) * float(100))
if (prog > old):
if prog > old:
print_progress(prog, 100, prefix='Progress:', suffix='Complete', bar_length=50)
old = prog
if display and prog != 100:
@ -482,7 +490,7 @@ class qualcomm_firehose:
# time.sleep(0.2)
info = self.xml.getlog(self.cdc.read(self.cfg.MaxXMLSizeInBytes))
rsp = self.xml.getresponse(self.cdc.read(self.cfg.MaxXMLSizeInBytes))
#wr.stop()
# wr.stop()
if "value" in rsp:
if rsp["value"] == "ACK":
return tmp
@ -500,13 +508,14 @@ class qualcomm_firehose:
def cmd_read_buffer(self, physical_partition_number, start_sector, num_partition_sectors, display=True):
if display:
self.log.info(
f"\nReading from physical partition {str(physical_partition_number)}, sector {str(start_sector)}, sectors {str(num_partition_sectors)}")
f"\nReading from physical partition {str(physical_partition_number)}, " + \
f"sector {str(start_sector)}, sectors {str(num_partition_sectors)}")
data = f"<?xml version=\"1.0\" ?><data><read SECTOR_SIZE_IN_BYTES=\"{self.cfg.SECTOR_SIZE_IN_BYTES}\"" + \
f" num_partition_sectors=\"{num_partition_sectors}\"" + \
f" physical_partition_number=\"{physical_partition_number}\"" + \
f" start_sector=\"{start_sector}\"/>\n</data>"
rsp = self.xmlsend(data,self.skipresponse)
rsp = self.xmlsend(data, self.skipresponse)
resData = bytearray()
if rsp[0]:
if "value" in rsp[1]:
@ -527,7 +536,7 @@ class qualcomm_firehose:
dataread += len(tmp)
resData += tmp
prog = int(float(dataread) / float(total) * float(100))
if (prog > old):
if prog > old:
if display:
print_progress(prog, 100, prefix='Progress:', suffix='Complete', bar_length=50)
old = prog
@ -547,9 +556,10 @@ class qualcomm_firehose:
else:
return resData
else:
self.log.error(f"Error:{rsp[2]}")
if display:
self.log.error(f"Error:{rsp[2]}")
return b""
return resData #Do not remove, needed for oneplus
return resData # Do not remove, needed for oneplus
def get_gpt(self, lun, gpt_num_part_entries, gpt_part_entry_size, gpt_part_entry_start_lba):
data = self.cmd_read_buffer(lun, 0, 2, False)
@ -563,10 +573,10 @@ class qualcomm_firehose:
header = guid_gpt.parseheader(data, self.cfg.SECTOR_SIZE_IN_BYTES)
if "first_usable_lba" in header:
sectors = header["first_usable_lba"]
if sectors==0:
if sectors == 0:
return None, None
data = self.cmd_read_buffer(lun, 0, sectors, False)
if data==b"":
if data == b"":
return None, None
guid_gpt.parse(data, self.cfg.SECTOR_SIZE_IN_BYTES)
return data, guid_gpt
@ -586,12 +596,17 @@ class qualcomm_firehose:
if "backup_lba" in header:
sectors = header["first_usable_lba"] - 1
data = self.cmd_read_buffer(lun, header["backup_lba"], sectors, False)
if data==b"":
if data == b"":
return None
return data
else:
return None
def calc_offset(self, sector, offset):
sector = sector + (offset // self.cfg.SECTOR_SIZE_IN_BYTES)
offset = offset % self.cfg.SECTOR_SIZE_IN_BYTES
return sector, offset
def connect(self, lvl):
v = b'-1'
if lvl != 1:
@ -602,22 +617,24 @@ class qualcomm_firehose:
info = []
while v != b'':
try:
v = self.cdc.read()
v = self.cdc.read(self.cfg.MaxXMLSizeInBytes)
if v == b'':
break
data = self.xml.getlog(v)
if len(data) > 0:
info.append(data[0])
if info == []:
if not info:
break
except:
break
supfunc=False
if info==[]:
info=self.cmd_nop()
if info==[]:
supfunc = False
if info == [] or (len(info) > 0 and 'ERROR' in info[0]):
info = self.cmd_nop()
if not info:
self.log.info("No supported functions detected, configuring qc generic commands")
self.supported_functions = ['configure','program','firmwarewrite','patch','setbootablestoragedrive','ufs','emmc','power','benchmark','read','getstorageinfo','getcrc16digest','getsha256digest','erase','peek','poke','nop','xml']
self.supported_functions = ['configure', 'program', 'firmwarewrite', 'patch', 'setbootablestoragedrive',
'ufs', 'emmc', 'power', 'benchmark', 'read', 'getstorageinfo',
'getcrc16digest', 'getsha256digest', 'erase', 'peek', 'poke', 'nop', 'xml']
else:
self.supported_functions = []
for line in info:
@ -625,7 +642,7 @@ class qualcomm_firehose:
self.log.info(line)
try:
serial = line.split("0x")[1][:-1]
self.serial = int(serial,16)
self.serial = int(serial, 16)
except:
serial = line.split(": ")[2]
self.serial = int(serial.split(" ")[0])
@ -655,34 +672,38 @@ class qualcomm_firehose:
supfunc = True
'''
try:
self.modules = modules(fh=self,serial=self.serial,supported_functions=self.supported_functions,log=self.log,devicemodel=self.devicemodel)
self.modules = modules(fh=self, serial=self.serial, supported_functions=self.supported_functions,
log=self.log, devicemodel=self.devicemodel, args=self.args)
except Exception as e:
self.modules = None
data=self.cdc.read() #logbuf
data = self.cdc.read(self.cfg.MaxXMLSizeInBytes) # logbuf
try:
self.log.info(data.decode('utf-8'))
except:
pass
connectcmd = f"<?xml version =\"1.0\" ?><data>" + \
f"<configure MemoryName=\"{self.cfg.MemoryName}\" ZLPAwareHost=\"{str(self.cfg.ZLPAwareHost)}\" " + \
f"SkipStorageInit=\"{str(int(self.cfg.SkipStorageInit))}\" SkipWrite=\"{str(int(self.cfg.SkipWrite))}\" " + \
f"<configure MemoryName=\"{self.cfg.MemoryName}\" " + \
f"ZLPAwareHost=\"{str(self.cfg.ZLPAwareHost)}\" " + \
f"SkipStorageInit=\"{str(int(self.cfg.SkipStorageInit))}\" " + \
f"SkipWrite=\"{str(int(self.cfg.SkipWrite))}\" " + \
f"MaxPayloadSizeToTargetInBytes=\"{str(self.cfg.MaxPayloadSizeToTargetInBytes)}\"/>" + \
"</data>"
'''
"<?xml version=\"1.0\" encoding=\"UTF-8\" ?><data><response value=\"ACK\" MinVersionSupported=\"1\"" \
"MemoryName=\"eMMC\" MaxPayloadSizeFromTargetInBytes=\"4096\" MaxPayloadSizeToTargetInBytes=\"1048576\" " \
"MaxPayloadSizeToTargetInBytesSupported=\"1048576\" MaxXMLSizeInBytes=\"4096\" Version=\"1\" TargetName=\"8953\" />" \
"</data>"
"<?xml version=\"1.0\" encoding=\"UTF-8\" ?><data><response value=\"ACK\" MinVersionSupported=\"1\"" \
"MemoryName=\"eMMC\" MaxPayloadSizeFromTargetInBytes=\"4096\" MaxPayloadSizeToTargetInBytes=\"1048576\" " \
"MaxPayloadSizeToTargetInBytesSupported=\"1048576\" MaxXMLSizeInBytes=\"4096\" Version=\"1\"
TargetName=\"8953\" />" \
"</data>"
'''
rsp = self.xmlsend(connectcmd)
if rsp[0] == True:
data=self.cdc.read()
if rsp[0]:
data = self.cdc.read(self.cfg.MaxXMLSizeInBytes)
if not "MemoryName" in rsp[1]:
#print(rsp[1])
rsp[1]["MemoryName"]="eMMC"
# print(rsp[1])
rsp[1]["MemoryName"] = "eMMC"
if not "MaxXMLSizeInBytes" in rsp[1]:
rsp[1]["MaxXMLSizeInBytes"]="4096"
rsp[1]["MaxXMLSizeInBytes"] = "4096"
self.log.warning("Couldn't detect MaxPayloadSizeFromTargetinBytes")
if not "MaxPayloadSizeToTargetInBytes" in rsp[1]:
rsp[1]["MaxPayloadSizeToTargetInBytes"] = "1038576"
@ -714,7 +735,8 @@ class qualcomm_firehose:
try:
self.cfg.MemoryName = rsp[1]["MemoryName"]
self.cfg.MaxPayloadSizeToTargetInBytes = int(rsp[1]["MaxPayloadSizeToTargetInBytes"])
self.cfg.MaxPayloadSizeToTargetInBytesSupported = int(rsp[1]["MaxPayloadSizeToTargetInBytesSupported"])
self.cfg.MaxPayloadSizeToTargetInBytesSupported = int(
rsp[1]["MaxPayloadSizeToTargetInBytesSupported"])
self.cfg.MaxXMLSizeInBytes = int(rsp[1]["MaxXMLSizeInBytes"])
self.cfg.MaxPayloadSizeFromTargetInBytes = int(rsp[1]["MaxPayloadSizeFromTargetInBytes"])
self.cfg.TargetName = rsp[1]["TargetName"]
@ -745,7 +767,7 @@ class qualcomm_firehose:
return False
data = "<?xml version=\"1.0\" ?><data><writeIMEI len=\"16\"/></data>"
val = self.xmlsend(data)
if val[0] == True:
if val[0]:
self.log.info("writeIMEI succeeded.")
return True
else:
@ -755,7 +777,7 @@ class qualcomm_firehose:
def cmd_getstorageinfo(self):
data = "<?xml version=\"1.0\" ?><data><getstorageinfo /></data>"
val = self.xmlsend(data)
if val[0] == True:
if val[0]:
self.log.info(f"GetStorageInfo:\n--------------------\n")
self.log.info(val[1])
return True
@ -796,8 +818,8 @@ class qualcomm_firehose:
mode = 0
if info:
print_progress(0, 100, prefix='Progress:', suffix='Complete', bar_length=50)
while (lengthtowrite > 0):
if rf != None:
while lengthtowrite > 0:
if rf is not None:
content = hex(int(hexlify(rf.read(maxsize)).decode('utf-8'), 16))
else:
content = 0
@ -809,41 +831,44 @@ class qualcomm_firehose:
# content=hex(int(hexlify(data[pos:pos+maxsize]).decode('utf-8'),16))
content = hex(content)
if mode == 0:
xdata = f"<?xml version=\"1.0\" ?><data><poke address64=\"{str(address + pos)}\" size_in_bytes=\"{str(maxsize)}\" value64=\"{content}\" /></data>\n"
xdata = f"<?xml version=\"1.0\" ?><data><poke address64=\"{str(address + pos)}\" " + \
f"size_in_bytes=\"{str(maxsize)}\" value64=\"{content}\" /></data>\n"
else:
xdata = f"<?xml version=\"1.0\" ?><data><poke address64=\"{str(address + pos)}\" SizeInBytes=\"{str(maxsize)}\" value64=\"{content}\" /></data>\n"
xdata = f"<?xml version=\"1.0\" ?><data><poke address64=\"{str(address + pos)}\" " + \
f"SizeInBytes=\"{str(maxsize)}\" value64=\"{content}\" /></data>\n"
try:
self.cdc.write(xdata, self.cfg.MaxXMLSizeInBytes)
except:
pass
addrinfo = self.cdc.read(self.cfg.MaxXMLSizeInBytes)
if (b"SizeInBytes" in addrinfo or b"Invalid parameters" in addrinfo):
if b"SizeInBytes" in addrinfo or b"Invalid parameters" in addrinfo:
tmp = b""
while b"NAK" not in tmp and b"ACK" not in tmp:
tmp += self.cdc.read(self.cfg.MaxXMLSizeInBytes)
xdata = f"<?xml version=\"1.0\" ?><data><poke address64=\"{str(address + pos)}\" SizeInBytes=\"{str(maxsize)}\" value64=\"{content}\" /></data>\n"
xdata = f"<?xml version=\"1.0\" ?><data><poke address64=\"{str(address + pos)}\" " + \
f"SizeInBytes=\"{str(maxsize)}\" value64=\"{content}\" /></data>\n"
self.cdc.write(xdata, self.cfg.MaxXMLSizeInBytes)
addrinfo = self.cdc.read(self.cfg.MaxXMLSizeInBytes)
if (b'<response' in addrinfo and 'NAK' in addrinfo) or b"Invalid parameters" in addrinfo:
self.log.error(f"Error:{addrinfo}")
return
if (b"address" in addrinfo and b"can\'t" in addrinfo):
return False
if b"address" in addrinfo and b"can\'t" in addrinfo:
tmp = b""
while b"NAK" not in tmp and b"ACK" not in tmp:
tmp += self.cdc.read(self.cfg.MaxXMLSizeInBytes)
self.log.error(f"Error:{addrinfo}")
return
return False
addrinfo = self.cdc.read(self.cfg.MaxXMLSizeInBytes)
if b'<response' in addrinfo and b'NAK' in addrinfo:
print(f"Error:{addrinfo}")
return
return False
pos += maxsize
datawritten += maxsize
lengthtowrite -= maxsize
if info:
prog = int(float(datawritten) / float(SizeInBytes) * float(100))
if (prog > old):
if prog > old:
print_progress(prog, 100, prefix='Progress:', suffix='Complete', bar_length=50)
old = prog
if info:
@ -859,31 +884,34 @@ class qualcomm_firehose:
'''
<?xml version="1.0" ?><data><peek address64="1048576" SizeInBytes="90112" /></data>
'''
data = f"<?xml version=\"1.0\" ?><data><peek address64=\"{address}\" size_in_bytes=\"{SizeInBytes}\" /></data>\n"
data = f"<?xml version=\"1.0\" ?><data><peek address64=\"{address}\" " + \
f"size_in_bytes=\"{SizeInBytes}\" /></data>\n"
'''
<?xml version="1.0" encoding="UTF-8" ?><data><log value="Using address 00100000" /></data>
<?xml version="1.0" encoding="UTF-8" ?><data><log value="0x22 0x00 0x00 0xEA 0x70 0x00 0x00 0xEA 0x74 0x00 0x00 0xEA 0x78 0x00 0
x00 0xEA 0x7C 0x00 0x00 0xEA 0x80 0x00 0x00 0xEA 0x84 0x00 0x00 0xEA 0x88 0x00 0x00 0xEA 0xFE 0xFF 0xFF 0xEA 0xFE 0xFF 0xFF 0xEA
0xFE 0xFF 0xFF 0xEA 0xFE 0xFF 0xFF 0xEA 0xFE 0xFF 0xFF 0xEA 0xFE 0xFF 0xFF 0xEA 0xFE 0xFF 0xFF 0xEA 0xFE 0xFF 0xFF 0xEA 0xFE 0x
FF 0xFF 0xEA 0xFE 0xFF 0xFF 0xEA 0xFE 0xFF 0xFF 0xEA 0xFE 0xFF 0xFF 0xEA 0xFE 0xFF 0xFF 0xEA 0xFE 0xFF 0xFF 0xEA 0xFE 0xFF 0xFF
0xEA 0xFE 0xFF 0xFF 0xEA 0xFE 0xFF 0xFF 0xEA 0xFE 0xFF " /></data>
<?xml version="1.0" encoding="UTF-8" ?><data><log value="0x22 0x00 0x00 0xEA 0x70 0x00 0x00 0xEA 0x74 0x00
0x00 0xEA 0x78 0x00 0x00 0xEA 0x7C 0x00 0x00 0xEA 0x80 0x00 0x00 0xEA 0x84 0x00 0x00 0xEA 0x88 0x00 0x00
0xEA 0xFE 0xFF 0xFF 0xEA 0xFE 0xFF 0xFF 0xEA 0xFE 0xFF 0xFF 0xEA 0xFE 0xFF 0xFF 0xEA 0xFE 0xFF 0xFF 0xEA
0xFE 0xFF 0xFF 0xEA 0xFE 0xFF 0xFF 0xEA 0xFE 0xFF 0xFF 0xEA 0xFE 0xFF 0xFF 0xEA 0xFE 0xFF 0xFF 0xEA 0xFE
0xFF 0xFF 0xEA 0xFE 0xFF 0xFF 0xEA 0xFE 0xFF 0xFF 0xEA 0xFE 0xFF 0xFF 0xEA 0xFE 0xFF 0xFF 0xEA 0xFE 0xFF
0xFF 0xEA 0xFE 0xFF 0xFF 0xEA 0xFE 0xFF " /></data>
'''
try:
self.cdc.write(data, self.cfg.MaxXMLSizeInBytes)
except:
pass
addrinfo = self.cdc.read(self.cfg.MaxXMLSizeInBytes)
if (b"SizeInBytes" in addrinfo or b"Invalid parameters" in addrinfo):
if b"SizeInBytes" in addrinfo or b"Invalid parameters" in addrinfo:
tmp = b""
while b"NAK" not in tmp and b"ACK" not in tmp:
tmp += self.cdc.read(self.cfg.MaxXMLSizeInBytes)
data = f"<?xml version=\"1.0\" ?><data><peek address64=\"{hex(address)}\" SizeInBytes=\"{hex(SizeInBytes)}\" /></data>"
data = f"<?xml version=\"1.0\" ?><data><peek address64=\"{hex(address)}\" " + \
f"SizeInBytes=\"{hex(SizeInBytes)}\" /></data>"
self.cdc.write(data, self.cfg.MaxXMLSizeInBytes)
addrinfo = self.cdc.read(self.cfg.MaxXMLSizeInBytes)
if (b'<response' in addrinfo and 'NAK' in addrinfo) or b"Invalid parameters" in addrinfo:
self.log.error(f"Error:{addrinfo}")
return
if (b"address" in addrinfo and b"can\'t" in addrinfo):
return False
if b"address" in addrinfo and b"can\'t" in addrinfo:
tmp = b""
while b"NAK" not in tmp and b"ACK" not in tmp:
tmp += self.cdc.read(self.cfg.MaxXMLSizeInBytes)
@ -895,7 +923,7 @@ class qualcomm_firehose:
old = 0
if info:
print_progress(0, 100, prefix='Progress:', suffix='Complete', bar_length=50)
while (True):
while True:
tmp = self.cdc.read(self.cfg.MaxXMLSizeInBytes)
if b'<response' in tmp or b"ERROR" in tmp:
break
@ -916,7 +944,7 @@ class qualcomm_firehose:
print_progress(prog, 100, prefix='Progress:', suffix='Complete', bar_length=50)
old = prog
if wf != None:
if wf is not None:
wf.close()
if b'<response' in tmp and b'ACK' in tmp:
if info:
@ -930,7 +958,7 @@ class qualcomm_firehose:
def cmd_memcpy(self, destaddress, sourceaddress, size):
data = self.cmd_peek(sourceaddress, size)
if data != b"" and data != False:
if data != b"" and data:
if self.cmd_poke(destaddress, data):
return True
return False
@ -938,7 +966,7 @@ class qualcomm_firehose:
def cmd_rawxml(self, data, response=True):
if response:
val = self.xmlsend(data)
if val[0] == True:
if val[0]:
self.log.info(f"{data} succeeded.")
return val[2]
else:

689
Library/firehose_client.py Normal file
View file

@ -0,0 +1,689 @@
import os
import sys
from binascii import hexlify, unhexlify
from struct import unpack, pack
from Library.firehose import qualcomm_firehose
from Config.qualcomm_config import infotbl, msmids, secureboottbl, sochw
from Library.xmlparser import xmlparser
from Library.utils import do_tcp_server
class firehose_client:
def __init__(self, arguments, cdc, sahara, LOGGER, printer):
self.LOGGER = LOGGER
self.cdc = cdc
self.sahara = sahara
self.arguments = arguments
self.printer = printer
self.cfg = qualcomm_firehose.cfg()
self.cfg.MemoryName = arguments["--memory"]
self.cfg.ZLPAwareHost = 1
self.cfg.SkipStorageInit = arguments["--skipstorageinit"]
self.cfg.SkipWrite = arguments["--skipwrite"]
self.cfg.MaxPayloadSizeToTargetInBytes = int(arguments["--maxpayload"], 16)
self.cfg.SECTOR_SIZE_IN_BYTES = int(arguments["--sectorsize"], 16)
self.cfg.bit64 = sahara.bit64
devicemodel = ""
skipresponse = False
if "--skipresponse" in arguments:
if arguments["--skipresponse"]:
skipresponse = True
if "--devicemodel" in arguments:
if arguments["--devicemodel"] is not None:
devicemodel = arguments["--devicemodel"]
self.firehose = qualcomm_firehose(cdc, xmlparser(), self.cfg, LOGGER, devicemodel, sahara.serial, skipresponse,
self.getluns(arguments), arguments)
self.supported_functions = self.firehose.connect(0)
funcs = "Supported functions:\n-----------------\n"
for function in self.supported_functions:
funcs += function + ","
funcs = funcs[:-1]
LOGGER.info(funcs)
self.target_name = self.firehose.cfg.TargetName
if "hwid" in dir(sahara):
hwid = sahara.hwid >> 32
if hwid in msmids:
self.target_name = msmids[hwid]
elif hwid in sochw:
self.target_name = sochw[hwid].split(",")[0]
def check_cmd(self, func):
if not self.supported_functions:
return True
for sfunc in self.supported_functions:
if func.lower() == sfunc.lower():
return True
return False
def getluns(self, argument):
if argument["--lun"] != "None":
return [int(argument["--lun"])]
luns = []
if not argument["--memory"].lower() == "emmc":
for i in range(0, 99):
luns.append(i)
else:
luns = [0]
return luns
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 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
command = options["<command>"]
options = options["<options>"]
if self.firehose.modules is None:
self.LOGGER.error("Feature is not supported")
return False
else:
return self.firehose.modules.run(mainargs=options, command=command)
else:
self.LOGGER.error("Unknown/Missing command, a command is required.")
return False

View file

@ -1,6 +1,7 @@
import binascii
from Library.utils import *
class gpt:
from enum import Enum
gpt_header = [
@ -28,91 +29,91 @@ class gpt:
('name', '72s')]
class efi_type(Enum):
EFI_UNUSED = 0x00000000
EFI_MBR = 0x024DEE41
EFI_SYSTEM = 0xC12A7328
EFI_BIOS_BOOT = 0x21686148
EFI_IFFS = 0xD3BFE2DE
EFI_SONY_BOOT = 0xF4019732
EFI_LENOVO_BOOT = 0xBFBFAFE7
EFI_MSR = 0xE3C9E316
EFI_BASIC_DATA = 0xEBD0A0A2
EFI_LDM_META = 0x5808C8AA
EFI_LDM = 0xAF9B60A0
EFI_RECOVERY = 0xDE94BBA4
EFI_GPFS = 0x37AFFC90
EFI_STORAGE_SPACES = 0xE75CAF8F
EFI_HPUX_DATA = 0x75894C1E
EFI_HPUX_SERVICE = 0xE2A1E728
EFI_LINUX_DAYA = 0x0FC63DAF
EFI_LINUX_RAID = 0xA19D880F
EFI_LINUX_ROOT32 = 0x44479540
EFI_LINUX_ROOT64 = 0x4F68BCE3
EFI_LINUX_ROOT_ARM32 = 0x69DAD710
EFI_LINUX_ROOT_ARM64 = 0xB921B045
EFI_LINUX_SWAP = 0x0657FD6D
EFI_LINUX_LVM = 0xE6D6D379
EFI_LINUX_HOME = 0x933AC7E1
EFI_LINUX_SRV = 0x3B8F8425
EFI_LINUX_DM_CRYPT = 0x7FFEC5C9
EFI_LINUX_LUKS = 0xCA7D7CCB
EFI_LINUX_RESERVED = 0x8DA63339
EFI_FREEBSD_BOOT = 0x83BD6B9D
EFI_FREEBSD_DATA = 0x516E7CB4
EFI_FREEBSD_SWAP = 0x516E7CB5
EFI_FREEBSD_UFS = 0x516E7CB6
EFI_FREEBSD_VINUM = 0x516E7CB8
EFI_FREEBSD_ZFS = 0x516E7CBA
EFI_OSX_HFS = 0x48465300
EFI_OSX_UFS = 0x55465300
EFI_OSX_ZFS = 0x6A898CC3
EFI_OSX_RAID = 0x52414944
EFI_OSX_RAID_OFFLINE = 0x52414944
EFI_OSX_RECOVERY = 0x426F6F74
EFI_OSX_LABEL = 0x4C616265
EFI_OSX_TV_RECOVERY = 0x5265636F
EFI_OSX_CORE_STORAGE = 0x53746F72
EFI_SOLARIS_BOOT = 0x6A82CB45
EFI_SOLARIS_ROOT = 0x6A85CF4D
EFI_SOLARIS_SWAP = 0x6A87C46F
EFI_SOLARIS_BACKUP = 0x6A8B642B
EFI_SOLARIS_USR = 0x6A898CC3
EFI_SOLARIS_VAR = 0x6A8EF2E9
EFI_SOLARIS_HOME = 0x6A90BA39
EFI_SOLARIS_ALTERNATE = 0x6A9283A5
EFI_SOLARIS_RESERVED1 = 0x6A945A3B
EFI_SOLARIS_RESERVED2 = 0x6A9630D1
EFI_SOLARIS_RESERVED3 = 0x6A980767
EFI_SOLARIS_RESERVED4 = 0x6A96237F
EFI_SOLARIS_RESERVED5 = 0x6A8D2AC7
EFI_NETBSD_SWAP = 0x49F48D32
EFI_NETBSD_FFS = 0x49F48D5A
EFI_NETBSD_LFS = 0x49F48D82
EFI_NETBSD_RAID = 0x49F48DAA
EFI_NETBSD_CONCAT = 0x2DB519C4
EFI_NETBSD_ENCRYPT = 0x2DB519EC
EFI_CHROMEOS_KERNEL = 0xFE3A2A5D
EFI_CHROMEOS_ROOTFS = 0x3CB8E202
EFI_CHROMEOS_FUTURE = 0x2E0A753D
EFI_HAIKU = 0x42465331
EFI_MIDNIGHTBSD_BOOT = 0x85D5E45E
EFI_MIDNIGHTBSD_DATA = 0x85D5E45A
EFI_MIDNIGHTBSD_SWAP = 0x85D5E45B
EFI_MIDNIGHTBSD_UFS = 0x0394EF8B
EFI_MIDNIGHTBSD_VINUM = 0x85D5E45C
EFI_MIDNIGHTBSD_ZFS = 0x85D5E45D
EFI_CEPH_JOURNAL = 0x45B0969E
EFI_CEPH_ENCRYPT = 0x45B0969E
EFI_CEPH_OSD = 0x4FBD7E29
EFI_CEPH_ENCRYPT_OSD = 0x4FBD7E29
EFI_CEPH_CREATE = 0x89C57F98
EFI_UNUSED = 0x00000000
EFI_MBR = 0x024DEE41
EFI_SYSTEM = 0xC12A7328
EFI_BIOS_BOOT = 0x21686148
EFI_IFFS = 0xD3BFE2DE
EFI_SONY_BOOT = 0xF4019732
EFI_LENOVO_BOOT = 0xBFBFAFE7
EFI_MSR = 0xE3C9E316
EFI_BASIC_DATA = 0xEBD0A0A2
EFI_LDM_META = 0x5808C8AA
EFI_LDM = 0xAF9B60A0
EFI_RECOVERY = 0xDE94BBA4
EFI_GPFS = 0x37AFFC90
EFI_STORAGE_SPACES = 0xE75CAF8F
EFI_HPUX_DATA = 0x75894C1E
EFI_HPUX_SERVICE = 0xE2A1E728
EFI_LINUX_DAYA = 0x0FC63DAF
EFI_LINUX_RAID = 0xA19D880F
EFI_LINUX_ROOT32 = 0x44479540
EFI_LINUX_ROOT64 = 0x4F68BCE3
EFI_LINUX_ROOT_ARM32 = 0x69DAD710
EFI_LINUX_ROOT_ARM64 = 0xB921B045
EFI_LINUX_SWAP = 0x0657FD6D
EFI_LINUX_LVM = 0xE6D6D379
EFI_LINUX_HOME = 0x933AC7E1
EFI_LINUX_SRV = 0x3B8F8425
EFI_LINUX_DM_CRYPT = 0x7FFEC5C9
EFI_LINUX_LUKS = 0xCA7D7CCB
EFI_LINUX_RESERVED = 0x8DA63339
EFI_FREEBSD_BOOT = 0x83BD6B9D
EFI_FREEBSD_DATA = 0x516E7CB4
EFI_FREEBSD_SWAP = 0x516E7CB5
EFI_FREEBSD_UFS = 0x516E7CB6
EFI_FREEBSD_VINUM = 0x516E7CB8
EFI_FREEBSD_ZFS = 0x516E7CBA
EFI_OSX_HFS = 0x48465300
EFI_OSX_UFS = 0x55465300
EFI_OSX_ZFS = 0x6A898CC3
EFI_OSX_RAID = 0x52414944
EFI_OSX_RAID_OFFLINE = 0x52414944
EFI_OSX_RECOVERY = 0x426F6F74
EFI_OSX_LABEL = 0x4C616265
EFI_OSX_TV_RECOVERY = 0x5265636F
EFI_OSX_CORE_STORAGE = 0x53746F72
EFI_SOLARIS_BOOT = 0x6A82CB45
EFI_SOLARIS_ROOT = 0x6A85CF4D
EFI_SOLARIS_SWAP = 0x6A87C46F
EFI_SOLARIS_BACKUP = 0x6A8B642B
EFI_SOLARIS_USR = 0x6A898CC3
EFI_SOLARIS_VAR = 0x6A8EF2E9
EFI_SOLARIS_HOME = 0x6A90BA39
EFI_SOLARIS_ALTERNATE = 0x6A9283A5
EFI_SOLARIS_RESERVED1 = 0x6A945A3B
EFI_SOLARIS_RESERVED2 = 0x6A9630D1
EFI_SOLARIS_RESERVED3 = 0x6A980767
EFI_SOLARIS_RESERVED4 = 0x6A96237F
EFI_SOLARIS_RESERVED5 = 0x6A8D2AC7
EFI_NETBSD_SWAP = 0x49F48D32
EFI_NETBSD_FFS = 0x49F48D5A
EFI_NETBSD_LFS = 0x49F48D82
EFI_NETBSD_RAID = 0x49F48DAA
EFI_NETBSD_CONCAT = 0x2DB519C4
EFI_NETBSD_ENCRYPT = 0x2DB519EC
EFI_CHROMEOS_KERNEL = 0xFE3A2A5D
EFI_CHROMEOS_ROOTFS = 0x3CB8E202
EFI_CHROMEOS_FUTURE = 0x2E0A753D
EFI_HAIKU = 0x42465331
EFI_MIDNIGHTBSD_BOOT = 0x85D5E45E
EFI_MIDNIGHTBSD_DATA = 0x85D5E45A
EFI_MIDNIGHTBSD_SWAP = 0x85D5E45B
EFI_MIDNIGHTBSD_UFS = 0x0394EF8B
EFI_MIDNIGHTBSD_VINUM = 0x85D5E45C
EFI_MIDNIGHTBSD_ZFS = 0x85D5E45D
EFI_CEPH_JOURNAL = 0x45B0969E
EFI_CEPH_ENCRYPT = 0x45B0969E
EFI_CEPH_OSD = 0x4FBD7E29
EFI_CEPH_ENCRYPT_OSD = 0x4FBD7E29
EFI_CEPH_CREATE = 0x89C57F98
EFI_CEPH_ENCRYPT_CREATE = 0x89C57F98
EFI_OPENBSD = 0x824CC7A0
EFI_QNX = 0xCEF5A9AD
EFI_PLAN9 = 0xC91818F9
EFI_VMWARE_VMKCORE = 0x9D275380
EFI_VMWARE_VMFS = 0xAA31E02A
EFI_VMWARE_RESERVED = 0x9198EFFC
EFI_OPENBSD = 0x824CC7A0
EFI_QNX = 0xCEF5A9AD
EFI_PLAN9 = 0xC91818F9
EFI_VMWARE_VMKCORE = 0x9D275380
EFI_VMWARE_VMFS = 0xAA31E02A
EFI_VMWARE_RESERVED = 0x9198EFFC
def __init__(self, num_part_entries=0, part_entry_size=0, part_entry_start_lba=0, *args, **kwargs):
self.num_part_entries = num_part_entries
@ -126,82 +127,90 @@ class gpt:
'''
def parseheader(self, gptdata, sectorsize=512):
return read_object(gptdata[sectorsize:sectorsize+0x5C], self.gpt_header)
return read_object(gptdata[sectorsize:sectorsize + 0x5C], self.gpt_header)
def parse(self, gptdata, sectorsize=512):
self.header = read_object(gptdata[sectorsize:sectorsize+0x5C], self.gpt_header)
self.sectorsize=sectorsize
if self.header["signature"]!=b"EFI PART":
self.header = read_object(gptdata[sectorsize:sectorsize + 0x5C], self.gpt_header)
self.sectorsize = sectorsize
if self.header["signature"] != b"EFI PART":
print("Invalid or unknown GPT magic.")
return False
if self.header["revision"]!=0x100:
if self.header["revision"] != 0x100:
print("Unknown GPT revision.")
return False
if self.part_entry_start_lba!=0:
if self.part_entry_start_lba != 0:
start = self.part_entry_start_lba
else:
start=self.header["part_entry_start_lba"]*sectorsize
start = self.header["part_entry_start_lba"] * sectorsize
if "part_entry_size" in self.header:
entrysize=self.header["part_entry_size"]
entrysize = self.header["part_entry_size"]
else:
entrysize=self.part_entry_size
self.partentries=[]
entrysize = self.part_entry_size
self.partentries = []
class partf:
unique=b""
first_lba=0
last_lba=0
flags=0
type=b""
name=b""
unique = b""
first_lba = 0
last_lba = 0
flags = 0
sector = 0
sectors = 0
type = b""
name = b""
if "num_part_entries" in self.header:
num_part_entries=self.header["num_part_entries"]
num_part_entries = self.header["num_part_entries"]
else:
num_part_entries=self.num_part_entries
for idx in range(0,num_part_entries):
data=gptdata[start+(idx*entrysize):start+(idx*entrysize)+entrysize]
if int(hexlify(data[0:16]),16)==0:
num_part_entries = self.num_part_entries
for idx in range(0, num_part_entries):
data = gptdata[start + (idx * entrysize):start + (idx * entrysize) + entrysize]
if int(hexlify(data[0:16]), 16) == 0:
break
partentry=read_object(data,self.gpt_partition)
pa=partf()
guid1=struct.unpack("<I",partentry["unique"][0:0x4])[0]
guid2=struct.unpack("<H",partentry["unique"][0x4:0x6])[0]
guid3=struct.unpack("<H",partentry["unique"][0x6:0x8])[0]
guid4=struct.unpack("<H",partentry["unique"][0x8:0xA])[0]
guid5=binascii.hexlify(partentry["unique"][0xA:0x10]).decode('utf-8')
pa.unique = "{:08x}-{:04x}-{:04x}-{:04x}-{}".format(guid1,guid2,guid3,guid4,guid5)
partentry = read_object(data, self.gpt_partition)
pa = partf()
guid1 = struct.unpack("<I", partentry["unique"][0:0x4])[0]
guid2 = struct.unpack("<H", partentry["unique"][0x4:0x6])[0]
guid3 = struct.unpack("<H", partentry["unique"][0x6:0x8])[0]
guid4 = struct.unpack("<H", partentry["unique"][0x8:0xA])[0]
guid5 = binascii.hexlify(partentry["unique"][0xA:0x10]).decode('utf-8')
pa.unique = "{:08x}-{:04x}-{:04x}-{:04x}-{}".format(guid1, guid2, guid3, guid4, guid5)
pa.sector = partentry["first_lba"]
pa.sectors = partentry["last_lba"]-partentry["first_lba"]+1
pa.sectors = partentry["last_lba"] - partentry["first_lba"] + 1
pa.flags = partentry["flags"]
type=int(struct.unpack("<I",partentry["type"][0:0x4])[0])
type = int(struct.unpack("<I", partentry["type"][0:0x4])[0])
try:
pa.type = self.efi_type(type).name
except:
pa.type = hex(type)
pa.name = partentry["name"].replace(b"\x00\x00",b"").decode('utf-16')
if pa.type=="EFI_UNUSED":
pa.name = partentry["name"].replace(b"\x00\x00", b"").decode('utf-16')
if pa.type == "EFI_UNUSED":
break
self.partentries.append(pa)
self.totalsectors=self.header["last_usable_lba"]
self.totalsectors = self.header["last_usable_lba"]
return True
def print(self):
print("\nGPT Table:\n-------------")
for partition in self.partentries:
print("{:20} Offset 0x{:016x}, Length 0x{:016x}, Flags 0x{:08x}, UUID {}, Type {}".format(partition.name+":",partition.sector*self.sectorsize,partition.sectors*self.sectorsize,partition.flags,partition.unique,partition.type))
print("\nTotal disk size:0x{:016x}, sectors:0x{:016x}".format(self.totalsectors*self.sectorsize,self.totalsectors))
print("{:20} Offset 0x{:016x}, Length 0x{:016x}, Flags 0x{:08x}, UUID {}, Type {}".format(
partition.name + ":", partition.sector * self.sectorsize, partition.sectors * self.sectorsize,
partition.flags, partition.unique, partition.type))
print("\nTotal disk size:0x{:016x}, sectors:0x{:016x}".format(self.totalsectors * self.sectorsize,
self.totalsectors))
def tostring(self):
mstr=("\nGPT Table:\n-------------")
mstr = ("\nGPT Table:\n-------------")
for partition in self.partentries:
mstr+=("{:20} Offset 0x{:016x}, Length 0x{:016x}, Flags 0x{:08x}, UUID {}, Type {}".format(partition.name+":",partition.sector*self.sectorsize,partition.sectors*self.sectorsize,partition.flags,partition.unique,partition.type))
mstr+=("\nTotal disk size:0x{:016x}, sectors:0x{:016x}".format(self.totalsectors*self.sectorsize,self.totalsectors))
mstr += ("{:20} Offset 0x{:016x}, Length 0x{:016x}, Flags 0x{:08x}, UUID {}, Type {}".format(
partition.name + ":", partition.sector * self.sectorsize, partition.sectors * self.sectorsize,
partition.flags, partition.unique, partition.type))
mstr += ("\nTotal disk size:0x{:016x}, sectors:0x{:016x}".format(self.totalsectors * self.sectorsize,
self.totalsectors))
return mstr
def generate_rawprogram(self, lun, sectorsize, directory):
fname="rawprogram" + str(lun) + ".xml"
fname = "rawprogram" + str(lun) + ".xml"
with open(os.path.join(directory, fname), "wb") as wf:
mstr = "<?xml version=\"1.0\" ?>\n<data>\n"
partofsingleimage = "false"
@ -210,16 +219,16 @@ class gpt:
for partition in self.partentries:
filename = partition.name + ".bin"
mstr += f"\t<program SECTOR_SIZE_IN_BYTES=\"{sectorsize}\" " + \
f"file_sector_offset=\"0\" filename=\"{filename}\" " + \
f"label=\"{partition.name}\" num_partition_sectors=\"{partition.sectors}\" " + \
f"partofsingleimage=\"{partofsingleimage}\" physical_partition_number=\"{str(lun)}\" " + \
f"readbackverify=\"{readbackverify}\" size_in_KB=\"{(partition.sector * sectorsize / 1024):.1f}\" sparse=\"{sparse}\" " + \
f"start_byte_hex=\"{hex(partition.sector * sectorsize)}\" start_sector=\"{partition.sector}\"/>\n"
partofsingleimage="true"
sectors=self.header["first_usable_lba"]
f"file_sector_offset=\"0\" filename=\"{filename}\" " + \
f"label=\"{partition.name}\" num_partition_sectors=\"{partition.sectors}\" " + \
f"partofsingleimage=\"{partofsingleimage}\" physical_partition_number=\"{str(lun)}\" " + \
f"readbackverify=\"{readbackverify}\" size_in_KB=\"{(partition.sector * sectorsize / 1024):.1f}\" sparse=\"{sparse}\" " + \
f"start_byte_hex=\"{hex(partition.sector * sectorsize)}\" start_sector=\"{partition.sector}\"/>\n"
partofsingleimage = "true"
sectors = self.header["first_usable_lba"]
mstr += f"\t<program SECTOR_SIZE_IN_BYTES=\"{sectorsize}\" file_sector_offset=\"0\" filename=\"gpt_main{str(lun)}.bin\" label=\"PrimaryGPT\" num_partition_sectors=\"{sectors}\" partofsingleimage=\"{partofsingleimage}\" physical_partition_number=\"{str(lun)}\" readbackverify=\"{readbackverify}\" size_in_KB=\"{(sectors * sectorsize / 1024):.1f}\" sparse=\"{sparse}\" start_byte_hex=\"0x0\" start_sector=\"0\"/>\n"
sectors=self.header["first_usable_lba"]-1
mstr += f"\t<program SECTOR_SIZE_IN_BYTES=\"{sectorsize}\" file_sector_offset=\"0\" filename=\"gpt_backup{str(lun)}.bin\" label=\"BackupGPT\" num_partition_sectors=\"{sectors}\" partofsingleimage=\"{partofsingleimage}\" physical_partition_number=\"{str(lun)}\" readbackverify=\"{readbackverify}\" size_in_KB=\"{(sectors * sectorsize / 1024):.1f}\" sparse=\"{sparse}\" start_byte_hex=\"({sectorsize}*NUM_DISK_SECTORS)-{sectorsize*sectors}.\" start_sector=\"NUM_DISK_SECTORS-{sectors}.\"/>\n"
sectors = self.header["first_usable_lba"] - 1
mstr += f"\t<program SECTOR_SIZE_IN_BYTES=\"{sectorsize}\" file_sector_offset=\"0\" filename=\"gpt_backup{str(lun)}.bin\" label=\"BackupGPT\" num_partition_sectors=\"{sectors}\" partofsingleimage=\"{partofsingleimage}\" physical_partition_number=\"{str(lun)}\" readbackverify=\"{readbackverify}\" size_in_KB=\"{(sectors * sectorsize / 1024):.1f}\" sparse=\"{sparse}\" start_byte_hex=\"({sectorsize}*NUM_DISK_SECTORS)-{sectorsize * sectors}.\" start_sector=\"NUM_DISK_SECTORS-{sectors}.\"/>\n"
mstr += "</data>"
wf.write(bytes(mstr, 'utf-8'))
print(f"Wrote partition xml as {fname}")

View file

@ -1,9 +1,9 @@
import logging
from binascii import hexlify, unhexlify
from struct import pack, unpack
from binascii import hexlify
from struct import unpack
import time
MAX_PACKET_LEN=4096
MAX_PACKET_LEN = 4096
crcTbl = (
0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
@ -40,31 +40,31 @@ crcTbl = (
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78)
class hdlc():
def __init__(self, cdc, timeout=5000):
class hdlc:
def __init__(self, cdc):
self.cdc = cdc
self.programmer = None
self.timeout=500
self.timeout = 1500
def serial16(self,data):
def serial16(self, data):
out = bytearray()
out.append((data >> 8) & 0xFF)
out.append(data & 0xFF)
return out
def serial16le(self,data):
def serial16le(self, data):
out = bytearray()
out.append(data & 0xFF)
out.append((data >> 8) & 0xFF)
return out
def serial32(self,data):
def serial32(self, data):
out = bytearray()
out += self.serial16((data >> 16) & 0xFFFF)
out += self.serial16(data & 0xFFFF)
return out
def serial32le(self,data):
def serial32le(self, data):
out = bytearray()
out += self.serial16le(data & 0xFFFF)
out += self.serial16le((data >> 16) & 0xFFFF)
@ -75,21 +75,21 @@ class hdlc():
iv = ((iv >> 8) & 0xFFFF) ^ crcTbl[(iv ^ byte) & 0xFF]
return ~iv & 0xFFFF
def convert_cmdbuf(self,indata):
crc16val=self.crc16(0xFFFF,indata)
def convert_cmdbuf(self, indata):
crc16val = self.crc16(0xFFFF, indata)
indata.extend(bytearray(self.serial16le(crc16val)))
outdata=self.escape(indata)
outdata = self.escape(indata)
outdata.append(0x7E)
return outdata
def escape(self,indata):
outdata=bytearray()
for i in range(0,len(indata)):
buf=indata[i]
if buf==0x7e:
def escape(self, indata):
outdata = bytearray()
for i in range(0, len(indata)):
buf = indata[i]
if buf == 0x7e:
outdata.append(0x7d)
outdata.append(0x5e)
elif buf==0x7d:
elif buf == 0x7d:
outdata.append(0x7d)
outdata.append(0x5d)
else:
@ -118,51 +118,105 @@ class hdlc():
return None
return out
def receive_reply(self,masslen):
replybuf=bytearray()
tmp=self.cdc.read(MAX_PACKET_LEN,self.timeout)
if tmp==bytearray():
def receive_reply(self):
replybuf = bytearray()
tmp = self.cdc.read(MAX_PACKET_LEN, self.timeout)
if tmp == bytearray():
return 0
if tmp == b"":
return 0
retry = 0
while tmp[-1] != 0x7E:
time.sleep(0.05)
tmp += self.cdc.read(MAX_PACKET_LEN, self.timeout)
retry += 1
if retry > 5:
break
replybuf.extend(tmp)
data=self.unescape(replybuf)
#print(hexlify(data))
crc16val = self.crc16(0xFFFF, data[:-3])
reccrc=int(data[-3])+(int(data[-2])<<8)
if crc16val!=reccrc:
return -1
data = self.unescape(replybuf)
# print(hexlify(data))
if len(data) > 3:
crc16val = self.crc16(0xFFFF, data[:-3])
reccrc = int(data[-3]) + (int(data[-2]) << 8)
if crc16val != reccrc:
return -1
else:
time.sleep(0.5)
data = self.cdc.read(MAX_PACKET_LEN, self.timeout)
if len(data) > 3:
crc16val = self.crc16(0xFFFF, data[:-3])
reccrc = int(data[-3]) + (int(data[-2]) << 8)
if crc16val != reccrc:
return -1
return data
return data[:-3]
def send_unframed_buf(self,outdata,prefixflag):
#ttyflush()
def receive_reply_nocrc(self):
replybuf = bytearray()
tmp = self.cdc.read(MAX_PACKET_LEN, self.timeout)
if tmp == bytearray():
return 0
if tmp == b"":
return 0
retry = 0
while tmp[-1] != 0x7E:
# time.sleep(0.05)
tmp += self.cdc.read(MAX_PACKET_LEN, self.timeout)
retry += 1
if retry > 5:
break
replybuf.extend(tmp)
data = self.unescape(replybuf)
# print(hexlify(data))
if len(data) > 3:
# crc16val = self.crc16(0xFFFF, data[:-3])
# reccrc = int(data[-3]) + (int(data[-2]) << 8)
return data[:-3]
else:
time.sleep(0.5)
data = self.cdc.read(MAX_PACKET_LEN, self.timeout)
if len(data) > 3:
# crc16val = self.crc16(0xFFFF, data[:-3])
# reccrc = int(data[-3]) + (int(data[-2]) << 8)
return data[:-3]
else:
return data
def send_unframed_buf(self, outdata, prefixflag):
# ttyflush()
if prefixflag:
tmp=bytearray()
tmp = bytearray()
tmp.append(0x7E)
tmp.extend(outdata)
outdata=tmp
return self.cdc.write(outdata,MAX_PACKET_LEN)
#FlushFileBuffers(ser)
outdata = tmp
return self.cdc.write(outdata, MAX_PACKET_LEN)
# FlushFileBuffers(ser)
def send_cmd_base(self,outdata,prefixflag):
packet=self.convert_cmdbuf(bytearray(outdata))
if (self.send_unframed_buf(packet, prefixflag)):
return self.receive_reply(0)
def send_cmd_base(self, outdata, prefixflag, nocrc=False):
packet = self.convert_cmdbuf(bytearray(outdata))
if self.send_unframed_buf(packet, prefixflag):
if nocrc:
return self.receive_reply_nocrc()
else:
return self.receive_reply()
return b""
def send_cmd(self,outdata):
return self.send_cmd_base(outdata,1)
def send_cmd(self, outdata, nocrc=False):
return self.send_cmd_base(outdata, 1, nocrc)
def send_cmd_np(self,outdata):
return self.send_cmd_base(outdata,0)
def send_cmd_np(self, outdata, nocrc=False):
return self.send_cmd_base(outdata, 0, nocrc)
def show_errpacket(self, descr, pktbuf):
if (len(pktbuf) == 0):
if len(pktbuf) == 0:
return
logging.error("Error: %s " % descr)
if (pktbuf[1] == 0x0e):
pktbuf[len-4]=0
#puts(pktbuf+2)
ret=self.receive_reply(0)
errorcode=unpack("<I",ret[2:2+4])
logging.error("Error code = %08x\n\n",errorcode)
if pktbuf[1] == 0x0e:
pktbuf[-4] = 0
# puts(pktbuf+2)
ret = self.receive_reply()
errorcode = unpack("<I", ret[2:2 + 4])
logging.error("Error code = %08x\n\n", errorcode)
else:
print(hexlify(pktbuf))
print(hexlify(pktbuf))

View file

@ -49,7 +49,7 @@ def pt32_walk(data, ttbr, skip):
pt.parse_spt(sldata, va)
def main():
parser = argparse.ArgumentParser(\
parser = argparse.ArgumentParser(
prog="memparse",
usage="python memparse.py -arch <32,64> -in <filename> -mem <offset>",
formatter_class=argparse.RawTextHelpFormatter)
@ -57,7 +57,7 @@ def main():
parser.add_argument('-arch', '--arch', dest='arch', help='architecture=32,64', default="32")
parser.add_argument('-mem', '--mem', dest='mem', help='memoryoffset', default="0x200000")
args = parser.parse_args()
if (args.infile==""):
if args.infile=="":
print("You need to add an -in [memorydump filename]")
return

846
Library/nand_config.py Normal file
View file

@ -0,0 +1,846 @@
import ctypes
from enum import Enum
from struct import unpack, pack
c_uint8 = ctypes.c_uint8
supported_flash = {
# Flash ID Density(MB) Wid Pgsz Blksz oobsz onenand Manuf */
0x2690ac2c: [(512 << 20), 0, 4096, (4096 << 6), 224, 0], # QUECTEL_NAND_FM6BD4G2GXA
0x2690ac98: [(512 << 20), 0, 4096, (4096 << 6), 256, 0], # QUECTEL_NAND_NM14FSK2LAXCL
0x1500aa98: [(256 << 20), 0, 2048, (2048 << 6), 64, 0],
0x5500ba98: [(256 << 20), 1, 2048, (2048 << 6), 64, 0],
0xd580b12c: [(256 << 20), 1, 2048, (2048 << 6), 64, 0],
0x5590bc2c: [(512 << 20), 1, 2048, (2048 << 6), 64, 0],
0x1580aa2c: [(256 << 20), 0, 2048, (2048 << 6), 64, 0],
0x1590aa2c: [(256 << 20), 0, 2048, (2048 << 6), 64, 0],
0x1590ac2c: [(512 << 20), 0, 2048, (2048 << 6), 64, 0],
0x5580baad: [(256 << 20), 1, 2048, (2048 << 6), 64, 0],
0x5510baad: [(256 << 20), 1, 2048, (2048 << 6), 64, 0],
# 0x004000ec: [(256 << 20), 0, 2048, (2048 << 6), 64, 1],
# 0x005c00ec: [(256 << 20), 0, 2048, (2048 << 6), 64, 1],
# 0x005800ec: [(256 << 20), 0, 2048, (2048 << 6), 64, 1],
0x5580ba2c: [(256 << 20), 1, 2048, (2048 << 6), 64, 0],
0x6600b3ec: [(1024 << 20), 1, 4096, (4096 << 6), 128, 0],
0x55d1b32c: [(1024 << 20), 1, 2048, (2048 << 6), 64, 0]
# 0x1500aaec: 0xFF00FFFF, (256 << 20), 0, 2048, (2048 << 6), 64, 0],
# 0x5500baec: 0xFF00FFFF, (256 << 20), 1, 2048, (2048 << 6), 64, 0}, /*Sams */
# 0x6600bcec: 0xFF00FFFF, (512 << 20), 1, 4096, (4096 << 6), 128, 0}, /*Sams */
# 0x2600482c: 0xFF00FFFF, (2048 << 20), 0, 4096, (4096 << 7), 224, 0}, /*8bit bch ecc */
}
class BadFlags(Enum):
BAD_UNDEF = 0
BAD_FILL = 1
BAD_SKIP = 2
BAD_IGNORE = 3
BAD_DISABLE = 4
nand_ids = [
("NAND 16MiB 1,8V 8-bit", 0x33, 16),
("NAND 16MiB 3,3V 8-bit", 0x73, 16),
("NAND 16MiB 1,8V 16-bit", 0x43, 16),
("NAND 16MiB 3,3V 16-bit", 0x53, 16),
("NAND 32MiB 1,8V 8-bit", 0x35, 32),
("NAND 32MiB 3,3V 8-bit", 0x75, 32),
("NAND 32MiB 1,8V 16-bit", 0x45, 32),
("NAND 32MiB 3,3V 16-bit", 0x55, 32),
("NAND 64MiB 1,8V 8-bit", 0x36, 64),
("NAND 64MiB 3,3V 8-bit", 0x76, 64),
("NAND 64MiB 1,8V 16-bit", 0x46, 64),
("NAND 64MiB 3,3V 16-bit", 0x56, 64),
("NAND 128MiB 1,8V 8-bit", 0x78, 128),
("NAND 128MiB 1,8V 8-bit", 0x39, 128),
("NAND 128MiB 3,3V 8-bit", 0x79, 128),
("NAND 128MiB 1,8V 16-bit", 0x72, 128),
("NAND 128MiB 1,8V 16-bit", 0x49, 128),
("NAND 128MiB 3,3V 16-bit", 0x74, 128),
("NAND 128MiB 3,3V 16-bit", 0x59, 128),
("NAND 256MiB 3,3V 8-bit", 0x71, 256),
# 512 Megabit
("NAND 64MiB 1,8V 8-bit", 0xA2, 64),
("NAND 64MiB 1,8V 8-bit", 0xA0, 64),
("NAND 64MiB 3,3V 8-bit", 0xF2, 64),
("NAND 64MiB 3,3V 8-bit", 0xD0, 64),
("NAND 64MiB 1,8V 16-bit", 0xB2, 64),
("NAND 64MiB 1,8V 16-bit", 0xB0, 64),
("NAND 64MiB 3,3V 16-bit", 0xC2, 64),
("NAND 64MiB 3,3V 16-bit", 0xC0, 64),
# 1 Gigabit
("NAND 128MiB 1,8V 8-bit", 0xA1, 128),
("NAND 128MiB 3,3V 8-bit", 0xF1, 128),
("NAND 128MiB 3,3V 8-bit", 0xD1, 128),
("NAND 128MiB 1,8V 16-bit", 0xB1, 128),
("NAND 128MiB 3,3V 16-bit", 0xC1, 128),
("NAND 128MiB 1,8V 16-bit", 0xAD, 128),
# 2 Gigabit
("NAND 256MiB 1.8V 8-bit", 0xAA, 256),
("NAND 256MiB 3.3V 8-bit", 0xDA, 256),
("NAND 256MiB 1.8V 16-bit", 0xBA, 256),
("NAND 256MiB 3.3V 16-bit", 0xCA, 256),
# 4 Gigabit
("NAND 512MiB 1.8V 8-bit", 0xAC, 512),
("NAND 512MiB 3.3V 8-bit", 0xDC, 512),
("NAND 512MiB 1.8V 16-bit", 0xBC, 512),
("NAND 512MiB 3.3V 16-bit", 0xCC, 512),
# 8 Gigabit
("NAND 1GiB 1.8V 8-bit", 0xA3, 1024),
("NAND 1GiB 3.3V 8-bit", 0xD3, 1024),
("NAND 1GiB 1.8V 16-bit", 0xB3, 1024),
("NAND 1GiB 3.3V 16-bit", 0xC3, 1024),
# 16 Gigabit
("NAND 2GiB 1.8V 8-bit", 0xA5, 2048),
("NAND 2GiB 3.3V 8-bit", 0xD5, 2048),
("NAND 2GiB 1.8V 16-bit", 0xB5, 2048),
("NAND 2GiB 3.3V 16-bit", 0xC5, 2048),
# 32 Gigabit
("NAND 4GiB 1.8V 8-bit", 0xA7, 4096),
("NAND 4GiB 3.3V 8-bit", 0xD7, 4096),
("NAND 4GiB 1.8V 16-bit", 0xB7, 4096),
("NAND 4GiB 3.3V 16-bit", 0xC7, 4096),
# 64 Gigabit
("NAND 8GiB 1.8V 8-bit", 0xAE, 8192),
("NAND 8GiB 3.3V 8-bit", 0xDE, 8192),
("NAND 8GiB 1.8V 16-bit", 0xBE, 8192),
("NAND 8GiB 3.3V 16-bit", 0xCE, 8192),
# 128 Gigabit
("NAND 16GiB 1.8V 8-bit", 0x1A, 16384),
("NAND 16GiB 3.3V 8-bit", 0x3A, 16384),
("NAND 16GiB 1.8V 16-bit", 0x2A, 16384),
("NAND 16GiB 3.3V 16-bit", 0x4A, 16384),
# 256 Gigabit
("NAND 32GiB 1.8V 8-bit", 0x1C, 32768),
("NAND 32GiB 3.3V 8-bit", 0x3C, 32768),
("NAND 32GiB 1.8V 16-bit", 0x2C, 32768),
("NAND 32GiB 3.3V 16-bit", 0x4C, 32768),
# 512 Gigabit
("NAND 64GiB 1.8V 8-bit", 0x1E, 65536),
("NAND 64GiB 3.3V 8-bit", 0x3E, 65536),
("NAND 64GiB 1.8V 16-bit", 0x2E, 65536),
("NAND 64GiB 3.3V 16-bit", 0x4E, 65536),
(0, 0, 0),
]
nand_manuf_ids = [
(0x98, "Toshiba"),
(0xec, "Samsung"),
(0x04, "Fujitsu"),
(0x8f, "National"),
(0x07, "Renesas"),
(0x20, "ST Micro"),
(0xad, "Hynix"),
(0x2c, "Micron"),
(0xc8, "Elite Semiconductor"),
(0x01, "Spansion/AMD"),
(0xef, "Winbond"),
(0x0, "")
]
toshiba_tbl = {
# small_slc,device_width,density_mbits
0x36: [True, 8, 512],
0x46: [True, 16, 512],
0x79: [True, 8, 1024],
0xA0: [False, -1, 512],
0xB0: [False, -1, 512],
0xC0: [False, -1, 512],
0xD0: [False, -1, 512],
0xA1: [False, -1, 1024],
0xB1: [False, -1, 1024],
0xC1: [False, -1, 1024],
0xD1: [False, -1, 1024],
0xAA: [False, -1, 2048],
0xBA: [False, -1, 2048],
0xCA: [False, -1, 2048],
0xDA: [False, -1, 2048],
0xAC: [False, -1, 4096],
0xBC: [False, -1, 4096],
0xCC: [False, -1, 4096],
0xDC: [False, -1, 4096],
0xA3: [False, -1, 8192],
0xB3: [False, -1, 8192],
0xC3: [False, -1, 8192],
0xD3: [False, -1, 8192],
0xA5: [False, -1, 16384],
0xB5: [False, -1, 16384],
0xC5: [False, -1, 16384],
0xD5: [False, -1, 16384],
}
samsung_tbl = {
# small_slc,device_width,density_mbits
0x45: [True, 16, 256],
0x55: [True, 16, 256],
0x35: [True, 8, 256],
0x75: [True, 8, 256],
0x46: [True, 16, 512],
0x56: [True, 16, 512],
0x76: [True, 8, 512],
0x36: [True, 8, 512],
0x72: [True, 16, 1024],
0x74: [True, 16, 1024],
0x79: [True, 8, 1024],
0x78: [True, 8, 1024],
0x71: [True, 8, 2048],
0xDC: [True, 8, 4096],
0xA1: [False, -1, 1024],
0xB1: [False, -1, 1024],
0xC1: [False, -1, 1024],
0xD1: [False, -1, 1024],
0xAA: [False, -1, 2048],
0xBA: [False, -1, 2048],
0xCA: [False, -1, 2048],
0xDA: [False, -1, 2048],
0xAC: [False, -1, 4096],
0xBC: [False, -1, 4096],
0xCC: [False, -1, 4096],
0xA3: [False, -1, 8192],
0xB3: [False, -1, 8192],
0xC3: [False, -1, 8192],
0xD3: [False, -1, 8192],
0xA5: [False, -1, 16384],
0xB5: [False, -1, 16384],
0xC5: [False, -1, 16384],
0xD5: [False, -1, 16384]
}
class SettingsOpt:
def __init__(self, parent, chipset, logger, verbose=False):
self.PAGESIZE = 4096
self.parent = parent
logger.setLevel(verbose)
self.logger = logger
self.bad_loader = 0
self.sectors_per_page = 0
self.sectorsize = 512
self.flash_mfr = ""
self.flash_descr = ""
self.IsWideFlash = 0
self.badsector = 0
self.badflag = 0
self.badposition = 0
self.badplace = 0
self.bch_mode = 0
self.ecc_size = 0
self.ecc_bit = 0
self.num_pages_per_blk = 64
self.udflag = 0
self.sahara = 1
self.args_disable_ecc = 0 # 0=enable, 1=disable
self.bad_processing_flag = BadFlags.BAD_SKIP.value
self.cwsize = 0
self.rflag = 0
self.cfg1_enable_bch_ecc = 0
self.bad_loader = 0
self.OOBSIZE = 0
self.MAXBLOCK = 0
self.UD_SIZE_BYTES = 516
self.BAD_BLOCK_BYTE_NUM = 0
self.BAD_BLOCK_IN_SPARE_AREA = 0
self.ECC_MODE = 0
if chipset <= 0:
self.bad_loader = 1
if chipset == 3:
self.name = "MDM9x25"
self.loader = "NPRG9x25p.bin"
self.eloader = "ENPRG9x25p.bin"
self.msmid = [0x07f1]
self.ctrl_type = 0
self.udflag = 1
self.nandbase = 0xf9af0000
self.bcraddr = 0xfc401a40
self.secureboot = 0xFC4B8000 + 0x6080
self.pbl = [0xFC010000, 0x18000]
self.qfprom = [0xFC4B8000, 0x6000] # SECURITY_CONTROL_BASE_PHYS
self.memtbl = [0x200000, 0x24000]
elif chipset == 8:
self.name = "MDM9x3X"
self.loader = "NPRG9x35p.bin"
self.eloader = "ENPRG9x35p.bin"
self.msmid = [0x0922]
self.ctrl_type = 0
self.udflag = 1
self.nandbase = 0xf9af0000 # MSM_NAND_BASE
self.bcraddr = 0xfc401a40
self.secureboot = 0xFC4B8000 + 0x6080
self.pbl = [0xFC010000, 0x18000]
self.qfprom = [0xFC4B8000, 0x6000]
self.memtbl = [0x200000, 0x24000]
elif chipset == 10:
self.name = "MDM9x4X"
self.loader = "NPRG9x45p.bin"
self.eloader = "ENPRG9x45p.bin"
self.msmid = [0x0950, 0x0951]
self.ctrl_type = 0
self.udflag = 1
self.nandbase = 0x79B0000
self.bcraddr = 0x183f000
self.secureboot = 0xFC4B8000 + 0x6080
self.pbl = [0xFC010000, 0x18000]
self.qfprom = [0x58000, 0x6000]
self.memtbl = [0x200000, 0x24000]
elif chipset == 11:
self.name = "MDM9x5X"
self.loader = "NPRG9x55p.bin"
self.eloader = "ENPRG9x55p.bin"
self.msmid = [0x0320, 0x03e0, 0x03a0]
self.ctrl_type = 0
self.udflag = 1
self.nandbase = 0x79B0000
self.bcraddr = 0x183F000
self.secureboot = 0x000a01d0
self.pbl = [0x100000, 0x18000]
self.qfprom = [0x000A0000, 0x6000]
self.memtbl = [0x200000, 0x24000]
elif chipset == 12:
self.name = "MDM9x07"
self.loader = "NPRG9x07p.bin"
self.eloader = "ENPRG9x07p.bin"
self.msmid = [0x0480, 0x4a0]
self.ctrl_type = 0
self.udflag = 1
self.nandbase = 0x79B0000
self.bcraddr = 0x183F000
self.secureboot = 0x000a01d0
self.pbl = [0x100000, 0x18000]
self.qfprom = [0x000A0000, 0x6000]
self.memtbl = [0x200000, 0x24000]
class nand_toshiba_ids(ctypes.LittleEndianStructure):
_fields_ = [
("mid", c_uint8, 8),
("did", c_uint8, 8),
("icn", c_uint8, 2),
("bpc", c_uint8, 2),
("rsvd0", c_uint8, 4),
("page_size", c_uint8, 2),
("spare_size", c_uint8, 2),
("block_size", c_uint8, 2),
("org", c_uint8, 1),
("rsvd1", c_uint8, 1),
("rsvd2", c_uint8, 8),
]
class nand_toshiba_id_t(ctypes.Union):
_anonymous_ = ("bit",)
_fields_ = [
("bit", nand_toshiba_ids),
("asDword", ctypes.c_uint32)
]
class nand_samsung_ids(ctypes.LittleEndianStructure):
_fields_ = [
("mid", c_uint8, 8),
("did", c_uint8, 8),
("icn", c_uint8, 2),
("bpc", c_uint8, 2),
("nspp", c_uint8, 2),
("ip", c_uint8, 1),
("cp", c_uint8, 1),
("page_size", c_uint8, 2),
("spare_size", c_uint8, 2),
("sam0", c_uint8, 1),
("block_size", c_uint8, 2),
("org", c_uint8, 1),
("sam1", c_uint8, 1),
("ecc", c_uint8, 2),
("plane", c_uint8, 2),
("plane_size", c_uint8, 3),
("rsvd", c_uint8, 1),
]
class nand_samsung_id_t(ctypes.Union):
_anonymous_ = ("bit",)
_fields_ = [
("bit", nand_toshiba_ids),
("asDword", ctypes.c_uint32)
]
class NandDevice:
# NAND_DEVn_CFG0 bits
DISABLE_STATUS_AFTER_WRITE = 4
CW_PER_PAGE = 6
UD_SIZE_BYTES = 9
ECC_PARITY_SIZE_BYTES_RS = 19
SPARE_SIZE_BYTES = 23
NUM_ADDR_CYCLES = 27
STATUS_BFR_READ = 30
SET_RD_MODE_AFTER_STATUS = 31
# NAND_DEV1_CFG0 bits
DEV0_CFG1_ECC_DISABLE = 0
WIDE_FLASH = 1
NAND_RECOVERY_CYCLES = 2
CS_ACTIVE_BSY = 5
BAD_BLOCK_BYTE_NUM = 6
BAD_BLOCK_IN_SPARE_AREA = 16
WR_RD_BSY_GAP = 17
ENABLE_BCH_ECC = 27
ECC_ENCODER_CGC_EN = 23
ECC_DECODER_CGC_EN = 24
DISABLE_ECC_RESET_AFTER_OPDONE = 25
ENABLE_NEW_ECC = 27
ECC_MODE_DEV1 = 28 # 28:29
# NAND_DEV0_ECC_CFG bits
ECC_CFG_ECC_DISABLE = 0
ECC_SW_RESET = 1
ECC_MODE = 4
ECC_PARITY_SIZE_BYTES_BCH = 8
ECC_NUM_DATA_BYTES = 16
ECC_ENC_CLK_SHUTDOWN = 28
ECC_DEC_CLK_SHUTDOWN = 29
ECC_FORCE_CLK_OPEN = 30
# NAND_DEV_CMD1 bits
READ_ADDR = 0
# NAND_DEV_CMD_VLD bits
READ_START_VLD = 0
READ_STOP_VLD = 1
WRITE_START_VLD = 2
ERASE_START_VLD = 3
SEQ_READ_START_VLD = 4
NAND_CMD_PARAM = 0xec
ECC_BCH_4BIT = 2
def __init__(self, settings):
self.settings = settings
if settings.ctrl_type == 0:
# device commands
self.NAND_CMD_SOFT_RESET = 0x01
self.NAND_CMD_PAGE_READ = 0x32
self.NAND_CMD_PAGE_READ_ECC = 0x33
self.NAND_CMD_PAGE_READ_ALL = 0x34
self.NAND_CMD_SEQ_PAGE_READ = 0x15
self.NAND_CMD_PRG_PAGE = 0x36
self.NAND_CMD_PRG_PAGE_ECC = 0x37
self.NAND_CMD_PRG_PAGE_ALL = 0x39
self.NAND_CMD_BLOCK_ERASE = 0x3A
self.NAND_CMD_FETCH_ID = 0x0B
self.NAND_CMD_STATUS = 0x0C
self.NAND_CMD_RESET = 0x0D
# addr offsets
self.NAND_FLASH_CMD = settings.nandbase + 0
self.NAND_ADDR0 = settings.nandbase + 4
self.NAND_ADDR1 = settings.nandbase + 8
self.NAND_FLASH_CHIP_SELECT = settings.nandbase + 0xc
self.NAND_EXEC_CMD = settings.nandbase + 0x10
self.NAND_FLASH_STATUS = settings.nandbase + 0x14
self.NAND_BUFFER_STATUS = settings.nandbase + 0x18
self.NAND_DEV0_CFG0 = settings.nandbase + 0x20
self.NAND_DEV0_CFG1 = settings.nandbase + 0x24
self.NAND_DEV0_ECC_CFG = settings.nandbase + 0x28
self.NAND_DEV1_ECC_CFG = settings.nandbase + 0x2C
self.NAND_DEV1_CFG0 = settings.nandbase + 0x30
self.NAND_DEV1_CFG1 = settings.nandbase + 0x34
self.NAND_SFLASHC_CMD = settings.nandbase + 0x38
self.NAND_SFLASHC_EXEC = settings.nandbase + 0x3C
self.NAND_READ_ID = settings.nandbase + 0x40
self.NAND_READ_STATUS = settings.nandbase + 0x44
self.NAND_CONFIG_DATA = settings.nandbase + 0x50
self.NAND_CONFIG = settings.nandbase + 0x54
self.NAND_CONFIG_MODE = settings.nandbase + 0x58
self.NAND_CONFIG_STATUS = settings.nandbase + 0x60
self.NAND_DEV_CMD0 = settings.nandbase + 0xA0
self.NAND_DEV_CMD1 = settings.nandbase + 0xA4
self.NAND_DEV_CMD2 = settings.nandbase + 0xA8
self.NAND_DEV_CMD_VLD = settings.nandbase + 0xAC
self.SFLASHC_BURST_CFG = settings.nandbase + 0xe0
self.NAND_EBI2_ECC_BUF_CFG = settings.nandbase + 0xF0
self.NAND_HW_INFO = settings.nandbase + 0xFC
self.NAND_FLASH_BUFFER = settings.nandbase + 0x100
elif settings.ctrl_type == 1:
self.NAND_CMD_SOFT_RESET = 0x07
self.NAND_CMD_PAGE_READ = 0x01
self.NAND_CMD_PAGE_READ_ALL = 0xffff
self.NAND_CMD_PRG_PAGE = 0x03
self.NAND_CMD_PRG_PAGE_ALL = 0xffff
self.NAND_CMD_BLOCK_ERASE = 0x04
self.NAND_CMD_FETCH_ID = 0x05
self.NAND_FLASH_CMD = settings.nandbase + 0x304
self.NAND_ADDR0 = settings.nandbase + 0x300
self.NAND_ADDR1 = settings.nandbase + 0xffff
self.NAND_FLASH_CHIP_SELECT = settings.nandbase + 0x30c
self.NAND_EXEC_CMD = settings.nandbase + 0xffff
self.NAND_BUFFER_STATUS = settings.nandbase + 0xffff
self.NAND_FLASH_STATUS = settings.nandbase + 0x308
self.NAND_DEV0_CFG0 = settings.nandbase + 0xffff
self.NAND_DEV0_CFG1 = settings.nandbase + 0x328
self.NAND_DEV0_ECC_CFG = settings.nandbase + 0xffff
self.NAND_READ_ID = settings.nandbase + 0x320
self.NAND_FLASH_BUFFER = settings.nandbase + 0x0
self.PAGE_ACC = 1 << 4
self.LAST_PAGE = 1 << 5
self.CW_PER_PAGE = 6
self.ECC_CFG_ECC_DISABLE = 0
self.flashinfo = None
def gettbl(self, nandid, tbl):
flashinfo = {}
tid = nand_toshiba_id_t()
tid.asDword = nandid
small_slc = False
# did,slc_small_device,device_width,density_mbits
if tid.did in tbl:
fdev = tbl[tid.did]
small_slc = fdev[0]
slc_device_width = fdev[1]
density_mbits = fdev[2]
else:
return None
if small_slc:
flashinfo["page_size"] = 512
flashinfo["feature_flags1_ecc"] = 2
flashinfo["block_size_kbytes"] = 16
flashinfo["param_per_block"] = 32
flashinfo["spare_size"] = 16
flashinfo["otp_sequence_cfg"] = "FLASH_NAND_OTP_SEQUENCE_CFG6"
flashinfo["dev_width"] = slc_device_width
else:
if tid.org == 0:
flashinfo["dev_width"] = 8
else:
flashinfo["dev_width"] = 16
if tid.spare_size == 0 or tid.spare_size == 1:
flashinfo["feature_flags1_ecc"] = 1
elif tid.spare_size == 2:
flashinfo["feature_flags1_ecc"] = 8
else:
flashinfo["feature_flags1_ecc"] = 0
flashinfo["page_size"] = 1024 << tid.page_size
flashinfo["page_size_kb"] = flashinfo["page_size"] >> 10
flashinfo["block_size_kb"] = 64 << tid.block_size
flashinfo["pages_per_block"] = flashinfo["block_size_kb"] // flashinfo["page_size_kb"]
flashinfo["spare_size"] = (8 << tid.spare_size) * (flashinfo["page_size"] // 512)
if flashinfo["page_size"] == 2048 or flashinfo["page_size"] == 4096:
flashinfo["otp_sequence_cfg"] = "FLASH_NAND_OTP_SEQUENCE_CFG2"
else:
flashinfo["otp_sequence_cfg"] = "FLASH_NAND_OTP_SEQUENCE_UNKNOWN"
flashinfo["block_count"] = (1024 // 8 * density_mbits) // flashinfo["block_size_kb"]
if flashinfo["page_size"] == 2048 and flashinfo["feature_flags1_ecc"] > 0:
flashinfo["bad_block_info_byte_offset"] = 2048
flashinfo["udata_max"] = 16
flashinfo["max_corrected_udata_bytes"] = 16
flashinfo["bad_block_info_byte_length"] = 1 if flashinfo["dev_width"] == 8 else 2
elif flashinfo["page_size"] == 4096 and flashinfo["feature_flags1_ecc"] > 0:
flashinfo["bad_block_info_byte_offset"] = 4096
flashinfo["udata_max"] = 32
flashinfo["max_corrected_udata_bytes"] = 32
flashinfo["bad_block_info_byte_length"] = 1 if flashinfo["dev_width"] == 8 else 2
self.settings.PAGESIZE = flashinfo["page_size"]
self.settings.BLOCKSIZE = flashinfo["block_size_kb"] * 1024
if flashinfo["dev_width"] == 8:
self.settings.IsWideFlash = 0
else:
self.settings.IsWideFlash = 1
self.settings.MAXBLOCK = flashinfo["block_count"]
self.settings.BAD_BLOCK_IN_SPARE_AREA = flashinfo["bad_block_info_byte_offset"]
return flashinfo
def toshiba_config(self, nandid):
flashinfo = self.gettbl(nandid, toshiba_tbl)
self.flashinfo = flashinfo
if (nandid >> 8) & 0xFF == 0xac:
self.settings.OOBSIZE = 256
self.settings.PAGESIZE = 4096
self.settings.MAXBLOCK = 2048
# 8Bit_HW_ECC
elif (nandid >> 8) & 0xFF == 0xaa:
self.settings.OOBSIZE = 128
self.settings.PAGESIZE = 2048
self.settings.MAXBLOCK = 2048
# 8Bit_HW_ECC
elif (nandid >> 8) & 0xFF == 0xa1:
self.settings.OOBSIZE = 128
self.settings.PAGESIZE = 2048
self.settings.MAXBLOCK = 1024
# 8Bit_HW_ECC
self.settings.CW_PER_PAGE = (self.settings.PAGESIZE >> 9) - 1
self.settings.SPARE_SIZE_BYTES = 0
def samsung_config(self, nandid):
flashinfo = self.gettbl(nandid, samsung_tbl)
self.flashinfo = flashinfo
# self.settings.SPARE_SIZE_BYTES = flashinfo["spare_size"]
self.settings.CW_PER_PAGE = (self.settings.PAGESIZE >> 9) - 1
self.settings.SPARE_SIZE_BYTES = 0
def generic_config(self, nandid, chipsize):
devcfg = (nandid >> 24) & 0xff
self.settings.PAGESIZE = 1024 << (devcfg & 0x3)
self.settings.BLOCKSIZE = 64 << ((devcfg >> 4) & 0x3)
if chipsize != 0:
self.settings.MAXBLOCK = chipsize * 1024 // self.settings.BLOCKSIZE
else:
self.settings.MAXBLOCK = 0x800
self.settings.CW_PER_PAGE = (self.settings.PAGESIZE >> 9) - 1
def nand_setup(self, nandid):
"""
qcommand -p%qdl% -k11 -c "m 79b0020 295409c0" #NAND_DEV0_CFG0
qcommand -p%qdl% -k11 -c "m 79b0024 08065d5d" #NAND_DEV0_CFG1
qcommand -p%qdl% -k11 -c "m 79b0028 42040d10" #NAND_DEV0_ECC_CFG
qcommand -p%qdl% -k11 -c "m 79b00f0 00000203" NAND_EBI2_ECC_BUF_CFG
"""
fid = (nandid >> 8) & 0xff
pid = nandid & 0xff
self.settings.flash_mfr = ""
for info in nand_manuf_ids:
if info[0] == pid:
self.settings.flash_mfr = info[1]
break
chipsize = 0
for info in nand_ids:
if info[1] == fid:
chipsize = info[2]
self.settings.flash_descr = info[0]
break
self.settings.cfg1_enable_bch_ecc = 1
self.settings.IsWideFlash = 0
self.settings.SPARE_SIZE_BYTES = 0
self.settings.OOBSIZE = 0
self.settings.ECC_PARITY_SIZE_BYTES = 0
self.settings.BAD_BLOCK_BYTE_NUM = 0
self.settings.ecc_bit = 4
if pid == 0x98: # Toshiba
self.toshiba_config(nandid)
if nandid == 0x2690AC98:
self.settings.ecc_bit = 8
elif pid == 0xEC: # Samsung
self.samsung_config(nandid)
elif pid == 0x2C:
self.generic_config(nandid, chipsize)
if nandid == 0x2690AC2C: # MT29AZ5A3CHHWD
self.settings.ecc_bit = 8
elif pid == 0x01:
self.generic_config(nandid, chipsize)
if nandid == 0x1590AC01: # jsfc 4G
self.settings.OOBSIZE = 128
self.settings.PAGESIZE = 2048
self.settings.SPARE_SIZE_BYTES = 4
else:
self.generic_config(nandid, chipsize)
if nandid in supported_flash:
nd = supported_flash[nandid]
# density = nd[]
# width
chipsize = nd[0] // 1024
self.settings.IsWideFlash = nd[1]
self.settings.PAGESIZE = nd[2]
self.settings.BLOCKSIZE = nd[3]
self.settings.OOBSIZE = nd[4]
self.settings.IsOneNand = nd[5]
if chipsize != 0:
self.settings.MAXBLOCK = chipsize * 1024 // self.settings.BLOCKSIZE
else:
self.settings.MAXBLOCK = 0x800
self.settings.sectorsize = 512
self.settings.sectors_per_page = self.settings.PAGESIZE // self.settings.sectorsize
if self.settings.ecc_bit == 4:
self.settings.ECC_MODE = 0 # 0=4 bit ECC error
elif self.settings.ecc_bit == 8:
self.settings.ECC_MODE = 1 # 1=8 bit ECC error
elif self.settings.ecc_bit == 16:
self.settings.ECC_MODE = 2 # 2=16 bit ECC error
if self.settings.ecc_size == 0:
if self.settings.ecc_bit == 4:
self.settings.ecc_size = 1
elif self.settings.ecc_bit == 8 or self.settings.ecc_bit == 16:
self.settings.ecc_size = 2
if self.settings.OOBSIZE == 0:
self.settings.OOBSIZE = (8 << self.settings.ecc_size) * (self.settings.CW_PER_PAGE + 1)
if 256 >= self.settings.OOBSIZE > 128:
self.settings.OOBSIZE = 256
if self.settings.SPARE_SIZE_BYTES == 0:
# HAM1
if self.settings.ECC_MODE == 0:
self.settings.SPARE_SIZE_BYTES = 4
else:
self.settings.SPARE_SIZE_BYTES = 2
if self.settings.cfg1_enable_bch_ecc:
hw_ecc_bytes = 0
self.settings.UD_SIZE_BYTES = self.settings.SPARE_SIZE_BYTES + self.settings.sectorsize # 516 or 517
if self.settings.SPARE_SIZE_BYTES == 2:
self.settings.UD_SIZE_BYTES += 2
if self.settings.IsWideFlash:
self.settings.UD_SIZE_BYTES += 1
else:
hw_ecc_bytes = 10
self.settings.UD_SIZE_BYTES = 512
if self.settings.ECC_PARITY_SIZE_BYTES == 0:
self.settings.ECC_PARITY_SIZE_BYTES = 3 # HAM1
if self.settings.ecc_bit == 4: # BCH4
self.settings.ECC_PARITY_SIZE_BYTES = 7
elif self.settings.ecc_bit == 8: # BCH8
self.settings.ECC_PARITY_SIZE_BYTES = 13
elif self.settings.ecc_bit == 16: # BCH16
self.settings.ECC_PARITY_SIZE_BYTES = 26
linuxcwsize = 528
if self.settings.cfg1_enable_bch_ecc and self.settings.ecc_bit == 8:
linuxcwsize = 532
if nandid == 0x1590AC2C: # fixme
linuxcwsize = 532
if self.settings.BAD_BLOCK_BYTE_NUM == 0:
self.settings.BAD_BLOCK_BYTE_NUM = (
self.settings.PAGESIZE - (linuxcwsize * (self.settings.sectors_per_page - 1)) + 1)
# UD_SIZE_BYTES must be 512, 516 or 517. If ECC-Protection 516 for x16Bit-Nand and 517 for x8-bit Nand
cfg0 = 0 << self.SET_RD_MODE_AFTER_STATUS \
| 0 << self.STATUS_BFR_READ \
| 5 << self.NUM_ADDR_CYCLES \
| self.settings.SPARE_SIZE_BYTES << self.SPARE_SIZE_BYTES \
| hw_ecc_bytes << self.ECC_PARITY_SIZE_BYTES_RS \
| self.settings.UD_SIZE_BYTES << self.UD_SIZE_BYTES \
| self.settings.CW_PER_PAGE << self.CW_PER_PAGE \
| 0 << self.DISABLE_STATUS_AFTER_WRITE
bad_block_byte = self.settings.BAD_BLOCK_BYTE_NUM
wide_bus = self.settings.IsWideFlash
bch_disabled = self.settings.args_disable_ecc # option in gui, implemented
cfg1 = 0 << self.ECC_MODE_DEV1 \
| 1 << self.ENABLE_NEW_ECC \
| 0 << self.DISABLE_ECC_RESET_AFTER_OPDONE \
| 0 << self.ECC_DECODER_CGC_EN \
| 0 << self.ECC_ENCODER_CGC_EN \
| 2 << self.WR_RD_BSY_GAP \
| 0 << self.BAD_BLOCK_IN_SPARE_AREA \
| bad_block_byte << self.BAD_BLOCK_BYTE_NUM \
| 0 << self.CS_ACTIVE_BSY \
| 7 << self.NAND_RECOVERY_CYCLES \
| wide_bus << self.WIDE_FLASH \
| bch_disabled << self.ENABLE_BCH_ECC
"""
cfg0_raw = (self.settings.CW_PER_PAGE-1) << CW_PER_PAGE \
| self.settings.UD_SIZE_BYTES << UD_SIZE_BYTES \
| 5 << NUM_ADDR_CYCLES \
| 0 << SPARE_SIZE_BYTES
cfg1_raw = 7 << NAND_RECOVERY_CYCLES \
| 0 << CS_ACTIVE_BSY \
| 17 << BAD_BLOCK_BYTE_NUM \
| 1 << BAD_BLOCK_IN_SPARE_AREA \
| 2 << WR_RD_BSY_GAP \
| wide_bus << WIDE_FLASH \
| 1 << DEV0_CFG1_ECC_DISABLE
"""
ecc_bch_cfg = 1 << self.ECC_FORCE_CLK_OPEN \
| 0 << self.ECC_DEC_CLK_SHUTDOWN \
| 0 << self.ECC_ENC_CLK_SHUTDOWN \
| self.settings.UD_SIZE_BYTES << self.ECC_NUM_DATA_BYTES \
| self.settings.ECC_PARITY_SIZE_BYTES << self.ECC_PARITY_SIZE_BYTES_BCH \
| self.settings.ECC_MODE << self.ECC_MODE \
| 0 << self.ECC_SW_RESET \
| bch_disabled << self.ECC_CFG_ECC_DISABLE
if self.settings.UD_SIZE_BYTES == 516:
ecc_buf_cfg = 0x203
elif self.settings.UD_SIZE_BYTES == 517:
ecc_buf_cfg = 0x204
else:
ecc_buf_cfg = 0x1FF
return cfg0, cfg1, ecc_buf_cfg, ecc_bch_cfg
class nandregs:
def __init__(self, parent):
self.register_mapping = {
}
self.reverse_mapping = {}
self.create_reverse_mapping()
self.parent = parent
def __getattribute__(self, name):
if name in ("register_mapping", "parent"):
return super(nandregs, self).__getattribute__(name)
if name in self.register_mapping:
return self.parent.mempeek(self.register_mapping[name])
return super(nandregs, self).__getattribute__(name)
def __setattr__(self, name, value):
if name in ("register_mapping", "parent"):
super(nandregs, self).__setattr__(name, value)
if name in self.register_mapping:
self.parent.mempoke(self.register_mapping[name], value)
else:
super(nandregs, self).__setattr__(name, value)
def read(self, register):
if isinstance(register, str):
register = self.register_mapping.get(register.lower(), None)
return self.parent.mempeek(register)
def write(self, register, value):
if isinstance(register, str):
register = self.register_mapping.get(register.lower(), None)
return self.parent.mempoke(register, value)
def save(self):
reg_dict = {}
for reg in self.register_mapping:
reg_v = self.read(reg)
reg_dict[reg] = reg_v
return reg_dict
def restore(self, value=None):
if value is None:
value = {}
for reg in self.register_mapping:
reg_v = value[reg]
self.write(reg, reg_v)
def create_reverse_mapping(self):
self.reverse_mapping = {v: k for k, v in self.register_mapping.items()}

View file

@ -2,22 +2,22 @@ import struct
def get_n(x):
return int(x[6:8]+x[4:6]+x[2:4]+x[0:2], 16)
return int(x[6:8] + x[4:6] + x[2:4] + x[0:2], 16)
def parse_pt(data):
va = 0
entries = []
while va < len(data):
entry = struct.unpack("<L", data[va:va+4])[0]
entry = struct.unpack("<L", data[va:va + 4])[0]
f = get_fld(entry)
if f is None:
va += 4
continue
entries.append((int(va/4) << 20,f))
print("%08x %s" % ((int(va/4) << 20), str(f)))
entries.append((int(va / 4) << 20, f))
print("%08x %s" % ((int(va / 4) << 20), str(f)))
va += 4
return entries
@ -26,13 +26,13 @@ def parse_pt(data):
def parse_spt(data, base):
va = 0
while va < 0x400:
entry = struct.unpack("<L", data[va:va+4])[0]
entry = struct.unpack("<L", data[va:va + 4])[0]
f = get_sld(entry)
if (f!='UNSUPPORTED' and f.apx==0 and f.ap==3 and f.nx==0):
if f != 'UNSUPPORTED' and f.apx == 0 and f.ap == 3 and f.nx == 0:
print("%08x %s - WX !!" % (base + (int(va / 4) << 12), f))
else:
print("%08x %s" % (base+(int(va/4) << 12), f))
print("%08x %s" % (base + (int(va / 4) << 12), f))
va += 4
@ -49,6 +49,7 @@ def get_fld(fld):
if s == 3:
return reserved_desc(fld)
return None
def get_sld(sld):
@ -66,6 +67,9 @@ class descriptor(object):
def __init__(self, fld):
pass
def get_name(self):
pass
def __repr__(self):
s = "%8s " % self.get_name()
for attr, value in self.__dict__.items():
@ -103,7 +107,6 @@ class pt_desc(fld):
self.ns = (desc >> 3) & 1
self.sbz2 = (desc >> 2) & 1
def get_name(self):
return "PT"
@ -124,7 +127,6 @@ class section_desc(fld):
self.c = (desc >> 3) & 1
self.b = (desc >> 2) & 1
def get_name(self):
return "SECTION"
@ -147,7 +149,6 @@ class sld_lp(sld):
self.c = (desc >> 3) & 1
self.b = (desc >> 2) & 1
def get_name(self):
return "LARGEPAGE"
@ -166,6 +167,5 @@ class sld_xsp(sld):
self.b = (desc >> 2) & 1
self.nx = desc & 1
def get_name(self):
return "XSMALLPAGE"

View file

@ -6,8 +6,8 @@ https://armv8-ref.codingbelief.com/en/chapter_d4/d42_7_the_algorithm_for_finding
"""
def get_level_index(va, level):
def get_level_index(va, level):
if level == 1:
return (va >> 30) & 0x3F
@ -22,7 +22,7 @@ def get_level_index(va, level):
def get_level_bits(level, tnsz):
if level == 1:
return 37-tnsz+26+1-30
return 37 - tnsz + 26 + 1 - 30
if level == 2:
return 9
@ -34,32 +34,34 @@ def get_level_bits(level, tnsz):
def get_level_size(tnsz, level):
return 2**get_level_bits(level, tnsz)*8
return 2 ** get_level_bits(level, tnsz) * 8
def get_va_for_level(va, index, level):
if level == 1:
return va + (index<<30)
return va + (index << 30)
if level == 2:
return va + (index<<21)
return va + (index << 21)
if level == 3:
return va + (index<<12)
return va + (index << 12)
return va
def parse_pt(data, base, tnsz, level=1):
i = 0
entries = []
while i < min(len(data), get_level_size(tnsz, level)):
entry = struct.unpack("<Q", data[i:i+8])[0]
entry = struct.unpack("<Q", data[i:i + 8])[0]
f = get_fld(entry, level)
if f is None:
i += 8
continue
va = get_va_for_level(base, int(i/8), level)
if (f!='UNSUPPORTED' and f.apx==0 and f.ap==3 and f.xn==0):
va = get_va_for_level(base, int(i / 8), level)
if (f != 'UNSUPPORTED' and f.apx == 0 and f.ap == 3 and f.xn == 0):
print("%016x %s - WX !!" % (va, f))
else:
print("%016x %s" % (va, f))
@ -83,9 +85,12 @@ def get_fld(fld, level):
if s == 3:
return table_entry4k(fld, level)
return None
class descriptor(object):
def get_name(self):
pass
class descriptor(object):
def __repr__(self):
s = "%8s " % self.get_name()
for attr, value in self.__dict__.items():
@ -108,12 +113,12 @@ class entry(fld):
self.apx = (desc >> 61) & 3
self.xn = (desc >> 60) & 1
self.pxn = (desc >> 59) & 1
self.attrindex = (desc>>2) & 7
self.ns = (desc>>5) & 1
self.ap = (desc>>6) & 3
self.sh = (desc>>8) & 3
self.af = (desc>>10) & 1
self.nG = (desc>>11) & 1
self.attrindex = (desc >> 2) & 7
self.ns = (desc >> 5) & 1
self.ap = (desc >> 6) & 3
self.sh = (desc >> 8) & 3
self.af = (desc >> 10) & 1
self.nG = (desc >> 11) & 1
class entry4k(entry):
@ -144,6 +149,5 @@ class table_entry4k(entry4k):
def __init__(self, desc, level):
entry4k.__init__(self, desc, level)
def get_name(self):
return "TABLE4"

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

414
Library/streaming_client.py Normal file
View file

@ -0,0 +1,414 @@
import sys
import os
from Library.streaming import QualcommStreaming
from binascii import hexlify, unhexlify
from struct import unpack, pack
from Library.utils import do_tcp_server
class streaming_client:
def __init__(self, arguments, cdc, sahara, LOGGER, printer):
self.LOGGER = LOGGER
self.cdc = cdc
self.sahara = sahara
self.arguments = arguments
self.streaming = QualcommStreaming(cdc, sahara)
self.printer = printer
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
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

View file

@ -1,37 +1,33 @@
import usb.core # pyusb
import usb.core # pyusb
import usb.util
import struct
from enum import Enum
from binascii import hexlify,unhexlify
import usb.core # pyusb
import usb.core # pyusb
import usb.util
import time
import inspect
import platform
import logging
from Library.utils import *
USB_DIR_OUT=0 # to device
USB_DIR_IN=0x80 # to host
USB_DIR_OUT = 0 # to device
USB_DIR_IN = 0x80 # to host
# USB types, the second of three bRequestType fields
USB_TYPE_MASK=(0x03 << 5)
USB_TYPE_STANDARD=(0x00 << 5)
USB_TYPE_CLASS=(0x01 << 5)
USB_TYPE_VENDOR=(0x02 << 5)
USB_TYPE_RESERVED=(0x03 << 5)
USB_TYPE_MASK = (0x03 << 5)
USB_TYPE_STANDARD = (0x00 << 5)
USB_TYPE_CLASS = (0x01 << 5)
USB_TYPE_VENDOR = (0x02 << 5)
USB_TYPE_RESERVED = (0x03 << 5)
# USB recipients, the third of three bRequestType fields
USB_RECIP_MASK=0x1f
USB_RECIP_DEVICE=0x00
USB_RECIP_INTERFACE=0x01
USB_RECIP_ENDPOINT=0x02
USB_RECIP_OTHER=0x03
#From Wireless USB 1.0
USB_RECIP_PORT= 0x04
USB_RECIP_RPIPE=0x05
USB_RECIP_MASK = 0x1f
USB_RECIP_DEVICE = 0x00
USB_RECIP_INTERFACE = 0x01
USB_RECIP_ENDPOINT = 0x02
USB_RECIP_OTHER = 0x03
# From Wireless USB 1.0
USB_RECIP_PORT = 0x04
USB_RECIP_RPIPE = 0x05
tag=0
tag = 0
CDC_CMDS = {
"SEND_ENCAPSULATED_COMMAND": 0x00,
@ -42,34 +38,40 @@ CDC_CMDS = {
"SET_LINE_CODING": 0x20,
"GET_LINE_CODING": 0x21,
"SET_CONTROL_LINE_STATE": 0x22,
"SEND_BREAK": 0x23, # wValue is break time
"SEND_BREAK": 0x23, # wValue is break time
}
class usb_class():
def __init__(self,vid=0x05c6, pid=0x9008, interface=-1, devclass=-1, log=None):
self.vid=vid
self.pid=pid
self.interface=interface
self.connected=False
self.devclass=devclass
self.timeout=None
self.log=log
class usb_class:
def __init__(self, vidpid=None, interface=-1, devclass=-1, log=None):
self.vidpid = vidpid
self.interface = interface
self.connected = False
self.devclass = devclass
self.timeout = None
self.log = log
self.vid = None
self.pid = None
def getInterfaceCount(self):
self.device = usb.core.find(idVendor=self.vid, idProduct=self.pid)
if self.device is None:
self.log.debug("Couldn't detect the device. Is it connected ?")
return False
try:
self.device.set_configuration()
except:
pass
self.configuration = self.device.get_active_configuration()
self.log.debug(2, self.configuration)
return self.configuration.bNumInterfaces
if self.vid is not None:
self.device = usb.core.find(idVendor=self.vid, idProduct=self.pid)
if self.device is None:
self.log.debug("Couldn't detect the device. Is it connected ?")
return False
try:
self.device.set_configuration()
except:
pass
self.configuration = self.device.get_active_configuration()
self.log.debug(2, self.configuration)
return self.configuration.bNumInterfaces
else:
self.log.error("No device detected. Is it connected ?")
return 0
def setLineCoding(self, baudrate=None, parity=None,databits=None, stopbits=None):
def setLineCoding(self, baudrate=None, parity=None, databits=None, stopbits=None):
sbits = {1: 0, 1.5: 1, 2: 2}
dbits = {5, 6, 7, 8, 16}
pmodes = {0, 1, 2, 3, 4}
@ -82,7 +84,7 @@ class usb_class():
raise ValueError("Valid stopbits are " + valid)
self.stopbits = stopbits
else:
self.stopbits =0
self.stopbits = 0
if databits is not None:
if databits not in dbits:
@ -90,7 +92,7 @@ class usb_class():
raise ValueError("Valid databits are " + valid)
self.databits = databits
else:
self.databits=0
self.databits = 0
if parity is not None:
if parity not in pmodes:
@ -98,7 +100,7 @@ class usb_class():
raise ValueError("Valid parity modes are " + valid)
self.parity = parity
else:
self.parity=0
self.parity = 0
if baudrate is not None:
if baudrate not in brates:
@ -110,53 +112,61 @@ class usb_class():
self.baudrate = baudrate
linecode = [
self.baudrate & 0xff,
(self.baudrate >> 8) & 0xff,
(self.baudrate >> 16) & 0xff,
(self.baudrate >> 24) & 0xff,
sbits[self.stopbits],
self.parity,
self.databits]
self.baudrate & 0xff,
(self.baudrate >> 8) & 0xff,
(self.baudrate >> 16) & 0xff,
(self.baudrate >> 24) & 0xff,
sbits[self.stopbits],
self.parity,
self.databits]
txdir = 0 # 0:OUT, 1:IN
req_type = 1 # 0:std, 1:class, 2:vendor
recipient = 1 # 0:device, 1:interface, 2:endpoint, 3:other
txdir = 0 # 0:OUT, 1:IN
req_type = 1 # 0:std, 1:class, 2:vendor
recipient = 1 # 0:device, 1:interface, 2:endpoint, 3:other
req_type = (txdir << 7) + (req_type << 5) + recipient
data=bytearray(linecode)
data = bytearray(linecode)
wlen = self.device.ctrl_transfer(
req_type, CDC_CMDS["SET_LINE_CODING"],
data_or_wLength=data, wIndex=1)
req_type, CDC_CMDS["SET_LINE_CODING"],
data_or_wLength=data, wIndex=1)
self.log.debug("Linecoding set, {}b sent".format(wlen))
def connect(self, EP_IN=-1, EP_OUT=-1):
if self.connected==True:
if self.connected:
self.close()
self.connected=False
self.device = usb.core.find(idVendor=self.vid, idProduct=self.pid)
self.connected = False
for usbid in self.vidpid:
vid = usbid[0]
pid = usbid[1]
self.device = usb.core.find(idVendor=vid, idProduct=pid)
if self.device is not None:
self.vid = vid
self.pid = pid
break
if self.device is None:
self.log.debug("Couldn't detect the device. Is it connected ?")
return False
try:
self.device.set_configuration()
except:
pass
# try:
# self.device.set_configuration()
# except:
# pass
self.configuration = self.device.get_active_configuration()
if self.interface==-1:
for interfacenum in range(0,self.configuration.bNumInterfaces):
itf = usb.util.find_descriptor(self.configuration,bInterfaceNumber=interfacenum)
if self.devclass!=-1:
if itf.bInterfaceClass==self.devclass: #MassStorage
self.interface=interfacenum
if self.interface == -1:
for interfacenum in range(0, self.configuration.bNumInterfaces):
itf = usb.util.find_descriptor(self.configuration, bInterfaceNumber=interfacenum)
if self.devclass != -1:
if itf.bInterfaceClass == self.devclass: # MassStorage
self.interface = interfacenum
break
else:
self.interface=interfacenum
self.interface = interfacenum
break
self.log.debug(self.configuration)
if self.interface>self.configuration.bNumInterfaces:
if self.interface > self.configuration.bNumInterfaces:
print("Invalid interface, max number is %d" % self.configuration.bNumInterfaces)
return False
if self.interface!=-1:
if self.interface != -1:
itf = usb.util.find_descriptor(self.configuration, bInterfaceNumber=self.interface)
try:
if self.device.is_kernel_driver_active(self.interface):
@ -166,241 +176,225 @@ class usb_class():
self.log.debug("No kernel driver supported.")
usb.util.claim_interface(self.device, self.interface)
if EP_OUT==-1:
if EP_OUT == -1:
self.EP_OUT = usb.util.find_descriptor(itf,
# match the first OUT endpoint
custom_match= \
lambda e: \
usb.util.endpoint_direction(e.bEndpointAddress) == \
usb.util.ENDPOINT_OUT)
# match the first OUT endpoint
custom_match= \
lambda e: \
usb.util.endpoint_direction(e.bEndpointAddress) == \
usb.util.ENDPOINT_OUT)
else:
self.EP_OUT=EP_OUT
if EP_IN==-1:
self.EP_OUT = EP_OUT
if EP_IN == -1:
self.EP_IN = usb.util.find_descriptor(itf,
# match the first OUT endpoint
custom_match= \
lambda e: \
usb.util.endpoint_direction(e.bEndpointAddress) == \
usb.util.ENDPOINT_IN)
# match the first OUT endpoint
custom_match= \
lambda e: \
usb.util.endpoint_direction(e.bEndpointAddress) == \
usb.util.ENDPOINT_IN)
else:
self.EP_IN=EP_IN
self.EP_IN = EP_IN
self.connected=True
self.connected = True
return True
else:
print("Couldn't find MassStorage interface. Aborting.")
self.connected=False
self.connected = False
return False
def close(self):
if (self.connected==True):
def close(self,reset=False):
if self.connected:
usb.util.dispose_resources(self.device)
try:
if self.device.is_kernel_driver_active(self.interface):
self.device.attach_kernel_driver(self.interface)
if not self.device.is_kernel_driver_active(self.interface):
self.device.attach_kernel_driver(self.interface)
if reset:
self.device.reset()
except:
pass
def write(self,command,pktsize=64):
pos=0
if command==b'':
def write(self, command, pktsize=64):
if isinstance(command, str):
command = bytes(command, 'utf-8')
pos = 0
if command == b'':
self.device.write(self.EP_OUT, b'')
else:
i=0
while pos<len(command):
i = 0
while pos < len(command):
try:
self.device.write(self.EP_OUT,command[pos:pos+pktsize])
self.device.write(self.EP_OUT, command[pos:pos + pktsize])
pos += pktsize
except:
#print("Error while writing")
# print("Error while writing")
time.sleep(0.05)
i+=1
if i==5:
i += 1
if i == 5:
return False
pass
self.log.verify_data(bytearray(command),"TX:")
self.log.verify_data(bytearray(command), "TX:")
return True
def read(self,length=0x80000, timeout=None):
tmp=b''
self.log.debug(inspect.currentframe().f_back.f_code.co_name+":"+hex(length))
if timeout==None:
timeout=self.timeout
while (bytearray(tmp) == b''):
try:
tmp=self.device.read(self.EP_IN, length,timeout)
except usb.core.USBError as e:
try:
error=e.strerror.decode('utf-8')
except:
error=e.strerror
if "timed out" in error:
#if platform.system()=='Windows':
#time.sleep(0.05)
#print("Waiting...")
self.log.debug("Timed out")
self.log.debug(tmp)
return bytearray(tmp)
elif e.errno != None:
print(repr(e), type(e), e.errno)
self.connect()
raise(e)
else:
break
def read(self, length=0x80, timeout=None):
tmp = b''
self.log.debug(inspect.currentframe().f_back.f_code.co_name + ":" + hex(length))
if timeout is None:
timeout = self.timeout
while bytearray(tmp) == b'':
try:
tmp = self.device.read(self.EP_IN, length, timeout)
except usb.core.USBError as e:
error = str(e.strerror)
if "timed out" in error:
# if platform.system()=='Windows':
# time.sleep(0.05)
# print("Waiting...")
self.log.debug("Timed out")
self.log.debug(tmp)
return bytearray(tmp)
elif e.errno is not None:
print(repr(e), type(e), e.errno)
self.connect()
raise e
else:
break
self.log.verify_data(bytearray(tmp), "RX:")
return bytearray(tmp)
def ctrl_transfer(self,bmRequestType,bRequest,wValue,wIndex,data_or_wLength):
ret=self.device.ctrl_transfer(bmRequestType=bmRequestType,bRequest=bRequest,wValue=wValue,wIndex=wIndex,data_or_wLength=data_or_wLength)
def ctrl_transfer(self, bmRequestType, bRequest, wValue, wIndex, data_or_wLength):
ret = self.device.ctrl_transfer(bmRequestType=bmRequestType, bRequest=bRequest, wValue=wValue, wIndex=wIndex,
data_or_wLength=data_or_wLength)
return ret[0] | (ret[1] << 8)
class scsi_cmds(Enum):
SC_TEST_UNIT_READY=0x00,
SC_REQUEST_SENSE=0x03,
SC_FORMAT_UNIT=0x04,
SC_READ_6=0x08,
SC_WRITE_6=0x0a,
SC_INQUIRY=0x12,
SC_MODE_SELECT_6=0x15,
SC_RESERVE=0x16,
SC_RELEASE=0x17,
SC_MODE_SENSE_6=0x1a,
SC_START_STOP_UNIT=0x1b,
SC_SEND_DIAGNOSTIC=0x1d,
SC_PREVENT_ALLOW_MEDIUM_REMOVAL=0x1e,
SC_READ_FORMAT_CAPACITIES=0x23,
SC_READ_CAPACITY=0x25,
SC_WRITE_10=0x2a,
SC_VERIFY=0x2f,
SC_READ_10=0x28,
SC_SYNCHRONIZE_CACHE=0x35,
SC_READ_TOC=0x43,
SC_READ_HEADER=0x44,
SC_MODE_SELECT_10=0x55,
SC_MODE_SENSE_10=0x5a,
SC_READ_12=0xa8,
SC_WRITE_12=0xaa,
SC_PASCAL_MODE=0xff
SC_TEST_UNIT_READY = 0x00,
SC_REQUEST_SENSE = 0x03,
SC_FORMAT_UNIT = 0x04,
SC_READ_6 = 0x08,
SC_WRITE_6 = 0x0a,
SC_INQUIRY = 0x12,
SC_MODE_SELECT_6 = 0x15,
SC_RESERVE = 0x16,
SC_RELEASE = 0x17,
SC_MODE_SENSE_6 = 0x1a,
SC_START_STOP_UNIT = 0x1b,
SC_SEND_DIAGNOSTIC = 0x1d,
SC_PREVENT_ALLOW_MEDIUM_REMOVAL = 0x1e,
SC_READ_FORMAT_CAPACITIES = 0x23,
SC_READ_CAPACITY = 0x25,
SC_WRITE_10 = 0x2a,
SC_VERIFY = 0x2f,
SC_READ_10 = 0x28,
SC_SYNCHRONIZE_CACHE = 0x35,
SC_READ_TOC = 0x43,
SC_READ_HEADER = 0x44,
SC_MODE_SELECT_10 = 0x55,
SC_MODE_SENSE_10 = 0x5a,
SC_READ_12 = 0xa8,
SC_WRITE_12 = 0xaa,
SC_PASCAL_MODE = 0xff
command_block_wrapper=[
('dCBWSignature', '4s'),
('dCBWTag', 'I'),
('dCBWDataTransferLength', 'I'),
('bmCBWFlags', 'B'),
('bCBWLUN', 'B'),
('bCBWCBLength', 'B'),
('CBWCB', '16s'),
command_block_wrapper = [
('dCBWSignature', '4s'),
('dCBWTag', 'I'),
('dCBWDataTransferLength', 'I'),
('bmCBWFlags', 'B'),
('bCBWLUN', 'B'),
('bCBWCBLength', 'B'),
('CBWCB', '16s'),
]
command_block_wrapper_len=31
command_block_wrapper_len = 31
command_status_wrapper=[
('dCSWSignature', '4s'),
('dCSWTag', 'I'),
('dCSWDataResidue', 'I'),
('bCSWStatus', 'B')
command_status_wrapper = [
('dCSWSignature', '4s'),
('dCSWTag', 'I'),
('dCSWDataResidue', 'I'),
('bCSWStatus', 'B')
]
command_status_wrapper_len=13
command_status_wrapper_len = 13
def write_object(definition,*args):
'''
Unpacks a structure using the given data and definition.
'''
obj = {}
object_size = 0
data=b""
i=0
for (name, stype) in definition:
object_size += struct.calcsize(stype)
arg=args[i]
try:
data += struct.pack(stype, arg)
except Exception as e:
print("Error:"+str(e))
break
i+=1
obj['object_size'] = len(data)
obj['raw_data'] = data
return obj
class scsi():
'''
class scsi:
"""
FIHTDC, PCtool
'''
SC_READ_NV=0xf0
SC_SWITCH_STATUS=0xf1
SC_SWITCH_PORT=0xf2
SC_MODEM_STATUS=0xf4
SC_SHOW_PORT=0xf5
SC_MODEM_DISCONNECT=0xf6
SC_MODEM_CONNECT=0xf7
SC_DIAG_RUT=0xf8
SC_READ_BATTERY=0xf9
SC_READ_IMAGE=0xfa
SC_ENABLE_ALL_PORT=0xfd
SC_MASS_STORGE=0xfe
SC_ENTER_DOWNLOADMODE=0xff
SC_ENTER_FTMMODE=0xe0
SC_SWITCH_ROOT=0xe1
'''
"""
SC_READ_NV = 0xf0
SC_SWITCH_STATUS = 0xf1
SC_SWITCH_PORT = 0xf2
SC_MODEM_STATUS = 0xf4
SC_SHOW_PORT = 0xf5
SC_MODEM_DISCONNECT = 0xf6
SC_MODEM_CONNECT = 0xf7
SC_DIAG_RUT = 0xf8
SC_READ_BATTERY = 0xf9
SC_READ_IMAGE = 0xfa
SC_ENABLE_ALL_PORT = 0xfd
SC_MASS_STORGE = 0xfe
SC_ENTER_DOWNLOADMODE = 0xff
SC_ENTER_FTMMODE = 0xe0
SC_SWITCH_ROOT = 0xe1
"""
//Div2-5-3-Peripheral-LL-ADB_ROOT-00+/* } FIHTDC, PCtool */
//StevenCPHuang 2011/08/12 porting base on 1050 --
//StevenCPHuang_20110820,add Moto's mode switch cmd to support PID switch function ++
'''
SC_MODE_SWITCH=0xD6
#/StevenCPHuang_20110820,add Moto's mode switch cmd to support PID switch function --
"""
SC_MODE_SWITCH = 0xD6
def __init__(self,vid,pid,interface=-1):
self.vid=vid
self.pid=pid
self.interface=interface
self.Debug=False
self.usb=None
# /StevenCPHuang_20110820,add Moto's mode switch cmd to support PID switch function --
def __init__(self, vid, pid, interface=-1):
self.vid = vid
self.pid = pid
self.interface = interface
self.Debug = False
self.usb = None
def connect(self):
self.usb = usb_class(vid=self.vid, pid=self.pid, interface=self.interface, devclass=8)
self.usb = usb_class(vidpid=[self.vid, self.pid], interface=self.interface, devclass=8)
if self.usb.connect():
return True
return False
#htcadb = "55534243123456780002000080000616687463800100000000000000000000"; // Len 0x6, Command 0x16, "HTC" 01 = Enable, 02 = Disable
def send_mass_storage_command(self,lun, cdb, direction, data_length):
# htcadb = "55534243123456780002000080000616687463800100000000000000000000"; // Len 0x6, Command 0x16, "HTC" 01 = Enable, 02 = Disable
def send_mass_storage_command(self, lun, cdb, direction, data_length):
global tag
cmd=cdb[0]
if cmd>=0 and cmd<0x20:
cdb_len=6
elif cmd>=0x20 and cmd<0x60:
cdb_len=10
elif cmd>=0x60 and cmd<0x80:
cdb_len=0
elif cmd>=0x80 and cmd<0xA0:
cdb_len=16
elif cmd>=0xA0 and cmd<0xC0:
cdb_len=12
cmd = cdb[0]
if 0 <= cmd < 0x20:
cdb_len = 6
elif 0x20 <= cmd < 0x60:
cdb_len = 10
elif 0x60 <= cmd < 0x80:
cdb_len = 0
elif 0x80 <= cmd < 0xA0:
cdb_len = 16
elif 0xA0 <= cmd < 0xC0:
cdb_len = 12
else:
cdb_len=6
cdb_len = 6
if len(cdb)!=cdb_len:
if len(cdb) != cdb_len:
print("Error, cdb length doesn't fit allowed cbw packet length")
return 0
if (cdb_len==0) or (cdb_len > command_block_wrapper_len):
if (cdb_len == 0) or (cdb_len > command_block_wrapper_len):
print("Error, invalid data packet length, should be max of 31 bytes.")
return 0
else:
data=write_object(command_block_wrapper,b"USBC",tag, data_length, direction, lun, cdb_len,cdb)['raw_data']
data = write_object(command_block_wrapper, b"USBC", tag, data_length, direction, lun, cdb_len, cdb)[
'raw_data']
print(hexlify(data))
if len(data)!=31:
if len(data) != 31:
print("Error, invalid data packet length, should be 31 bytes, but length is %d" % len(data))
return 0
tag+=1
self.usb.write(data,31)
tag += 1
self.usb.write(data, 31)
return tag
def send_htc_adbenable(self):
#do_reserve from f_mass_storage.c
# do_reserve from f_mass_storage.c
print("Sending HTC adb enable command")
common_cmnd=b"\x16htc\x80\x01" #reserve_cmd + 'htc' + len + flag
common_cmnd = b"\x16htc\x80\x01" # reserve_cmd + 'htc' + len + flag
'''
Flag values:
1: Enable adb daemon from mass_storage
@ -408,35 +402,35 @@ class scsi():
3: cancel unmount BAP cdrom
4: cancel unmount HSM rom
'''
lun=0
datasize=common_cmnd[4]
timeout=5000
ret_tag=self.send_mass_storage_command(lun,common_cmnd,USB_DIR_IN,datasize)
ret_tag+=self.send_mass_storage_command(lun, common_cmnd, USB_DIR_IN, datasize)
if datasize>0:
data=self.usb.read(datasize,timeout)
print("DATA: "+hexlify(data))
lun = 0
datasize = common_cmnd[4]
timeout = 5000
ret_tag = self.send_mass_storage_command(lun, common_cmnd, USB_DIR_IN, datasize)
ret_tag += self.send_mass_storage_command(lun, common_cmnd, USB_DIR_IN, datasize)
if datasize > 0:
data = self.usb.read(datasize, timeout)
print("DATA: " + hexlify(data).decode('utf-8'))
print("Sent HTC adb enable command")
def send_htc_ums_adbenable(self):#HTC10
#ums_ctrlrequest from f_mass_storage.c
def send_htc_ums_adbenable(self): # HTC10
# ums_ctrlrequest from f_mass_storage.c
print("Sending HTC ums adb enable command")
bRequestType=USB_DIR_IN|USB_TYPE_VENDOR|USB_RECIP_DEVICE
bRequest=0xa0
wValue=1
bRequestType = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE
bRequest = 0xa0
wValue = 1
'''
wValue:
0: Disable adb daemon
1: Enable adb daemon
'''
wIndex=0
w_length=1
ret=self.usb.ctrl_transfer(bRequestType,bRequest,wValue,wIndex,w_length)
wIndex = 0
w_length = 1
ret = self.usb.ctrl_transfer(bRequestType, bRequest, wValue, wIndex, w_length)
print("Sent HTC ums adb enable command: %x" % ret)
def send_zte_adbenable(self): #zte blade
common_cmnd=b"\x86zte\x80\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" #reserve_cmd + 'zte' + len + flag
common_cmnd2=b"\x86zte\x80\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" # reserve_cmd + 'zte' + len + flag
def send_zte_adbenable(self): # zte blade
common_cmnd = b"\x86zte\x80\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" # reserve_cmd + 'zte' + len + flag
common_cmnd2 = b"\x86zte\x80\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" # reserve_cmd + 'zte' + len + flag
'''
Flag values:
0: disable adbd ---for 736T
@ -444,53 +438,55 @@ class scsi():
2: disable adbd ---for All except 736T
3: enable adbd ---for All except 736T
'''
lun=0
datasize=common_cmnd[4]
timeout=5000
ret_tag=self.send_mass_storage_command(lun,common_cmnd,USB_DIR_IN,datasize)
ret_tag+=self.send_mass_storage_command(lun, common_cmnd, USB_DIR_IN, datasize)
ret_tag=self.send_mass_storage_command(lun, common_cmnd2, USB_DIR_IN, datasize)
ret_tag+=self.send_mass_storage_command(lun, common_cmnd2, USB_DIR_IN, datasize)
if datasize>0:
data=self.usb.read(datasize,timeout)
print("DATA: "+hexlify(data))
lun = 0
datasize = common_cmnd[4]
timeout = 5000
ret_tag = self.send_mass_storage_command(lun, common_cmnd, USB_DIR_IN, datasize)
ret_tag += self.send_mass_storage_command(lun, common_cmnd, USB_DIR_IN, datasize)
ret_tag = self.send_mass_storage_command(lun, common_cmnd2, USB_DIR_IN, datasize)
ret_tag += self.send_mass_storage_command(lun, common_cmnd2, USB_DIR_IN, datasize)
if datasize > 0:
data = self.usb.read(datasize, timeout)
print("DATA: " + hexlify(data).decode('utf-8'))
print("Send HTC adb enable command")
def send_fih_adbenable(self): #motorola xt560, nokia 3.1, #f_mass_storage.c
def send_fih_adbenable(self): # motorola xt560, nokia 3.1, #f_mass_storage.c
if self.usb.connect():
print("Sending FIH adb enable command")
datasize=0x24
common_cmnd=bytes([self.SC_SWITCH_PORT])+b"FI1"+struct.pack("<H",datasize) #reserve_cmd + 'FI' + flag + len + none
datasize = 0x24
common_cmnd = bytes([self.SC_SWITCH_PORT]) + b"FI1" + struct.pack("<H",
datasize) # reserve_cmd + 'FI' + flag + len + none
'''
Flag values:
common_cmnd[3]->1: Enable adb daemon from mass_storage
common_cmnd[3]->0: Disable adb daemon from mass_storage
'''
lun=0
#datasize=common_cmnd[4]
timeout=5000
ret_tag=self.send_mass_storage_command(lun,common_cmnd,USB_DIR_IN,0x600)
#ret_tag+=self.send_mass_storage_command(lun, common_cmnd, USB_DIR_IN, 0x600)
if datasize>0:
data=self.usb.read(datasize,timeout)
print("DATA: "+str(hexlify(data)))
lun = 0
# datasize=common_cmnd[4]
timeout = 5000
ret_tag = self.send_mass_storage_command(lun, common_cmnd, USB_DIR_IN, 0x600)
# ret_tag+=self.send_mass_storage_command(lun, common_cmnd, USB_DIR_IN, 0x600)
if datasize > 0:
data = self.usb.read(datasize, timeout)
print("DATA: " + hexlify(data).decode('utf-8'))
print("Sent FIH adb enable command")
self.usb.close()
def send_fih_root(self): # motorola xt560, nokia 3.1, huawei u8850, huawei Ideos X6, lenovo s2109, triumph M410, viewpad 7, #f_mass_storage.c
def send_fih_root(
self): # motorola xt560, nokia 3.1, huawei u8850, huawei Ideos X6, lenovo s2109, triumph M410, viewpad 7, #f_mass_storage.c
if self.usb.connect():
print("Sending FIH root command")
datasize=0x24
common_cmnd = bytes([self.SC_SWITCH_ROOT]) + b"FIH"+struct.pack("<H",datasize) # reserve_cmd + 'FIH' + len + flag + none
datasize = 0x24
common_cmnd = bytes([self.SC_SWITCH_ROOT]) + b"FIH" + struct.pack("<H",
datasize) # reserve_cmd + 'FIH' + len + flag + none
lun = 0
#datasize = common_cmnd[4]
# datasize = common_cmnd[4]
timeout = 5000
ret_tag = self.send_mass_storage_command(lun, common_cmnd, USB_DIR_IN, 0x600)
ret_tag += self.send_mass_storage_command(lun, common_cmnd, USB_DIR_IN, 0x600)
if datasize > 0:
data = self.usb.read(datasize, timeout)
print("DATA: " + str(hexlify(data)))
print("DATA: " + hexlify(data).decode('utf-8'))
print("Sent FIH root command")
self.usb.close()

View file

@ -1,14 +1,152 @@
import sys
import struct
import logging
import codecs
import struct
import os
import shutil
import stat
from binascii import hexlify
try:
from capstone import *
from keystone import *
except:
print("Capstone and Keystone libraries missing.")
def do_tcp_server(client,arguments, handler):
def tcpprint(arg):
if isinstance(arg, bytes) or isinstance(arg, bytearray):
return connection.sendall(arg)
else:
return connection.sendall(bytes(str(arg), 'utf-8'))
client.printer=tcpprint
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
port = int(arguments["--tcpport"])
server_address = ('localhost', port)
print('starting up on %s port %s' % server_address)
sock.bind(server_address)
sock.listen(1)
while True:
print('waiting for a connection')
connection, client_address = sock.accept()
try:
print('connection from', client_address)
while True:
data = connection.recv(4096).decode('utf-8')
if data == '':
break
print('received %s' % data)
if data:
print('handling request')
lines = data.split("\n")
for line in lines:
if ":" in line:
cmd = line.split(":")[0]
marguments = line.split(":")[1]
try:
opts = parse_args(cmd, marguments, arguments)
except:
response = "Wrong arguments\n<NAK>\n"
opts = None
if opts is not None:
if handler(cmd, opts):
response = "<ACK>\n"
else:
response = "<NAK>\n"
connection.sendall(bytes(response, 'utf-8'))
finally:
connection.close()
def parse_args(cmd, args, mainargs):
options = {}
opts = None
if "," in args:
opts = args.split(",")
else:
opts = [args]
for arg in mainargs:
if "--" in arg:
options[arg] = mainargs[arg]
if cmd == "gpt":
options["<directory>"] = opts[0]
elif cmd == "r":
options["<partitionname>"] = opts[0]
options["<filename>"] = opts[1]
elif cmd == "rl":
options["<directory>"] = opts[0]
elif cmd == "rf":
options["<filename>"] = opts[0]
elif cmd == "rs":
options["<start_sector>"] = opts[0]
options["<sectors>"] = opts[1]
options["<filename>"] = opts[2]
elif cmd == "w":
options["<partitionname>"] = opts[0]
options["<filename>"] = opts[0]
elif cmd == "wl":
options["<directory>"] = opts[0]
elif cmd == "wf":
options["<filename>"] = opts[0]
elif cmd == "ws":
options["<start_sector>"] = opts[0]
options["<filename>"] = opts[1]
elif cmd == "e":
options["<partitionname>"] = opts[0]
elif cmd == "es":
options["<start_sector>"] = opts[0]
options["<sectors>"] = opts[1]
elif cmd == "footer":
options["<filename>"] = opts[0]
elif cmd == "peek":
options["<offset>"] = opts[0]
options["<length>"] = opts[1]
options["<filename>"] = opts[2]
elif cmd == "peekhex":
options["<offset>"] = opts[0]
options["<length>"] = opts[1]
elif cmd == "peekdword":
options["<offset>"] = opts[0]
elif cmd == "peekqword":
options["<offset>"] = opts[0]
elif cmd == "memtbl":
options["<filename>"] = opts[0]
elif cmd == "poke":
options["<offset>"] = opts[0]
options["<filename>"] = opts[1]
elif cmd == "pokehex":
options["<offset>"] = opts[0]
options["<data>"] = opts[1]
elif cmd == "pokedword":
options["<offset>"] = opts[0]
options["<data>"] = opts[1]
elif cmd == "pokeqword":
options["<offset>"] = opts[0]
options["<data>"] = opts[1]
elif cmd == "memcpy":
options["<offset>"] = opts[0]
options["<size>"] = opts[1]
elif cmd == "pbl":
options["<filename>"] = opts[0]
elif cmd == "qfp":
options["<filename>"] = opts[0]
elif cmd == "setbootablestoragedrive":
options["<lun>"] = opts[0]
elif cmd == "send":
options["<command>"] = opts[0]
elif cmd == "xml":
options["<xmlfile>"] = opts[0]
elif cmd == "rawxml":
options["<xmlstring>"] = opts[0]
return options
class log_class:
def __init__(self,level=logging.INFO,filename="log.txt"):
self.level=level
def __init__(self, level=logging.INFO, filename="log.txt"):
self.level = level
logging.basicConfig(level=self.level, format="%(name)s - %(message)s")
self.logger = logging.getLogger(__name__)
self.logger.setLevel(level)
if level==logging.DEBUG:
if level == logging.DEBUG:
if os.path.exists(filename):
os.remove(filename)
fh = logging.FileHandler(filename)
@ -17,34 +155,34 @@ class log_class:
def getlevel(self):
return self.level
def setlevel(self,level):
self.level=level
def setlevel(self, level):
self.level = level
return self.logger.setLevel(level)
def decoder(self,data):
if isinstance(data,bytes) or isinstance(data,bytearray):
if data[:5]==b"<?xml":
def decoder(self, data):
if isinstance(data, bytes) or isinstance(data, bytearray):
if data[:5] == b"<?xml":
try:
rdata = ""
for line in data.split(b"\n"):
try:
rdata += line.decode('utf-8')+"\n"
rdata += line.decode('utf-8') + "\n"
except:
rdata += hexlify(line).decode('utf-8')+"\n"
rdata += hexlify(line).decode('utf-8') + "\n"
return rdata
except:
pass
return data
def verify_data(self,data,pre="RX:"):
if isinstance(data,bytes) or isinstance(data,bytearray):
if data[:5]==b"<?xml":
def verify_data(self, data, pre="RX:"):
if isinstance(data, bytes) or isinstance(data, bytearray):
if data[:5] == b"<?xml":
try:
rdata = b""
for line in data.split(b"\n"):
try:
self.logger.debug(pre + line.decode('utf-8'))
rdata += line+b"\n"
rdata += line + b"\n"
except:
v = hexlify(line)
self.logger.debug(pre + v.decode('utf-8'))
@ -52,85 +190,75 @@ class log_class:
except:
pass
if logging.DEBUG >= logging.root.level:
self.logger.debug(pre+hexlify(data).decode('utf-8'))
self.logger.debug(pre + hexlify(data).decode('utf-8'))
else:
if logging.DEBUG >= logging.root.level:
self.logger.debug(pre+data)
self.logger.debug(pre + data)
return data
def debug(self,info):
def debug(self, info):
return self.logger.debug(info)
def info(self,info):
def info(self, info):
return self.logger.info(info)
def error(self,info):
def error(self, info):
return self.logger.error(info)
def warning(self,info):
def warning(self, info):
return self.logger.warning(info)
import codecs
from binascii import hexlify, unhexlify
import struct
import os
import shutil
import stat
try:
from capstone import *
from keystone import *
except:
print("Capstone and Keystone libraries missing.")
def del_rw(action, name, exc):
os.chmod(name, stat.S_IWRITE)
os.remove(name)
def rmrf(path):
if os.path.exists(path):
if os.path.isfile(path):
del_rw("",path,"")
del_rw("", path, "")
else:
shutil.rmtree(path, onerror=del_rw)
class elf:
class memorysegment:
phy_addr=0
virt_start_addr=0
virt_end_addr=0
file_start_addr=0
file_end_addr=0
phy_addr = 0
virt_start_addr = 0
virt_end_addr = 0
file_start_addr = 0
file_end_addr = 0
def __init__(self,indata,filename):
self.data=indata
self.filename=filename
def __init__(self, indata, filename):
self.data = indata
self.filename = filename
self.header, self.pentry = self.parse()
self.memorylayout = []
for entry in self.pentry:
ms=self.memorysegment()
ms.phy_addr=entry.phy_addr
ms.virt_start_addr=entry.virt_addr
ms.virt_end_addr=entry.virt_addr+entry.seg_mem_len
ms.file_start_addr=entry.from_file
ms.file_end_addr=entry.from_file+entry.seg_file_len
ms = self.memorysegment()
ms.phy_addr = entry.phy_addr
ms.virt_start_addr = entry.virt_addr
ms.virt_end_addr = entry.virt_addr + entry.seg_mem_len
ms.file_start_addr = entry.from_file
ms.file_end_addr = entry.from_file + entry.seg_file_len
self.memorylayout.append(ms)
def getfileoffset(self,offset):
def getfileoffset(self, offset):
for memsegment in self.memorylayout:
if offset<=memsegment.virt_end_addr and offset>=memsegment.virt_start_addr:
return offset-memsegment.virt_start_addr+memsegment.file_start_addr
if memsegment.virt_end_addr >= offset >= memsegment.virt_start_addr:
return offset - memsegment.virt_start_addr + memsegment.file_start_addr
return None
def getvirtaddr(self,fileoffset):
def getvirtaddr(self, fileoffset):
for memsegment in self.memorylayout:
if fileoffset<=memsegment.file_end_addr and fileoffset>=memsegment.file_start_addr:
return memsegment.virt_start_addr+fileoffset-memsegment.file_start_addr
if memsegment.file_end_addr >= fileoffset >= memsegment.file_start_addr:
return memsegment.virt_start_addr + fileoffset - memsegment.file_start_addr
return None
def getbaseaddr(self,offset):
def getbaseaddr(self, offset):
for memsegment in self.memorylayout:
if offset<=memsegment.virt_end_addr and offset>=memsegment.virt_start_addr:
if memsegment.virt_end_addr >= offset >= memsegment.virt_start_addr:
return memsegment.virt_start_addr
return None
@ -144,46 +272,47 @@ class elf:
p_flags = 0
p_align = 0
def parse_programentry(self,dat):
def parse_programentry(self, dat):
pe = self.programentry()
if self.elfclass==1:
(pe.p_type,pe.from_file,pe.virt_addr,pe.phy_addr,pe.seg_file_len,pe.seg_mem_len,pe.p_flags,pe.p_align) = struct.unpack("<IIIIIIII",dat)
elif self.elfclass==2:
(pe.p_type, pe.p_flags, pe.from_file, pe.virt_addr, pe.phy_addr, pe.seg_file_len, pe.seg_mem_len,pe.p_align) = struct.unpack("<IIQQQQQQ", dat)
if self.elfclass == 1:
(pe.p_type, pe.from_file, pe.virt_addr, pe.phy_addr, pe.seg_file_len, pe.seg_mem_len, pe.p_flags,
pe.p_align) = struct.unpack("<IIIIIIII", dat)
elif self.elfclass == 2:
(pe.p_type, pe.p_flags, pe.from_file, pe.virt_addr, pe.phy_addr, pe.seg_file_len, pe.seg_mem_len,
pe.p_align) = struct.unpack("<IIQQQQQQ", dat)
return pe
def parse(self):
self.elfclass=self.data[4]
if self.elfclass==1: #32Bit
start=0x28
elif self.elfclass==2: #64Bit
start=0x34
self.elfclass = self.data[4]
if self.elfclass == 1: # 32Bit
start = 0x28
elif self.elfclass == 2: # 64Bit
start = 0x34
else:
print("Error on parsing "+self.filename)
return ['','']
elfheadersize, programheaderentrysize, programheaderentrycount = struct.unpack("<HHH", self.data[start:start + 3 * 2])
print("Error on parsing " + self.filename)
return ['', '']
elfheadersize, programheaderentrysize, programheaderentrycount = struct.unpack("<HHH",
self.data[start:start + 3 * 2])
programheadersize = programheaderentrysize * programheaderentrycount
header = self.data[0:elfheadersize+programheadersize]
pentry=[]
for i in range(0,programheaderentrycount):
start=elfheadersize+(i*programheaderentrysize)
end=start+programheaderentrysize
header = self.data[0:elfheadersize + programheadersize]
pentry = []
for i in range(0, programheaderentrycount):
start = elfheadersize + (i * programheaderentrysize)
end = start + programheaderentrysize
pentry.append(self.parse_programentry(self.data[start:end]))
return [header,pentry]
return [header, pentry]
class patchtools:
cstyle=False
bDebug=False
cstyle = False
bDebug = False
def __init__(self, bDebug=False):
self.bDebug = bDebug
def __init__(self, bdebug=False):
self.bDebug = bdebug
def has_bad_uart_chars(self, data):
badchars = [b'\x00', b'\n', b'\r', b'\x08', b'\x7f', b'\x20', b'\x09']
bad = False
for idx, c in enumerate(data):
c = bytes([c])
if c in badchars:
@ -193,11 +322,11 @@ class patchtools:
def generate_offset(self, offset):
div = 0
found = False
while (found == False and div < 0x606):
while not found and div < 0x606:
data = struct.pack("<I", offset + div)
data2 = struct.pack("<H", div)
badchars = self.has_bad_uart_chars(data)
if not (badchars):
if not badchars:
badchars = self.has_bad_uart_chars(data2)
if not (badchars):
return div
@ -205,37 +334,36 @@ class patchtools:
# if div is not found within positive offset, try negative offset
div = 0
while (found == False and div < 0x606):
while not found and div < 0x606:
data = struct.pack("<I", offset - div)
data2 = struct.pack("<H", div)
badchars = self.has_bad_uart_chars(data)
if not (badchars):
if not badchars:
badchars = self.has_bad_uart_chars(data2)
if not (badchars):
if not badchars:
return -div
break
div += 4
return 0
#Usage: offset, "X24"
# Usage: offset, "X24"
def generate_offset_asm(self, offset, reg):
div = self.generate_offset(offset)
abase = ((offset + div) & 0xFFFF0000) >> 16
a = ((offset + div) & 0xFFFF)
str = ""
if (div > 0):
str += "# " + hex(offset) + "\n"
str += "mov " + reg + ", #" + hex(a) + ";\n"
str += "movk " + reg + ", #" + hex(abase) + ", LSL#16;\n"
str += "sub " + reg + ", " + reg + ", #" + hex(div) + ";\n"
strasm = ""
if div > 0:
strasm += "# " + hex(offset) + "\n"
strasm += "mov " + reg + ", #" + hex(a) + ";\n"
strasm += "movk " + reg + ", #" + hex(abase) + ", LSL#16;\n"
strasm += "sub " + reg + ", " + reg + ", #" + hex(div) + ";\n"
else:
str += "# " + hex(offset) + "\n"
str += "mov " + reg + ", #" + hex(a) + ";\n"
str += "movk " + reg + ", #" + hex(abase) + ", LSL#16;\n"
str += "add " + reg + ", " + reg + ", #" + hex(-div) + ";\n"
return str
strasm += "# " + hex(offset) + "\n"
strasm += "mov " + reg + ", #" + hex(a) + ";\n"
strasm += "movk " + reg + ", #" + hex(abase) + ", LSL#16;\n"
strasm += "add " + reg + ", " + reg + ", #" + hex(-div) + ";\n"
return strasm
def UART_validSC(self, sc):
def uart_valid_sc(self, sc):
badchars = [b'\x00', b'\n', b'\r', b'\x08', b'\x7f', b'\x20', b'\x09']
for idx, c in enumerate(sc):
c = bytes([c])
@ -270,8 +398,8 @@ class patchtools:
if len(line) and line[0] != '.':
try:
encoding, count = ks.asm(line)
except:
print("bummer")
except Exception as e:
print("bummer: " + str(e))
else:
exit(0)
else:
@ -293,19 +421,19 @@ class patchtools:
return out
def find_binary(self,data,strf,pos=0):
t=strf.split(b".")
pre=0
offsets=[]
while (pre!=-1):
pre = data[pos:].find(t[0],pre)
if (pre==-1):
if len(offsets)>0:
def find_binary(self, data, strf, pos=0):
t = strf.split(b".")
pre = 0
offsets = []
while pre != -1:
pre = data[pos:].find(t[0], pre)
if pre == -1:
if len(offsets) > 0:
for offset in offsets:
error = 0
rt = offset + len(t[0])
for i in range(1, len(t)):
if (t[i] == b''):
if t[i] == b'':
rt += 1
continue
rt += 1
@ -320,45 +448,48 @@ class patchtools:
return None
else:
offsets.append(pre)
pre+=1
pre += 1
return None
def read_object(data, definition):
'''
def read_object(data: object, definition: object) -> object:
"""
Unpacks a structure using the given data and definition.
'''
"""
obj = {}
object_size = 0
pos=0
pos = 0
for (name, stype) in definition:
object_size += struct.calcsize(stype)
obj[name] = struct.unpack(stype, data[pos:pos+struct.calcsize(stype)])[0]
pos+=struct.calcsize(stype)
obj[name] = struct.unpack(stype, data[pos:pos + struct.calcsize(stype)])[0]
pos += struct.calcsize(stype)
obj['object_size'] = object_size
obj['raw_data'] = data
return obj
def write_object(definition,*args):
'''
def write_object(definition, *args):
"""
Unpacks a structure using the given data and definition.
'''
"""
obj = {}
object_size = 0
data=b""
i=0
data = b""
i = 0
for (name, stype) in definition:
object_size += struct.calcsize(stype)
arg=args[i]
arg = args[i]
try:
data += struct.pack(stype, arg)
except Exception as e:
print("Error:"+str(e))
print("Error:" + str(e))
break
i+=1
i += 1
obj['object_size'] = len(data)
obj['raw_data'] = data
return obj
def print_progress(iteration, total, prefix='', suffix='', decimals=1, bar_length=100):
"""
Call in a loop to create terminal progress bar
@ -375,7 +506,7 @@ def print_progress(iteration, total, prefix='', suffix='', decimals=1, bar_lengt
filled_length = int(round(bar_length * iteration / float(total)))
bar = '' * filled_length + '-' * (bar_length - filled_length)
sys.stdout.write('\r%s |%s| %s%s %s' % (prefix, bar, percents, '%', suffix)),
sys.stdout.write('\r%s |%s| %s%s %s' % (prefix, bar, percents, '%', suffix))
if iteration == total:
sys.stdout.write('\n')

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -18,7 +18,7 @@
- sudo sudo apt install liblzma-dev
Linux/Windows:
- "python -m pip install -r requirements.txt" (use python3 instead of python if you use python2 and python3)
- "python -m pip install -r requirements.txt"
Windows:
- Boot device into 9008 mode, install Qualcomm_Diag_QD_Loader_2016_driver.exe from Drivers\Windows,
@ -40,7 +40,7 @@ or
### Generic
- "./edl.py -h" -> to see help with all options
- "./edl.py server --memory=ufs --tcpport=1340" -> Run TCP/IP server on port 1340, see Example/tcpclient.py for an example client
- "./edl.py server --memory=ufs --tcpport=1340" -> Run TCP/IP server on port 1340, see Examples/tcpclient.py for an example client
- "./edl.py xml run.xml" -> To send a xml file run.xml via firehose
- "./edl.py reset" -> To reboot the phone
- "./edl.py rawxml <xmlstring>' -> To send own xml string, example :
@ -97,8 +97,20 @@ or
- "./edl.py pbl pbl.bin" -> To dump pbl (only on EL3 loaders)
- "./edl.py qfp qfp.bin" -> To dump qfprom fuses (only on EL3 loaders)
### For generic unlocking
- "./edl.py modules oemunlock" -> Unlocks OEM if partition "config" exists, fastboot oem unlock is still needed afterwards
### Streaming mode (credits to forth32)
#### Dump memory (0x900E mode)
- "./edl.py dumpmemory"
#### Sierra Wireless Modem
- Send AT!BOOTHOLD and AT!QPSTDLOAD to modem port or use ./boottodwnload.py script
- Send AT!ENTERCND="A710" and then AT!EROPTION=0 for memory dump
- "./edl.py --vid 1199 --pid 9070 --loader=Loaders/qualcomm/patched/NPRG9x35p.bin printgpt" -> To show the partition table
#### ZTE MF920V
- Send to at port "AT+ZCDRUN=E", or run "./diag.py -sahara"
- "adb reboot edl"
- "./edl.py printgpt" -> To show the partition table
### QFIL in linux console (credits to LyuOnLine):
@ -133,18 +145,12 @@ For Oneplus 6T, enter *#801#* on dialpad, set Engineer Mode and Serial to on and
## Issues
- Secure loader with SDM660 on Xiaomi not yet supported
- Secure loader with SDM660 on Xiaomi (EDL auth) and Oppo (VIP Programming) not yet supported
- EFS directory write and file read has to be added
## Tested with
- Oneplus 3T/5/6T/7T, BQ X, BQ X5, BQ X2, Gigaset ME Pure, ZTE MF210
## Contributions
- We need an implementation of the VIP Programming, functions addprogram and addpatch should be used (as a Module in Modules)
## Report issues
- Please run using the option --debugmode and then commit an issue and attach the "log.txt" file
- Oneplus 3T/5/6T/7T/8/8t/N10/N100 (Read-Only), BQ X, BQ X5, BQ X2, Gigaset ME Pure, ZTE MF210, ZTE MF920V, Sierra Wireless EM7455, Quectel EC25
Published under MIT license
Additional license limitations: No use in commercial products without prior permit.

1378
diag.py

File diff suppressed because it is too large Load diff

1528
edl.py

File diff suppressed because it is too large Load diff

View file

@ -1,13 +1,13 @@
#!/usr/bin/env python3
from Library.utils import elf
import os
import sys
from os import walk
import hashlib
import struct
from shutil import copyfile
from binascii import hexlify
from Config.qualcomm_config import *
from Config.qualcomm_config import sochw, msmids
from Library.utils import elf
from Library.sahara import convertmsmid
vendor = {}
vendor["0000"] = "Qualcomm "
@ -35,47 +35,52 @@ vendor["143A"] = "Asus "
vendor["1978"] = "Blackphone "
vendor["2A70"] = "Oxygen "
class Signed:
filename = ''
filesize = 0
oem_id = ''
model_id = ''
hw_id = ''
sw_id = ''
app_id = ''
sw_size = ''
qc_version = ''
image_variant = ''
oem_version = ''
pk_hash = ''
hash=b''
filename = ''
filesize = 0
oem_id = ''
model_id = ''
hw_id = ''
sw_id = ''
app_id = ''
sw_size = ''
qc_version = ''
image_variant = ''
oem_version = ''
pk_hash = ''
hash = b''
def grabtext(data):
i=len(data)
t=0
text=''
while (i>0):
if (data[t]==0):
i = len(data)
j = 0
text = ''
while i > 0:
if data[j] == 0:
break
text+=chr(data[t])
t+=1
i-=1
text += chr(data[j])
j += 1
i -= 1
return text
def extract_hdr(memsection,si,mm,code_size,signature_size):
def extract_hdr(memsection, sign_info, mem_section, code_size, signature_size):
try:
md_size = struct.unpack("<I", mm[memsection.file_start_addr + 0x2C:memsection.file_start_addr + 0x2C + 0x4])[0]
md_offset=memsection.file_start_addr + 0x2C + 0x4
major,minor,sw_id,hw_id,oem_id,model_id,app_id=struct.unpack("<IIIIIII",mm[md_offset:md_offset+(7*4)])
si.hw_id="%08X" % hw_id
si.sw_id = "%08X" % sw_id
si.oem_id="%04X" % oem_id
si.model_id="%04X" % model_id
si.hw_id += si.oem_id + si.model_id
si.app_id="%08X" % app_id
md_offset+=(7 * 4)
v=struct.unpack("<I", mm[md_offset:md_offset + 4])[0]
md_size = \
struct.unpack("<I", mem_section[memsection.file_start_addr + 0x2C:memsection.file_start_addr + 0x2C + 0x4])[0]
md_offset = memsection.file_start_addr + 0x2C + 0x4
major, minor, sw_id, hw_id, oem_id, model_id, app_id = struct.unpack("<IIIIIII",
mem_section[md_offset:md_offset + (7 * 4)])
sign_info.hw_id = "%08X" % hw_id
sign_info.sw_id = "%08X" % sw_id
sign_info.oem_id = "%04X" % oem_id
sign_info.model_id = "%04X" % model_id
sign_info.hw_id += sign_info.oem_id + sign_info.model_id
sign_info.app_id = "%08X" % app_id
md_offset += (7 * 4)
# v=struct.unpack("<I", mem_section[md_offset:md_offset + 4])[0]
'''
rot_en=(v >> 0) & 1
in_use_soc_hw_version=(v >> 1) & 1
use_serial_number_in_signing=(v >> 2) & 1
@ -91,134 +96,126 @@ def extract_hdr(memsection,si,mm,code_size,signature_size):
mrc_index=struct.unpack("<I", mm[md_offset:md_offset + 4])[0]
md_offset+=4
anti_rollback_version=struct.unpack("<I", mm[md_offset:md_offset + 4])[0]
'''
signatureoffset = memsection.file_start_addr + 0x30 + md_size + code_size + signature_size
try:
if mm[signatureoffset] != 0x30:
print("Error on " + si.filename + ", unknown signaturelength")
if mem_section[signatureoffset] != 0x30:
print("Error on " + sign_info.filename + ", unknown signaturelength")
return None
except:
return None
if len(mm) < signatureoffset + 4:
print("Signature error on " + si.filename)
return None
len1 = struct.unpack(">H", mm[signatureoffset + 2:signatureoffset + 4])[0] + 4
if len(mem_section) < signatureoffset + 4:
print("Signature error on " + sign_info.filename)
return None
len1 = struct.unpack(">H", mem_section[signatureoffset + 2:signatureoffset + 4])[0] + 4
casignature2offset = signatureoffset + len1
len2 = struct.unpack(">H", mm[casignature2offset + 2:casignature2offset + 4])[0] + 4
len2 = struct.unpack(">H", mem_section[casignature2offset + 2:casignature2offset + 4])[0] + 4
rootsignature3offset = casignature2offset + len2
len3 = struct.unpack(">H", mm[rootsignature3offset + 2:rootsignature3offset + 4])[0] + 4
si.pk_hash = hashlib.sha384(mm[rootsignature3offset:rootsignature3offset + len3]).hexdigest()
len3 = struct.unpack(">H", mem_section[rootsignature3offset + 2:rootsignature3offset + 4])[0] + 4
sign_info.pk_hash = hashlib.sha384(mem_section[rootsignature3offset:rootsignature3offset + len3]).hexdigest()
except:
return None
return si
return sign_info
def extract_old_hdr(memsection,si,mm,code_size,signature_size):
def extract_old_hdr(memsection, sign_info, mem_section, code_size, signature_size):
signatureoffset = memsection.file_start_addr + 0x28 + code_size + signature_size
signature = {}
if mm[signatureoffset] != 0x30:
print("Error on " + si.filename + ", unknown signaturelength")
if mem_section[signatureoffset] != 0x30:
print("Error on " + sign_info.filename + ", unknown signaturelength")
return None
if signatureoffset != -1:
if len(mm) < signatureoffset + 4:
print("Signature error on " + si.filename)
if len(mem_section) < signatureoffset + 4:
print("Signature error on " + sign_info.filename)
return None
len1 = struct.unpack(">H", mm[signatureoffset + 2:signatureoffset + 4])[0] + 4
len1 = struct.unpack(">H", mem_section[signatureoffset + 2:signatureoffset + 4])[0] + 4
casignature2offset = signatureoffset + len1
len2 = struct.unpack(">H", mm[casignature2offset + 2:casignature2offset + 4])[0] + 4
len2 = struct.unpack(">H", mem_section[casignature2offset + 2:casignature2offset + 4])[0] + 4
rootsignature3offset = casignature2offset + len2
len3 = struct.unpack(">H", mm[rootsignature3offset + 2:rootsignature3offset + 4])[0] + 4
si.pk_hash = hashlib.sha256(mm[rootsignature3offset:rootsignature3offset + len3]).hexdigest()
len3 = struct.unpack(">H", mem_section[rootsignature3offset + 2:rootsignature3offset + 4])[0] + 4
sign_info.pk_hash = hashlib.sha256(mem_section[rootsignature3offset:rootsignature3offset + len3]).hexdigest()
idx = signatureoffset
while (idx != -1):
if (idx >= len(mm)):
while idx != -1:
if idx >= len(mem_section):
break
idx = mm.find('\x04\x0B'.encode(), idx)
if (idx == -1):
idx = mem_section.find('\x04\x0B'.encode(), idx)
if idx == -1:
break
length = mm[idx + 3]
if (length > 60):
length = mem_section[idx + 3]
if length > 60:
idx += 1
continue
try:
text = mm[idx + 4:idx + 4 + length].decode().split(' ')
text = mem_section[idx + 4:idx + 4 + length].decode().split(' ')
signature[text[2]] = text[1]
except:
text = ""
idx += 1
idx = mm.find('QC_IMAGE_VERSION_STRING='.encode(), 0)
idx = mem_section.find('QC_IMAGE_VERSION_STRING='.encode(), 0)
if idx != -1:
si.qc_version = grabtext(mm[idx + len("QC_IMAGE_VERSION_STRING="):])
idx = mm.find('OEM_IMAGE_VERSION_STRING='.encode(), 0)
sign_info.qc_version = grabtext(mem_section[idx + len("QC_IMAGE_VERSION_STRING="):])
idx = mem_section.find('OEM_IMAGE_VERSION_STRING='.encode(), 0)
if idx != -1:
si.oem_version = grabtext(mm[idx + len("OEM_IMAGE_VERSION_STRING="):])
idx = mm.find('IMAGE_VARIANT_STRING='.encode(), 0)
sign_info.oem_version = grabtext(mem_section[idx + len("OEM_IMAGE_VERSION_STRING="):])
idx = mem_section.find('IMAGE_VARIANT_STRING='.encode(), 0)
if idx != -1:
si.image_variant = grabtext(mm[idx + len("IMAGE_VARIANT_STRING="):])
sign_info.image_variant = grabtext(mem_section[idx + len("IMAGE_VARIANT_STRING="):])
if "OEM_ID" in signature:
if signature["OEM_ID"] in vendor:
si.oem_id = vendor[signature["OEM_ID"]]
sign_info.oem_id = vendor[signature["OEM_ID"]]
else:
si.oem_id = signature["OEM_ID"]
sign_info.oem_id = signature["OEM_ID"]
if "MODEL_ID" in signature:
si.model_id = signature["MODEL_ID"]
sign_info.model_id = signature["MODEL_ID"]
if "HW_ID" in signature:
si.hw_id = signature["HW_ID"]
sign_info.hw_id = signature["HW_ID"]
if "SW_ID" in signature:
si.sw_id = signature["SW_ID"]
sign_info.sw_id = signature["SW_ID"]
if "SW_SIZE" in signature:
si.sw_size = signature["SW_SIZE"]
return si
sign_info.sw_size = signature["SW_SIZE"]
return sign_info
def convertmsmid(msmid):
if int(msmid, 16) in sochw:
names = sochw[int(msmid, 16)].split(",")
for name in names:
for ids in msmids:
if msmids[ids] == name:
msmid = hex(ids)[2:].lower()
while (len(msmid) < 8):
msmid = '0' + msmid
return msmid
def init_loader_db():
loaderdb = {}
for (dirpath, dirnames, filenames) in os.walk("Loaders"):
for filename in filenames:
fn = os.path.join(dirpath, filename)
found=False
for ext in [".bin",".mbn",".elf"]:
file_name = os.path.join(dirpath, filename)
found = False
for ext in [".bin", ".mbn", ".elf"]:
if ext in filename[-4:]:
found=True
found = True
break
if found==False:
if not found:
continue
try:
hwid = filename.split("_")[0].lower()
msmid=hwid[:8]
devid=hwid[8:]
msmid = hwid[:8]
devid = hwid[8:]
pkhash = filename.split("_")[1].lower()
msmid=convertmsmid(msmid)
mhwid=convertmsmid(msmid)+devid
msmid = convertmsmid(msmid)
mhwid = convertmsmid(msmid) + devid
if mhwid not in loaderdb:
loaderdb[mhwid] = {}
if pkhash not in loaderdb[mhwid]:
loaderdb[mhwid][pkhash] = fn
loaderdb[mhwid][pkhash] = file_name
else:
loaderdb[mhwid][pkhash].append(fn)
loaderdb[mhwid][pkhash].append(file_name)
except:
continue
return loaderdb
def is_duplicate(loaderdb, si):
lhash = si.pk_hash[:16].lower()
msmid = si.hw_id[:8].lower()
devid = si.hw_id[8:].lower()
hwid=si.hw_id.lower()
def is_duplicate(loaderdb, sign_info):
lhash = sign_info.pk_hash[:16].lower()
msmid = sign_info.hw_id[:8].lower()
devid = sign_info.hw_id[8:].lower()
hwid = sign_info.hw_id.lower()
rid = (convertmsmid(msmid) + devid).lower()
if hwid in loaderdb:
loader=loaderdb[hwid]
loader = loaderdb[hwid]
if lhash in loader:
return True
if rid in loaderdb:
@ -227,10 +224,11 @@ def is_duplicate(loaderdb, si):
return True
return False
def main(argv):
f = []
file_list = []
path = ""
if (len(argv)<3):
if len(argv) < 3:
print("Usage: ./fhloaderparse.py [FHLoaderDir] [OutputDir]")
exit(0)
else:
@ -239,137 +237,144 @@ def main(argv):
if not os.path.exists(outputdir):
os.mkdir(outputdir)
loaderdb=init_loader_db()
loaderdb = init_loader_db()
for (dirpath, dirnames, filenames) in walk(path):
for filename in filenames:
f.append(os.path.join(dirpath, filename))
file_list.append(os.path.join(dirpath, filename))
hashes={}
hashes = {}
for (dirpath, dirnames, filenames) in walk(outputdir):
for filename in filenames:
fname=os.path.join(dirpath, filename)
with open(fname,'rb') as rf:
data=rf.read()
fname = os.path.join(dirpath, filename)
with open(fname, 'rb') as rhandle:
data = rhandle.read()
sha256 = hashlib.sha256()
sha256.update(data)
hashes[sha256.digest()]=fname
hashes[sha256.digest()] = fname
filelist = []
rt=open(os.path.join(outputdir,argv[1]+".log"),"w")
extensions=["elf","mbn","bin"]
if not os.path.exists(os.path.join(outputdir,"unknown")):
os.makedirs(os.path.join(outputdir,"unknown"))
for filename in f:
found=False
rt = open(os.path.join(outputdir, argv[1] + ".log"), "w")
extensions = ["elf", "mbn", "bin"]
if not os.path.exists(os.path.join(outputdir, "unknown")):
os.makedirs(os.path.join(outputdir, "unknown"))
for filename in file_list:
found = False
for ext in extensions:
if "."+ext in filename:
found=True
if "." + ext in filename:
found = True
break
if found!=True:
if found != True:
continue
with open(filename,'rb') as rf:
mm = rf.read()
with open(filename, 'rb') as rhandle:
mem_section = rhandle.read()
sha256 = hashlib.sha256()
sha256.update(mm)
sha256.update(mem_section)
si=Signed()
si.hash=sha256.digest()
si.filename=filename
si.filesize=os.stat(filename).st_size
if len(mm)<4:
signinfo = Signed()
signinfo.hash = sha256.digest()
signinfo.filename = filename
signinfo.filesize = os.stat(filename).st_size
if len(mem_section) < 4:
continue
hdr=struct.unpack("<I", mm[0:4])[0]
hdr = struct.unpack("<I", mem_section[0:4])[0]
'''
if hdr == 0x844BDCD1: # mbn
signatureoffset = struct.unpack("<I", mm[0x14:0x18])[0] + struct.unpack("<I", mm[0x20:0x24])[0] + \
struct.unpack("<I", mm[0x28:0x2C])[0]
if struct.unpack("<I", mm[0x28:0x2C])[0] == 0:
signatureoffset = struct.unpack("<I", mem_section[0x14:0x18])[0] + struct.unpack("<I", mem_section[0x20:0x24])[0] + \
struct.unpack("<I", mem_section[0x28:0x2C])[0]
if struct.unpack("<I", mem_section[0x28:0x2C])[0] == 0:
signatureoffset = -1
elif hdr == 0x464C457F:
elfheader = elf(mm,si.filename)
'''
if hdr == 0x464C457F:
elfheader = elf(mem_section, signinfo.filename)
if 'memorylayout' in dir(elfheader):
memsection=elfheader.memorylayout[1]
memsection = elfheader.memorylayout[1]
try:
version=struct.unpack("<I",mm[memsection.file_start_addr + 0x04:memsection.file_start_addr + 0x04+0x4])[0]
version = struct.unpack("<I", mem_section[
memsection.file_start_addr + 0x04:memsection.file_start_addr + 0x04 + 0x4])[
0]
code_size = \
struct.unpack("<I", mm[memsection.file_start_addr + 0x14:memsection.file_start_addr + 0x14 + 0x4])[
0]
struct.unpack("<I", mem_section[
memsection.file_start_addr + 0x14:memsection.file_start_addr + 0x14 + 0x4])[
0]
signature_size = \
struct.unpack("<I", mm[memsection.file_start_addr + 0x1C:memsection.file_start_addr + 0x1C + 0x4])[
0]
cert_chain_size=struct.unpack("<I", mm[memsection.file_start_addr + 0x24:memsection.file_start_addr + 0x24 + 0x4])[
0]
struct.unpack("<I", mem_section[
memsection.file_start_addr + 0x1C:memsection.file_start_addr + 0x1C + 0x4])[
0]
# cert_chain_size=struct.unpack("<I", mem_section[memsection.file_start_addr + 0x24:memsection.file_start_addr + 0x24 + 0x4])[0]
except:
continue
if signature_size==0:
if signature_size == 0:
print("%s has no signature." % filename)
continue
if version<6: #MSM,MDM
si=extract_old_hdr(memsection,si,mm,code_size,signature_size)
if si==None:
if version < 6: # MSM,MDM
signinfo = extract_old_hdr(memsection, signinfo, mem_section, code_size, signature_size)
if signinfo is None:
continue
filelist.append(si)
elif version>=6: #SDM
si = extract_hdr(memsection, si, mm, code_size, signature_size)
if si == None:
filelist.append(signinfo)
elif version >= 6: # SDM
signinfo = extract_hdr(memsection, signinfo, mem_section, code_size, signature_size)
if signinfo is None:
continue
filelist.append(si)
filelist.append(signinfo)
else:
print("Unknown version for "+filename)
print("Unknown version for " + filename)
continue
else:
print("Error on " + filename)
continue
sorted_x = sorted(filelist, key=lambda x: (x.hw_id, -x.filesize))
class loaderinfo:
hw_id=''
item=''
if not os.path.exists(os.path.join(outputdir,"Duplicate")):
os.mkdir(os.path.join(outputdir,"Duplicate"))
hw_id = ''
item = ''
if not os.path.exists(os.path.join(outputdir, "Duplicate")):
os.mkdir(os.path.join(outputdir, "Duplicate"))
loaderlists = {}
for item in sorted_x:
if item.oem_id!='':
info=f"OEM:{item.oem_id}\tMODEL:{item.model_id}\tHWID:{item.hw_id}\tSWID:{item.sw_id}\tSWSIZE:{item.sw_size}\tPK_HASH:{item.pk_hash}\t{item.filename}\t{str(item.filesize)}"
if item.oem_version!='':
info+="\tOEMVER:"+item.oem_version+"\tQCVER:"+item.qc_version+"\tVAR:"+item.image_variant
lf=loaderinfo()
lf.hw_id=item.hw_id
lf.pk_hash=item.pk_hash
if item.oem_id != '':
info = f"OEM:{item.oem_id}\tMODEL:{item.model_id}\tHWID:{item.hw_id}\tSWID:{item.sw_id}\tSWSIZE:{item.sw_size}\tPK_HASH:{item.pk_hash}\t{item.filename}\t{str(item.filesize)}"
if item.oem_version != '':
info += "\tOEMVER:" + item.oem_version + "\tQCVER:" + item.qc_version + "\tVAR:" + item.image_variant
loader_info = loaderinfo()
loader_info.hw_id = item.hw_id
loader_info.pk_hash = item.pk_hash
if item.hash not in hashes:
if (lf not in loaderlists):
if loader_info not in loaderlists:
if not is_duplicate(loaderdb, item):
loaderlists[lf]=item.filename
loaderlists[loader_info] = item.filename
print(info)
msmid = lf.hw_id[:8]
devid = lf.hw_id[8:]
msmid = loader_info.hw_id[:8]
devid = loader_info.hw_id[8:]
hwid = convertmsmid(msmid) + devid
copyfile(item.filename,os.path.join(outputdir,hwid+"_"+lf.pk_hash[0:16]+"_FHPRG.bin"))
copyfile(item.filename,
os.path.join(outputdir, hwid + "_" + loader_info.pk_hash[0:16] + "_FHPRG.bin"))
else:
print("Duplicate: "+info)
copyfile(item.filename,os.path.join(outputdir, "Duplicate", lf.hw_id + "_" + lf.pk_hash[0:16] + "_FHPRG.bin"))
print("Duplicate: " + info)
copyfile(item.filename, os.path.join(outputdir, "Duplicate",
loader_info.hw_id + "_" + loader_info.pk_hash[
0:16] + "_FHPRG.bin"))
else:
copyfile(item.filename,os.path.join(outputdir,"unknown",item.filename[item.filename.rfind("\\")+1:]+"_"+lf.pk_hash[0:16]+"_FHPRG.bin"))
copyfile(item.filename, os.path.join(outputdir, "unknown", item.filename[item.filename.rfind(
"\\") + 1:] + "_" + loader_info.pk_hash[0:16] + "_FHPRG.bin"))
else:
print(item.filename+" does already exist. Skipping")
print(item.filename + " does already exist. Skipping")
try:
rt.write(info+"\n")
rt.write(info + "\n")
except:
continue
for item in filelist:
if item.oem_id=='' and (".bin" in item.filename or ".mbn" in item.filename or ".hex" in item.filename):
info="Unsigned:"+item.filename+"\t"+str(item.filesize)
if item.oem_id == '' and (".bin" in item.filename or ".mbn" in item.filename or ".hex" in item.filename):
info = "Unsigned:" + item.filename + "\t" + str(item.filesize)
if item.oem_version != '':
info += "\tOEMVER:" + item.oem_version + "\tQCVER:" + item.qc_version + "\tVAR:" + item.image_variant
print(info)
rt.write(info+"\n")
copyfile(item.filename,os.path.join(outputdir,"unknown",item.filename[item.filename.rfind("\\")+1:]))
rt.write(info + "\n")
copyfile(item.filename, os.path.join(outputdir, "unknown", item.filename[item.filename.rfind("\\") + 1:]))
rt.close()
main(sys.argv)
main(sys.argv)

22
modem/netgear_boottodwnload.py Executable file
View file

@ -0,0 +1,22 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# (c) B.Kerler 2020 under MIT license
# If you use my code, make sure you refer to my name
# If you want to use in a commercial product, ask me before integrating it
def sendcmd(tn,cmd):
tn.write(bytes(cmd,'utf-8')+b"\n")
time.sleep(0.05)
return tn.read_eager().strip().decode('utf-8')
def main():
from telnetlib import Telnet
tn = Telnet("localhost", 5510)
print("Sending download mode command to localhost:5510")
print(sendcmd(tn,"AT!BOOTHOLD\r"))
print(sendcmd(tn,'AT!QPSTDLOAD\r'))
print("Done switching to download mode")
tn.close()
if __name__=="__main__":
main()

29
modem/quectel_adb.py Executable file
View file

@ -0,0 +1,29 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# (c) B.Kerler 2020 under MIT license
# If you use my code, make sure you refer to my name
# If you want to use in a commercial product, ask me before integrating it
import crypt
import sys
import serial
if len(sys.argv)<2:
print("Usage: ./quectel_adb.py [enable,disable]")
sys.exit()
ser = serial.Serial('/dev/ttyUSB2')
ser.baudrate=115200
if sys.argv[1]=="enable":
print("Sending download mode command to /dev/ttyUSB2")
ser.write(b"AT+QADBKEY?\r")
salt=ser.readline()
salt+=ser.readline()
if not b"ERROR" in salt:
salt=sys.argv[1]
code=crypt.crypt("SH_adb_quectel","$1$"+salt)
code=code[12:]
ser.write(b"AT+QADBKEY=\"%s\"\n" % code)
ser.write(b"AT+QCFG=\"usbcfg\",0x2C7C,0x125,1,1,1,1,1,1,0\n\n")
else:
print("In order to disable adb:")
ser.write("AT+QCFG=\"usbcfg\",0x2C7C,0x125,1,1,1,1,1,0,0\n")
print(ser.readline())

18
modem/sierra_boottodwnload.py Executable file
View file

@ -0,0 +1,18 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# (c) B.Kerler 2019 under MIT license
# If you use my code, make sure you refer to my name
# If you want to use in a commercial product, ask me before integrating it
import serial
print("Sending download mode command to /dev/ttyUSB2")
ser = serial.Serial('/dev/ttyUSB2')
ser.baudrate=115200
ser.write(b'AT!BOOTHOLD\r')
print(ser.readline())
ser.write(b'AT!QPSTDLOAD\r')
print(ser.readline())
#ser.write(b'AT!QPSTDLOAD\r')
#print(ser.readline())
print("Done switching to download mode")
ser.close()

166
qfil.py
View file

@ -1,7 +1,7 @@
#!/usr/bin/env python3
"""
QFIL tools for qualcomm IC based on https://github.com/bkerler/edl by LyuOnLine
"""QFIL tools for qualcomm IC based on https://github.com/bkerler/edl
by LyuOnLine
QFIL tools for qualcomm ICs.
- Detail logs for sahara and firehose communications.
- Support config xml file samed as qualcomm tools.
@ -12,18 +12,17 @@ Args:
- patch : patch config xml, such as patch0.xml or patch*.xml.
- imagedir : directory name of images resides.
"""
from Library.utils import *
import argparse
import logging.config
import time
import copy
import os
import sys
import colorama
from Library.usblib import usb_class
from Library.sahara import qualcomm_sahara
from Library.firehose import qualcomm_firehose
from Library.xmlparser import xmlparser
import argparse
import logging
import logging.config
import time
import colorama
import copy
import os
try:
import xml.etree.cElementTree as ET
from xml.etree import cElementTree as ElementTree
@ -57,32 +56,9 @@ class ColorFormatter(logging.Formatter):
# now we can let standart formatting take care of the rest
return super(ColorFormatter, self).format(new_record, *args, **kwargs)
def getluns(memory):
luns = []
if not memory == "emmc":
for i in range(0, 99):
luns.append(i)
else:
luns = [0]
return luns
def find_bootable_partition(rawprogram):
part = -1
for xml in rawprogram:
fl = open(xml, "r")
for evt, elem in ET.iterparse(fl, events=["end"]):
if elem.tag == "program":
label = elem.get("label")
if label in [ 'xbl', 'xbl_a', 'sbl1' ]:
if part != -1:
log.error("[FIREHOSE] multiple bootloader found!")
return -1
part = elem.get("physical_partition_number")
return part
if __name__ == '__main__':
global log
parser = argparse.ArgumentParser(description="Qualcomm QFIL tools")
parser.add_argument("--vid", "-V", type=lambda x: int(x, 16),
default=0x05c6, help="usb vendor id, default is 0x05c6.")
@ -100,49 +76,100 @@ if __name__ == '__main__':
"warn", "info", "debug"], required=False, default="info", help="log level")
parser.add_argument("--skipresponse", "-s", type=bool, help="Skip read/write final response from mobile")
parser.add_argument("--memory", "-m", choices=["emmc", "ufs"], default="emmc", help="memory type")
parser.add_argument("--lun", "-lun", default="0", help="lun")
parser.add_argument("--devicemodel", "-dev", default="", help="Device prjid")
args = parser.parse_args()
log_level = {"warn": logging.WARN, "info": logging.INFO,
"debug": logging.DEBUG}[args.log_level]
filename="log.txt"
log = log_class(log_level, filename)
log.info("[INFO] firehose image: %s" % args.firehose)
log.info("[INFO] rawprogram files: %s" % str(args.rawprogram))
log.info("[INFO] patch files: %s" % str(args.patch))
log.info("[INFO] USB device 0x%04x:0x%04x" % (args.vid, args.pid))
cdc = usb_class(vid=args.vid, pid=args.pid, log=log)
def getluns(memory):
luns = []
if not memory == "emmc":
for i in range(0, 99):
luns.append(i)
else:
luns = [0]
return luns
def find_bootable_partition(rawprogram):
part = -1
for xml in rawprogram:
fl = open(xml, "r")
for evt, elem in ET.iterparse(fl, events=["end"]):
if elem.tag == "program":
label = elem.get("label")
if label in ['xbl', 'xbl_a', 'sbl1']:
if part != -1:
logging.error("[FIREHOSE] multiple bootloader found!")
return -1
part = elem.get("physical_partition_number")
return part
LOG_CONFIG = {
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"root": {
"()": ColorFormatter,
"format": "%(message)s",
}
},
"handlers": {
"root": {
"level": log_level,
"formatter": "root",
"class": "logging.StreamHandler",
"stream": "ext://sys.stdout",
}
},
"loggers": {
"": {
"handlers": ["root"],
"level": log_level,
"propagate": False
}
},
}
logging.config.dictConfig(LOG_CONFIG)
logging.info("[INFO] firehose image: %s" % args.firehose)
logging.info("[INFO] rawprogram files: %s" % str(args.rawprogram))
logging.info("[INFO] patch files: %s" % str(args.patch))
logging.info("[INFO] USB device 0x%04x:0x%04x" % (args.vid, args.pid))
cdc = usb_class(vidpid=[args.vid, args.pid])
cdc.timeout = 100
sahara = qualcomm_sahara(cdc)
log.info("[USB] waiting for device connecting...")
logging.info("[USB] waiting for device connecting...")
while True:
if cdc.connect():
break
else:
time.sleep(1)
time.sleep(1)
log.info("[SAHARA] reading firehose images.")
logging.info("[SAHARA] reading firehose images.")
fl = open(args.firehose, "rb")
sahara.programmer = fl.read()
fl.close()
log.info("[SAHARA] connecting...")
logging.info("[SAHARA] connecting...")
sahara.connect()
log.info("[SAHARA] reading sahara info, hwid, sn, sbl version...")
logging.info("[SAHARA] reading sahara info, hwid, sn, sbl version...")
sahara.info()
log.info("[SAHARA] entering image tx mode...")
logging.info("[SAHARA] entering image tx mode...")
sahara.connect()
log.info("[SAHARA] upload firehose image...")
logging.info("[SAHARA] upload firehose image...")
m = sahara.upload_loader()
if not m:
log.error("[ERROR] update firehose image failed!")
logging.error("[ERROR] update firehose image failed!")
sys.exit(1)
log.info("[FIREHOSE] waiting connecting...")
logging.info("[FIREHOSE] waiting connecting...")
cfg = qualcomm_firehose.cfg()
cfg.MemoryName = args.memory
cfg.ZLPAwareHost = 1
@ -151,15 +178,15 @@ if __name__ == '__main__':
cfg.MaxPayloadSizeToTargetInBytes = 1048576
cfg.SECTOR_SIZE_IN_BYTES = 512
cfg.bit64 = True
fh = qualcomm_firehose(cdc, xmlparser(), cfg,
log, None, sahara.serial,args.skipresponse, getluns(args.memory))
fh = qualcomm_firehose(cdc, xmlparser(), cfg, log_level, args.devicemodel, sahara.serial,args.skipresponse,
getluns(args.memory))
supported_functions = fh.connect(0)
log.info("[FIREHOSE] connected ok. supported functions: %s" %
logging.info("[FIREHOSE] connected ok. supported functions: %s" %
supported_functions)
log.info("[FIREHOSE] raw programming...")
logging.info("[FIREHOSE] raw programming...")
for xml in args.rawprogram:
log.info("[FIREHOSE] programming %s" % xml)
logging.info("[FIREHOSE] programming %s" % xml)
fl = open(xml, "r")
for evt, elem in ET.iterparse(fl, events=["end"]):
if elem.tag == "program":
@ -167,18 +194,18 @@ if __name__ == '__main__':
filename = os.path.join(
args.imagedir, elem.get("filename"))
if not os.path.isfile(filename):
log.error("[ERROR] %s not existed!" % filename)
logging.error("[ERROR] %s not existed!" % filename)
sys.exit(1)
partition_number = elem.get("physical_partition_number")
start_sector = elem.get("start_sector")
log.info("[FIREHOSE] programming {filename} to partition({partition})@sector({start_sector})...".format(
logging.info("[FIREHOSE] programming {filename} to partition({partition})@sector({start_sector})...".format(
filename=filename, partition=partition_number, start_sector=start_sector))
fh.cmd_program(partition_number, start_sector, filename)
log.info("[FIREHOSE] raw programming ok.")
logging.info("[FIREHOSE] raw programming ok.")
log.info("[FIREHOSE] patching...")
logging.info("[FIREHOSE] patching...")
for xml in args.patch:
log.info("[FIREHOSE] patching with %s" % xml)
logging.info("[FIREHOSE] patching with %s" % xml)
fl = open(xml, "r")
for evt, elem in ET.iterparse(fl, events=["end"]):
if elem.tag == "patch":
@ -187,23 +214,22 @@ if __name__ == '__main__':
continue
start_sector = elem.get("start_sector")
size_in_bytes = elem.get("size_in_bytes")
log.info("[FIREHOSE] patching {filename} sector({start_sector}), size={size_in_bytes}".format(
logging.info("[FIREHOSE] 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(
CMD = "<?xml version=\"1.0\" ?><data>\n<{content} /></data>".format(
content=content)
print(cmd)
fh.xmlsend(cmd)
log.info("[FIREHOSE] patching ok")
print(CMD)
fh.xmlsend(CMD)
logging.info("[FIREHOSE] patching ok")
bootable = find_bootable_partition(args.rawprogram)
if bootable != -1:
if fh.cmd_setbootablestoragedrive(bootable):
log.info("[FIREHOSE] partition({partition}) is now bootable\n". format(partition=bootable));
logging.info("[FIREHOSE] partition({partition}) is now bootable\n".format(partition=bootable));
else:
log.info("[FIREHOSE] set partition({partition}) as bootable failed\n". format(partition=bootable));
logging.info("[FIREHOSE] set partition({partition}) as bootable failed\n".format(partition=bootable));
log.info("[INFO] reset target...")
logging.info("[INFO] reset target...")
fh.cmd_reset()
log.info("[INFO] QFIL ok!")
logging.info("[INFO] QFIL ok!")

View file

@ -1,7 +1,29 @@
pyusb
pyserial
docopt
pylzma
pyusb>=1.1.0
pyserial>=3.4
docopt>=0.6.2
pylzma>=0.5.0
pycryptodome
qrcode
colorama~=0.4.4
enum34>=1.1.10
capstone>=4.0.2
keystone-engine
unicorn>=1.0.2
lxml>=4.6.1
future>=0.18.2
matplotlib>=3.3.3
numpy>=1.19.4
idna>=2.10
dnspython>=2.0.0
pyasn1>=0.4.8
ldap3>=2.8.1
asn1crypto>=1.4.0
pytz>=2020.4
qiling>=1.2
six>=1.15.0
requests>=2.25.0
grequests>=0.6.0
PyQt5~=5.14.1
coverage~=5.2
simplejson~=3.16.0