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
@@ -0,0 +1,136 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Static verification of patch v2 (capstone).
|
||||
|
||||
Checks:
|
||||
1. callback registration at 0x4efe28/2c now points to cave 0x41b8b0
|
||||
2. cave disassembles without obvious corruption; entry guard present
|
||||
3. key globals/strings land in the expected .data zero region
|
||||
4. diff vs stock confined to the cave + registration bytes
|
||||
"""
|
||||
import sys, struct
|
||||
from capstone import Cs, CS_ARCH_MIPS, CS_MODE_MIPS32, CS_MODE_LITTLE_ENDIAN
|
||||
|
||||
STOCK = "hiby_player_stock"
|
||||
PATCHED = "hiby_player_patched_v2"
|
||||
|
||||
def rd(fn, off, n):
|
||||
with open(fn, "rb") as f:
|
||||
f.seek(off)
|
||||
return f.read(n)
|
||||
|
||||
def disasm(data, vaddr):
|
||||
md = Cs(CS_ARCH_MIPS, CS_MODE_MIPS32 + CS_MODE_LITTLE_ENDIAN)
|
||||
return list(md.disasm(data, vaddr))
|
||||
|
||||
ok = True
|
||||
def check(cond, msg):
|
||||
global ok
|
||||
print(("PASS " if cond else "FAIL ") + msg)
|
||||
if not cond:
|
||||
ok = False
|
||||
|
||||
# 1. callback registration
|
||||
pat = rd(PATCHED, 0x4EFE28 - 0x400000, 8)
|
||||
lui = struct.unpack_from("<I", pat, 0)[0]
|
||||
add = struct.unpack_from("<I", pat, 4)[0]
|
||||
check(lui == 0x3C050041, f"0x4efe28 lui $a1, 0x41 (got {lui:#010x})")
|
||||
check(add == 0x24A5B8B0, f"0x4efe2c addiu $a1, $a1, 0xb8b0 (got {add:#010x})")
|
||||
|
||||
# 2. cave disassembly
|
||||
CAVE = 0x41B8B0
|
||||
cave = rd(PATCHED, CAVE - 0x400000, 0x1000)
|
||||
insns = disasm(cave, CAVE)
|
||||
print(f"\ncave disasm ({len(insns)} instructions):")
|
||||
for ins in insns[:14]:
|
||||
print(f" {ins.address:#010x}: {ins.mnemonic} {ins.op_str}")
|
||||
|
||||
# entry guard structure (after gp setup): lw $v0,0($a2); slti $v1,$v0,7; bne...
|
||||
first = insns[2]
|
||||
check(first.mnemonic == "lw" and "v0" in first.op_str and "a2" in first.op_str,
|
||||
f"cave[2] = lw $v0, 0($a2) (got '{first.mnemonic} {first.op_str}')")
|
||||
check(insns[3].mnemonic == "slti", f"cave[3] = slti (type<7 guard) (got '{insns[3].mnemonic} {insns[3].op_str}')")
|
||||
|
||||
# scan for raw syscalls: they should appear in launch()
|
||||
syscalls = [(i.address, i.mnemonic) for i in insns if i.mnemonic == "syscall"]
|
||||
check(len(syscalls) >= 4, f"syscall instructions present ({len(syscalls)})")
|
||||
|
||||
# find addiu $v0,$zero,0xN patterns for fork/execve/waitpid (capstone prints hex)
|
||||
def find_li_v0(val):
|
||||
s = hex(val)
|
||||
for i in range(len(insns) - 1):
|
||||
a, b = insns[i], insns[i + 1]
|
||||
if a.mnemonic == "addiu" and "$v0" in a.op_str and s in a.op_str:
|
||||
return True
|
||||
return False
|
||||
check(find_li_v0(4002), "fork syscall number 4002 (0xfa2) present")
|
||||
check(find_li_v0(4011), "execve syscall number 4011 (0xfab) present")
|
||||
check(find_li_v0(4007), "waitpid syscall number 4007 (0xfa7) present")
|
||||
|
||||
# key control-flow references
|
||||
def has_call(target):
|
||||
for i in insns:
|
||||
if i.mnemonic == "jal" and hex(target) in i.op_str:
|
||||
return True
|
||||
return False
|
||||
check(has_call(0x49BE00), "calls 0x49be00 (create view)")
|
||||
check(has_call(0x46C800), "calls 0x46c800 (activate view)")
|
||||
check(has_call(0x46C2C0), "calls 0x46c2c0 (set callback)")
|
||||
check(has_call(0x8E6C00), "calls opendir (0x8e6c00)")
|
||||
check(has_call(0x8E6240), "calls access (0x8e6240)")
|
||||
|
||||
# v2.2: watchdog integration
|
||||
import re as _re
|
||||
def find_li_v0x(val):
|
||||
s = hex(val)
|
||||
for i in range(len(insns) - 1):
|
||||
a, b = insns[i], insns[i + 1]
|
||||
if a.mnemonic == "addiu" and "$v0" in a.op_str and s in a.op_str:
|
||||
return True
|
||||
return False
|
||||
check(find_li_v0x(4037), "kill syscall 4037 present (watchdog cleanup)")
|
||||
check(find_li_v0x(4002) and find_li_v0x(4011), "double fork (app+watchdog) syscalls present")
|
||||
wds = rd(PATCHED, 0x41C8B0 - 0x400000, 400)
|
||||
check(b"/usr/data/meow_watchdog\x00" in wds, "watchdog path string present")
|
||||
# itoa: divu + mflo/mfhi present
|
||||
divu = [i for i in insns if i.mnemonic == "divu"]
|
||||
mflo = [i for i in insns if i.mnemonic == "mflo"]
|
||||
check(len(divu) >= 1 and len(mflo) >= 1, f"itoa divu/mflo present ({len(divu)}/{len(mflo)})")
|
||||
check(has_call(0x8E65B0), "calls readdir (0x8e65b0)")
|
||||
|
||||
# 3. string area
|
||||
s = rd(PATCHED, 0x41C8B0 - 0x400000, 300) # STR_BASE = CAVE+0x1000 = 0x41c8b0
|
||||
check(b"hiby_apps_main\x00" in s, "string 'hiby_apps_main' present")
|
||||
check(b"/usr/data/mnt/sd_0/MeowAPPs\x00" in s, "string MeowAPPs dir present")
|
||||
check(b"/proc/mounts\x00" in s, "string /proc/mounts present")
|
||||
check("未检测到存储卡".encode() in s, "utf8 no-card hint present")
|
||||
check("无可用应用".encode() in s, "utf8 no-app hint present")
|
||||
check(b'"name":\x00' in s and b'"exec":\x00' in s, "json key strings present")
|
||||
|
||||
# 4. diff vs stock
|
||||
st = open(STOCK, "rb").read()
|
||||
pt = open(PATCHED, "rb").read()
|
||||
assert len(st) == len(pt)
|
||||
diffs = [i for i in range(len(st)) if st[i] != pt[i]]
|
||||
regions = []
|
||||
for d in diffs:
|
||||
if regions and d - regions[-1][1] <= 4:
|
||||
regions[-1][1] = d
|
||||
else:
|
||||
regions.append([d, d])
|
||||
print(f"\ndiff bytes vs stock: {len(diffs)}, regions:")
|
||||
for r in regions:
|
||||
print(f" file {r[0]:#x}-{r[1]:#x} ({r[1]-r[0]+1} B)")
|
||||
# must be exactly 2 regions: registration (0xE28/0xE2c) + cave (0x1B8B0..)
|
||||
# cave code + strings extend from CAVE to CAVE+0x1000+~0x120 (strings)
|
||||
CAVE_END = CAVE + 0x1000 + 0x160
|
||||
ok_regions = all(
|
||||
(0x4EFE28 - 0x400000 <= r[0] <= 0x4EFE30 - 0x400000) or
|
||||
(0x47B820 - 0x400000 <= r[0] <= 0x47B824 - 0x400000) or
|
||||
(0x436FC0 - 0x400000 <= r[0] <= 0x436FC4 - 0x400000) or
|
||||
(CAVE - 0x400000 <= r[0] and r[1] <= CAVE_END - 0x400000)
|
||||
for r in regions
|
||||
)
|
||||
check(ok_regions, "diff confined to registration + cave region")
|
||||
|
||||
print("\nRESULT:", "OK" if ok else "FAILED")
|
||||
sys.exit(0 if ok else 1)
|
||||
Reference in new issue
Block a user