mirror of
https://github.com/bkerler/edl.git
synced 2024-11-24 00:17:52 -05:00
Add streaming mode
This commit is contained in:
parent
1eb773f553
commit
036bc63efd
38 changed files with 5769 additions and 4268 deletions
0
Config/nvitems.xml
Normal file → Executable file
0
Config/nvitems.xml
Normal file → Executable 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
0
Drivers/50-android.rules
Normal file → Executable file
0
Drivers/51-edl.rules
Normal file → Executable file
0
Drivers/51-edl.rules
Normal file → Executable 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
0
Example/benchmark.xml
Normal file → Executable 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"
|
||||
]
|
||||
|
|
97
Library/Modules/generic.py
Normal file
97
Library/Modules/generic.py
Normal 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)
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
689
Library/firehose_client.py
Normal 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
|
277
Library/gpt.py
277
Library/gpt.py
|
@ -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}")
|
||||
|
|
156
Library/hdlc.py
156
Library/hdlc.py
|
@ -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))
|
||||
|
|
|
@ -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
846
Library/nand_config.py
Normal 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()}
|
|
@ -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"
|
||||
|
|
|
@ -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
1332
Library/streaming.py
1332
Library/streaming.py
File diff suppressed because it is too large
Load diff
414
Library/streaming_client.py
Normal file
414
Library/streaming_client.py
Normal 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
|
|
@ -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()
|
||||
|
||||
|
|
387
Library/utils.py
387
Library/utils.py
|
@ -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')
|
||||
|
|
BIN
Loaders/qualcomm/patched/ENPRG9x35p.bin
Normal file
BIN
Loaders/qualcomm/patched/ENPRG9x35p.bin
Normal file
Binary file not shown.
BIN
Loaders/qualcomm/patched/ENPRG9x45p.bin
Normal file
BIN
Loaders/qualcomm/patched/ENPRG9x45p.bin
Normal file
Binary file not shown.
BIN
Loaders/qualcomm/patched/NPRG9x35p.bin
Normal file
BIN
Loaders/qualcomm/patched/NPRG9x35p.bin
Normal file
Binary file not shown.
BIN
Loaders/qualcomm/patched/NPRG9x45p.bin
Normal file
BIN
Loaders/qualcomm/patched/NPRG9x45p.bin
Normal file
Binary file not shown.
Binary file not shown.
30
README.md
30
README.md
|
@ -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.
|
||||
|
|
369
fhloaderparse.py
369
fhloaderparse.py
|
@ -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
22
modem/netgear_boottodwnload.py
Executable 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
29
modem/quectel_adb.py
Executable 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
18
modem/sierra_boottodwnload.py
Executable 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
166
qfil.py
|
@ -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!")
|
||||
|
|
|
@ -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
|
Loading…
Reference in a new issue