校验和本身*在ram中的C代码*

Jus*_*eff 17 c embedded load data-integrity

我正在尝试将一个ram驻留图像放到校验和本身,这说起来容易做起来难.

代码首先在交叉开发平台上编译,生成.elf输出.实用程序用于去除二进制图像,并将该图像与图像大小一起刻录到目标平台上的闪存.当目标启动时,它会将二进制文件复制到ram的正确区域,并跳转到它.该实用程序还会计算精灵中所有用于ram的单词的校验和,并且这些单词也会被刻录到闪存中.所以我的图像理论上可以使用先验的起始地址和闪存中保存的大小来校验自己的ram驻留图像,并与闪存中保存的总和进行比较.

无论如何,这就是理论.问题是图像开始执行后,.data随着变量的修改,部分会发生变化.到总和时,已经求和的图像不再是效用计算总和的图像.

我已经消除了由于我的应用程序定义的变量导致的更改,通过在应用程序中的所有其他初始化之前移动校验和例程(这有意义b/c为什么在完整性检查失败时运行任何一个,对吧?),但是杀手是C运行时间本身.似乎有一些与之相关的项目malloc和指针转换以及main()甚至在输入之前被改变的其他事物.

自我校验和C代码的整个想法是蹩脚的吗?如果有办法强制app和CRT .data进入不同的部分,我可以避免CRT捶打,但有人可能会争辩说,如果目标是在执行(大部分)之前检查图像,那么初始化的CRT数据应该成为其中的一部分.有没有办法像这样在RAM中进行代码校验和?

FWIW,我似乎坚持要求.就个人而言,我认为要走的路是在转移到ram之前校验闪存中的二进制文件,并信任加载器和ram.偏执狂必须在某个地方结束吧?

其他细节:工具链是GNU,图像包含.text,.rodata.data作为一个连续加载的块.没有操作系统,这是裸机嵌入式.主加载器本质上memcpy是我的二进制文件,在预定的地址.没有重新安置.VM未使用.校验和仅需要在init初始化一次.


更新 通过这样做发现..

__attribute__((constructor)) void sumItUp(void) {
    // sum it up
    // leave result where it can be found
}
Run Code Online (Sandbox Code Playgroud)

..除了CRT init 初始化malloc/ sbrkvars以及"impure.o"和"locale.o"拥有的一些变量之外,我几乎可以完成所有操作.现在,malloc/ sbrkvalue是我从项目链接器脚本中知道的.如果impure.o和locale.o可以减轻,可能会有业务.

更新 因为我可以控制入口点(通过闪存中为主加载器说明的内容),现在似乎最好的攻击角度是使用一段自定义汇编程序代码来设置堆栈和sdata指针,调用校验和例程,然后分支到"正常"_start代码.

Mat*_*son 5

如果校验和足够早地完成,您可以仅使用堆栈变量,而不写入任何数据部分变量 - 也就是说,执行校验和所需的一切[以及到达该点的所有前面的步骤]仅使用本地用于存储内容的变量[当然你可以读取全局数据]。

我相当确信正确的方法是相信闪存和加载器来加载闪存中的内容。如果您想对代码进行校验和,当然,请执行此操作[当然假设它没有被加载程序修改 - 例如共享库的运行时加载或可执行文件本身的重定位,例如随机虚拟地址空间等]。但一旦执行正常开始,从闪存加载的数据就不再可靠。

如果其他人要求您这样做,请向他们解释这是不可行的,并且“现有的要求”已“被破坏”。