This commit is contained in:
Bjoern Kerler 2020-02-13 14:09:53 +01:00
parent 963a774b74
commit db91abc8c3
4 changed files with 202 additions and 23 deletions

View file

@ -5,7 +5,7 @@ from Library.utils import *
from Library.gpt import gpt
try:
from Library.oppo import oppo
except:
except Exception as e:
pass
logger = logging.getLogger(__name__)
@ -199,6 +199,36 @@ class qualcomm_firehose:
self.xmlsend(data, False)
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."/>
'''
data = f"<?xml version=\"1.0\" ?><data>\n" + \
f"<patch SECTOR_SIZE_IN_BYTES=\"{self.cfg.SECTOR_SIZE_IN_BYTES}\"" + \
f" byte_offset=\"{byte_offset}\"" + \
f" filename=\"DISK\"" + \
f" physical_partition_number=\"{physical_partition_number}\"" + \
f" size_in_bytes=\"{size_in_bytes}\" " + \
f" start_sector=\"{start_sector}\" " + \
f" value=\"{value}\" "
data += f"/>\n</data>"
if self.ops is not None and "setprojmodel" in self.supported_functions:
pk, token = self.ops.generatetoken(True)
data += f"pk=\"{pk}\" token=\"{token}\" "
rsp = self.xmlsend(data)
if rsp[0] == True:
if display:
logger.info(f"Patch:\n--------------------\n")
logger.info(rsp[1])
return True
else:
logger.warning("Patch command isn't supported.")
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
@ -272,6 +302,78 @@ class qualcomm_firehose:
return False
return False
def cmd_program_buffer(self, physical_partition_number, start_sector, wfdata, display=True):
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:
logger.info(
f"\nWriting to physical partition {str(physical_partition_number)}, 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}\"" + \
f" physical_partition_number=\"{physical_partition_number}\"" + \
f" start_sector=\"{start_sector}\" "
if self.ops is not None and "setprojmodel" in self.supported_functions:
pk, token = self.ops.generatetoken(True)
data += f"pk=\"{pk}\" token=\"{token}\" "
data += f"/>\n</data>"
rsp = self.xmlsend(data)
pos = 0
prog = 0
if display:
print_progress(prog, 100, prefix='Progress:', suffix='Complete', bar_length=50)
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
fpos=0
fsize=len(wfdata)
while fsize > 0:
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]
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
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 display:
print_progress(prog, 100, prefix='Progress:', suffix='Complete', bar_length=50)
if display and prog != 100:
print_progress(100, 100, prefix='Progress:', suffix='Complete', bar_length=50)
self.cdc.write(b'', self.cfg.MaxPayloadSizeToTargetInBytes)
time.sleep(0.2)
info = self.xml.getlog(self.cdc.read(self.cfg.MaxXMLSizeInBytes))
rsp = self.xml.getresponse(self.cdc.read(self.cfg.MaxXMLSizeInBytes))
if "value" in rsp:
if rsp["value"] == "ACK":
return True
else:
logger.error(f"Error:")
for line in info:
logger.error(line)
return False
else:
return True
else:
logger.error(f"Error:{rsp}")
return False
return False
def cmd_erase(self, physical_partition_number, start_sector, num_partition_sectors, display=True):
if display:
logger.info(
@ -393,7 +495,7 @@ class qualcomm_firehose:
if rsp[1]["value"] == "NAK":
if display:
logger.error(rsp[2].decode('utf-8'))
return ""
return b""
bytesToRead = self.cfg.SECTOR_SIZE_IN_BYTES * num_partition_sectors
total = bytesToRead
dataread = 0
@ -423,15 +525,15 @@ class qualcomm_firehose:
logger.error(f"Error:")
for line in info:
logger.error(line)
return ""
return b""
else:
logger.error(f"Error:{rsp[2]}")
return ""
return b""
return resData #Do not remove, needed for oppo
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)
if data == "":
if data == b"":
return None, None
guid_gpt = gpt(
num_part_entries=gpt_num_part_entries,
@ -444,6 +546,8 @@ class qualcomm_firehose:
if sectors==0:
return None, None
data = self.cmd_read_buffer(lun, 0, sectors, False)
if data==b"":
return None, None
guid_gpt.parse(data, self.cfg.SECTOR_SIZE_IN_BYTES)
return data, guid_gpt
else:
@ -451,7 +555,7 @@ class qualcomm_firehose:
def get_backup_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)
if data == "":
if data == b"":
return None
guid_gpt = gpt(
num_part_entries=gpt_num_part_entries,
@ -462,6 +566,8 @@ 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"":
return None
return data
else:
return None
@ -489,6 +595,8 @@ class qualcomm_firehose:
if info==[]:
info=self.cmd_nop()
supfunc = False
self.supported_functions = ['program','write','read','patch']
'''
self.supported_functions = []
for line in info:
if "chip serial num" in line.lower():
@ -505,10 +613,10 @@ class qualcomm_firehose:
self.supported_functions.append(rs)
if "supported functions" in line.lower():
supfunc = True
'''
try:
self.ops = oppo(self,projid=self.oppoprjid, serials=[self.serial, self.serial])
except:
except Exception as e:
self.ops = None
data=self.cdc.read() #logbuf
try:

66
edl.py
View file

@ -43,6 +43,8 @@ Usage:
edl.py rawxml <xmlstring> [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--oppo=projid]
edl.py reset [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid]
edl.py nop [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid]
edl.py oemunlock [--memory=memtype] [--lun=lun] [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid]
edl.py ops <mode> [--memory=memtype] [--lun=lun] [--loader=filename] [--debugmode] [--vid=vid] [--pid=pid] [--oppo=projid]
Description:
server [--tcpport=portnumber] # Run tcp/ip server
@ -707,6 +709,8 @@ def do_firehose_server(mainargs, cdc, sahara):
partition.sectors - (0x4000 // cfg.SECTOR_SIZE_IN_BYTES)),
(0x4000 // cfg.SECTOR_SIZE_IN_BYTES),
filename)
if data==b"":
continue
val = struct.unpack("<I", data[:4])[0]
if (val & 0xFFFFFFF0) == 0xD0B5B1C0:
with open(filename, "wb") as wf:
@ -1384,6 +1388,8 @@ def handle_firehose(arguments, cdc, sahara, verbose):
partition.sector + (
partition.sectors - (0x4000 // cfg.SECTOR_SIZE_IN_BYTES)),
(0x4000 // cfg.SECTOR_SIZE_IN_BYTES), filename)
if data==b"":
continue
val = struct.unpack("<I", data[:4])[0]
if (val & 0xFFFFFFF0) == 0xD0B5B1C0:
with open(filename, "wb") as wf:
@ -1703,6 +1709,66 @@ def handle_firehose(arguments, cdc, sahara, verbose):
elif arguments["server"]:
do_firehose_server(arguments, cdc, sahara)
exit(0)
elif arguments["oemunlock"]:
partition = "config"
res=detect_partition(fh, arguments, partition)
if res[0]==True:
lun=res[1]
rpartition=res[2]
offsettopatch=0x7FFFF
sector=rpartition.sector + (offsettopatch//cfg.SECTOR_SIZE_IN_BYTES)
offset=offsettopatch%cfg.SECTOR_SIZE_IN_BYTES
value=0x1
size_in_bytes=1
if 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:
fpartitions=res[1]
logger.error(f"Error: Couldn't detect partition: {partition}\nAvailable partitions:")
for lun in fpartitions:
for rpartition in fpartitions[lun]:
if arguments["--memory"].lower() == "emmc":
logger.error("\t" + rpartition)
else:
logger.error(lun + ":\t" + rpartition)
exit(0)
elif arguments["ops"]:
if fh.ops==None:
logger.error("Feature is not supported")
exit(0)
partition = "param"
mode=arguments["<mode>"]
enable=False
if mode=="enable":
enable=True
elif mode=="disable":
enable=False
else:
logger.error("Unknown mode given. Available are: enable, disable.")
exit(0)
res=detect_partition(fh, arguments, partition)
if res[0]==True:
lun=res[1]
rpartition=res[2]
paramdata=fh.cmd_read_buffer(lun,rpartition.sector,rpartition.sectors,False)
if paramdata==b"":
logger.error("Error on reading param partition.")
exit(1)
paramdata=fh.ops.enable_ops(paramdata,enable)
if fh.cmd_program_buffer(lun,rpartition.sector,paramdata,False):
print("Successfully set mode")
else:
logger.error("Error on writing param partition")
else:
fpartitions=res[1]
logger.error(f"Error: Couldn't detect partition: {partition}\nAvailable partitions:")
for lun in fpartitions:
for rpartition in fpartitions[lun]:
if arguments["--memory"].lower() == "emmc":
logger.error("\t"+rpartition)
else:
logger.error(lun + ":\t" + rpartition)
exit(0)
else:
logger.error("Unknown/Missing command, a command is required.")
exit(0)

View file

@ -123,11 +123,12 @@ def extract_hdr(memsection,si,mm,code_size,signature_size):
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
if mm[signatureoffset] != 0x30:
print("Error on " + si.filename + ", unknown signaturelength")
try:
if mm[signatureoffset] != 0x30:
print("Error on " + si.filename + ", unknown signaturelength")
return None
except:
return None
if len(mm) < signatureoffset + 4:
print("Signature error on " + si.filename)
return None
@ -201,17 +202,20 @@ def extract_old_hdr(memsection,si,mm,code_size,signature_size):
def main(argv):
f = []
path = ""
if (len(argv)<2):
print("Usage: ./fhloaderparse.py [FHLoaderDir]")
if (len(argv)<3):
print("Usage: ./fhloaderparse.py [FHLoaderDir] [OutputDir]")
exit(0)
else:
path = argv[1]
outputdir = argv[2]
if not os.path.exists(outputdir):
os.mkdir(outputdir)
for (dirpath, dirnames, filenames) in walk(path):
for filename in filenames:
f.append(os.path.join(dirpath, filename))
hashes={}
for (dirpath, dirnames, filenames) in walk('Loaders'):
for (dirpath, dirnames, filenames) in walk(outputdir):
for filename in filenames:
fname=os.path.join(dirpath, filename)
with open(fname,'rb') as rf:
@ -221,8 +225,12 @@ def main(argv):
hashes[sha256.digest()]=fname
filelist = []
rt=open("Loaders/"+argv[1]+".log","w")
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
for ext in extensions:
@ -283,9 +291,6 @@ def main(argv):
if not os.path.exists("Loaders/unknown"):
os.makedirs("Loaders/unknown")
sorted_x = sorted(filelist, key=lambda x: (x.hw_id, -x.filesize))
class loaderinfo:
hw_id=''
@ -304,9 +309,9 @@ def main(argv):
if (lf not in loaderlists):
loaderlists[lf]=item.filename
print(info)
copyfile(item.filename,"Loaders/"+lf.hw_id+"_"+lf.pk_hash[0:16]+"_FHPRG.bin")
copyfile(item.filename,os.path.join(outputdir,lf.hw_id+"_"+lf.pk_hash[0:16]+"_FHPRG.bin"))
else:
copyfile(item.filename,"Loaders/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:]+"_"+lf.pk_hash[0:16]+"_FHPRG.bin"))
else:
print(item.filename+" does already exist. Skipping")
try:
@ -321,7 +326,7 @@ def main(argv):
info += "\tOEMVER:" + item.oem_version + "\tQCVER:" + item.qc_version + "\tVAR:" + item.image_variant
print(info)
rt.write(info+"\n")
copyfile(item.filename,"Loaders/unknown/"+item.filename[item.filename.rfind("\\")+1:])
copyfile(item.filename,os.path.join(outputdir,"unknown",item.filename[item.filename.rfind("\\")+1:]))
rt.close()
main(sys.argv)

View file

@ -6,7 +6,7 @@ class client():
self.commands=[]
def send(self):
self.tcp = tcpclient(1340) #define Port 1340
self.tcp = tcpclient()
self.tcp.sendcommands(self.commands)
def read(self,src):