论文部分内容阅读
摘 要:Binder是Android系统进程间通信方式之一。Linux已经拥有管道system V IPC、socket等IPC手段,却还要倚赖Binder来实现进程间通信,说明Binder具有无可比拟的优势。本文通过对Binder的详细介绍以及与其他IPC通信方式的调用,使大家对Binder的优势和使用Binder作为Android主要IPC方式的原因有所了解。
关键词:Android system_server binder
本文内容包含使用在拥有root权限的Android2.3平台上针对system_server中binder通信的拦截。
一、动态链接机制及Binder拦截选址
要拦截模块甲对乙的调用,一般思路是通过ptrace远程注入并加载一新拦截模块至模块甲,并搜索模块甲的GOT表,找到对模块乙的调用地址,改成新模块内的某函数地址,然后新模块内的这个函数在进行了自己的处理后,再跳到模块乙中。
这里用户进程空间所加载的libbinder.so和system_server端加载的libbinder.so在逻辑上不是同一个东西。正因为不是同一个东西,我们才能针对system_server进程中加载的libbinder.so动手,拦截其GOT表中对ioctl的调用,从而提前知道Service要返回的内容。这个ioctl就是拦截的选址所在。
二、具体实现
在这个常驻system_server进程内的共享库里,只实现了简单几个函数,其中do_hook函数在注入后通过外界调用,它不做具体的hook动作,仅仅只是把所需的两个函数地址写入Android的Property供外界使用:
[cpp] view plaincopy01.//将新旧ioctl地址写入Andorid的Property供外界使用;
02.int do_hook(void * param)
03.{
04.old_ioctl = ioctl;
05.printf("Ioctl addr: %p. New addr %p\n", ioctl, new_ioctl);
06.
07.char value[PROPERTY_VALUE_MAX] = {’\0’};
08.snprintf(value, PROPERTY_VALUE_MAX, "%u", ioctl);
09.property_set(PROP_OLD_IOCTL_ADDR, value);
10.
11.snprintf(value, PROPERTY_VALUE_MAX, "%u", new_ioctl);
12.property_set(PROP_NEW_IOCTL_ADDR, value);
13.
14.return 0;
15.}
16.
17.//全局变量用以保存旧的ioctl地址,其实也可直接使用ioctl;
18.int (*old_ioctl) (int __fd,unsigned long int __request, void * arg) = 0;
19.int res = (*old_ioctl)(__fd,__request, arg);
20.return res;
21.}.
三、小结
第一,每个被加载的模块,无论是可执行程序还是共享库,均有自己独立的PLT和GOT表。所以拦截这个模块的对外调用的GOT,不影响其他模块。
第二,本文只实现了拦截模块的调出到其他模块的动作,其他模块的调入没有涉及到。
第三,system_server是system用户,不是有权限写所有名字的Property,这里用了persist.sys.开头的属性名,而persist.sys.开头的属性会保存至磁盘,因此性能会差一些。
第四,如果不以root身份运行注入程序,则ptrace附加时会失败。
第五,Andriod系统的大部分Service都运行在system_server进程中,可以拦截到。但部分自定义的用户Service在用户进程中,如需要拦截,则要ptrace到那个用户进程才行,拦截方法也类似。
以上是笔者关于Android下binder的调用与拦截的一些思路与实现方法。Android自身由于具有集成性、控制性、交互性等特点,所以可以激发学生的学习兴趣、调动学生的积极参与、扩大学生知识面,为学生提供多种学习的路径。
关键词:Android system_server binder
本文内容包含使用在拥有root权限的Android2.3平台上针对system_server中binder通信的拦截。
一、动态链接机制及Binder拦截选址
要拦截模块甲对乙的调用,一般思路是通过ptrace远程注入并加载一新拦截模块至模块甲,并搜索模块甲的GOT表,找到对模块乙的调用地址,改成新模块内的某函数地址,然后新模块内的这个函数在进行了自己的处理后,再跳到模块乙中。
这里用户进程空间所加载的libbinder.so和system_server端加载的libbinder.so在逻辑上不是同一个东西。正因为不是同一个东西,我们才能针对system_server进程中加载的libbinder.so动手,拦截其GOT表中对ioctl的调用,从而提前知道Service要返回的内容。这个ioctl就是拦截的选址所在。
二、具体实现
在这个常驻system_server进程内的共享库里,只实现了简单几个函数,其中do_hook函数在注入后通过外界调用,它不做具体的hook动作,仅仅只是把所需的两个函数地址写入Android的Property供外界使用:
[cpp] view plaincopy01.//将新旧ioctl地址写入Andorid的Property供外界使用;
02.int do_hook(void * param)
03.{
04.old_ioctl = ioctl;
05.printf("Ioctl addr: %p. New addr %p\n", ioctl, new_ioctl);
06.
07.char value[PROPERTY_VALUE_MAX] = {’\0’};
08.snprintf(value, PROPERTY_VALUE_MAX, "%u", ioctl);
09.property_set(PROP_OLD_IOCTL_ADDR, value);
10.
11.snprintf(value, PROPERTY_VALUE_MAX, "%u", new_ioctl);
12.property_set(PROP_NEW_IOCTL_ADDR, value);
13.
14.return 0;
15.}
16.
17.//全局变量用以保存旧的ioctl地址,其实也可直接使用ioctl;
18.int (*old_ioctl) (int __fd,unsigned long int __request, void * arg) = 0;
19.int res = (*old_ioctl)(__fd,__request, arg);
20.return res;
21.}.
三、小结
第一,每个被加载的模块,无论是可执行程序还是共享库,均有自己独立的PLT和GOT表。所以拦截这个模块的对外调用的GOT,不影响其他模块。
第二,本文只实现了拦截模块的调出到其他模块的动作,其他模块的调入没有涉及到。
第三,system_server是system用户,不是有权限写所有名字的Property,这里用了persist.sys.开头的属性名,而persist.sys.开头的属性会保存至磁盘,因此性能会差一些。
第四,如果不以root身份运行注入程序,则ptrace附加时会失败。
第五,Andriod系统的大部分Service都运行在system_server进程中,可以拦截到。但部分自定义的用户Service在用户进程中,如需要拦截,则要ptrace到那个用户进程才行,拦截方法也类似。
以上是笔者关于Android下binder的调用与拦截的一些思路与实现方法。Android自身由于具有集成性、控制性、交互性等特点,所以可以激发学生的学习兴趣、调动学生的积极参与、扩大学生知识面,为学生提供多种学习的路径。