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

时间:2012-12-31 14:57:17

标签: c load embedded 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
}

..除了CRT init初始化malloc / sbrk变量之外几乎所有事情之前我都可以完成总和,以及“impure.o”和“locale”拥有的一些变量的.o”。现在,malloc / sbrk值是我从项目链接器脚本中知道的。如果impure.o和locale.o可以减轻,可能会有业务。

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

5 个答案:

答案 0 :(得分:4)

如果校验和已经足够完成,你可以使用ONLY堆栈变量,而不是写入任何数据段变量 - 也就是说,你需要执行校验和[以及所有前面的步骤才能达到这一点]只使用局部变量来存储[当然可以读取全局数据]。

我相信正确的方法是相信闪光灯和闪光灯。加载器加载闪存中的内容。如果你想对代码进行校验和,请确保执行该操作[假设它当前没有被加载程序修改 - 例如,共享库的运行时加载或可执行文件本身的重定位,例如随机虚拟地址空间等]。但是,一旦执行正确启动,就无法依赖从闪存加载的数据。

如果其他人要求你这样做,那么请向他们解释这是不可行的,并且“要求,因为它”是“破坏”。

答案 1 :(得分:2)

我建议将其作为可执行的打包程序来处理,例如upx

在其他答案和你的问题中有几件事情,由于缺乏更好的术语,让我感到紧张。

  • 我不相信装载机或闪光灯中任何没有强迫我的东西。
  • 网上有浮动的源代码,用于保护HTC最近的手机之一。浏览一下forum.xda-developers.com,看看你是否可以找到它并以它为例。
  • 我会推迟这个要求。手机制造商花费大量时间来保持他们的图像锁定,最终,所有这些都被打败了。这似乎是一个恶性循环。

答案 2 :(得分:1)

你可以使用链接器脚本在其他所有内容之前或之后放置impure.o和locale.o,允许你校验除了那些和malloc / sbrk之外的所有内容吗?我猜测malloc和sbrk是在加载你的应用程序的bootloader中调用的,所以那些引起的捶打不能被消除?

只是告诉你打击这个要求不是答案,但我同意这似乎是过度思考。我敢肯定你不能详细说明,但我假设规范作者关注的是恶意用户/黑客,而不是由于宇宙射线造成的常规内存损坏等。在这种情况下,如果是恶意的用户/黑客可以改变加载到RAM中的内容,他们可以只改变你的校验和例程(它本身就是从RAM运行,对吗?)总是返回一个快乐的状态,无论他们不再运行的校验和例程如何设计好了。

即使他们担心常规内存损坏,这个校验和例程只会捕获原始复制到内存期间发生的错误,这实际上是发生此类错误的最不可能的时间,仅仅是因为系统没有'已经运行了足够长的时间,很可能发生腐败事件。

答案 3 :(得分:0)

一般来说,你想要做的是不可能的,因为在许多(大多数?)平台上,程序加载器可能会“重新定位”一些程序地址常量。

答案 4 :(得分:0)

在将闪存驻留二进制映像复制到ram之前,是否可以更新加载程序以对闪存驻留二进制映像执行校验和测试?