原创Android下通过root实现对systemserver中binder的ioctl调用拦截.docx

上传人:b****1 文档编号:10161510 上传时间:2023-05-24 格式:DOCX 页数:28 大小:31.63KB
下载 相关 举报
原创Android下通过root实现对systemserver中binder的ioctl调用拦截.docx_第1页
第1页 / 共28页
原创Android下通过root实现对systemserver中binder的ioctl调用拦截.docx_第2页
第2页 / 共28页
原创Android下通过root实现对systemserver中binder的ioctl调用拦截.docx_第3页
第3页 / 共28页
原创Android下通过root实现对systemserver中binder的ioctl调用拦截.docx_第4页
第4页 / 共28页
原创Android下通过root实现对systemserver中binder的ioctl调用拦截.docx_第5页
第5页 / 共28页
原创Android下通过root实现对systemserver中binder的ioctl调用拦截.docx_第6页
第6页 / 共28页
原创Android下通过root实现对systemserver中binder的ioctl调用拦截.docx_第7页
第7页 / 共28页
原创Android下通过root实现对systemserver中binder的ioctl调用拦截.docx_第8页
第8页 / 共28页
原创Android下通过root实现对systemserver中binder的ioctl调用拦截.docx_第9页
第9页 / 共28页
原创Android下通过root实现对systemserver中binder的ioctl调用拦截.docx_第10页
第10页 / 共28页
原创Android下通过root实现对systemserver中binder的ioctl调用拦截.docx_第11页
第11页 / 共28页
原创Android下通过root实现对systemserver中binder的ioctl调用拦截.docx_第12页
第12页 / 共28页
原创Android下通过root实现对systemserver中binder的ioctl调用拦截.docx_第13页
第13页 / 共28页
原创Android下通过root实现对systemserver中binder的ioctl调用拦截.docx_第14页
第14页 / 共28页
原创Android下通过root实现对systemserver中binder的ioctl调用拦截.docx_第15页
第15页 / 共28页
原创Android下通过root实现对systemserver中binder的ioctl调用拦截.docx_第16页
第16页 / 共28页
原创Android下通过root实现对systemserver中binder的ioctl调用拦截.docx_第17页
第17页 / 共28页
原创Android下通过root实现对systemserver中binder的ioctl调用拦截.docx_第18页
第18页 / 共28页
原创Android下通过root实现对systemserver中binder的ioctl调用拦截.docx_第19页
第19页 / 共28页
原创Android下通过root实现对systemserver中binder的ioctl调用拦截.docx_第20页
第20页 / 共28页
亲,该文档总共28页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

原创Android下通过root实现对systemserver中binder的ioctl调用拦截.docx

《原创Android下通过root实现对systemserver中binder的ioctl调用拦截.docx》由会员分享,可在线阅读,更多相关《原创Android下通过root实现对systemserver中binder的ioctl调用拦截.docx(28页珍藏版)》请在冰点文库上搜索。

原创Android下通过root实现对systemserver中binder的ioctl调用拦截.docx

原创Android下通过root实现对systemserver中binder的ioctl调用拦截

【原创】Android下通过root实现对system_server中binder的ioctl调用拦截

Linux下的远程注入与HOOK网上已有不少文章与代码实现,而对于Android平台,注入有不少,但HOOK却不多。

经过了两个多礼拜的研究,我初步实现了在拥有root权限的Android2.3平台上针对system_server中binder通讯的拦截,写下来分享一下。

======================================================================

一、动态链接机制

======================================================================

首先回顾一下Linux平台上,一个模块甲需要调用另外一个模块乙中的函数时的动态链接机制:

1、模块甲在编译期间,将要引用的模块乙的名字与函数名写入自身的符号表。

2、运行期模块甲调用时,调用流程是从调用代码到PLT表到GOT表再跳入模块乙。

而如何保证模块甲的代码能从其PLT/GOT跳到正确的模块乙入口,这就是链接器做的事情。

标准Linux链接器是ld.so,支持懒绑定,也就是说,模块甲在编译期间生成的调用模块乙的原始代码,流程是从调用代码到PLT表到链接器。

运行期第一次调模块乙时,首先进入链接器,链接器根据调用信息加载模块乙搜寻其符号并将找到的函数地址填入GOT表,之后的后续调用流程就直接走PLT/GOT表了。

这种机制能减少加载时的开销,为Linux发行版等采用。

Android虽然内核基于Linux,但其动态链接机制却不是ld.so而是自带的linker,不支持懒绑定。

也就是说,上述模块甲乙如果在Android平台上,则是模块甲加载时,linker就会根据模块甲中的.rel.plt表和字符串表中的内容加载模块乙并搜索其所需函数地址并预先填入GOT表。

之后调用流程每次都直接走PLT/GOT表,不再进linker,PLT表中也省去了跳至linker的代码,这种流程和“勤劳”绑定类似,倒是为拦截提供了一点方便。

如果拦截懒绑定的入口时模块乙还没加载地址也没找到,拦截就没法进行了。

要拦截模块甲对乙的调用,一般思路是通过ptrace远程注入并加载一新拦截模块至模块甲,并搜索模块甲的GOT表,找到对模块乙的调用地址,改成新模块内的某函数地址,然后新模块内的这个函数在进行了自己的处理后,再跳到模块乙中。

Android和Linux的链接器不同导致了内存布局的差异,也导致了网上流行的Linux注入与HOOK的方法行不通。

网上的方法是通过ptrace注入后,搜索dynamic的section中的PLTGOT区,去里头取link_map以遍历此进程所加载的模块来搜索需要hook的函数地址。

但Android上,dynamic的section的PLTGOT区前几项都是空的,没有link_map这个数据结构,只能通过分析/proc//maps来遍历模块。

======================================================================

二、Binder拦截选址

======================================================================

Binder是Andorid上的轻量级跨进程通讯机制,由用户空间的libbinder.so和内核的binder驱动协作构成。

一次完整的Binder调用的流程(拿对system_server中的Service的调用举例)是从用户进程到用户进程加载的libbinder.so到ioctl到binder驱动并阻塞,Service端在等待时通过libbinder.so收到驱动传上来的调用请求,把数据整好后通过libbinder.so再通过ioctl返回给驱动,之前用户端阻塞的ioctl收到应答而返回,回到libbinder.so再回到用户进程,从而完成了一次完整的调用请求。

注意,这里用户进程空间所加载的libbinder.so和system_server端加载的libbinder.so在逻辑上不是同一个东西。

正因为不是同一个东西,我们才能针对system_server进程中加载的libbinder.so动手,拦截其GOT表中对ioctl的调用,从而提前知道Service要返回的内容(如果想改,则需要分析Binder数据再改了)。

这个ioctl就是拦截的选址所在。

======================================================================

三、具体实现

======================================================================

----------------------------------------------------------------------

3.1实现思路

----------------------------------------------------------------------

在尝试了各种思路并失败了很多次后,最终确定下来拦截system_server进程中的binder通讯的思路如下:

1、以root身份运行注入程序,通过ptrace停止并附加system_server。

2、远程注入shellcode,加载注入的共享库并解除附加,让其调用共享库中的一特定函数。

3、此特定函数将库中待接替ioctl的新函数地址以及ioctl的真实地址写入Android的Property供外界使用。

4、注入程序通过Android的Property获得ioctl的原始地址以及接替ioctl的新函数地址。

5、注入程序再次通过ptrace附加system_server,定位libbinder.so中名为.got的Section,并搜索其项寻找ioctl的原始地址。

6、找到GOT表中的原始地址后将其替换为接替ioctl的新函数地址。

7、解除附加system_server让其重新运行,完成拦截。

其中,1和2在网上有现成的实现,是一个叫LibInject的包,其中有inject.c/h以及Android.mk,还有个大牛给出的shellcode.s。

不过这段shellcode加载共享库并调用后会立即dlclose卸载之,不符合我们常驻的需求,因此我又写了个新共享库让shellcode加载的共享库调用,多了一步。

此库最终常驻system_server的内存。

----------------------------------------------------------------------

3.2注入共享库中的新函数实现

----------------------------------------------------------------------

在这个常驻system_server进程内的共享库里,只实现了简单几个函数,其中do_hook函数在注入后通过外界调用,它不做具体的hook动作,仅仅只是把所需的两个函数地址写入Android的Property供外界使用:

代码:

//将新旧ioctl地址写入Andorid的Property供外界使用

intdo_hook(void*param)

{

old_ioctl=ioctl;

printf("Ioctladdr:

%p.Newaddr%p\n",ioctl,new_ioctl);

charvalue[PROPERTY_VALUE_MAX]={'\0'};

snprintf(value,PROPERTY_VALUE_MAX,"%u",ioctl);

property_set(PROP_OLD_IOCTL_ADDR,value);

snprintf(value,PROPERTY_VALUE_MAX,"%u",new_ioctl);

property_set(PROP_NEW_IOCTL_ADDR,value);

return0;

}

//全局变量用以保存旧的ioctl地址,其实也可直接使用ioctl

int(*old_ioctl)(int__fd,unsignedlongint__request,void*arg)=0;

//欲接替ioctl的新函数地址,其中内部调用了老的ioctl

intnew_ioctl(int__fd,unsignedlongint__request,void*arg)

{

if(__request==BINDER_WRITE_READ)

{

call_count++;

charvalue[PROPERTY_VALUE_MAX]={'\0'};

snprintf(value,PROPERTY_VALUE_MAX,"%d",call_count);

property_set(PROP_IOCTL_CALL_COUNT,value);

}

intres=(*old_ioctl)(__fd,__request,arg);

returnres;

}

new_ioctl函数中,判断调用参数是否是BINDER_WRITE_READ通讯命令,是的话增加计数,并将计数写入Property,这样外界就能看见调用计数,才知道拦截成功了。

----------------------------------------------------------------------

3.3注入程序的搜索机制实现

----------------------------------------------------------------------

注入程序在上述第四步之后的流程是本文的核心。

程序由于涉及到elf解析,还得使用linux下的elf.h。

由于设置属性的property_set是个异步过程,因此调用共享库中的设置Property函数后,注入程序需要循环等待属性被设置上,类似于:

代码:

charvalue[PROPERTY_VALUE_MAX]={'\0'};

do{

sleep(0);

property_get(PROP_OLD_IOCTL_ADDR,value,"0");

}while(strcmp(value,"0")==0);

unsignedlongold_ioctl_addr=atoi(value);

然后通过调用get_module_base,分析/proc//maps文件,得到libbinder.so的加载基址(get_module_base也是LibInject中提供的)。

代码:

void*binder_addr=get_module_base(target_pid,BINDER_LIB_PATH);

拿到新旧ioctl地址和libbinder.so基址后,就要搜索libbinder.so的GOT表,找匹配项。

搜索libbinder.so既可以搜/system/lib/libbinder.so文件的内容,也可以通过ptrace的PEEKTEXT来搜system_server中被加载的libbinder.so在内存中的映像,我选择了前者,因为后者在实现时似乎有点问题,读到的Section内容不太对头,不确定是我程序问题还是被linker给改了。

打开/system/lib/libbinder.so文件,获取其ELF头。

代码:

read(fd,ehdr,sizeof(Elf32_Ehdr));

获得其SectionHeader区表的地址、数量和大小,并获得字符串表Section的索引号:

代码:

unsignedlongshdr_addr=ehdr->e_shoff;

intshnum=ehdr->e_shnum;

intshent_size=ehdr->e_shentsize;

unsignedlongstridx=ehdr->e_shstrndx;

先提前把字符串表的内容读出来供遍历Section时比对其name用:

代码:

//读取SectionHeader中关于字符串表的描述,得到其尺寸和位置

lseek(fd,shdr_addr+stridx*shent_size,SEEK_SET);

read(fd,shdr,shent_size);

//根据尺寸分配内存

char*string_table=(char*)malloc(shdr->sh_size);

lseek(fd,shdr->sh_offset,SEEK_SET);

//将字符串表内容读入

read(fd,string_table,shdr->sh_size);

再重新遍历SectionHeader,找名为.got表的Section:

代码:

lseek(fd,shdr_addr,SEEK_SET);

inti;

for(i=0;i

{

read(fd,shdr,shent_size);

if(shdr->sh_type==SHT_PROGBITS)

{

intname_idx=shdr->sh_name;

if(strcmp(&(string_table[name_idx]),".got")==0)

{

/*就是GOT表!

*/

*out_addr=base_addr+shdr->sh_offset;

*out_size=shdr->sh_size;

return0;

}

}

}

这样,out_addr和out_size,就是system_server中libbinder.so的GOT表所在的位置和长度。

然后搜索与Hook就好办了:

代码:

for(i=0;i

{

ptrace_readdata(target_pid,out_addr,&got_item,4);

if(got_item==old_ioctl_addr)

{

/*!

!

!

拿到了ioctl地址!

!

!

改成我们的。

*/

ptrace_writedata(target_pid,out_addr,&new_ioctl_addr,sizeof(new_ioctl_addr));

break;

}

elseif(got_item==new_ioctl_addr)

{

/*已经是我们的了,不重复Hook。

*/

break;

}

out_addr++;

}

写Android.mk将其在Android2.3源码树下编译后,adbpush上去(共有注入程序、shellcode使用的共享库、我们的共享库三个文件),运行注入程序,提示注入成功。

如果再次运行,则提示已经注入过了。

再跑命令:

#getproppersist.sys.ioctl.callcount

getproppersist.sys.ioctl.callcount

502

随便动动手机,数字在不断增加中,不过有点影响性能。

======================================================================

四、补充说明

======================================================================

1、每个被加载的模块,无论是可执行程序还是共享库,均有自己独立的PLT和GOT表。

所以拦截这个模块的对外调用的GOT,不影响其他模块。

2、本文只实现了拦截模块的调出到其他模块的动作,其他模块的调入没有涉及到(可能还涉及到比较复杂的重定位操作)。

3、system_server是system用户,不是有权限写所有名字的Property,这里用了persist.sys.开头的属性名,而persist.sys.开头的属性会保存至磁盘,因此性能会差点儿。

4、ioctl虽然实质声明是个可变参数:

intnew_ioctl(int__fd,unsignedlongint__request,/*void*arg*/...),这种声明的函数要直接透明地将参数从旧函数传递给新函数似乎还不可行,搜了很多资料也没找到。

幸好搜了一把libbinder.so源码,里头对ioctl的调用参数均是仨,干脆就不处理变长形式了。

5、如果不以root身份运行注入程序,则ptrace附加时会失败。

6、Andriod系统的大部分Service都运行在system_server进程中,可以拦截到。

但部分自定义的用户Service在用户进程中,如需要拦截,则要ptrace到那个用户进程才行,拦截方法也类似。

7、至于拦截Binder的数据分析与修改,则是下一篇文章的内容了。

======================================================================

五、参考资料

======================================================================

:

8080/gaikuang/submission/TN05.ELF.Format.Summary.pdf

还有不少,没法全写下来,在此向所有无私共享自己研究成果的人致以诚挚的谢意。

【原创】Android应用破解之SSHDroid去广告

SSHDroid这个软件是用来在android手机上架设ssh服务器的,这个小应用有两个版本一个免费版,一个pro版。

区别就是有无广告。

发现装了Adfreeandroid这个应用之后,SSHDroid就不干活了,说ad被block了,然后就只能选择“退出”或者“购买付费版”。

这个,多少让我有些不爽啊。

如图:

提示广告被屏蔽,只能点“退出”或者使用收费版(adfreeversion):

名称:

alert-ad-blocked.png

查看次数:

162

文件大小:

23.6KB

有了想暴破它的想法了~~于是操刀把它菊花暴了,爽了一把。

在linux下面那个adb硬是没有运行起来,运行以后没有任何输出,不知何故。

先在win下把这app搞定吧。

用到的暴菊工具:

引用:

adb.rar(从网上下载的,里面有adb及其依赖的库,我懒得装androidsdk了。

Auto-sign(WIN7系统).rar 用于给app签名的,随便在网上搜索到的

apktool1.4.1.tar.bz2 在google项目:

apktool-install-windows-r04-brut1.tar.bz2

EmEditor(我机子上一直装着呢)

先说下adfreeandroid这个软件屏蔽广告的原理,其实这个软件就是修改andorid/system/etc/hosts这个文件,把ad相关域名的ip指向127.0.0.1来达到屏蔽广告的目的。

爪机注意开启调试。

从机器里把程序拖出来(不知道app文件名就先用ls找一下):

代码:

adbpull/data/app/berserker.android.apps.sshdroid-1.apk

然后用apktool对其进行解压缩和反汇编

代码:

apktooldberserker.android.apps.sshdroid-1.apkreversing

进入到reversing目录,里面有露出来的菊花(反汇编出来的东东):

代码:

cdreversing

下面是正式暴菊了。

zhiwei.li给出了三种方案来搞定ad:

引用:

1.对com.google.ads打补丁.这将是一个比较通用的方法,对那些使用到com.google.ads的所有应用都有效.

2.对app 打补丁.找到此app调用com.google.ads的地方

3.对资源文件进行补丁,让广告资源不可见.

我这里采用的是2和3相结合的方法,算是比较彻底。

进入smali目录,用emeditor随便打开一个.smali文件,在此目录及其子目录搜索 /etc/hosts

共找到两个:

引用:

smali\berserker\android\a\a.smali(59)

smali\berserker\android\a\f.smali(227)

打开反汇编的文件一看,前一个是定义的检测hosts的类。

很快可以发现:

代码:

const-stringv3,"admob"

这个程序是投放的admob广告。

代码:

const-stringv3,"admob"

invoke-virtual{v2,v3},Ljava/lang/String;->contains(Ljava/lang/CharSequence;)Z

move-resultv2

if-eqzv2,:

cond_0

sget-objectv1,Ljava/lang/Boolean;->TRUE:

Ljava/lang/Boolean;

sput-objectv1,Lberserker/android/a/a;->b:

Ljava/lang/Boolean;

从以上代码可以看出,它是检测hosts中是否有admob字符串,然后根据返回的结果要决定跳转还是不跳转.

这里可以修改常量,也可以修改if-eqz为if-nez.我是采用的修改常量,

把前面的

代码:

const-stringv3,"admob"

修改为:

代码:

const-stringv3,"notexi

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 高等教育 > 经济学

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2