Files
nxnative-easy/dm/host/tests/oe_notify.py
T
seedds d1b17080ed smbw-mobile: Mac host boots Mario Wonder v0 into its frame loop
Generic host, gfx and tools taken from d2r-mobile (MIT), with the D2R
gameplay, diagnostics and Blizzard/Granny/movie layers removed.

- hle_hid.c: generic standard-controller layer (all Npad styles)
- hle_sdk16.c: newer-SDK oe/time/pl/vsync/diag hooks
- hle_offline.c: offline stubs for prepo/ldn/socket/ssl/nifm/nsd/friends/ngc/err
- hle_fs.c, hle_account.c: SDK 16 overloads
- loader.c: unreferenced forced hooks only logged (DM_FORCE_STRICT=1 aborts)
- NVN: API 55.15, 13 newer names, ~45 state-only functions, tex_t packed
  to 0x80 (Mario allocates NVNtexture as 0x80; 0x88 corrupted the heap)

Frontier: null read at main+0x64763c inside the frame loop.
2026-10-12 22:04:20 +08:00

60 lines
4.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 直接跑原映像 main+e10d30;只替换系统查询与resize回调,不重写消费函数。
# 手写期望:消息循环结束focus/op/perf各为当前值;目标尺寸对应性能档;相同目标仅resize一次。
# Runs the original image main+e10d30 directly; only the system queries and the resize callback are replaced, the consumer function is not rewritten.
# Hand-written expectations: at the end of the message loop focus/op/perf each hold the current value; the target size corresponds to the performance mode; the same target is resized only once.
import struct,itertools,hashlib,sys
from pathlib import Path
from unicorn import Uc,UC_ARCH_ARM64,UC_MODE_ARM,UC_HOOK_CODE
from unicorn.arm64_const import *
P=Path(sys.argv[1]);b=P.read_bytes()
u=Uc(UC_ARCH_ARM64,UC_MODE_ARM);u.mem_map(0,0x4000000);u.mem_write(0,b);u.mem_map(0x7000000,0x2000);u.mem_map(0x7100000,0x10000)
if sys.argv[2:] == ['--negative']:
u.mem_write(0xe10e24,bytes.fromhex('1f2003d5')) # 只在负对照中移除尺寸相同跳过,重复通知会重复resize | only in the negative control is the same-size skip removed, so repeated notifications resize repeatedly
print('NEGATIVE:本地原函数副本e10e24 b.eq→nop,不改资源正本')
u.mem_write(0x3211718,struct.pack('<Q',0x7001001));u.mem_write(0x7001000,struct.pack('<Q',0x7001100));u.mem_write(0x7001110,struct.pack('<Q',0x7001200))
state={}
def hook(u,a,n,d):
if a==0x7001800:u.emu_stop();return
if a==0x1b77890:
q=state['q'];out=u.reg_read(UC_ARM64_REG_X0)
if q:u.mem_write(out,struct.pack('<I',q.pop(0)));u.reg_write(UC_ARM64_REG_X0,1)
else:u.reg_write(UC_ARM64_REG_X0,0)
elif a==0x1b778a0:u.reg_write(UC_ARM64_REG_X0,state['mode'])
elif a==0x1b778b0:u.reg_write(UC_ARM64_REG_X0,state['focus'])
elif a==0x1b778c0:u.reg_write(UC_ARM64_REG_X0,state['mode'])
elif a==0x7001200:
w=struct.unpack('<Q',u.mem_read(u.reg_read(UC_ARM64_REG_X3),8))[0];h=struct.unpack('<Q',u.mem_read(u.reg_read(UC_ARM64_REG_X4),8))[0]
state['resize'].append((w,h));u.reg_write(UC_ARM64_REG_X0,0)
else:return
u.reg_write(UC_ARM64_REG_PC,u.reg_read(UC_ARM64_REG_LR))
u.hook_add(UC_HOOK_CODE,hook)
def run(q,mode,focus,canvas=(1600,900),target=(0,0)):
state.update(q=list(q),mode=mode,focus=focus,resize=[])
u.mem_write(0x211da30,struct.pack('<II',*canvas));u.mem_write(0x211da38,struct.pack('<II',*target))
for a in [0x315e628,0x315e630,0x32137e8,0x32137ec]:u.mem_write(a,b'\x00'*8)
u.reg_write(UC_ARM64_REG_SP,0x710fff0);u.reg_write(UC_ARM64_REG_LR,0x7001800)
try:u.emu_start(0xe10d30,0x7001804,count=20000)
except Exception:
print("FAIL PC",hex(u.reg_read(UC_ARM64_REG_PC)),"LR",hex(u.reg_read(UC_ARM64_REG_LR)),"SP",hex(u.reg_read(UC_ARM64_REG_SP)));raise
assert u.reg_read(UC_ARM64_REG_PC)==0x7001800,'未返回'
return (struct.unpack('<I',u.mem_read(0x315e628,4))[0],u.mem_read(0x315e630,2),u.mem_read(0x32137e8,1),u.mem_read(0x32137ec,1),struct.unpack('<II',u.mem_read(0x211da38,8)),list(state['resize']))
checks=0
print('原映像SHA256',hashlib.sha256(b).hexdigest())
for focus,mode in [(1,0),(3,1)]:
for order in itertools.permutations([15,30,31]):
full=[m for m in order for _ in range(11)] # 33条,确实超过旧32容量;每个消息仍不携带历史值 | 33 messages, really exceeding the old capacity of 32; each message still carries no historical value
a=run(full,mode,focus);c=run(order,mode,focus);checks+=1
size=(1280,720) if mode==0 else (1600,900)
want=(focus,bytes([mode,mode]),bytes([mode]),bytes([mode]),size,[size])
ok=a==c==want
print(('✓' if ok else '✗')+f' 顺序{order} focus={focus} mode={mode}:33条原始通知/3条状态通知 → 写回相同且resize恰1次 {c}')
if not ok:raise SystemExit(1)
for mode in [0,1]:
size=(1280,720) if mode==0 else (1600,900)
for name,canvas,target,out,resizes in [('目标已匹配',(1600,900),size,size,[]),('容量不足',(1,1),(777,333),(777,333),[]),('宽度匹配高度不同',(1600,900),(size[0],333),size,[size])]:
a=run([15]*11+[30]*11+[31]*11,mode,2,canvas,target);c=run([15,30,31],mode,2,canvas,target);checks+=1
want=(2,bytes([mode,mode]),bytes([mode]),bytes([mode]),out,resizes)
ok=a==c==want;print(('✓' if ok else '✗')+f' {name} mode={mode} focus=2:33/3条通知写回符合手写期望,resize={len(c[-1])}')
if not ok:raise SystemExit(1)
print(f'CONSUMER_EQUIV OK {checks}/{checks}:原版ARM消费函数、33→3通知、手写状态/尺寸/resize')