你好逆向工程师,
我正在分析一个胖 Macho-O 二进制文件,它有一个 ADRP 和一个 ADD 指令。我说的是这些说明:
__text:00000001002E050C ADRP X8, #some_function@PAGE
__text:00000001002E0510 ADD X8, X8, #some_function@PAGEOFF
ADRP 指令具有字节“08 00 00 90”。
ADD 指令的字节为“08 61 0D 91” 如何从 2 条指令中获取值?这是我计算 some_function 地址的程序:它应该对 21 位偏移进行符号扩展,将其左移 12,然后将其添加到 PC 并清除低 12 位。然后我应该从 ADD 指令中获取最后 12 位,并将其添加到该值中。
int instr = 0x90000008;
//int instr = 0x80000090;
int value = 0x1fffff & instr;
int mask = 0x100000;
if(mask & instr)
{
value += 0xffe00000;
}
printf("value : %08x\n", value);
value = value << 12;
printf("value : %08x\n", value);
int instr2 = 0x910d6108;
//int instr2 = 0x08610d91;
value += (instr2 & 0xfff); //get the last 12 bits from instr2
printf("value : %08x\n", value);
执行指令后,值00000001002E0358应该在X8中,因为那是我们要计算的函数的地址。我的程序的输出是:
value : 00000008
value : 00008000
value : 00008108
我究竟做错了什么?
结论:我读错了 ARM 手册。ARM 的官方 AArch64 手册是您应该使用的手册。
最终代码:
const int tab32[32] = {
0, 9, 1, 10, 13, 21, 2, 29,
11, 14, 16, 18, 22, 25, 3, 30,
8, 12, 20, 28, 15, 17, 24, 7,
19, 27, 23, 6, 26, 5, 4, 31};
int log2_32 (uint32_t value)
{
value |= value >> 1;
value |= value >> 2;
value |= value >> 4;
value |= value >> 8;
value |= value >> 16;
return tab32[(uint32_t)(value*0x07C4ACDD) >> 27];
}
uint64_t get_page_address_64(uint64_t addr, uint32_t pagesize)
{
int bits_page_offset;
bits_page_offset = log2_32(pagesize);
return (addr >> (bits_page_offset - 1)) << (bits_page_offset - 1);
}
uint64_t get_adrp_add_va(unsigned char *adrp_loc, uint64_t va){
uint32_t instr, instr2, immlo, immhi;
int32_t value;
int64_t value_64;
//imm12 64 bits if sf = 1, else 32 bits
uint64_t imm12;
instr = *(uint32_t *)adrp_loc;
immlo = (0x60000000 & instr) >> 29;
immhi = (0xffffe0 & instr) >> 3;
value = (immlo | immhi) << 12;
//sign extend value to 64 bits
value_64 = value;
//get the imm value from add instruction
instr2 = *(uint32_t *)(adrp_loc + 4);
imm12 = (instr2 & 0x3ffc00) >> 10;
if(instr2 & 0xc00000)
{
imm12 <<= 12;
}
return get_page_address_64(va, PAGE_SIZE) + value_64 + imm12;
}