反转ARM64文件时如何知道子程序何时开始?

逆向工程 艾达 手臂
2021-06-27 01:58:20

我是 ARM 世界的新手,我突然想到一个问题:(你最喜欢的逆向工程工具)如何知道 ARM64 文件的子程序从哪里开始(因为我想编写一个工具来知道文件有多少功能)?

提前致谢。

1个回答

我不知道我的工具在幕后是如何做的,但如果我必须自己做,我会搜索一些与我选择的架构相关的函数的序言。

这是识别函数的一个很好的“签名”,因为这是标准的东西(即使您可能会发现某些函数没有任何序言/尾声的情况)。

如您所知,函数的序言旨在保存前一个堆栈帧,并设置一个新的堆栈帧,该帧能够处理函数的局部变量,而不会弄乱前一个函数在堆栈中存储的内容。它还用于存储函数结束时返回的地址(基本上保存旧指令指针 + x,并在函数结束时覆盖它)。

相反,一个函数的结尾包含一个结语,女巫应该恢复之前的堆栈帧,并返回到之前的例程。

这完全取决于用于生成目标二进制文件的编译器,但典型的 ARM64 函数的结尾如下所示:

sub    sp, sp, #32          ; make rooms on the stack for the new stack frame
stp    x29, x30, [sp, #16]  ; save what is needed to restore the previous stack frame and where to return (respectively x29 the previous SP, and x30 the return address)
add    x29, sp, #16         ; new frame pointer

如果您有包含某些函数的二进制代码块,请尝试查找这些指令的操作码。它应该指明函数从哪里开始。

现在是实施本身:利用您的工具和现有的工具。您添加了“IDA”标签,所以我想这就是您在提及“最喜欢的工具”时所考虑的内容。

当 IDA 无法找到任何函数时(例如,如果我尝试反汇编没有入口点和一些间隔函数的大块 ARM 数据),我使用这个能够搜索给定二进制模式的小 IDAPython 片段,反汇编以此开头的所有内容,并将其添加到函数和反汇编列表中。IDA 自动分析将由此触发,它应该找到第一个内部调用的其他函数,依此类推。

from idaapi import *
from ida_search import *
from ida_funcs import *

cnt = 0
my_pattern = '' # The hex value of the opcodes you are looking for

def is_function(start_addr):
   content = get_bytes(start_addr, 4, False).hex()
   if content == my_pattern:
      return True
   return False

addr = find_unknown(0, 1)
while addr != BADADDR
   is_valid = is_function(addr)
   if is_valid:
      add_func(addr)
      cnt += 1
   addr = find_unknown(addr, 1)

print('A total of ' + str(cnt) + ' new functions where defined')

这个非常具有攻击性,如果一团垃圾数据包含看起来像您的二进制模式的内容,则可能会发现“误报”。

如果没有发现,则说明您的模式不是一个好模式。在这种情况下,在 IDA 中的随机位置反汇编,直到找到有效的函数。当你有一个时,检查这个函数序言的样子。它可能略有不同,并且您的签名与它不匹配。用这个新签名更新脚本,你应该很好。