我想在Shadowgate中为NES提取字符串。我在图像上运行了file,然后运行了strings,没有运气。我找到了有关NES墨盒文件格式的信息。该文档提到了“名称表”的使用。有没有一种方法可以反汇编此文件并查看字符串?我尝试过

 strings -e -T rom.bin


我也尝试过:

 objdump -i rom.bin


处理器看起来像是M6502处理器, Windows反汇编程序可用。

评论

如果您阅读该文档,将会看到“名称表”与字符串无关。这似乎与用于滚动背景的NES存储精灵图块的方式有关。

如果您这样说-“ 0-3字符串“ NES ^ Z”用于识别.NES文件。“不幸的是,这是我在该文档中只能找到的对“字符串”的引用。我不是iNES黑客-我想你是吗?字符串的C定义是“ abcd \ 0”-它本身告诉我们关于如何绘制字符串的任何信息,对吗?在“ PPU内存”下讨论“名称表”,这就是它的意思:“名称表与文本模式屏幕缓冲区非常相似,其中包含要在屏幕上显示的字符代码。”请仔细阅读“与文本模式屏幕缓冲区非常相似”

字符串不写入文本模式屏幕缓冲区吗?

名称表用于平铺,而文本缓冲区则用于文本-这就是为什么它们“非常像”但不相等的原因。至于您的原始问题:字符串会查找非常特定的文本类型:仅ASCII文本。我扫描了您的文件中的非ASCII字符串,但没有发现(有用或其他)。字符串必须经过加密或压缩,并且可能需要反汇编才能找到它们。

这就是字符串的手册页所说的:“-e编码选择要找到的字符串的字符编码。...对于查找宽字符串有用。”还是编码?

#1 楼

有几种方法可以在未知文件中定位字符串。您已经尝试过的一个:strings。这将查找未编码的纯ASCII文本:用换行符或null。 (man strings


但是,这种幼稚的方法可能会失败的原因很多。首先,世界上并非每个文本都是ASCII编码的。实际上,使用二进制编辑器检查文件时,您可以找到偏移量0x20010(8x16像素的单色位图)中用于游戏的字体的图形图像。如果您假设第一个字符(“ 0”)的编号为零,则“ A”位于位置31 -绝对不是ASCII文本。当然,文本绘制例程可能知道这一点,并根据此方案对要打印的字符进行重新排序;但是,考虑到这种特定游戏的年代(1987年),文本数据很可能是按照这种奇怪的编码存储的。 />
搜索该游戏提供了许多屏幕快照,您可以阅读其中可能出现的一些文字,例如“您记得的最后一件事”,“您的历史任务的话”等,并且值得注意的一点是所有文本都显示为“全部大写”。

有什么帮助?好吧,如果编码几乎是“正常”的,则“ A”的字符代码可以是任何东西,但是您可以放心地假设code+1为“ B”,code+2为“ C”,依此类推。现在,我们假设文本“ THE”出现在任何地方(一个安全的假设)。从数据的第一个字节中减去“ T”,并记下差异。从下一个字节减去该差异,然后测试是否为“ H”;如果是这样,请在下一个字节上测试相同的差异,然后查看它是否为'E'。三倍是一种魅力(在这种情况下),并且由于字符串“ THE”应该非常频繁地出现,因此您应该看到许多具有相同差异的点击。然后,您可以编写一个自定义例程,以根据此方案“转换”所有数据字节,然后再次检查是否找到有用的字符串。

这对Shadowgate无效。 />另一个选择是故意对文本进行模糊处理。一种流行的(因为快速)选项是使用常量对文本进行XOR。这样,当使用十六进制查看器检查文本时,文本不容易看到,但可以轻松显示。因此,我只执行了上述操作,只是现在使用了XOR操作而不是恒定减法。它也不起作用。在如此古老的游戏中找到现实世界的压缩(ZIP,LZW)是相当罕见的,压缩方案往往非常简单。毕竟,不仅RAM受限制,而且CPU速度也受限制。如果每个字符都以5位序列存储怎么办?这样可以节省大量内存-文本的每8个字符可以存储为5个字节,压缩率为62.5%。

为什么是“ 5位”?我们在这里说的是英文文本,加上一些标点符号,再加上(也许)数字“ 0”到“ 9”。字母表本身是26个字符长,剩下的6个值用于其他任何字符,而且,其中一个附加代码可能意味着“对于下一个字符,请使用所有8位”。我的测试字符串(在密码学中称为“婴儿床”)有5位,我发现了以下内容:

您可以看到它的工作原理,因为我还在测试字符串的前后解码了一些字节,这也可以识别为“某物”。显示的'delta'是五位代码(0..31)和ASCII之间的差异,对于大多数字符串,您可以看到它是41(唯一的异常似乎是假肯定)。 />为了确保这是正确的,我尝试了另一个婴儿床:KING(这是一个奇幻游戏):我期待的是“王”,但结果不错,增量为41,随机值则为另一个增量。

但是以这种方式找到有用的字符串是相当幸运的,因为当然不能保证阅读从第一个字节开始的每5位应该显示任何有用的内容。所示之间可能还有许多其他字符串,但它们并非恰好以5 * 8位的倍数开头。假设位置0处没有文本,但位置1处有文本,那么我看不到它:

candidate at 0570, delta is 41 H_A\`THE[TROLL[
candidate at 0670, delta is 41 _H\`ATHE[TROLL[
candidate at 0878, delta is 41 `AN`QTHE[TROLL[
candidate at 09E3, delta is 41 FROM^THE[DEPTHS
candidate at 1380, delta is 41 E[OF[THEM_A[THI
candidate at 13F0, delta is 41 ]NX_ATHE[WORDS[
candidate at 14C0, delta is 41 PD^`QTHE[FLAME[
candidate at 1BBA, delta is 41 UDGE[THEM[BY_A_
candidate at 22E0, delta is 41 ]BX_ATHE[GLASS[
candidate at 230D, delta is 41 ID_A[THE^SIGN[O
candidate at 2375, delta is 41 S[ON[THEM_A\`AB
candidate at 2390, delta is 41 LLOW[THE^VISCOU
candidate at 2528, delta is 41 F]PX_THE[STONE[
candidate at 25E6, delta is 36 @CP=KTHE@?OFHBS
candidate at 27F8, delta is 41 YDP]ATHE[BARK[O
candidate at 2B1E, delta is 41 D_H\]THE[WATER[


要正确解码所有字符串,现在,请遵循以下路线:


我的结果列表包含可读的文本,但也有一些垃圾。找出“垃圾”是什么([似乎是一个简单的空间,但是THEM_A\'AB需要仔细看)。地址。毕竟,如果“使用”了它们,则需要对其进行一些引用。
在这些地址之前和之后,将会有更多。这些是搜索算法找不到的字符串地址,但仍然有效。
通常,此类列表是连续的(尽管每个字符串可能有一些数据)。上下扫描二进制文件以查找相似的地址,直到找到肯定是开始和结束的地方。
遍历列表并根据解码方案显示所有内容。
坐下来欣赏一下做得好。


评论


哇!凉!谢谢:)非常清楚!

–user3094
13年3月3日在1:27

这是您可能需要了解的节省时间的方法:输入文件由几个部分组成(我认为这类似于原始的物理ROM芯片)。前16个字节为“标头”,可以忽略。然后遵循65,536字节的代码,其余的是图形数据-对您的目的不感兴趣。您只需要扫描代码部分。

–杂件
13年3月3日,下午2:02

嗨!您是否使用工具进行扫描?我正在使用python手动编写脚本。

–user3094
13年3月3日在4:59

另一个ROM奇怪之处是:交换了64K映像的前一半和后一半!难怪我花了3.00 /晚才能找到有用的东西。顺便说一句,有用的字符串偏移量列表位于0x8000(更正ROM映像文件之后);例如,在偏移量A182处:“知道了吗?将^ ME(THE)应答到我的^ RIDDLE,然后我让^ THEE PASS。哦,我使用普通的C语言。并不是那么重要,只要您可以操纵位流,就可以了。

–杂件
13年11月3日,12:59



实际上,将ROM分成两半。整个事情肯定不是按照逻辑顺序排列的,但是却没有我想象的那么容易。这需要真正的NES-ROM黑客来理解。仍然可以提取字符串,但是如果您无法获得“实际”地址,则“查找偏移量”部分将无法执行。

–杂件
13年3月3日,14:23