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 软件仓库
This commit is contained in:
commit
245bee2946
136 files changed
+32730
No files matched your search
+139
@@ -0,0 +1,139 @@
|
||||
#!/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}")
|
||||
Reference in new issue
Block a user