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

标签 c load embedded data-integrity

我正在尝试获取 ram 驻留图像以校验和本身,事实证明这说起来容易做起来难。

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

无论如何,这就是理论。问题在于,一旦图像开始执行,.data 部分就会随着变量的修改而发生变化。当求和完成时,已求和的图像不再是实用程序计算求和的图像。

我已经消除了由于我的应用程序定义的变量而导致的变化,方法是将校验和例程移动到应用程序中所有其他初始化之前(这是有道理的 b/c 为什么在完整性检查失败时运行其中的任何一个,对吗?) ,但 killer 是 C 运行时本身。似乎有一些与 malloc 和指针转换相关的项目以及甚至在输入 main() 之前更改的其他内容。

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

FWIW,我似乎坚持这个要求。就个人而言,我认为要走的路是在传输到 ram 之前对闪存中的二进制 进行校验和,然后信任加载程序和 ram。偏执狂必须在某个地方结束吗?

杂项详细信息:工具链是 GNU,图像包含 .text.rodata.data 作为一个连续加载的 block 。没有操作系统,这是嵌入式裸机。主加载程序本质上是将我的二进制文件 memcpy 放入 ram 中的预定地址。没有搬迁发生。不使用虚拟机。校验和只需要在初始化时测试一次。


已更新 发现通过这样做..

__attribute__((constructor)) void sumItUp(void) {
    // sum it up
    // leave result where it can be found
}

.. 除了由 CRT init 初始化 malloc/sbrk vars 和一些由“不纯.o”和“locale.o”。现在,malloc/sbrk 值是我从项目链接描述文件中了解到的。如果 impure.o 和 locale.o 可以得到缓解,可能会成功。

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

最佳答案

如果校验和足够早地完成,您可以只使用堆栈变量,而不写入任何数据段变量——也就是说,制作执行校验和所需的一切[以及所有前面的步骤来达到这一点]只使用局部变量来存储东西 [当然你可以读取全局数据]。

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

如果其他人有要求您应该这样做,那么请向他们解释这是不可行的,并且“按原样提出的要求”已“损坏”。

关于校验和自身*在 ram* 中的 C 代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14103061/

相关文章:

javascript - jQuery 在一个元素中加载多个 html 文件

仅LSI/LSE/HSE中Stm32L中RTC的时钟配置?

c - 使用sleep()时计算执行时间

c - 如何在 C 中使用 GTK 使用 G_CALLBACK 获取输入值

jquery改变加载获取url

c - 设置创建多少个信号量?

php - 上传 csv 文件以选择表中的列

c++ - 使用 C 的 ARM9 上未对齐内存访问异常的解决方法是什么?

c - 如何从磁盘镜像复制文件?

c++ - 为什么最后一个十进制数字为 5 的 float 在浮点比较中给出正确的输出,而在其他情况下却不是?