btrace:binder_transaction+eBPF+Golang实现通用的Android APP动态行为追踪工具

一、简介:

    在进行Android恶意APP检测时,需要进行自动化的行为分析,一般至少包括行为采集和行为分析两个模块。其中,行为分析有基于规则、基于机器学习、基于深度学习甚至基于大模型的方案,各有各的优缺点,不是本文关注的重点,本文主要关注Android APP的动态行为采集。在做Android APP逆向分析时经常需要通过hook系统调用观察APP的行为,也需要一个动态行为追踪工具。

    btrace(GitHub - null-luo/btrace: btrace:binder_transaction+eBPF+Golang实现通用的Android APP动态行为追踪工具)就是一个开源的针对Android APP的动态行为采集/追踪工具。目标是通用可靠简单。如果类比到Linux tracing systems的话,我们的工具也可以分成三部分:data sources我们的方案是kprobe/binder_transaction;way to extract data我们采用eBPF;frontends我们使用Golang。

 

 接下来分别介绍这三个部分的方案。

二、data sources:kprobe/binder_transaction

    binder是Android IPC的核心机制,Android APP在访问系统服务的时候,实际上就是在进行跨进程通信,因此,监控binder就可以获取到APP调用系统服务的行为。

这里就不再重复说明了,我们重点看一下在kernel层的哪个函数做监控比较好。我们的目标是要获取:APP的包名、调用服务

 

   首先想到的是内核已经定义的tracepoint: 

  可惜大部分tracepoint都没有带上binder核心数据的指针,也就是没有办法获取到目标服务名和函数参数:   只有binder_ioctl这个tracepoint里面的arg指向的是struct binder_write_read:

 

 

 

     但问题是struct binder_write_read相当的原始,解析起来比较复杂:

 

 这是因为binder_ioctl是链路上kernel层的第一个函数,传进来的数据还没有经过处理。那么,我们能不能找一找binder_ioctl后面的函数,尽可能让系统对数据进行解析和处理之后我们直接拿到想要的字段呢?

    我们把binder_ioctl->binder_ioctl_write_read->binder_thread_write->binder_transaction这条调用链分析了一下,发现binder_transaction是一个比较合适的点,在它之前的函数已经对用户层传入的数据进行了很多解析和过滤,这里拿到的数据是struct binder_transaction_data,相对比较简单了:

   其实,仔细看binder_transaction函数的代码可以发现,本来通过binder_debug和trace_binder_transaction这两个地方直接拿到数据是最方便的,可惜的是binder_debug没有输出code(调用函数的编号),trace_binder_transaction又没有输出调用服务名和参数的数据指针。导致没有办法直接使用这两个点。

 

 

 尤其是trace_binder_transaction,如果往后一点放到内存拷贝(user->kernel)完成之后,再将数据指针输出的话就非常完美了。

所以,最后我们还是回到对binder_transaction这个内核函数进行监控,解析参数struct binder_transaction_data来拿到数据的方案。

三、way to extract data:eBPF

    eBPF是一个运行在Linux内核里面的虚拟机组件,它可以在无需改变内核代码或者加载内核模块的情况下,安全而又高效地拓展内核的功能。是一种非侵入性的内核函数hook方法。

    并且,Google 为了解决 Android 碎片化提出了GKI(通用内核镜像),要求Android 12以上版本的设备出厂必须使用GKI内核,而且GKI内核的编译选项把eBPF相关的功能都是打开的。

    所以eBPF特别适合用于对Android设备中Linux内核函数的监控。

    binder_transaction函数总共5个参数,我们可以根据第4个参数来过滤掉回应的transaction,只关注请求的transaction:

 我们的目标是要获取:APP的包名、调用服务名、调用函数名、调用参数这几个字段:

  •     APP的包名可以通过当前UID来获取(因为binder_transaction函数是在client的进程内);

  •     调用函数名可以通过binder_transaction_data->code来获取;

  •     调用服务名和调用参数可以通过binder_transaction_data->data.ptr.buffer来获取;

   其中要注意的是,binder_transaction_data->data.ptr.buffer指向的数据目前还在用户空间,还没有完成向内核空间的拷贝,所以需要使用bpf_probe_read_user函数。(这就是我上节说的如果把trace_binder_transaction往后移到内存拷贝之后,并且把内核空间的数据地址输出,那就完美了,可惜!):

四、frontend:Golang

    eBPF的核心程序一般是使用C语言编写,clang进行编译后,需要将其加载到内核中。目前有多个项目对eBPF的编写调试运行的流程进行了封装和优化,比如bcc、libbpf等,我们选择的是cilium/ebpf。

    它封装了BPF系统调用,与内核提供的libbpf类似,区别在于这个库是Go语言的,更加方便进行用户态程序的开发,而且外部依赖少,与此同时其还提供了bpf2go工具,可用来将eBPF程序编译成Go语言中的一部分,使得交付更加方便。也就是说很容易将项目编译为一个独立可运行的ELF文件。

    我们的开发环境是Ubuntu arm64的虚拟机(主机是Mac):

 

  cilium/ebpf使用起来非常方便,整个框架分为三个部分:

  • 运行在内核态用C写eBPF代码,llvm编译为eBPF字节码;
  • 用户态使用Golang编写,cilium/ebpf纯go类库,做eBPF字节码的内核加载,kprobe HOOK对应函数;
  • 用户态使用Golang做事件读取、解码、处理。

    我们在内核态程序里将需要的数据放到ringbuf里传递给用户态:

 

 

 

 

   用户态程序收到数据后做处理:

    1、APP的包名

    知道UID后执行命令"pm list packages -U"去查一下就能知道:

  2、调用函数名、调用服务名、调用参数

    Android进程间通信基于Proxy与Stub的设计模式,AIDL是Android接口定义语言,在写完AIDL文件后,编译器自动生成一个同名的.java文件,里面包含Stub和Proxy两个类,Stub类是服务端抽象层的体现。Proxy的接口供客户端程序调用,然后它内部会把信息包装好,通过binder传递给Stub,而后者通过对应的接口作用于服务端系统,从而完成了“远程调用”。

    先来看看Proxy的代码,红色对应的就是要调用函数的编号,也就是binder_transaction_data->code。蓝色就是要调用的服务的接口名,绿色部分则是要调用函数的参数,可以看出来这两部分被打包到一个Parcel里面去,对应的就是binder_transaction_data->data.ptr。最后通过transact函数将以上三部分内容往binder传递。

 

  writeInterfaceToken函数在写入接口名之前,还写了12字节(4+4+4)的其他数据: 

   我们在解析的时候先跳过头部12字节,接下来的4字节代表接口名字符串的长度,接着的数据即是接口名字符串: 

   最后,看一下binder_transaction_data->code如何转换成函数名,仔细分析了binder流程代码,函数名在编译.aidl文件的时候就已经转换成code了,之后一直传递的都是code,直到服务端的onTransact函数里才根据code去选择函数:

    

    所以在整个binder数据传输的过程中都找不到合适的hook点,后来偶然发现.aidl文件自动生成的Stub类里面有getTransactionName、getDefaultTransactionName这么两个函数可以根据函数编码获取到函数名,那么我们就可以使用反射来获取函数名 

顺手在Android代码里搜索了一下这两个函数,发现有一个类已经将对getDefaultTransactionName的调用包装好了: 

但是在golang里面不太好调用Android的API,所以换了一个思路,写了一个Android APP,利用反射把系统服务下所有的transactionCode和methodName的映射关系记录下来,输出给btrace在运行时候查询: 

 

 有几个注意点:

  • 系统所有的服务名可以通过service list获取:

        

  • 需要打开策略开关才能访问hide的API:adb shell settings put global hidden_api_policy 1。
  • 每一个服务内transaction函数一般是从1开始逐个编号的,而且每个函数对应一个field,所以我们获取服务类的field数目就知道此类最多有多少个transaction函数需要我们尝试去获取名字:

 

  最后效果(参数的解析暂不支持): 

五、总结:

    我们使用binder_transaction+eBPF+Golang来实现一个针对Android APP的动态行为追踪工具,目标是通用可靠简单

  • 通用:基于binder底层内核函数,可以监控到所有API调用,覆盖系统版本广泛;

  • 可靠:基于eBPF,对内核无侵入,并且有验证器的验证,安全可靠;

  • 简单:基于Golang作为frontend,灵活高效,逻辑简单清晰,外部依赖少,单一ELF可独立运行。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/27464.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CentOS 7基础操作14_Linux组账号管理

在5.1.2节学习了管理Linux操作系统中用户账号的相关命令,接下来继续学习组账号管理的相关命令。组账号管理命令的使用相对较少,主要包括groupadd、groupdel、gpasswd等。 对于用户账号来说.对应的组账号可分为基本组和附加组两种类型&#xf…

【AI开发】LangGraph基础

在LangGraph中有三个重要元素 StateGraphNodeEdge StateGraph 首先stategraph是用来描述整个图的,图中的状态会随着多个agent的工作不断的更新,节点node就是用来更新状态的 如何来定义一张图中的状态 每个应用的状态可能不同,所以我们需要…

kettle实时增量同步mysql数据

** 本文主要介绍运用kettle实时增量同步mysql数据 ** Debezium介绍 官网地址:https://debezium.io/documentation/ Debezium是一个开源项目,为捕获数据更改(Capture Data Change,CDC)提供了一个低延迟的流式处理平台,通过安装配置Debeziu…

Aigtek高压功率放大器在超声电机中的应用

超声电机是一种先进的电机技术,常用于各种应用,如医疗成像、工业自动化和汽车技术。这些电机在高速、高精度和低噪音要求的领域中表现出色。在驱动这些超声电机时,高压功率放大器发挥着关键作用。本文将介绍高压功率放大器如何驱动超声电机&a…

腾讯元宝APP:AIGC大模型的新篇章

随着科技的飞速发展,人工智能(AI)技术已经渗透到我们生活的方方面面。腾讯作为国内科技巨头,近期推出的元宝APP更是为AIGC(人工智能生成内容)市场注入了新的活力。这款大模型产品的上线,不仅丰富…

【kyuubi-spark】从0-1部署kyuubi集成spark执行spark sql到k8s读取iceberg的minio数据

一、背景 团队在升级大数据架构 前端使用trino查询,对trino也进行了很多优化,目前测试来看,运行还算稳定,但是不可避免的trino的任务总会出现失败的情况。原来的架构是trino失败后去跑hive,而hive是跑mapreduce依赖于…

PostgreSQL:在CASE WHEN语句中使用SELECT语句

CASE WHEN语句是一种条件语句,用于多条件查询,相当于java的if/else。它允许我们根据不同的条件执行不同的操作。你甚至能在条件里面写子查询。而在一些情况下,我们可能需要在CASE WHEN语句中使用SELECT语句来检索数据或计算结果。下面是一些示…

c->c++(一):部分KeyWord

本文主要探讨c相关关键字的使用。 char char默认是unsigned/signed取决平台,wchar_t宽字符:用于Unicode编码(超过一个字节),用wcin和wcout输入输出,字符串为wstring char8_t(20),char16_t(11起),char32_t(11):指定占用字节数且是无符号,字符串类u8string,u16s…

Debian 安装 kubernets

Docker环境 添加 Docker 的官方 GPG 密钥 安装 apt 依赖包,用于通过 HTTPS 来获取仓库 sudo apt-get install \apt-transport-https \ca-certificates \curl \gnupg2 \software-properties-common -y添加秘钥 curl -fsSL https://mirrors.ustc.edu.cn/docker-ce/li…

python之面向对象(一)

一.类与对象 1.1类和对象的创建 类提供了创建对象的蓝图。对象是类的实例,拥有类中定义的属性和方法。self 参数是对类实例自身的引用,用于访问类的属性和方法。 案例: 下面举一个“长方形”类的例子,包含长,宽属性…

关于对pagination.js源代码进行修改且引入项目使用

实现效果 使用定时器对组件进行每秒请求&#xff0c;每过固定时间之后&#xff0c;进行下一页项目请求&#xff0c;进行到最后一页请求的时候返回第一页。 首先引入js插件 <script src"./js/pagination.js" type"text/javascript"></script>…

Python 中国象棋游戏【含Python源码 MX_011期】

简介&#xff1a; 中国象棋是一种古老而深受喜爱的策略棋类游戏&#xff0c;也被称为中国的国粹之一。它在中国有着悠久的历史&#xff0c;起源可以追溯到几个世纪以前。Python 中国象棋游戏是一个用Python编程语言编写的软件程序&#xff0c;旨在模拟和提供中国象棋的游戏体验…

CVE-2024-23692:Rejetto HFS 2.x 远程代码执行漏洞[附POC]

文章目录 CVE-2024-23692&#xff1a;Rejetto HFS 2.x 远程代码执行漏洞[附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现 0x06 修复建议 CVE-2024-23692&#xff1a;Rejetto HFS 2.x 远程代码执行漏洞[附POC] 0x01 前言 …

Elasticsearch:简化数据流的数据生命周期管理

作者&#xff1a;来自 Elastic Andrei Dan 今天&#xff0c;我们将探索 Elasticsearch 针对数据流的新数据管理系统&#xff1a;数据流生命周期&#xff0c;从版本 8.14 开始提供。凭借其简单而强大的执行模型&#xff0c;数据流生命周期可让n 你专注于数据生命周期的业务相关方…

干货!电脑如何录屏?6款win10录屏大师软件深度测评

电脑如何录屏&#xff1f;在2024年&#xff0c;截图或屏幕录制可以说是一种无价的工具。它是捕捉重要信息、与朋友和同事分享说明&#xff0c;或者只是存储您最喜爱的游戏和应用程序中的记忆的好方法。在 Windows 上录制屏幕非常简单。在本篇文章中&#xff0c;我们将讨论在win…

113.网络游戏逆向分析与漏洞攻防-邮件系统数据分析-结构体数据更新思路分析

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 如果看不懂、不知道现在做的什么&#xff0c;那就跟着做完看效果&#xff0c;代码看不懂是正常的&#xff0c;只要会抄就行&#xff0c;抄着抄着就能懂了 内容…

绘唐科技官网

绘唐科技AI工具是一系列经过训练的人工智能工具&#xff0c;旨在提供各种智能化的解决方案。这些工具可以应用于多个领域&#xff0c;包括自然语言处理、图像识别、语音识别、机器学习等。 其中&#xff0c;自然语言处理工具可以帮助用户处理和理解文本数据。它可以实现文本分类…

Spring 内置BeanFactoryPostProcessor的子孙们

同样的Spring 也 内置了 一些实现 BeanFactoryPostProcessor的类&#xff0c;各有各的用处。 spring-context AspectJWeavingEnabler 用来把ClassPreProcessorAgentAdapter注册到LoadTimeWeaver中ConfigurationClassPostProcessor 一个重要的类&#xff0c;用来处理Configurat…

3、matlab单目相机标定原理、流程及实验

1、单目相机标定流程及步骤 单目相机标定是通过确定相机的内部和外部参数&#xff0c;以便准确地在图像空间和物体空间之间建立映射关系。下面是单目相机标定的流程及步骤&#xff1a; 搜集标定图像&#xff1a;使用不同角度、距离和姿态拍摄一组标定图像&#xff0c;并确保标…

树莓派 sudo apt-get install python-smbus 报错

sudo apt-get install python-smbus 报错 sudo apt-get install python-smbus 报错 python-smbus : Depends: python (< 2.8)Depends: python (> 2.7~)Depends: python:any (< 2.8)Depends: python:any (> 2.7~) E: Unable to correct problems, you have held b…