首页
论坛
专栏
课程

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

2017-1-5 14:39 17070

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

2017-1-5 14:39
17070
为什么有这文章?
前段时间用到点系统底层框架去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;

2020安全开发者峰会(2020 SDC)议题征集 中国.北京 7月!

上传的附件:
最新回复 (41)
KX头狼 2017-1-5 19:27
2
0
谢谢楼主,好方法
AqCxBoM 2017-1-5 19:47
3
0
能帮上忙就好
zhengsidie 2017-1-5 21:51
4
0
太感谢楼主了。不过我还想问一个问题,就是如果一个app有多个包,而我们要hook的函数不在标识这个app的主包里,而是在了另一个包里,那要怎么办呢?比如主包是com.mainpack 而我们的函数在包com.otherpack里.如果我们直接hook com.otherpack会提示找不到这个包~~~求教~~~
mingxuan三千 2017-1-6 09:39
5
0
支持原创  多出些这方面的教程
AqCxBoM 2017-1-6 09:43
6
0
不能很清晰地了解你所说的情况,就字面理解来说,你的APP不管多少包,只要在同一个APP的ClassLoader中加载的都能被找到,除非你自己调用动态去加载的JAR包可能会出现这个问题,如果是后面这种情况,目前我也还没有好的方法来解决,只能请万能的坛友指点一二了
malokch 2 2017-1-8 12:23
7
0
xposed的参数还是好给的,但是底层hook的就难给了。曾经在底层传参数我还用了ffi来做~
koflfy 1 2017-1-8 17:52
8
0
顶,mark
qqsunqiang 2017-1-8 18:22
9
0
谢谢楼主的分享。
fengmaple 2017-1-8 18:26
10
0
写得很不错
AqCxBoM 2017-1-9 00:21
11
0
底层传参?不明白
AqCxBoM 2017-1-9 00:22
12
0
谢谢捧场!!!
小豆芽 2017-1-9 04:09
13
0
感谢分享~!
zylyy 2017-1-9 09:18
14
0
真是好巧哦,最近我也在研究这东西
AqCxBoM 2017-1-9 14:17
15
0
AqCxBoM 2017-1-9 14:20
16
0

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

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



AqCxBoM



算了,世界这么大,总有些不同看法的人,不纠结
是的,世界这么大,总有不同看法的人,我个人觉得,不对的地方在于没有给分析原理的精华而不是给楼主这个精华懂吗?不管是实现还是原理都是值得优秀和精华的,你喷这个是水贴我就不认同了,而且随着年代的变化现在搞技术分享技术的越来越少,这不能得精华我不知道还有什么可以得的

我要吐槽的是,一些莫名其妙的病毒分析,上来就是一大坨汇编代码贴上来,搞了半天也就改改主页这种东西也能得精华才真的是水贴,像老V这种动不动就爆料还带码的经常都是慢慢沉了才是重点……这个远远不是问题
wormfox 2017-2-23 09:49
28
0
Mark 
ArcherJohn 2017-5-16 00:48
29
0
我是学习到了,关于hook  复杂的参数。 

  看别人大神写的hook  java层  完全看不懂,一脸懵逼
AqCxBoM 2017-7-2 10:04
30
0
ArcherJohn 我是学习到了,关于hook 复杂的参数。 看别人大神写的hook java层 完全看不懂,一脸懵逼
能帮助别人少走点弯路就达到这篇文的目的了,感谢
wx_洋葱1号 2017-7-25 17:25
31
0


 protected void beforeHookedMethod(MethodHookParam param) throws Throwable {

                           // 怎么获取到 参数 map的值  只有一个map参数

                        param.args  //这个类型怎么转成map?

                        }


keeslient 2017-7-27 12:01
32
0
谢谢分享  mark一下
roysue 3 2017-12-16 21:28
33
0
谢谢分享    mark一下
tsdl2011 2018-6-28 16:26
34
0
谢谢楼主,学习一下
fooree 2018-6-28 17:06
35
0
对于复杂的参数类型为什么不试试:https://bbs.pediy.com/thread-226413.htm
你瞒我瞒 2018-6-29 16:46
36
0
谢谢大佬,提供思路,非常有用。对于那个喷子就无视啦。能帮助到有需要的人,才是分享的重点。感谢
wx_La0s 2018-7-23 17:32
37
0
感谢楼主分享,很实用,话说这年头看雪都有喷子....结合https://bbs.pediy.com/thread-225190.htm给出一个hook加固应用的复杂参数的方法

默守 2019-4-5 00:09
38
0
大佬,求告知XposedHookTarget的ShowDeclaredMethods方法怎么使用啊
zhz刺猬 2019-4-6 17:39
39
0
此楼层已删除
miyuecao 2019-4-22 14:51
40
0
很实用的教程,mark下
tiantdyy 2019-11-25 11:40
41
0
可以,如果没弄过xposed能第一次就看到这个文章,绝对是首选,虽然后续工作可能不会特别顺利,毕竟“愚笨”的人,不说十有八九,对半开总不会说得太严重。
mb_syhcopwy 2019-11-26 16:56
42
0
感谢楼主
游客
登录 | 注册 方可回帖
返回