Files
MeowOS Dev 245bee2946 MeowOS for HiBy R3 Pro II — 公共发布版本(历史已重置)
• 全新单提交:清除含敏感信息的旧历史(sudo 口令、内网 IP、SSH 密钥路径、热点 SSID、设备 MAC)
• 本地开发文档/测试记录/构建脚本全部移入 gitignored 的 devdocs/ 与 scripts/build/(不入库)
• 保留:MeowOS 源码(launcher/watchdog/bootmenu/meow_svcd/SDK)、项目规范文档、mips-repo
增补组件:SDK 统一日志+通知 API、meow_svcd 服务管理器、mips-repo 软件仓库
2026-08-30 01:12:34 +08:00

140 lines
5.4 KiB
Python

#!/usr/bin/env python3
"""hiby_player MIPS32 static analysis helpers (capstone-based)."""
import sys, struct, subprocess
CAP_VER = None
try:
from capstone import Cs, CS_ARCH_MIPS, CS_MODE_MIPS32, CS_MODE_LITTLE_ENDIAN, CS_OP_MEM, CS_OP_IMM, CS_OP_REG
CAP_VER = "capstone"
except ImportError:
CAP_VER = None
BIN = "/home/Aska/Project/R3ProII/unpacked_v14/squashfs-root/usr/bin/hiby_player"
def load_segments():
"""Return list of (vaddr, size, bytes, name) for executable/rodata segments."""
with open(BIN, "rb") as f:
data = f.read()
segs = []
out = subprocess.run(["readelf", "-lW", BIN], capture_output=True, text=True).stdout
for line in out.splitlines():
parts = line.split()
if len(parts) >= 9 and parts[0] == "LOAD":
# Type Off VAddr PAddr FileSiz MemSiz Flg Align (Flg may split into "R E")
off, vaddr = int(parts[1], 16), int(parts[2], 16)
filesz = int(parts[4], 16)
flags = "".join(parts[6:8])
segs.append((vaddr, filesz, data[off:off + filesz], flags))
return segs
def text_ranges():
"""Executable section ranges: [(vaddr, size)] for .init/.text/.MIPS.stubs/.fini."""
out = []
res = subprocess.run(["readelf", "-SW", BIN], capture_output=True, text=True).stdout
for line in res.splitlines():
parts = line.split()
if len(parts) >= 7 and parts[1] in (".init", ".text", ".MIPS.stubs", ".fini"):
vaddr, size = int(parts[3], 16), int(parts[5], 16)
out.append((vaddr, size))
return out
def disasm_all():
"""Full disassembly of executable sections -> list of (addr, mnem, op_str).
Skips invalid bytes by stepping 4 bytes (MIPS instructions are 4-byte aligned)."""
insns = []
md = Cs(CS_ARCH_MIPS, CS_MODE_MIPS32 + CS_MODE_LITTLE_ENDIAN)
md.detail = True
with open(BIN, "rb") as f:
data = f.read()
for vaddr, size in text_ranges():
off = vaddr - 0x400000
blob = data[off:off + size]
addr = vaddr
end = vaddr + size
while addr < end:
try:
got = list(md.disasm(blob[addr - vaddr:addr - vaddr + 64], addr, count=1))
except Exception:
got = []
if not got:
addr += 4
continue
ins = got[0]
insns.append((ins.address, ins.mnemonic, ins.op_str))
addr += ins.size
return insns
def strings_with_addr(minlen=5):
"""Extract ASCII strings with their virtual addresses from all segments."""
import re
out = []
for vaddr, size, blob, flags in load_segments():
for m in re.finditer(rb"[\x20-\x7e]{%d,}" % minlen, blob):
out.append((vaddr + m.start(), m.group().decode()))
return out
def find_xrefs(target_vaddrs, insns=None, window=12):
"""Find instructions that reference any of target_vaddrs via lui+addiu or jalr patterns.
Returns list of (ref_insn_addr, ref_insn_str, target_str, disasm_window)."""
if insns is None:
insns = disasm_all()
results = []
targets = {v: s for v, s in target_vaddrs}
# MIPS address load: lui reg, hi16 ; addiu/ori reg, reg, lo16
# Build map: reg -> (insn_addr, value_hi) after lui
# We'll scan for lui whose hi16 matches, then look ahead for addiu with lo16.
for i, (addr, mnem, op) in enumerate(insns):
if mnem != "lui":
continue
try:
reg, imm = op.replace(" ", "").split(",")
hi = int(imm, 16) << 16
except Exception:
continue
for j in range(i + 1, min(i + window, len(insns))):
a2, m2, o2 = insns[j]
if m2 in ("addiu", "ori") and o2.startswith(reg + ","):
try:
raw = o2.split(",")[-1].strip()
lo = int(raw, 16) if raw.startswith(("0x", "0X")) else int(raw, 0)
except Exception:
continue
full = (hi + (lo if lo < 0x8000 else lo - 0x10000)) if m2 == "addiu" else hi + lo
if full in targets:
ctx = " | ".join(f"{x:08x}: {mn} {op}" for x, mn, op in insns[max(0, i - 3):i + 3])
results.append((addr, f"lui {reg}, 0x{hi >> 16:x}", targets[full], ctx))
return results
def dump(insns, start, count=40):
for a, m, o in insns:
if a >= start:
print(f"{a:08x}: {m:8s} {o}")
count -= 1
if count <= 0:
break
if __name__ == "__main__":
cmd = sys.argv[1] if len(sys.argv) > 1 else "info"
if cmd == "xref":
# usage: xref <string-substr> [n]
substr = sys.argv[2]
n = int(sys.argv[3]) if len(sys.argv) > 3 else 30
sw = strings_with_addr(5)
hits = [(v, s) for v, s in sw if substr in s]
print(f"strings matching '{substr}': {len(hits)}")
for v, s in hits[:20]:
print(f" {v:08x}: {s[:90]}")
insns = disasm_all()
print(f"\nxrefs ({len(insns)} instructions):")
for ref_addr, ref_str, tstr, ctx in find_xrefs(hits, insns)[:n]:
print(f"\n@ {ref_addr:08x} [{ref_str}] -> '{tstr[:70]}'")
print(f" ctx: {ctx}")
elif cmd == "dump":
start = int(sys.argv[2], 16)
insns = disasm_all()
dump(insns, start, int(sys.argv[3]) if len(sys.argv) > 3 else 40)
elif cmd == "info":
segs = load_segments()
for v, s, b, f in segs:
print(f"LOAD vaddr={v:#x} filesz={s:#x} flags={f}")