我正在尝试为校验和本身获取一个驻留在内存中的图像,事实证明这说起来容易做起来难。
代码首先在交叉开发平台上编译,生成 .elf 输出。使用实用程序去除二进制映像,并将该映像与映像大小一起刻录到目标平台上的闪存。当目标启动时,它会将二进制文件复制到 ram 的正确区域,然后跳转到该区域。该实用程序还计算精灵中所有用于 ram 的单词的校验和,并将其烧录到闪存中。所以我的图像理论上可以使用先验起始地址和保存在闪存中的大小来校验它自己的内存驻留图像,并与保存在闪存中的总和进行比较。
无论如何,这就是理论。问题是,一旦图像开始执行,.data
随着变量的修改,该部分就会发生变化。当求和完成时,已求和的图像不再是实用程序计算总和的图像。
我已经消除了由于我的应用程序定义的变量而导致的更改,方法是将校验和例程移动到应用程序中的所有其他初始化之前(这很有意义,因为如果完整性检查失败,为什么要运行它,对吧?),但是杀手是 C 运行时本身。似乎有一些malloc
与指针转换相关的项目以及在输入之前更改main()
的其他内容。
自校验和 C 代码的整个想法是蹩脚的吗?如果有办法强制应用程序和 CRT .data 进入不同的部分,我可以避免 CRT 颠簸,但有人可能会争辩说,如果目标是在执行(大部分)图像之前对图像进行完整性检查,那么初始化的 CRT 数据应该成为其中的一部分。有没有办法像这样在 RAM 中制作代码校验和本身?
FWIW,我似乎对此有一个要求。就我个人而言,我认为要走的路是在传输到 ram 之前对 flash 中的二进制文件进行校验和,并信任加载程序和 ram。偏执狂必须在某个地方结束,对吗?
其他详细信息:工具链是 GNU,图像包含.text
,.rodata
并且.data
作为一个连续加载的块。没有操作系统,这是嵌入式裸机。主加载器本质上memcpy
是将我的二进制文件放入 ram 中,位于预定地址。不会发生搬迁。不使用虚拟机。校验和只需要在初始化时测试一次。
更新 发现这样做..
__attribute__((constructor)) void sumItUp(void) {
// sum it up
// leave result where it can be found
}
..我可以在几乎所有事情之前完成总和,除了 CRT init 对malloc
/ sbrk
vars 的初始化,以及“impure.o”和“locale.o”拥有的一些 vars。现在,malloc
/sbrk
值是我从项目链接器脚本中知道的。如果 impure.o 和 locale.o 可以得到缓解,可能会做生意。
更新 由于我可以控制入口点(通过主加载程序的闪存中所述),现在似乎最好的攻击角度是使用一段自定义汇编代码来设置堆栈和 sdata 指针,调用校验和例程,然后分支到“正常” _start 代码。