首页
社区
课程
招聘
[原创]对AndroidInlineHook的一些研究以及对抗策略
发表于: 2019-9-28 17:20 9461

[原创]对AndroidInlineHook的一些研究以及对抗策略

2019-9-28 17:20
9461



    另外,如果一个类不是接口如何实现Hook呢?我们可以先写一个类继承它,然后重写里面的方法,再使用反射替换就行了。hook 点必须满足以下的条件:需要 hook 的方法,所属的对象必须是静态的,因为我们是通过反射来获取对象的,我们获取的是系统的对象,所以不能够 new 一个新的对象,必须用系统创建的那个对象,所以只有静态的才能保证和系统的对象一致。

   为什么说 queryLocalInterface方法也是一个Hook点呢?这里我以Hook queryLocalInterface方法的思路来阐述:

   这个方法的意思就是:先查看本进程是否存在这个Binder对象,如果有那么直接就是本进程调用了;

如果不存在那么创建一个代理对象,让代理对象委托驱动完成跨进程调用。

观察这个方法,前面的那个if语句判空返回肯定动不了手脚;最后一句调用构造函数然后直接返回我们也是无从下手,

要修改asInterface方法的返回值,我们唯一能做的就是从这一句下手:

   我们修改这个getService方法的返回值,让这个方法返回一个我们伪造过的IBinder对象;这样,

我们可以在自己伪造的IBinder对象的queryLocalInterface方法作处理,进而使得asInterface方法返回

在queryLocalInterface方法里面处理过的值,最终实现hook系统服务的目的。


   在跟踪这个getService方法之前我们思考一下,由于系统服务是一系列的远程Service,它们的本体,

也就是Binder本地对象一般都存在于某个单独的进程,在这个进程之外的其他进程存在的都是这些Binder本地对象的代理。

因此在我们的进程里面,存在的也只是这个Binder代理对象,我们也只能对这些Binder代理对象下手。然后,

这个getService是一个静态方法,如果此方法什么都不做,拿到Binder代理对象之后直接返回;

那么我们就无能为力了:我们没有办法拦截一个静态方法,也没有办法获取到这个静态方法里面的局部变量(即我们希望修改的那个Binder代理对象)。


   接下来就可以看这个getService的代码了:

    不难发现,ServiceManager为了避免每次都进行跨进程通信,把这些Binder代理对象缓存在一张map里面。

我们可以替换这个map里面的内容为Hook过的IBinder对象,由于系统在getService的时候每次都会优先查找缓存,

因此返回给使用者的都是被我们修改过的对象。从而可以Hook掉前文中所说的queryLocalInterface方法,紧接着

又可以愉快的Hook IPM了。


   我们可以自己反射 IPackageManager$Stub$Proxy 这个内部类产生一个IPM对象,来替换

   APP原始被Hook了的PMS服务对象。代码如下所示:


   获取真实PMS服务对象之前: recoverPMS(this, getIPackageManager());

    之前有分析过kstools以及XX管理器的去签名校验功能,XX管理器普通版以及kstools的去签名校验使用动态代理PackageManagerService接口生成的对象替换系统原PMS服务,增强版Hook了Native层标准函数库里的open函数以及对Java层的各种IO类进行了继承重写,然后使用反射替换系统的IO。重写与构造虚假Context绕过一般签名校验的思路一样。
    Android Hook技术目前非常火热,典型产品功能有App插件化,热修复等。在Android逆向破解方面就是注入了,不妨看看这篇:
   上面提到的去签名校验以及替换系统PMS服务都源自于这篇这篇帖子,有详细介绍,下面也会简单带过一下。

    Hook系统服务(修改系统API函数的执行逻辑),有全局Hook和单进程Hook,全局Hook需要Root权限,典型代表开源框架Xposed,Frida。单个进程Hook,代表开源框架Whale,爱奇艺的XHook。单个进程Hook就是自己Hook自己啦。前面提到的替换PMS服务对象就是。那么有人说不要Root权限能不能实现全局Hook呢?可以,你搞定SELinux就行。
     我们知道JDK原生动态代理只能代理接口,因为代理接口后经过动态字节码技术生成的代理class是继承Proxy类的。那为什么代理类一定要继承Proxy类呢?这个问题我查看了许多答案,看的也不是特别明白。如大家有兴趣,可以去搜索一下。下面是一个动态字节码class命名:
public final class $Proxy0 extends Proxy implements MyInterface

    $Proxy0有多少个代理类,0-N
    MyInterface即我们需要代理的接口

    其实我们知道Java平台还有一个动态代理框架:cglib,它不仅仅能够代理接口,还可以代理非接口的类,并且还能够为类的非final方法提供代理,为JDK的动态代理提供了很好的补充。那为什么我们为什么不在Android平台上使用它呢?


     cglib如此强大,但是,它有一个很致命的缺点是:cglib底层是采用著名的ASM字节码生成框架,使用字节码技术生成代理类,也就是通过操作字节码来生成的新的.class文件,而我们在android中加载的是优化后的.dex文件,也就是说我们需要可以动态生成.dex文件代理类,因此cglib在android中是不能使用的。不过,网上已经有人根据dexmaker框架(dex代码生成工具)来仿照cglib库动态生成.dex文件,实现了类似于cglib的AOP的功能,不过还有bug尚待修复,对高版本的Android支持不太友好。


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2020-2-24 21:20 被LivedForward编辑 ,原因:
收藏
免费 8
支持
分享
打赏 + 2.00雪花
打赏次数 2 雪花 + 2.00
 
赞赏  GitHub_Y   +1.00 2019/09/29 期待作者有更加优秀的作品哦!
赞赏  FanciSun   +1.00 2019/09/29 优秀!
最新回复 (25)
雪    币: 36207
活跃值: (7170)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
2
转给mt开发者会如何?  你们接着PK 
2019-9-28 21:27
1
雪    币: 6124
活跃值: (4716)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
3
这种对抗真的毫无意义
2019-9-28 23:01
0
雪    币: 1892
活跃值: (1618)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
4
黑洛 这种对抗真的毫无意义
这样说,攻防都是相对的,都是彼此互相发展.
2019-9-28 23:31
4
雪    币: 10
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
5
还可以
2019-9-29 10:00
3
雪    币: 7
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
6
优秀!
2019-9-29 10:00
3
雪    币: 162
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
8
楼主研究的是Inline Hook,针对所有的Inline Hook都有效,麻烦你看清楚再发表意见!
2019-9-29 10:24
2
雪    币: 46
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
9
不错,期待作者有更加优秀的作品哦!
2019-9-29 11:07
1
雪    币: 7
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
11
黑洛 这种对抗真的毫无意义
你以为世界上的都是以你为中心吗?你做的都是伟大的事情,别人做的都是毫无意义!再说楼主是研究的InlineHook,你搞破解也就算了,还不允许别人做防护是吗?
2019-9-29 17:51
1
雪    币: 15003
活跃值: (6213)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
hook不一定要修改APK?也就是说签名并没有修改呀
2019-9-30 08:10
0
雪    币: 1892
活跃值: (1618)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
13
tDasm hook不一定要修改APK?也就是说签名并没有修改呀
这里是InlineHook,不是全局Hook哦。
2019-9-30 13:11
0
雪    币: 35
活跃值: (88)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
LivedForward 这里是InlineHook,不是全局Hook哦。
inline hook也可以通过virtual app之类的方式进行,不需要修改签名吧
2019-9-30 14:00
0
雪    币: 1892
活跃值: (1618)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
15
winkar inline hook也可以通过virtual app之类的方式进行,不需要修改签名吧
VirtualApp检测防护:https://www.cnblogs.com/ichunqiu/p/9340364.html
最后于 2019-9-30 17:40 被LivedForward编辑 ,原因:
2019-9-30 17:37
0
雪    币: 1110
活跃值: (3364)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
19
楼主的方法还能再改进一下:
1. libc 的函数大多可以用系统调用替换或封装实现,如 `open` 对应的 `SYS_OPEN` ,从 Bionic 的源码里拷出来就能用;
2. dlopen/dlsym 也是被 Hook 的常见点,可以换成从 `/proc/self/maps` 中解析 SO 符号表
2019-10-8 10:47
0
雪    币: 1892
活跃值: (1618)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
20
Amun 楼主的方法还能再改进一下: 1. libc 的函数大多可以用系统调用替换或封装实现,如 `open` 对应的 `SYS_OPEN` ,从 Bionic 的源码里拷出来就能用; 2. dlopen/ ...
是的,感谢您的批评指正,小弟学到了!
2019-10-10 07:34
0
雪    币: 1892
活跃值: (1618)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
21
Amun 楼主的方法还能再改进一下: 1. libc 的函数大多可以用系统调用替换或封装实现,如 `open` 对应的 `SYS_OPEN` ,从 Bionic 的源码里拷出来就能用; 2. dlopen/ ...
大佬,我想再问一下,是否可以Hook SYS_OPEN呢?
2019-10-12 10:44
0
雪    币: 1110
活跃值: (3364)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
22
LivedForward 大佬,我想再问一下,是否可以Hook SYS_OPEN呢?
可以,用内核模块对 `sys_call_table` 里的函数地址进行替换,可能需要重新编译内核使其支持内核模块功能。
2019-10-12 12:41
0
雪    币: 1892
活跃值: (1618)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
23
Amun 楼主的方法还能再改进一下: 1. libc 的函数大多可以用系统调用替换或封装实现,如 `open` 对应的 `SYS_OPEN` ,从 Bionic 的源码里拷出来就能用; 2. dlopen/ ...
dlopen,dlsym我已经自己实现了,但是您说的第一种方案,我我从bionic拷贝出来后,我不能很好的编译它,请问您能对第一种方案作详细一点的解释吗?
最后于 2019-10-13 21:06 被LivedForward编辑 ,原因:
2019-10-13 16:56
0
雪    币: 1110
活跃值: (3364)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
24
LivedForward Amun 楼主的方法还能再改进一下: 1. libc 的函数大多可以用系统调用替换或封装实现,如 `open` 对应的 `SYS_OPEN` ,从 Bion ...
已经够清楚了,再好好研究下 CMakeLists.txt 的用法 [\doge]
2019-10-14 17:44
0
雪    币: 15003
活跃值: (6213)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
你用哪个函数获取签名?
既然inlinehook,别人不会hook你那个函数返回原始签名?
2019-10-21 09:37
0
游客
登录 | 注册 方可回帖
返回
//