assembly 是否有办法了解原始二进制固件是否为Cortex-M?

kjthegm6  于 2022-11-13  发布在  其他
关注(0)|答案(1)|浏览(173)

我有一个固件列表,我应该只过滤Cortex-M类型。是否有任何自动化方法可以将它们与其他ARM固件区分开来?
我有一些想法,比如中断向量表(ivt),或者寻找Cortex-M的其他特定功能,比如Systick,但我不确定它们是否有效。

bkkx9g8r

bkkx9g8r1#

你可以试探性地确定,并具有一定的可靠性:
原始和完整(即完全链接/可引导)Cortex-M映像在开始时具有向量表。向量表在Cortex-M上的区别在于从初始堆栈指针开始,该指针必须是比最小值稍大的RAM地址,随后是初始程序计数器地址(复位向量),它将是ROM地址(在某些器件上,它将位于闪存中,或者它可能是内部掩码ROM引导加载程序)。
此外,复位向量引用的地址值必须是有效指令。如果所有这些映像都是由相同的工具链以相同的运行时启动建立的,则它们将包含相同的代码(但具有不同的分支地址操作数),您可以将其用作签名。否则,在没有完全解码/反汇编的情况下,测试有效指令是复杂的。
有了这些信息,你可能会得到这样的结果:

bool isCortexM( uint32_t* image, uint32_t image_length )
{
    bool is_cortex_m = false ;

    uint32_t sp = image[0] ;
    if( sp > 0x20000000u + MIN_STACK_SIZE && 
        sp < 0x40000000u )
    {
        uint32_t pc = image[1] && 0x00FFFFFFu ;
        if( pc > MIN_VECTOR_TABLE_SIZE && 
            pc < 0x20000000u &&
            pc < image_length )
        {
            instruction = image[pc] ;
            is_cortex_m = instruction != 0 && instruction != 0xFFFFFFFFu ;
        }
    }

    return is_cortex_m ;
}

表达式:

uint32_t pc = image[1] && 0x00FFFFFFu ;

是因为在闪存器件上,闪存通常从较高的地址开始-例如STM32上的0x 08000000,尽管出于复位目的,它通常被别名为0x 0000000,链接器将生成相对于闪存起始地址的地址(因为0x 00000000处的存储器可以重新Map到RAM或片上 Boot ROM)。掩码确保索引相对于零,而不是代码空间的开始。
表达式:

is_cortex_m = instruction != 0 && instruction != 0xFFFFFFFFu ;

是一种适度的尝试,旨在排除属于无效指令的常见“填充”值-它不会确定该值是否真的是有效指令,但要达到这一点,它必须已经通过了前两个测试。
MIN_STACK_SIZE是任意的,但是一个最小的可行堆栈可能是256(0x 100)字节。如果你不确定,你可以使用零-一些运行时启动在任何情况下设置SP,即使硬件可以为你做,在这种情况下,它可能不会设置为表中任何有用的东西-但这是不寻常的和不明智的。
MIN_VECTOR_TABLE_SIZE应至少为0x 40(内核向量)。实际大小因供应商实施方案而异,以支持外设中断。
这不是一种简单的方法--但它实现了我在检查图像的十六进制转储以“猜测”它可能是Cortex-M图像时会手动执行的操作。

如果您不需要自动化这个过程,您最好通过反汇编运行代码,或者将其加载到指令集模拟器中,看看它是否运行。

相关问题