mirror of
https://github.com/MCKero6423/uv-k5-v3-emulator.git
synced 2026-10-06 05:00:15 +00:00
Round 62: the code loads byte-perfect and six bytes change 60 ms later; the memset is not the culprit
Sampling the overlay every 50 ms from MENU: before it, crc 169b5c51 matching 262/2568; at +0.00 s, crc 60234c72 matching 2568/2568, which is the app's own CRC; at +0.06 s, crc 4f23f6f3 matching 2562/2568; and every later sample identical. So the load is byte-perfect and the loader's own check would pass at that instant, and exactly six bytes -- the pointer 0x0801D640 plus 28 0a -- change sixty milliseconds later and never change again. That retires round 59's reading: a memset zeroing the whole 4 KiB would change thousands of bytes, not six, so the hundred-a-second memset is not what stops the app. The damage is a six-byte structure write. Together with the offset tracking code_size (code_size - 124 for both the 2744 and 2568 builds), something on the load path that knows code_size writes a six-byte structure at overlay + code_size - 124 just after the copy and before the app is entered. Next: watch those bytes again but ignore the memset, reporting only the first hit whose fill byte is not zero.
This commit is contained in:
1 parent
244c51c2e1
commit
27e84ca3da
2 files changed
+50
No files matched your search
@@ -2429,3 +2429,29 @@ overlay exactly once. Whatever the routine is called, nothing the loader writes
|
||||
|
||||
Next: identify 0x080175fe and 0x080047ca against the image itself rather than against a fetched file -- for
|
||||
instance by looking at what each calls and returns -- or fetch the sources for the exact build being run.
|
||||
|
||||
**Round 62: the code loads byte-perfect and exactly six bytes change sixty milliseconds later. The memset is not the culprit.**
|
||||
|
||||
Sampling the overlay every fifty milliseconds from the instant MENU is pressed:
|
||||
|
||||
before MENU crc 169b5c51 matching 262/2568
|
||||
+0.00 s crc 60234c72 matching 2568/2568 EXACT
|
||||
+0.06 s crc 4f23f6f3 matching 2562/2568
|
||||
... every later sample identical
|
||||
|
||||
60234c72 is the app's own CRC, so at that instant the overlay holds the code byte for byte and the loader's own
|
||||
verification would pass. Sixty milliseconds later exactly six bytes have changed -- the four-byte pointer
|
||||
0x0801D640, which appears once in the image, plus 28 0a -- and nothing changes after that.
|
||||
|
||||
That retires round 59's reading. A memset that zeroes the whole 4 KiB overlay would change thousands of bytes,
|
||||
not six, so the hundred-a-second memset is not what stops the app. It is a separate routine doing something
|
||||
else, and the damage is a six-byte structure write.
|
||||
|
||||
The two measurements together are what make this sharp: the offset that ends up wrong tracks the app's size
|
||||
(code_size - 124 for both the 2744-byte and the 2568-byte build), and the write is a pointer plus a small
|
||||
value. Something on the load path, which knows code_size, writes a six-byte structure at overlay + code_size
|
||||
- 124 just after the copy and before the app is entered.
|
||||
|
||||
Next: watch those four bytes again, but ignore the memset and report only the first hit whose fill byte is not
|
||||
zero -- and if that is still the memset, watch a byte of the six that the memset does not clear, so the budget
|
||||
is not spent on it.
|
||||
@@ -2123,3 +2123,27 @@ PC=0x0801ae7a(`memset` 内部,入口 0x0801ae70) SP=0x20003c50
|
||||
|
||||
**下一步**:**对着镜像本身、而不是对着取来的文件,去认 `0x080175fe` 与 `0x080047ca`** ✓ ——
|
||||
比如看它们各自调用与返回了什么 ✓ —— **或者去取「正在跑的那个构建」的源码** ✓。
|
||||
|
||||
**第 62 轮:代码是逐字节完美载入的,而恰好 6 个字节在六十毫秒后改变。那个 `memset` 不是元凶。**
|
||||
|
||||
从按下 MENU 的那一刻起,每五十毫秒给覆盖区采一次样:
|
||||
|
||||
```
|
||||
before MENU crc 169b5c51 匹配 262/2568
|
||||
+0.00 s crc 60234c72 匹配 2568/2568 EXACT
|
||||
+0.06 s crc 4f23f6f3 匹配 2562/2568
|
||||
... 此后每一次采样都相同
|
||||
```
|
||||
|
||||
`60234c72` **就是应用自己的 CRC** ✓ —— 所以**在那一刻覆盖区里逐字节就是那段代码 ✓,加载器自己的校验会通过** ✓。
|
||||
**六十毫秒之后恰好 6 个字节变了** ✗ —— 那个在镜像里只出现一次的 4 字节指针 `0x0801D640` ✓,加上 `28 0a` ✓ —— **而此后什么都不再变** ✓。
|
||||
|
||||
**这一条推翻了第 59 轮的读法** ✗:**把整片 4 KiB 覆盖区清零的 `memset` 会改掉成千上万个字节 ✓,而不是 6 个 ✓** ——
|
||||
**所以那个每秒一百次的 `memset` 并不是让应用停下来原因** ✓。**它是另一个例程在做别的事,而真正的损伤是一次 6 字节的结构写入** ✓。
|
||||
|
||||
**把这两条测量放在一起,图景才锋利起来** ✓:**出错位置随应用大小移动(2744 与 2568 两个构建都是 `code_size − 124`)** ✓,
|
||||
**而那次写入是一个指针加一个小值** ✓。**是加载路径上某个知道 `code_size` 的东西 ✓,在拷贝之后、应用被进入之前 ✓,
|
||||
在 `覆盖区 + code_size − 124` 处写下一个 6 字节的结构** ✓。
|
||||
|
||||
**下一步**:**再看那四个字节一次,但把 `memset` 忽略掉 ✓,只报第一个「填充字节不为零」的命中** ✓ ——
|
||||
**若那仍然是 `memset`,就改看那 6 个字节里 `memset` 不会清掉的一个字节 ✓,这样观察预算就不会被它吃光** ✓。
|
||||
Reference in new issue
Block a user