Created
July 14, 2025 08:44
-
-
Save lab313ru/9b461dd532f277526a63521b24b07f18 to your computer and use it in GitHub Desktop.
Dump MMC via UBoot
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import os.path | |
| import re | |
| import sys | |
| import struct | |
| import serial | |
| from tqdm import tqdm | |
| import re | |
| # 1.8192 .32768 .f4debf7b-01.0c | |
| # | |
| # 2.40960 .655360 .f4debf7b-02.83 | |
| # | |
| # 3.696320 .655360 .f4debf7b-03.83 | |
| # | |
| # 4.1351680 .6381568 .f4debf7b-04.83 | |
| PART_R = re.compile(r'[ \t]+(\d+)[ \t]+(\d+)[ \t]+(\d+)[ \t]+([0-9a-f\-]+)[ \t]+([0-9a-f]+)') | |
| DIR_R = re.compile(r'^<DIR>[ \t]+(\d+)[ \t]+(.+)$') | |
| FILE_R = re.compile(r'^[ \t]+(\d+)[ \t]+(.+)$') | |
| SYM_R = re.compile(r'^<SYM>[ \t]+(\d+)[ \t]+(.+)$') | |
| FILE_GOOD_R = re.compile(r'(\d+) bytes read in .+$') | |
| def exec_cmd(s, cmd): | |
| # print('executing %s' % cmd.decode()) | |
| s.write(b'%s\n' % cmd) | |
| lines = [] | |
| line = '' | |
| while True: | |
| b = s.read() | |
| if b in [b'\n', b'\r']: | |
| line = line.rstrip('\r\n') | |
| if len(line): | |
| lines.append(line) | |
| line = '' | |
| continue | |
| elif b == b'' and line.startswith('=> '): | |
| break | |
| line += b.decode('utf-8') | |
| return lines | |
| def read_part(s, part): | |
| start, count = part['start'], part['count'] | |
| res = exec_cmd(s, b'mmc read 10000000 %x %x' % (start, count)) | |
| print(res) | |
| def dump_part(s, part): | |
| size = 770 # 0x200 * part['count'] | |
| off = 0 | |
| bs = 0x1000 | |
| # with open('dump_part_%d.bin' % part['index'], 'wb') as w: | |
| with open('shadow.bin', 'wb') as w: | |
| with tqdm(total=size) as pb: | |
| while size > 0: | |
| lines = exec_cmd(s, b'md.b %x %x' % (0x10000000 + off, min(bs, size)))[1:] | |
| for line in lines: | |
| data, _ = line.split(" ", maxsplit=1) | |
| _, strdata = data.split(maxsplit=1) | |
| # addr = int.from_bytes(bytes.fromhex(straddr[:-1]), byteorder='big') | |
| data = bytes.fromhex(strdata) | |
| pb.update(0x10) | |
| w.write(data) | |
| size -= 0x10 | |
| off += bs | |
| def parse_hex_lines(lines, max_size): | |
| res = bytearray() | |
| for line in lines: | |
| data, _ = line.split(" ", maxsplit=1) | |
| _, strdata = data.split(maxsplit=1) | |
| data = bytes.fromhex(strdata) | |
| res.extend(data) | |
| return bytes(res)[:max_size] | |
| def dump_file(s, path, size): | |
| w_path = '/'.join(['./', path]) | |
| if size == 0: | |
| with open(w_path, 'wb') as w: | |
| pass | |
| return | |
| res = exec_cmd(s, b'ext2load mmc 1:2 10000000 %s' % path.encode()) | |
| m = FILE_GOOD_R.match(res[1]) | |
| real_sz = -1 | |
| if m is not None: | |
| real_sz = m.group(1) | |
| assert real_sz != -1 | |
| off = 0 | |
| bs = min(size, 0x1000) | |
| with open(w_path, 'wb') as w: | |
| with tqdm(total=size) as pb: | |
| lines = exec_cmd(s, b'md.b %x %x' % (0x10000000 + off, bs))[1:] | |
| buf = parse_hex_lines(lines, bs) | |
| w.write(buf) | |
| pb.update(bs) | |
| size -= bs | |
| while size > 0: | |
| lines = exec_cmd(s, b'\n') | |
| blk = min(size, bs) | |
| buf = parse_hex_lines(lines, blk) | |
| w.write(buf) | |
| pb.update(blk) | |
| size -= blk | |
| def dump_mmc_1_2(s, root='./', level=0): | |
| os.makedirs(root, exist_ok=True) | |
| res = exec_cmd(s, b'ext2ls mmc 1:2 %s' % root.encode()) | |
| res = res[1:] | |
| dirs = [] | |
| for line in res: | |
| m = DIR_R.match(line) | |
| if not m: | |
| m = SYM_R.match(line) | |
| if not m: | |
| m = FILE_R.match(line) | |
| if not m: | |
| continue | |
| # do file | |
| size = int(m.group(1)) | |
| name = m.group(2) | |
| print('%s%s %d' % (' ' * level, name, size)) | |
| dump_file(s, '/'.join([root, name]), size) | |
| continue | |
| # do sym | |
| size = int(m.group(1)) | |
| name = m.group(2) | |
| print('%s<%s> %d' % (' ' * level, name, size)) | |
| dump_file(s, '/'.join([root, name]), 0) | |
| continue | |
| # do dir | |
| name = m.group(2) | |
| if name not in ['.', '..']: | |
| print('%s[%s]' % (' ' * level, name)) | |
| dump_mmc_1_2(s, '/'.join([root, name]), level+1) | |
| # return sub_dirs | |
| def main(): | |
| s = serial.Serial('COM15', 115200, timeout=0.001) | |
| # s = serial.Serial('/dev/ttyUSB0', 115200, timeout=0.001) | |
| os.sep = '/' | |
| dump_mmc_1_2(s) | |
| # dump_part(s, '1') | |
| exit() | |
| res = exec_cmd(s, b'mmc part') | |
| parts = [] | |
| for line in res: | |
| m = PART_R.match(line) | |
| if not m: | |
| continue | |
| part = { | |
| 'index': int(m.group(1)), | |
| 'start': int(m.group(2)), | |
| 'count': int(m.group(3)), | |
| 'uuid': m.group(4), | |
| 'type': int(m.group(5), 16) | |
| } | |
| parts.append(part) | |
| read_part(s, parts[0]) | |
| dump_part(s, parts[0]) | |
| s.close() | |
| if __name__ == '__main__': | |
| main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment