【发布时间】:2017-11-11 01:15:52
【问题描述】:
我正在尝试用 C 语言编写概念证明,以演示从 ARM Cortex-M3 堆栈中的内存缓冲区执行代码。这将有助于证明正确使用 ARM MPU 可以防止此类攻击。我想出一种快速而肮脏的方法来将一些代码放入堆栈中,就是从常规函数中复制它,然后使用 goto 跳转到它,如下所示:
static void loopit(void)
{
printf("loopit\n");
while (1);
}
void attack(void)
{
uint8_t buffer[64] __attribute__((aligned(4)));
memcpy(buffer, loopit, sizeof(buffer));
goto *((void *) (int) buffer);
}
我希望当我调用攻击函数时,它会将代码复制到堆栈中,跳转到堆栈,打印消息并进入无限循环。但是,我在故障寄存器中得到以下值的异常:
HFSR = 0x40000000
CFSR = 0x00020000
PSR = 0x60000000
这似乎是 UFSR 中的 INVSTATE 位,表示“非法使用 EPSR”,我读到这通常是由于 BX 指令试图跳转到 LSB 设置为 0 的地址,处理器将其解释为一个包含非 Thumb 代码的函数,但 Cortex-M 处理器只允许 Thumb 代码。我看到 memcpy 被赋予了 loopit 函数的奇数地址,因为我假设编译器正在使用 1 对实际内存地址进行 ORing。所以我认为的解决方法是像这样重写我的攻击函数:
void attack(void)
{
uint8_t buffer[64] __attribute__((aligned(4)));
memcpy(buffer, ((int) loopit) & ~1, sizeof(buffer));
goto *((void *) ((int) buffer) | 1);
}
但是在这样做之后,我得到了一个错误寄存器的不同异常:
HFSR = 0x40000000
CFSR = 0x00080000
PSR = 0x81000000
这似乎没有任何意义,设置 UFSR 位 3 意味着“处理器已尝试访问协处理器”。这次看看 PC,它似乎跳转成功了,这很棒,但随后有些事情脱轨,CPU 似乎正在执行奇怪的指令,而不是进入无限循环。我尝试在 goto 之前关闭中断并注释掉 printf 但没有运气。任何线索出了什么问题以及如何使其工作?
【问题讨论】:
-
您是否尝试查看由 C 编译器生成的 loopit() 函数的汇编代码?这可能会提示为什么副本或其执行无法按预期工作。
-
为了确保您运行的是裸机 - 没有操作系统或 MMU 会自动阻止您在数据空间中运行代码?在调试器中运行可能会回答很多问题,包括你到底要跳转到什么。
-
为什么
(int)转换为(void *) ((int) buffer),取决于int的大小和指针的大小,int转换可能会改变地址。goto *((void *) buffer);会更好吗? -
修复代码中的编译错误后,它对我有用。没有故障,在缓冲区内循环。你用什么编译器?
-
调用 printf() 或任何其他函数会导致错误,因为生成的 BL 指令使用相对寻址,跳转到 RAM 中的随机地址。