17

我正在尝试为校验和本身获取一个驻留在内存中的图像,事实证明这说起来容易做起来难。

代码首先在交叉开发平台上编译,生成 .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/ sbrkvars 的初始化,以及“impure.o”和“locale.o”拥有的一些 vars。现在,malloc/sbrk值是我从项目链接器脚本中知道的。如果 impure.o 和 locale.o 可以得到缓解,可能会做生意。

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

4

5 回答 5

4

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

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

如果其他人要求您执行此操作,请向他们解释执行此操作不可行,并且“目前的要求”已“损坏”。

于 2012-12-31T15:19:12.273 回答
2

我建议像执行打包程序一样处理这个问题,比如upx

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

  • 我不会相信装载机或任何非强加于我的闪存中的东西。
  • 网上流传着一些源代码,用于保护我认为 HTC 最近推出的手机之一。在 forum.xda-developers.com 上四处看看,看看是否可以找到它并用作示例。
  • 我会反对这个要求。手机制造商花费大量时间来锁定他们的图像,最终,他们都被打败了。这似乎是一个恶性循环。
于 2012-12-31T17:13:15.390 回答
1

您可以使用链接器脚本将 impure.o 和 locale.o 放置在其他所有内容之前或之后,从而允许您对除这些和 malloc/sbrk 之外的所有内容进行校验和吗?我猜 malloc 和 sbrk 在加载您的应用程序的引导加载程序中被调用,因此无法消除由这些引起的抖动?

仅仅告诉你反对这个要求并不是一个答案,但我同意这似乎是多虑了。我敢肯定你不能详细说明,但我假设规范作者关心的是恶意用户/黑客,而不是由于宇宙射线等导致的常规内存损坏。在这种情况下,如果恶意用户/黑客可以更改加载到 RAM 中的内容,他们可以更改您的校验和例程(它本身是从 RAM 运行的,对吗?)以始终返回快乐状态,无论他们不再运行的校验和例程设计得有多好.

即使他们担心定期的内存损坏,这个校验和例程也只会在原始复制到内存期间发生错误时才会发现,这实际上是发生此类错误的可能性最小的时间,仅仅是因为系统尚未运行足够长的时间来发生腐败事件的可能性很高。

于 2012-12-31T17:40:02.410 回答
0

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

于 2012-12-31T15:43:54.147 回答
0

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

于 2012-12-31T21:16:55.870 回答