0

0

android linux内核层 Android 跨进程通信:IPC、Binder 与 ServiceManager 介绍

PHPz

PHPz

发布时间:2024-06-30 15:31:13

|

1413人浏览过

|

来源于ITcool

转载

Sora
Sora

Sora是OpenAI发布的一种文生视频AI大模型,可以根据文本指令创建现实和富有想象力的场景。

下载

作者峰会帐号:windy_ll

ebpf在Android安全上的应用:结合binder完成一个行为检查沙箱(上篇)一、IPC简单介绍

IPC是Inter-ProcessCommunication的简写,含意为进程间通讯或则跨进程通讯,是指两个进程之间进行数据交换的过程。

Android在哪些时侯会有跨进程通讯的须要?Android在恳求系统服务的时侯会有跨进程通讯的需求,比如访问手机通信录、获取定位等等行为,本文的目标即是实现一个简易的捕捉这种行为的沙箱

二、binder简单介绍

Binder是Android中的一种跨进程通讯形式,可以理解为是IPC的一种具体实现方法

三、ServiceManager简单介绍

ServiceManager是Android中一个及其重要的系统服务,从它的名称上就可以晓得,它是用于管理系统服务的

ServiceManager由init进程启动

ServiceManager负责了以下的一些功能:服务的注册与查找、进程间通讯、系统服务的启动与唤起、提供系统服务的清单实例

binder驱动决定了底层的通讯详情,这么ServiceManager则相当于导航,告诉具体的通讯该如何走,达到那儿等

四、通信剖析4.1顾客端调用JAVA层剖析

以WifiManager类的getConnectInfo函数(该函数获取wifi信息)为例进行剖析

ctrl+左键查看引用,可以发觉该函数定义在.wifi.WifiManager类中,如右图所示:

从上图可以看见,getConnectInfo函数具体代码只有一句thrownewRuntimeException("Stub!");,这告诉我们这个函数是由rom中相同的类去取代执行,该函数在这被定义是编译所须要(PS:可以参考),在android源码中的目录frameworks/base/wifi/java/amdroid/net/wifi下我们可以找到该类,之后找到该函数的具体实现,如右图所示:

可以发觉该函数调用了IWifiManager的getConnectionInfo函数,在frameworks/base/wifi/java/amdroid/net/wifi目录下可以找到IWifiManager.aidl文件,该aidl中定义了getConnectionInfo函数,如右图所示:

这儿须要引入一个概念---AIDL,AIDL是android的一种插口语言,用于公开android服务的插口,借此来实现跨进程的函数调用。AIDL在编译时会生成两个类,即Stub和Proxy两个类,Stub类是服务端具象层的彰显,Proxy是顾客端获取的实例,android通过proxy-stub这些设计模式实现了IPC

下边写一个aidl文件之后生成相应的java代码来瞧瞧是如何实现调用的,首先,我们在androidstudio中随意找一个项目,之后新建一个aidl文件,如右图所示:

内核层是什么细胞_android linux内核层_内核层向上提供的标准接口

之后Build->MakeProbject即可生成,生成的路径坐落build/generated/aidl_source_output_dir/debug/out/包名,如右图所示:

观察生成后的java文件可发觉,Proxy类早已生成,在Proxy类中我们可以找到我们定义的函数,如右图所示:

具体剖析一下该函数,首先通过obtain函数生成了一个Parcel实例,之后调用Parcel的write系列函数进行写入,虽然就是一个序列化的过程,之后调用了IBinder的transact函数,跟踪剖析一下该函数,在目录frameworks/base/core/java/android/os下可以找到该java文件,如右图所示:

内核层向上提供的标准接口_内核层是什么细胞_android linux内核层

android linux内核层_内核层是什么细胞_内核层向上提供的标准接口

内核层向上提供的标准接口_android linux内核层_内核层是什么细胞

可以发觉,IBinder仅仅是一个插口linux删除命令,其中定义了transact方式,该方式有4个参数,第一个参数code在我们的远程调用中为函数编号,服务端接受到这个编号后,会去找寻Stub类中的静态变量,因而解析出是调用哪个函数,第二个和第三个参数_data、_reply为传入的参数和返回的值,都是经过序列化后的数据android linux内核层,最后一个参数flags为指示是否须要阻塞等待结果,0为阻塞等待,1为立刻返回。

全局搜索一下,可以发觉同目录下的BinderProxy类实现了该插口(PS:值得注意的是,同目录下边还存在一个Binder类,也实现了该插口,但Binder类是服务端的实现,而不是顾客端的实现),如右图所示:

内核层是什么细胞_android linux内核层_内核层向上提供的标准接口

剖析该函数,可以发觉最后迈向了transactNative函数,到此为止,进行IPC通讯顾客端java层早已剖析完毕

4.2顾客端调用Native层剖析

全局搜索一下transactNative函数,可以发觉该函数在native层中注册信息,如右图所示:

内核层向上提供的标准接口_android linux内核层_内核层是什么细胞

跟踪一下android_os_BinderProxy_transact函数,可以发觉该函数首先通过getBPNativeData(env,obj)->mObject.get()获取到了一个BpBinder对象,之后调用了BpBinder的transact函数,如右图所示:

内核层是什么细胞_内核层向上提供的标准接口_android linux内核层

继续跟进下去,可以发觉步入了IPCThreadState的transact函数,如右图所示:

接着跟进,可以发觉首先调用writeTransactionData函数,该函数作用为填充binder_transaction_data结构体,为发送到binder驱动做打算,之后调用waitForResponse等待返回,如右图所示:

android linux内核层_内核层向上提供的标准接口_内核层是什么细胞

android linux内核层_内核层是什么细胞_内核层向上提供的标准接口

跟进waitForResponse函数,可以发觉该函数最重要的就是调用talkWithDriver函数,剖析一下talkWithDriver函数,可以发觉最终调用了ioctl,如右图所示:

四处为止,顾客端native层剖析完毕

4.3内核层剖析(binder驱动剖析)

到此处android linux内核层,我们的ebpf程序就可以开始捕捉之后解析数据格式了

当用户层调用ioctl时,会步入内核态,步入binder_ioctl内核函数(ps:可在内核设备源码中的binder.c找到相应的描述符),剖析一下binder_ioctl函数,可发觉该函数主要作用为在两个进程之间首发数据,我们的通讯数据ioctl命令是BINDER_WRITE_READ,当遇见该命令的时侯,会调用binder_ioctl_write_read函数,如右图所示:

内核层是什么细胞_android linux内核层_内核层向上提供的标准接口

内核层向上提供的标准接口_内核层是什么细胞_android linux内核层

跟进binder_ioctl_write_read函数,可以发觉,该函数首先将unsignedlong类型的arg参数指向的地址的值读取到结构体binder_write_read中,说明当ioctl命令为BINDER_WRITE_READ时,传递进来的参数为指向结构的binder_write_read的表针,如右图所示:

内核层是什么细胞_内核层向上提供的标准接口_android linux内核层

到这儿虽然我们内核态的剖析早已可以结束了,我们早已观察到了我们想要的数据了,即binder_write_read结构体,可以看一下该结构体的定义,如下所示:

<em style="cursor: pointer;font-size: 12px"> 复制代码</em><em style="cursor: pointer;font-size: 12px"> 隐藏代码<br /></em><code><span>struct</span> <span>binder_write_read</span> {<br />    <span>binder_size_t</span> write_size; <span>/* 写内容的数据总大小 */</span><br />    <span>binder_size_t</span> write_consumed; <span>/* 记录了从缓冲区读取写内容的大小 */</span><br />    <span>binder_uintptr_t</span> write_buffer; <span>/* 写内容的数据的虚拟地址 */</span><br />    <span>binder_size_t</span> read_size; <span>/* 读内容的数据总大小 */</span><br />    <span>binder_size_t</span> read_consumed; <span>/* 记录了从缓冲区读取读内容的大小 */</span><br />    <span>binder_uintptr_t</span> read_buffer; <span>/* 读内容的数据的虚拟地址 */</span><br />};</code>

这个结构体是拿来描述进程间通讯过程中所传输的数据,我们读取从顾客端发送到服务端的通讯包只须要关注write_size、write_consumed、write_buffer,其中,write_buffer指向的是一个链表,这个字段中就包含了binder_transaction_data结构体,这个结构体在native层writeTransactionData函数填充的,我们的目标通讯包即是这个结构体,其中,write_buffer和read_buffer指向的数据结构大致如下:

通常来说,驱动会一次性传递多条命令和地址的组合,而我们要在其中找到binder_transaction_data结构体对应的指令,在binder.h头文件中我们可以找到驱动定义的所有指令(+/refs/heads/android-mainline/include/uapi/linux/android/binder.h),如右图所示:

内核层向上提供的标准接口_android linux内核层_内核层是什么细胞

可以发觉,BC_TRANSACTION和BC_REPLY指令都对应着binder_transaction_data结构体参数,但我们只须要顾客端发往驱动的数据包,所以我们只须要BC_TRANSACTION指令对应的参数即可

经过前面的剖析,我们找到了我们须要的核心数据---binder_transaction_data结构体,现今来看一下该结构体的定义,定义如下:

<em style="cursor: pointer;font-size: 12px"> 复制代码</em><em style="cursor: pointer;font-size: 12px"> 隐藏代码<br /></em><code><span>struct</span> <span>binder_transaction_data</span> {<br />    <span>union</span> {<br />        __u32 handle;<br />        <span>binder_uintptr_t</span> ptr;<br />    } target; <span>/* 该事务的目标对象 */</span><br />    <span>binder_uintptr_t</span> cookie; <span>/* 只有当事务是由Binder驱动传递给用户空间时,cookie才有意思,它的值是处理该事务的Server位于C++层的本地Binder对象 */</span><br />    __u32 code; <span>/* 方法编号 */</span><br />    __u32 flags;<br />    <span>pid_t</span> sender_pid;<br />    <span>uid_t</span> sender_euid;<br />    <span>binder_size_t</span> data_size; <span>/* 数据长度 */</span><br />    <span>binder_size_t</span> offsets_size; <span>/* 若包含对象,对象的数据大小 */</span><br />    <span>union</span> {<br />        <span>struct</span> {<br />            <span>binder_uintptr_t</span> buffer; <span>/* 参数地址 */</span><br />            <span>binder_uintptr_t</span> offsets; <span>/* 参数对象地址 */</span><br />        } ptr;<br />        __u8 buf[<span>8</span>];<br />    } data; <span>/* 数据 */</span><br />};</code>

有了该数据结构linux安装,我们就可以晓得顾客端调用服务端的函数的函数、参数等数据了

五、实现疗效

内核层是什么细胞_内核层向上提供的标准接口_android linux内核层

PS:整套系统用于商业,就不做开源处理了,这儿只给出核心结构体复印的截图,就不再发后端的截图了

读取手机通信录(ps:这儿读取下来的数据采用了Toast复印的,所以将捕捉到的Toast相应的通讯包也一起复印了下来,下同):

获取地理位置

获取wifi信息:

六、其他

里面当然我们只剖析到了发送部份,反过来,虽然我们也可以读取返回包甚至于更改返回包,就可用于对风控的对抗,比如在内核态中更改APP恳求的设备标示信息(其实前提是app走系统提供的驱动通讯),亦或则用于逆向的工作,比如过root检查等等。

这部份验证代码就暂不放下来了,感兴趣的可以自己实现一下

-官方峰会

公众号设置“星标”,您不会错过新的消息通知

如开放注册、精华文章和周边活动等公告

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

490

2025.06.09

golang结构体方法
golang结构体方法

本专题整合了golang结构体相关内容,请阅读专题下面的文章了解更多。

202

2025.07.04

treenode的用法
treenode的用法

​在计算机编程领域,TreeNode是一种常见的数据结构,通常用于构建树形结构。在不同的编程语言中,TreeNode可能有不同的实现方式和用法,通常用于表示树的节点信息。更多关于treenode相关问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

549

2023.12.01

C++ 高效算法与数据结构
C++ 高效算法与数据结构

本专题讲解 C++ 中常用算法与数据结构的实现与优化,涵盖排序算法(快速排序、归并排序)、查找算法、图算法、动态规划、贪心算法等,并结合实际案例分析如何选择最优算法来提高程序效率。通过深入理解数据结构(链表、树、堆、哈希表等),帮助开发者提升 在复杂应用中的算法设计与性能优化能力。

30

2025.12.22

深入理解算法:高效算法与数据结构专题
深入理解算法:高效算法与数据结构专题

本专题专注于算法与数据结构的核心概念,适合想深入理解并提升编程能力的开发者。专题内容包括常见数据结构的实现与应用,如数组、链表、栈、队列、哈希表、树、图等;以及高效的排序算法、搜索算法、动态规划等经典算法。通过详细的讲解与复杂度分析,帮助开发者不仅能熟练运用这些基础知识,还能在实际编程中优化性能,提高代码的执行效率。本专题适合准备面试的开发者,也适合希望提高算法思维的编程爱好者。

44

2026.01.06

android开发三大框架
android开发三大框架

android开发三大框架是XUtil框架、volley框架、ImageLoader框架。本专题为大家提供android开发三大框架相关的各种文章、以及下载和课程。

338

2023.08.14

android是什么系统
android是什么系统

Android是一种功能强大、灵活可定制、应用丰富、多任务处理能力强、兼容性好、网络连接能力强的操作系统。本专题为大家提供android相关的文章、下载、课程内容,供大家免费下载体验。

1819

2023.08.22

android权限限制怎么解开
android权限限制怎么解开

android权限限制可以使用Root权限、第三方权限管理应用程序、ADB命令和Xposed框架解开。详细介绍:1、Root权限,通过获取Root权限,用户可以解锁所有权限,并对系统进行自定义和修改;2、第三方权限管理应用程序,用户可以轻松地控制和管理应用程序的权限;3、ADB命令,用户可以在设备上执行各种操作,包括解锁权限;4、Xposed框架,用户可以在不修改系统文件的情况下修改应用程序的行为和权限。

2136

2023.09.19

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

76

2026.03.11

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 10.5万人学习

Git 教程
Git 教程

共21课时 | 4.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号