红楼梦十二金钗游戏资源分析(二)

上次我们研究读取文件的时候卡了壳,那么我们不妨再回到显存下手。

目录

本系列已完结,以下是各章节说明,17 之前是 dos 版相关,之后是 2001 版:

  1. 背景、简单分析
  2. 显存位置
  3. 事件图保存算法: LZW
  4. 调色板
  5. MGP2
  6. 结局图
  7. 事件图中的眼睛
  8. 音频文件
  9. 按位读取
  10. 循环之前
  11. 读取循环
  12. 重现 LZW
  13. PAT 的图形格式
  14. STAFF 调色板
  15. 字体文件
  16. 脚本解密
  17. 版本比较
  18. 第一张图
  19. 调色板1
  20. 第二张图
  21. 调色板2
  22. 调色板处理
  23. 静态事件图、结局图
  24. 动态图、鉴赏模式

再次上路

我们基本可以确定,图像数据在内存中一定是连续的像素数据,这样才能复制给显卡进行显示,虽然不能说一定是这样,但是应该符合大部分情况。

这样的话,那么连续从一块内存复制到另一块内存的指令很可能就是在搬运图像数据。所以这次我们再开 cpu log,然后在屏幕上连续移动鼠标,让图像发生变化,这次日志不需要记录很多,只要能在晃动鼠标前不会结束就好。

然后我们在日志中寻找 repe movs,结果发现了 0217:20a7 这行,索性我们断点也设在这里:

单步执行几次,我们发现,屏幕上真的在绘制鼠标!于是我们找到了第一块显存的位置,0417

绘制图像

于是我们可以把 0417:0000 - ffff 这段内存 dump 下来,然后写程序把它画出来,程序的逻辑很简单,创建一个 640 × 480 的图像,然后把每个 byte 当成一个颜色依次绘制在图像上,看看是什么样子。当然,因为我们还不知道调色板在哪里,所以每个 byte 代表什么颜色我们不得而知,不过根据以往的经验,图形的外观还是可以分辨的,我们可以自定一个规则,比如 00 代表 rgb #000000,01 代表 #010101,这样我们可以画出一个 256 阶的灰度图:

确定显存

现在我们可以确认,这就是一部分屏幕图像了,接下来我们可以再去找 0417 中的数据是哪里来的,我们在第一篇的 8G 日志中,找到了这样几个位置:0287,03e7,03ef,03f7,03ff,0407,0507,我们注意到,03e7, 03ef, 03f7, 03ff, 0407 这几个数字是相差 8 的等差数列,感觉上像是一组,我们把它们拼一起画出来好了,有一点需要注意,因为有 5 段内存,数据量应该是 65536 * 5,这个数字已经超过了 640 × 480,所以 0407 最后一部分数据是多余的,画图时最后的数据需要舍去,我们看一下最终画出来是什么样子:

我知道很丑,不过我想你们也知道,当时我看着这张丑图,还挺高兴的。因为我们终于定位到图像数据了,一共五块:

  1. 03e7:0000 ~ 03e7:ffff
  2. 03ef:0000 ~ 03ef:ffff
  3. 03f7:0000 ~ 03f7:ffff
  4. 03ff:0000 ~ 03ff:ffff
  5. 0407:0000 ~0407:afff

正如我们预期的那样,0407 没有用满,从 0407:b000 开始每个 byte 都是 0x55,应该是未初始化的数据。

显存从哪里来

我们始终还是要回答这个问题,既然图像有 5 块,那么我们首先从 03e7 开始定位。我们在日志中搜索 repe movs.*ES:03e7 很快就会发现,03e7 是从 04e7 复制而来。

0237:000029DA  repe movsd    ESI:00000000 EDI:00000280 DS:04E7 ES:03E7 FS:0000 GS:0000 SS:028F

那么 04e7 从哪里来,还是搜 movs 就搜不到了,我们来搜 mov es:.*es:04e7

al 又来自哪里,我们顺藤摸瓜,似乎是这么一个流程:

028f:5740 → 0507:007e → 028f:4740~4742 → 04e7:di

如果你的记忆力非常非常好,那么也许还记得,5740 是我们上一期停下来的位置。

总结

我们从显示图像这边出发,找到了显存的五块地址,然后根据这个线索,又回到了文件处理的循环。现在两边都指向了同一个地方,看来 3c36 行的循环就是我们要解决的最大问题,对于这个问题 ,我们放在一起讲吧。