最近分析了一个 app,有 frida 检测,一旦 attach 之后,app 就退出了。过去分析的一些 app,通常都有 frida 的检测,但不会这么暴力的退出。于是我就分析了一下这个 app 的检测逻辑。基于此,我把市面上常见的一些 frida 检测逻辑都整理了一下。
检测frida-server 是否运行的方法有:
检测端口
检测 D-Bus 协议
检测文件路径
注入检测的方法有:
检测 /proc/xx/maps
内存中检索特殊字符串
检测 /proc/xx/task/xx/stat 或 /proc/xx/task/xx/status
检测 /proc/xx/fd
检测 inline hook
下面展开介绍一下每个检测方法的细节。
frida-server 启动的时候会监听 27042 端口, 所以检测这个端口可以认为存在 frida。
frida 通过 D-Bus 协议通信, 所以向所有端口发送 AUTH 消息, 如果收到了返回,那么就可以确认 frida-server 存在.
frida-server 启动之后, 会在本地生成一个 re.frida.server 的目录,可以检测这个路径来判断 fridaserver 是否启动过
在maps 文件中,会发现存在:
7327731000-7328057000 r--p 00000000 08:0d 917564 /data/local/tmp/re.frida.server/frida-agent-64.so
因此,可以判断 frida 是否注入到内存中。
此外,还可以先从 maps 中过滤出包含 /data/local/tmp/ 的路径, 通过解析elf 文件的导出表,查看是否含有frida 的特征。内存中检索特殊字符串
这是一个不太高效的方法,原理就是根据 maps 中的信息,访问内存,确认内存中是否存在带有 frida 特征的字符串,比如LIBFRIDA, 这个方法比较低效,所以不推荐。
frida 在注入的时候会启动一个线程,通过分析,可以发现,线程存在一定的特征,即 gum-js-loop 或者 gmain,如果扫描 status 文件发现这些特征,就可以认为是 frida 注入了。
frida 在注入的时候,会打开一个FIFO文件用于通信,通过 readlink 可以找到原始的文件名, 如果文件名中linjector则说明已经注入了。
:/proc/26047/fd # ls -al | grep /data/local/
l-wx------ 1 u0_a111 u0_a111 64 2023-05-25 19:24 386 -> /data/local/tmp/re.frida.server/linjector-4
frida 使用 inline hook 技术 hook 目标函数, 可以对常规的 libc 函数进行 hook, 一旦发现函数开头前几个字节符合特征,就可以认为是被 hook了。另外在分析一些app的过程中,我发现有的厂商会检测_ZN3art12PrettyMethodEPNS_6mirror9ArtMethodEb 方法是否会被hook。这个方法的主要作用是将 ArtMethod 对象的信息转换为易于阅读的格式, 可能可以做一些辅助分析。