在ARM Thumb中智能拆卸TBB?

时间:2017-02-24 11:31:00

标签: assembly arm disassembly thumb

在ARM中,TBB(表分支字节)基本上是一个开关指令,它在基于传入的索引(开关值)的指令之后从表中获取跳转地址,然后跳转到该地址。 ARM docs

我正在尝试自动反汇编TBB(和TBH)表,因此它们不会作为指令进行反汇编,而是在表后继续反汇编。麻烦的是,TBB表是可变长度的,并且没有边界检查。必须在TBB之前手动(或通过编译器)完成边界检查。

该表没有终结符,并且在表中任何字节都是有效的跳转偏移量。代码在表格后立即重新开始。

那么,有没有人遇到(或者可能会想到)一种自动确定TBB表长度的方法?我所拥有的最好的是在默认情况下搜索导致TBB的指令,但这似乎是一种不精确的方法。

1 个答案:

答案 0 :(得分:0)

这是我正在尝试的一种可能的方法,这似乎有效,至少对于一些表现良好的分支表。解码TBB后,我开始循环遍历分支字节。对于每一个,我找到它对应的地址,并跟踪这些地址中的最低地址(最接近分支表的末尾)。我还检查每个分支地址是否在当前解码的分支字节之后,因为表的末尾可能没有填充。

这取决于表的末尾和表中引用的代码的开头之间没有任何代码或数据。例如,如果默认情况紧接在表之后,但未从表中引用,则会遇到问题。对于我必须测试的示例,编译器将默认情况放在其他情况的末尾。

我正在使用Capstone进行反汇编,这里有一些代码在没有太多上下文的情况下应该有意义:

case ARM_INS_TBB:
// Table branch byte
if(insn->detail->arm.op_count == 1 &&
        insn->detail->arm.operands[0].type == ARM_OP_MEM &&
        insn->detail->arm.operands[0].mem.base == ARM_REG_PC){
    // PC relative TBB
    u64 min = U64_MAX;
    // loop over table bytes
    for(u64 i = 0; ; ++i){
        // check if current table byte is before minimum branch target
        if(insn_addr + insn->size + i < min){
            // get branch address from table byte
            u64 branchaddr = insn_addr + insn->size +
                (binary_image[insn_addr + insn->size + i] << 1);
            // check if branch address is larger than the 
            // location of the previous table byte
            if(branchaddr > insn_addr + insn->size + i){
                // new lower address branch target
                min = branchaddr;
                // do something with the code at branchaddr
            } else {
                break;
            }
        } else {
            break;
        }
    }
}
// Instructions immediately after this are junk, stop parsing
return;
break;