Last active
April 16, 2024 10:15
-
-
Save lab313ru/9be731c4800ba2ae09982d273c1efa07 to your computer and use it in GitHub Desktop.
Dump ext2 filesystem via U-Boot mmc menu
This file contains 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 | |
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 .+$') | |
IGNORE = ['.qmlc', '.jsc', '.wav', '.caf', '.mkv', '.png', '.mo', '.css', '.pdf'] | |
IGNORE_NAMES = tuple(['libQt5']) | |
IGNORE_DIRS = ['.//usr/share/zoneinfo', './/usr/lib/gstreamer-1.0', './/usr/lib/locale'] | |
RAM_ADDR = 0x10000000 | |
BLOCK_SIZE = 0x1000 | |
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(errors='replace') | |
return lines | |
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]) | |
fn, fe = os.path.splitext(path) | |
fn = os.path.basename(fn) | |
if size == 0 or fe in IGNORE or fn.startswith(IGNORE_NAMES): | |
with open(w_path, 'wb') as w: | |
pass | |
return | |
if os.path.exists(w_path) and os.path.getsize(w_path) == size: | |
return | |
res = exec_cmd(s, b'ext2load mmc 1:2 %x %s' % (RAM_ADDR, path.encode())) | |
m = FILE_GOOD_R.match(res[1]) | |
real_sz = -1 | |
if m is not None: | |
real_sz = m.group(1) | |
if real_sz == -1: | |
with open(w_path, 'wb') as w: | |
pass | |
return | |
off = 0 | |
bs = min(size, BLOCK_SIZE) | |
with open(w_path, 'wb') as w: | |
with tqdm(total=size) as pb: | |
lines = exec_cmd(s, b'md.b %x %x' % (RAM_ADDR + off, bs))[1:] | |
buf = parse_hex_lines(lines, bs) | |
w.write(buf) | |
pb.update(bs) | |
size -= bs | |
off += 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 | |
off += blk | |
def dump_mmc_1_2(s, root='./', level=0): | |
os.makedirs(root, exist_ok=True) | |
if root in IGNORE_DIRS: | |
return | |
res = exec_cmd(s, b'ext2ls mmc 1:2 %s' % root.encode()) | |
res = res[1:] | |
count = len(res) - 2 | |
dirs = [] | |
for i, line in enumerate(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[%04d/%04d] %s %d' % (' ' * level, i + 1 - 2, count, name, size)) | |
dump_file(s, '/'.join([root, name]), size) | |
continue | |
# do sym | |
size = int(m.group(1)) | |
name = m.group(2) | |
print('%s[%04d/%04d] <%s> %d' % (' ' * level, i + 1 - 2, count, name, size)) | |
dump_file(s, '/'.join([root, name]), 0) | |
continue | |
# do dir | |
name = m.group(2) | |
if name not in ['.', '..']: | |
print('%s[%04d/%04d] [%s]' % (' ' * level, i + 1 - 2, count, 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) | |
dump_mmc_1_2(s) | |
s.close() | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment