首页
社区
课程
招聘
[原创]安卓Hook函数的复杂参数如何给定?
发表于: 2017-1-5 14:39 24964

[原创]安卓Hook函数的复杂参数如何给定?

2017-1-5 14:39
24964
为什么有这文章?
前段时间用到点系统底层框架去HOOK安卓在JAVA层的流程函数,期间目标函数参数有简单类型也有复杂的数组参数,着实为HOOK时的传参头疼过一把,加上有个朋友之前也在某群问过相关的问题就组合当时网友给的提示自己来实现一次这个过程,顺便介绍下该框架插件的基本开发姿势,同时希望也可以为广大HOOK友们提供一点解决问题的根本办法。

需要些什么工具?具备些什么基本安卓开发知识?
上面说过用成熟的框架,现在在安卓上好用的扩展性框架不过两种:Xposed跟Cydia,由于本人只用过XPOSED框架所以在这篇文章中就用Xposed来给大家介绍使用,开发知识方面只要有基本的安卓经验皆可胜任,并没有什么技术含量。

怎么做?
一、HOOK 三要素:类对象、函数名、参数列表的获取。
二、构建XPOSED框架插件、编码完成测试。


这其中难点有两个,一个就是Xposed插件没开发过,网上的一些教程文章没有写得太详细,一些个小细节没有被重点提及导致一个小问题都要查找无数的资料,甚至还找不到问题所在,另一个就是网上示例都太过简单化,一般都用int\sting这种基本类型作为Demo,然而实际使用中难免会碰到一些稀奇古怪的函数参数,而没有经验的我们只能乱写一通,到最后只能不了了之,现在我想通过由浅入深的方式来记录下插件的开发过程,希望能为遇到这种情况的朋友们提供点小帮助吧。

动手:
一、HOOK JAVA层函数的三要素获取:
这其中目标类对象、函数名相信大家要拿到没有难度,问题的重点就在于函数的参数列表,在介绍插件开发步骤前,先来看看我们首要目标类及函数参数情况,截图如下:
目标类路径为:aqcxbom.xposedhooktarget;
函数名为:helloWorld
参数表:int,string

xposedhooktarget的onCreate方法中调用输出

当前未hook前输出log前后如下:

我们要实现的目标是分别在前后调用输出入咱自己的日志信息,如下面两箭头所指:


二、插件开发步骤
好,明确了我们初步的目标后,现在咱来看看XPOSED框架插件开发步骤:
1. 以provided 模式导入 lib 文件 XposedBridgeApi-54.jar(不参与编译到最终文件中)且用AS开发的你千万不要将其放在libs目录中,否则你会发现你的插件安装上却一直没有运行起来的尴尬情况(大坑一)。
2. 在AndroidManifest.xml中添加框架信息。
  <application>
  <meta-data android:name="xposedmodule" android:value="true"/>
  <meta-data android:name="xposeddescription" android:value="这里填写模块说明信息"/>
  <meta-data android:name="xposedminversion" android:value="30"/> 
  </application>

xposedminversion这一项非常重要,必须与JAR内版本一致,否则模块不能运行。(大坑二)
你可以用RAR等压缩工具打开XposedBridgeApi-XX.jar包,在assets\version文件中包含了该包的版本号,这个版本号正常情况下会与jar包名内的版本保持一致。

3.编写响应类并实现类IXposedHookLoadPackage接口handleLoadPackage函数方法:
在handleLoadPackage函数的findAndHookMethod 方法我们要提供HOOK目标的信息,参数为(类全路径,当前的CLASSLOADER,HOOK的函数名,参数1类类型...参数N类类型, XC_MethodHook的回调),具体代码如下:
package aqcxbom.myxposed;
import android.util.Log;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
/**
 * Created by AqCxBoM on 2016/12/24.
 */
//实现该类方法的类在注册为Xposed插件后会被框架自动调用
public class XposedMain implements IXposedHookLoadPackage 
{
    public String TAG = "AqCxBoM" ;
    private final String mStrPackageName = "aqcxbom.xposedhooktarget"; //HOOK APP目标的包名
    private final String mStrClassPath = "aqcxbom.xposedhooktarget.MyClass"; //HOOK 目标类全路径
    private final String helloworld = "helloWorld"; //HOOK 目标函数名
    private void LOGI(String ct){ Log.d(TAG, ct); }

    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
        //对比此时加载的包名是否与目标包名一致
        if (loadPackageParam.packageName.equals(mStrPackageName)) {
            LOGI("found target: " + loadPackageParam.packageName); 
// findAndHookMethod方法用于查找匹配HOOK的函数方法,这里参数为HOOK的目标信息
            XposedHelpers.findAndHookMethod(mStrClassPath, //类全路径
loadPackageParam.classLoader, //ClassLoader
helloworld, //HOOK目标函数名
                    int.class, //参数1类型
                    String.class, //参数2类型(这里目标函数有多少个参数就多少个,与HOOK目标函数保持一致)
                    new XC_MethodHook() { //最后一个参数为一个回调CALLBACK
                        @Override //故名思意,这个函数会在目标函数被调用前被调用
                        protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                            super.beforeHookedMethod(param);
                            LOGI("beforeHook");
                        }
                        @Override//这个函数会在目标函数被调用后被调用
                        protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                            super.afterHookedMethod(param);
                            LOGI("afterHooke param: ");
                        }
                    });
        }
    }
}

4. 将响应类添加到框架启动文件
新建assests 文件夹,并在其中新建 xposed_init 文件,写入插件入口类的信息
aqcxbom.myxposed.XposedMain

5. 安装我们的插件设置启用,并在机器重启后插件生效,这时运行我们的Target目标,如无意外就能见到类似如下的日志输出。(注意插件的启用要到Xposed框架的模块中勾选启用)

=============================我是墙裂的分割线================================================================
进阶篇
对于上面的函数参数为基本数据类型(INT\STRING)我们都能快速搞定,但如果函数的参数如果是数组、Map、ArrayList这种复杂类型大家是不是就瞬间懵逼了呢,下面我们就来假设有如下这个情况:

我们的目标MyClass类的fun1函数,先看一下参数原型声明:
public static boolean fun1(String[][] strAry, Map mp1, Map<String,String> mp2, Map<Integer, String> mp3,
                      ArrayList<String> al1, ArrayList<Integer> al2, ArgClass ac) 

摆在我们面前的问题是这个参数该怎么写?
这个问题让我来解决的话,我会想让安卓APP告诉我该怎么写,所以用反射调用的方式(具体的调用方式可以查看示例XposedHookTarget的ShowDeclaredMethods方法)打印出这个函数的参数列表输出如下:
([[Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/ArrayList;Ljava/util/ArrayList;Laqcxbom/xposedhooktarget/ArgClass;)

这一看很清晰嘛,总结如下:
String[][] ==> [[Ljava/lang/String;
Map数组不论何种形式 ==> Ljava/util/Map;
ArrayList 无论何种形式 ==> Ljava/util/ArrayList;
ArgClass ac 自定义类给个全路径的事==> Laqcxbom/xposedhooktarget/ArgClass;
但实际上并不是这么一回事,提示各种类找不到(Ljava/util/ArrayList; Ljava/util/Map; Laqcxbom/xposedhooktarget/ArgClass;)
那么正确的姿势该怎么呢?答案是通过上面找到的类路径,用Xposed自身提供的XposedHelpers的findClass方法加载每一个类,然后再将得到的类传递给hook函数作参数!
示例代码如下:
package aqcxbom.myxposed;
import android.util.Log;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
/**
 * Created by AqCxBoM on 2016/12/24.
 */
public class XposedMain implements IXposedHookLoadPackage
{
    public String TAG = "AqCxBoM" ;
    private final String mStrPackageName = "aqcxbom.xposedhooktarget"; //HOOK APP目标的包名
    private final String mStrClassPath = "aqcxbom.xposedhooktarget.MyClass";//HOOK 目标类全路径
    private final String mStrMethodName = "fun1"; //HOOK 目标函数名
    private void LOGI(String ct){ Log.d(TAG, ct); }
    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
//判断包名是否一致
        if (loadPackageParam.packageName.equals(mStrPackageName)) {
            LOGI("found target: " + loadPackageParam.packageName);
            final Class<?> ArgClass= XposedHelpers.findClass("aqcxbom.xposedhooktarget.ArgClass", loadPackageParam.classLoader);
            final Class<?> ArrayList= XposedHelpers.findClass("java.util.ArrayList", loadPackageParam.classLoader);
            final Class<?> Map= XposedHelpers.findClass("java.util.Map", loadPackageParam.classLoader);
//包名一致时查找是否有匹配参数的类及函数
            XposedHelpers.findAndHookMethod(mStrClassPath, //类路径
loadPackageParam.classLoader, //ClassLoader
mStrMethodName, //目标函数名
                    "[[Ljava.lang.String;", //参数1
                    Map, //参数2
                    Map, //参数3
                    Map, //参数4
                    ArrayList, //参数5
                    ArrayList, //参数6
                    ArgClass, //参数7
                    new XC_MethodHook() {
                        @Override
                        protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                            super.beforeHookedMethod(param); //这个函数会在被hook的函数执行前执行
                            LOGI("beforeHook");
                        }
                        @Override
                        protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                            super.afterHookedMethod(param);//这个函数会在被hook的函数执行后执行
                            LOGI("afterHooke param: ");
                        }
                    });
        }
    }
}


编译安装,重启并运行我们的target程序得到HOOK成功的效果图

至此,我想就算遇到再复杂的参数类型,朋友们都能游刃有余地解决了吧,如果答案是肯定的,那我这篇文件就算是达到目的了。

排版太菜上传pdf一份,涉及到的源代码可以在我github上找到,有需要的朋友可以自行下载:
https://github.com/FuhuiLiu/XposedHookTarget.git
https://github.com/FuhuiLiu/MyXposed.git

PS:如果有需求想让被hook函数不执行的话可以在执行前使用 setResult(NULL)函数终止其在后续执行。
其它Xposed插件使用未详尽说明处请移步Xpose官网察看,这里就不再展开细述了。

在这里非常感谢我北京一个亦师亦友的哥们提供的资料及其零日安全论坛及团队所出品的安卓零基础逆向教材,正是有他们的引领我才能顺利开启Xposed插件开发的大门,同时也感谢网上热心网友提供的真知灼见,所查资料太多,并没有详细记录为此篇小文所翻阅的网文,只能列出一二以表谢意: 
http://www.freebuf.com/articles/terminal/56453.html
http://bbs.pediy.com/showthread.php?t=202147&page=2
尤其是网友jzfcf提供的查找类对象并传参到hook函数的方法,非常的赞。
> 先知技术社区首发 https://xianzhi.aliyun.com/forum/read/611.html
> 先知技术社区独家发表本文,如需要转载,请先联系先知技术社区授权;未经授权请勿转载。
> 先知技术社区投稿邮箱:Aliyun_xianzhi@service.alibaba.com;

[课程]Linux pwn 探索篇!

上传的附件:
收藏
免费 3
支持
分享
最新回复 (40)
雪    币: 52
活跃值: (31)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
2
谢谢楼主,好方法
2017-1-5 19:27
0
雪    币: 63
活跃值: (324)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
3
能帮上忙就好
2017-1-5 19:47
0
雪    币: 81
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
太感谢楼主了。不过我还想问一个问题,就是如果一个app有多个包,而我们要hook的函数不在标识这个app的主包里,而是在了另一个包里,那要怎么办呢?比如主包是com.mainpack 而我们的函数在包com.otherpack里.如果我们直接hook com.otherpack会提示找不到这个包~~~求教~~~
2017-1-5 21:51
0
雪    币: 76
活跃值: (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
支持原创  多出些这方面的教程
2017-1-6 09:39
0
雪    币: 63
活跃值: (324)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
6
不能很清晰地了解你所说的情况,就字面理解来说,你的APP不管多少包,只要在同一个APP的ClassLoader中加载的都能被找到,除非你自己调用动态去加载的JAR包可能会出现这个问题,如果是后面这种情况,目前我也还没有好的方法来解决,只能请万能的坛友指点一二了
2017-1-6 09:43
0
雪    币: 43
活跃值: (388)
能力值: ( LV9,RANK:140 )
在线值:
发帖
回帖
粉丝
7
xposed的参数还是好给的,但是底层hook的就难给了。曾经在底层传参数我还用了ffi来做~
2017-1-8 12:23
0
雪    币: 102
活跃值: (1845)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
8
顶,mark
2017-1-8 17:52
0
雪    币: 440
活跃值: (193)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
谢谢楼主的分享。
2017-1-8 18:22
0
雪    币: 6
活跃值: (31)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
写得很不错
2017-1-8 18:26
0
雪    币: 63
活跃值: (324)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
11
底层传参?不明白
2017-1-9 00:21
0
雪    币: 63
活跃值: (324)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
12
谢谢捧场!!!
2017-1-9 00:22
0
雪    币: 268
活跃值: (28)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
感谢分享~!
2017-1-9 04:09
0
雪    币: 144
活跃值: (38)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
真是好巧哦,最近我也在研究这东西
2017-1-9 09:18
0
雪    币: 63
活跃值: (324)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
15
2017-1-9 14:17
0
雪    币: 63
活跃值: (324)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
16

共勉之
2017-1-9 14:20
0
雪    币: 3
活跃值: (45)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
我的妈啊为什么看雪总是把怎么用hook框架的文章标记为优秀啊,我想不明白啊,这些框架不是很久很久网上就有文章了吗~~~弄过来弄过去hook和注入没完没了了!!!!人家写的分析框架原理的文章都没有优秀,这些怎么使用居然也是优秀我醉了!!!晕啊!!!!!!!!!!我明白了看雪的文章不是已技术高低来评定优秀和精品,而是看是否对大多数人有用,如果这样那我写一篇hello world是不是也是优秀呢,我不明白管理怎么想的,我想吐槽,我爱看雪希望他会更好,而不是更水!!!!!!!!!!!
2017-1-11 18:23
0
雪    币: 47
活跃值: (418)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
18
+1,同意你的看法
2017-1-12 09:57
0
雪    币: 13
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
mark
2017-1-13 14:10
0
雪    币: 63
活跃值: (324)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
20
你的观点我个人保留意见,回复这个我只对看雪论坛的精神表达下自我的看法:
1.这些框架出来很久,甚至有人都已经用烂了这都不是个事,但据我个人从刚开始接触框架HOOK到小有心得的网上资料查找过程却告诉我,那些网上烂大街的使用要么示例灰常简单、更多的是示例代码只有片断而不全,更重要的是在框架使用过程中的坑并没有完全为小白点开,我个人为此断续花了不小于一个星期的时间才弄明白。(当然大部分原因是我太愚笨了)
2.对于你“看雪的文章不是已技术高低来评定优.."的说法,首先我觉得看雪论坛的精神是知识的共通有无,强调的是共享精神,一个文章的好坏除了内容的深度外还得讲究一个广度,我同意那些分析框架原理的大牛作者们的水平,看这些文章可以对其实现原理有很大的帮助,但往深处想,假设我连基本的使用方法都没有掌握,那看这些文章又有何用?世面上又何必有那么多”xx从浅入深“?

最后我在这里声明一下,该文章只是一个小白对于这个框架总结的使用心得,如我在文章开头写的“确实没有技术含量”!,纯属一种经验的总结,贴这也只是为了给广大跟我一样的入门级的Androider们一点指引性的总结,管理们能给个优秀是我的肯定,也是我的荣幸,我想信每个管理心中都有一把属于自己的尺子来丈量人生。至于像您这样的大牛们请直接忽视我吧,实在不行的请砖头轻拍,感谢!
2017-1-17 09:56
1
雪    币: 3
活跃值: (45)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
首先我表示我不是大神,别黑我,其次我想说不是写详细的东西不可以,而是写详细的东西是优秀是不行了,而且是这种没有技术含量的东西,如果是网上没说清楚的东西说清楚就可以优秀的话,那么你写个教人怎么用使用迅雷下载东西(目前网上没有怎么教人详细使用迅雷下载文件的帖子),写的详细,是不是也应该给你一个优秀啊?看雪在我的心中是技术的象征,而不是水贴的集合体
2017-1-17 21:00
0
雪    币: 63
活跃值: (324)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
22
如我前面回复你的一样,每个管理有自己的行事评判标准,对于这个我们没有必要纠结于此。
另外如你所言,如果大部分网友都不会用迅雷下载,而你又能写出通俗而令大众都能为之受益的入门使用文章我认为管理会给予正面的肯定,当然前提是你得发布到内容合适的平台上去,只不过你假设的这个前提是不是太过于偏激?
看雪依然还是技术的象征而不是你所说的水贴集合。
2017-1-19 09:41
0
雪    币: 393
活跃值: (224)
能力值: ( LV8,RANK:140 )
在线值:
发帖
回帖
粉丝
23
哦,厉害厉害。
一个没分享东西的人喷人家分享的知识浅,学习了,膜拜
2017-1-26 15:59
0
雪    币: 3
活跃值: (45)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
confused:他这些东西算是分享?需要我教你怎么用百度和谷歌吗
2017-2-4 09:29
0
雪    币: 393
活跃值: (224)
能力值: ( LV8,RANK:140 )
在线值:
发帖
回帖
粉丝
25
那你就百度谷歌也分享下呗 呵呵
2017-2-5 12:42
0
游客
登录 | 注册 方可回帖
返回
//