最近在github上看到了一个很让人叹为观止的项目。
作者通过显微镜摄取芯片ROM,将里面的二进制固件给还原了。搞芯片和BSP的朋友都知道这意味着什么。
于是翻译这篇文章与大家分享,受限于英语水平,如有不当之处,还请海涵。
- 原文:GameBoy ROM Tutorial[1]
- 译者:TrustZone
嘿,各位:
这是一篇关于掩码ROM恢复的简短教程,我们将从Nintendo GameBoy的掩码ROM照片开始,最终得到一个可以反汇编或模拟的ROM文件。
GameBoy是一个很好的目标,因为它使用的是所谓的Via ROM,这意味着金属Via位于各层之间,用于编码各个位,这些位可以从芯片表面读取。ROM的体积也足够小,我可以将其包含在Github存储库中,这样你就不会因为一些小的位错误而耗费数周的时间去调试了。
来自诺克斯维尔的祝福,
——特拉维斯·古德斯皮德
摄影
我们会从dmg01cpurom.bmp开始,这是我在家中的实验室拍摄的,拍摄前我先用硝酸将芯片去盖,然后用丙酮超声波浴清洗。这颗芯片不需要用氢氟酸去层或用Dash Etch溶液(由硝酸、氢氟酸和乙酸组成)进行位染色。
这张照片是在我的金相显微镜下以50倍放大拍摄的二十二帧图像,然后在Hugin软件中拼接而成。生物显微镜不适用,因为硅基底对可见光是不透明的;在金相显微镜下,光线从样品上反射,而不是穿过样品。
我原始的照片对于Github来说太大了,所以你将要处理的版本分辨率有所降低。这里避免了有损压缩,因为它可能会干扰图像识别。
如果你自己拍摄了DMG-01-CPU芯片的照片,这里的说明也同样适用。
位提取
在本教程中,我们将使用我的CAD程序MaskRomTool来提取位,这是一个用于快速位提取的工具。
首先,编译MaskRomTool并安装它。如果你熟悉Unix命令行,你希望可执行文件maskromtool和gatorom在你的 $PATH中。如果不熟悉,也不用担心,因为所有功能也可以从图形用户界面(GUI)中获得。
在Windows和macOS上,你可以通过使用预构建的发行版来避免编译代码。当代码感觉特别稳定时,这些发行版会每隔几个月编译一次。
安装并运行后,使用MaskRomTool打开dmg01cpurom.bmp。
注意灰色十字线是如何跟随你的鼠标移动的。它们开始时是直的,但很快就会倾斜以匹配你在ROM上放置的行和列线。这允许你预测相同角度的重复行和列将落在何处,因为大多数图像都是倾斜的,但大多数位都是完美的直线。
同时请注意,ROM中的位以规则的行对和八个规则列的组出现。在MaskRomTool中,你需要放置行和列,但对于匹配原始图像的分组没有严格的限制。如果你发现你可以可靠地放置一条贯穿整个图像宽度的巨大行,或者一条贯穿整个图像高度的巨大列,那就大胆地去做吧。如果图像是歪斜的,你需要用一条非常短的线来绕过错误,那也没问题。
导航
要在图像中移动,你可以使用鼠标或笔记本电脑的触摸板。但更推荐使用鼠标,因为右键点击更方便一些。
按下鼠标中键并拖动背景可以稍微滚动,或者在触摸板上使用两根手指来平移屏幕。如果按住Shift键,平移速度会更快。
在这些项目中,缩放功能非常重要。QAZ键用于缩放,其中Q键可以快速切换到原始分辨率,A键和Z键用于放大和缩小。对于鼠标,按住Ctrl键并滚动滚轮也可以调整缩放。对于触摸板,你可能需要使用捏合动作来缩放,但这只在你的操作系统支持此功能的情况下有效。
先花点时间在ROM照片上移动,猜猜看不同的结构是什么。之后,我们将开始标记图像。
放置行
我们先从几个短行开始,稍后再尝试长的。首先,点击最左边位的左侧一点,然后将鼠标向右移动但不要点击。而是按下R键来放置一行。这两点之间会出现一条细黑线。
你可以重复这个步骤来放置所有的行,但这会很费力,而且对于非常长的行可能会涉及很多滚动。相反,将鼠标保持在右侧但稍微向下移动。当你的十字线对齐行时,按下Shift+R或空格键来放置另一条长度和角度相同的行。
在多个行上重复此操作应该很快就能标记出它们。在以下截图中,我已经标记了前八行的短段。
一旦你掌握了仅从右侧标记重复行的技巧,为了节省时间和精力,你也可以在整个图像上标记它们。如果直线不能穿过整个图像,那么标记较短的长度或更好地对齐你的全景照片。
如果你将行放置在了错误的位置,有几种方法可以移动它。首先,用鼠标左键拖动一个框来选择一条或多条线,然后用鼠标右键拖动它们来移动。箭头键也可以移动所选内容,S键会将单条线的位置设置为新的终点。
识别位
为了识别位,软件不仅需要您提供的位位置,还需要一个阈值和颜色通道来区分这些位。点击“编辑”,然后选择“选择位阈值”以查看以下图表并选择您自己的阈值。
前64位的直方图显示了所有三个颜色通道中的间隙。绿色通道中的间隙最大,因此我会在该通道中将阈值设置为172。请注意,当您更改阈值时,位框是如何自动调整的。
尽管蓝色和红色通道也可以用于此图像,但我们想要使用绿色通道,因为它具有最大的间隙。当我们开始累加图像中的所有位时,较大的颜色距离将确保我们获得更少的位错误。
一旦你设置了前六十四位,点击“查看”和“ASCII预览”来查看它们。不是很棒吗?
11101011
01111111
00110111
01101111
10110001
01101110
01011100
10110101
更多位
既然你已经体验了识别六十四位,那我们现在就来识别所有的位。
首先,通过删除dmg01cpurom.bmp.json并在Mask ROM Tool的新实例中重新打开dmg01cpurom.bmp,或者批量擦除你的线条,来清除你之前的工作。批量擦除是通过拖动选择线条,然后按D键将它们剪除来完成的。
(严格来说,你也可以用很多非常小的行和列来标记图像。我之所以不推荐这样做,是因为它太费时间了。)
在擦除线条后,放置一行从屏幕的最左侧到最右侧。如果你重新开始而不是删除之前的工作,有时先画一条较短的行会有所帮助,这样十字线的角度就会与图像倾斜的角度相同。你可以使用R键尝试画一条行,然后使用D键删除它,而软件不会忘记你的第一个起始位置。
在画完第一条线后,将鼠标移到照片的右侧,每经过一行时按Shift+R或空格键来放置一条线。如果你发现你标记的位稍微有些偏差,你可以使用S键来设置最后一条线的位置,将其移动到新的鼠标位置。箭头键和右键拖动也会重新定位它,同时位的值会随着位置的变化而变化。
如果行特别规则,你可能一次放置几个。要做到这一点,用鼠标左键选择一些线条,然后按Shift+D复制这些线条的集合。然后可以用右键拖动将这些线条移动到新的位置,而原始位置会保留一份副本。
在画完长行之后,画列。只需在第一个位的上方点击一次以设置起点,然后在最后一个位的下方按C键来画一列。Shift+C将在另一个端点处放置相同角度的新列,因此你可以遍历图像并在短时间内绘制所有列。
当所有位都设置完毕后,使用“编辑/选择位阈值”来稍微调整阈值。注意,随着更多的位被设置,曲线变得更加平滑,而且151可能比172更合适。
发现和修正错误
将所有位都标记出来是一种很棒的感觉,但这通常并不是结束。在继续解码ROM之前,最好进行一些快速的合理性检查,确保没有犯下任何错误。
使用V键或DRC/评估规则(Evaluate Rules)来对你的设计进行一些快速的合理性检查。例如,如果你放错了一条线,某个位的颜色可疑地接近阈值怎么办?你可能会得到一个像这样的DRC错误,你可以通过更正线条的位置来解决这个问题。每个设计规则检查(DRC)违规都有一个位置,并在图形用户界面(GUI)中以黄色框的形式出现。E键将跳转到列表中的下一个错误位置。
虽然像线条放错这样的错误是你的责任,但那些不是你的错误的错误也必须被纠正。有时照片上会混入一些灰尘,遮挡了采样位置的位的值。有时化学错误会使位变得难以看清。
在这种情况下,当你比机器更了解情况时,请将鼠标放在该位上并按Shift+F来强制设置其值,并在该位周围放置一个小的绿色框。如果应用了错误的值,再次按Shift+F将会翻转它。
经过这一切之后,位终于完成了!
11101011111100101100101100110010011000110111110000100001011100101110000000110011110001001001001011000100001011110001101100001000
01111111011100110111111101100011001010110100111100000110101010110011001111110011001010111011000000111000001011101101011011101111
00110111110110110111011111010111011001101001011101111111110110100111000101110010010110000101011101110001111101110111101111011000
01101111111000111110111011110110001011100101011010100010001110000111100000111010011111000111001100101111010000110100111111101001
10110001001100001011100110110111000110011101100111100000111100111111011010110001111111100111011010111010000110100100001100010011
01101110011100110110100100110111011100110101101001001111111100110010111110100011001110011010011101111010000111100111001010110010
01011100011101111111110001110111101100000101101100111000011100010011000011110101001100001011111000110000100110010111011111010010
10110101110101111011101001011111001110101111101000010101111100011101011111000011111010111010101100001110011110011011011111000101
00011111000101000001101110011110101111001111000011111011011100000100011011010000110100111001100100110011110101000101101110110110
11011001000101100111100100011011001110010101010100001101111101110110010110000111010101101101111010101100101100101101111110010111
11111111111110011111101101010101001101111101000010100110101010011011010011111001101101001101010110101010010101011110010110100011
01011110111110100001111011010110001000011101000000111011001011100101001111101110100110110000101000101011100001000001111000100001
11011000100010111011110010010101001011000111000010011000111110001111011011000000100111001101010010001100111101100010100110111001
11111011001010011111101000111101001100101111100110110101011111011011110110000101001011001101000100110111001101011110110110001010
00111111111101100011101111110010001011001111010000011111101111010011011111110111001101110111010101011111111110110101011100111111
10101101111101111000110111110110100001010111100111001101101110100100111111000011011110101010001101011100100011111100111110011111
关于命令行界面(CLI)
到目前为止,我们一直在图形用户界面(GUI)中使用这个工具,但当你处理更大的项目时,你会想要使用命令行界面(CLI)来自动化一些操作。默认情况下,它会启动图形用户界面,因此当你单独运行它时,你会想要添加“-platform offscreen -e”参数,以避免打开窗口并在完成后退出。
Usage: maskromtool [options] image json
Mask ROM Tool
Options:
-h, --help Displays help on commandline options.
--help-all Displays help including Qt specific options.
-v, --version Displays version information.
-V, --verbose Print verbose debugging messages.
--stress Stress test bit marking.
-e, --exit Exit after processing arguments.
--disable-opengl Disable OpenGL.
--enable-opengl Enable OpenGL.
-d, --drc Run default Design Rule Checks.
-D, --DRC Run all Design Rule Checks.
--sampler <Default> Bit Sampling Algorithm.
--diff-ascii <file> Compares against ASCII art, for finding errors.
-a, --export-ascii <file> Export ASCII bits.
-o, --export <file> Export ROM bytes.
--export-histogram <file> Export histogram.
--export-csv <file> Export CSV bits for use in Matlab or Excel.
--export-json <file> Export JSON bit positions.
--export-python <file> Export Python arrays.
--export-photo <file> Export a photograph.
Arguments:
image ROM photograph to open.
json JSON lines to open.
假设我们有ROM文件dmg01cpurom.bmp和与之匹配的.json文件,我们可以在macOS或Linux中通过命令行界面(CLI)像这样导出位。在Windows中,我们调用maskromtoolcli.exe而不是maskromtool,以保持控制台连接。
dell% maskromtool -platform offscreen -e dmg01cpurom.bmp -a DMG_ROM.txt
Allocation limit was 128 MB
Disabling allocation limit.
Loaded background image of 9000 , 2249
Done loading, now marking bits.
Exporting to ASCII.
dell%
解码ROM文件
现在你已经有了你的项目按物理顺序排列的位,但这与反汇编器或模拟器更喜欢的逻辑顺序的字节截然不同。我们将首先以图形方式完成这个操作,然后也会看到如何在Unix命令行中执行它。
在开始之前,请安装MAME并确保其反汇编器unidasm在PATH中。如果你没有这样做,求解器仍然可以工作,但你将无法看到反汇编的代码。
图形化解码
你可以通过“编辑/解码”手动调整解码设置。首先,将反汇编架构设置为LR35902,并将字大小设置为8。翻转、旋转和存储体(banking)将在稍后为你解决,底部的标志列表显示了将传递给GatoROM用于在命令行中解码的选项。
你可以使用“查看/求解器”来求解特定的字节序列或Yara规则。双击某个解决方案将重新配置解码器并更新十六进制和反汇编视图,以便可以快速搜索它们。
首先,使用求解器的“字节”选项卡来求解0:31,1:fe,2:ff,这意味着前三个字节将是31 fe ff。这是LR35902机器代码,用于将堆栈指针设置为0xfffe。双击解决方案-z--decode-cols-downr-i-r180--flipx将把这些设置应用到解码器上。
“View/HexPreview”将以十六进制实时显示解码结果。选择某些字节后,你还可以使用“View/HighlightHexSelection”来高亮显示这些位在你的项目文件中的位置。
使用GatoROM进行解码
GatoROM是随MaskRomTool一起提供的一个位解码器。它运行在命令行下,但实际上它使用的是与GUI求解器中相同的库。
首先,我们需要一个ROM位的ASCII文件。你可以使用MaskRomTool的GUI中的“文件/导出/ASCII”来生成这个文件,或者在命令行中使用maskromtool -platform offscreen dmg01cpurom.bmp -a DMG_ROM.txt -e
来生成。
这是如何根据ROM进行求解,已知前两个字节是31和fe。-z
标志表示我们希望使用Zorrom兼容模式,它在写入正确的解码到DMG_ROM.bin
之前,准确地识别了三个潜在的解码。
dell% gatorom DMG_ROM.txt --solve --solve-bytes "0:31,1:fe" -z -o DMG_ROM.bin
Grade 50 31 11 47 fe 3e f9 1e 0e -z --decode-cols-left -i -r 180 --flipx
Grade 50 8a fe a8 01 d4 52 b0 a4 -z --decode-squeeze-lr -r 180 --flipx
Grade 100 31 fe ff af 21 ff 9f 32 -z --decode-cols-downr -i -r 180 --flipx
Exporting -z --decode-cols-downr -i -r 180 --flipx
dell%
我们也可以用其他方式进行搜索。如果我们知道31 fe ff存在于图像的某个地方,但不知道确切的位置,怎么办?这会产生三个潜在的解决方案,如果需要,我们可以将它们转储到文件中以进行探索。
dell% gatorom DMG_ROM.txt --solve --solve-string "31,fe,ff"
Grade 100 f5 06 19 78 86 23 05 20 --decode-cols-downl -i -r 0 --flipx
Grade 100 31 fe ff af 21 ff 9f 32 --decode-cols-downr -i -r 0 --flipx
Grade 100 f5 06 19 78 86 23 05 20 --decode-cols-downl-swap -i -r 0 --flipx
dell%
参考资料
[1]
GameBoy ROM Tutorial: https://github.com/travisgoodspeed/gbrom-tutorial/blob/master/README.md
作者:Hcoco
文章来源:TrustZone
推荐阅读
更多物联网安全,PSA等技术干货请关注平台安全架构(PSA)专栏。欢迎添加极术小姐姐微信(id:aijishu20)加入PSA技术交流群,请备注研究方向。