L1E6N0A2

监督自己不断学习

0%

安卓逆向学习(一)hook与xposed

安卓逆向学习(一)

从万能的淘宝买了一个谷歌手机。无root不安卓,安装好Xpose的框架,准备学习逆向,“玩”手机!

1.什么是hook

Hook 就是在事件传送到终点前截获并监控事件的传输,像个钩子钩上事件一样,并且能够在钩上事件时,处理一些自己特定的事件。Hook 的这个本领,使它能够将自身的代码「融入」被勾住(Hook)的程序的进程中,成为目标进程的一个部分。

需要注意的是hook方法的作用,是将v已有的点击事件,替换成我们代理的点击事件。所以,在v还没有点击事件的时候进行hook,是没用的。

2.什么是Xposed

Xposed框架是一款可以在不修改APK的情况下影响程序运行(修改系统)的框架服务。不需要修改安卓源文件,而是通过分析程序运行来拦截并影响运行情况。具体需要把安卓apk逆向后然后分析代码,定位到具体的类,方法等,然后通过xposed来拦截修改方法等。

通过替换 /system/bin/app_process 程序控制 Zygote 进程,使得 app_process 在启动过程中会加载 XposedBridge.jar 这个 Jar 包,从而完成对 Zygote 进程及其创建的 Dalvik 虚拟机的劫持。 Xposed 在开机的时候完成对所有的 Hook Function 的劫持,在原 Function 执行的前后加上自定义代码。

a

补充知识——java反射

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

在日常的第三方应用开发过程中,经常会遇到某个类的某个成员变量、方法或是属性是私有的或是只对系统应用开放,这时候就可以利用Java的反射机制通过反射来获取所需的私有成员或是方法。

反射就是把java类中的各种成分映射成一个个的Java对象

image-20201118212639008

3. hook的使用流程——“偷梁换柱”

a. 根据需求确定 要hook的对象

​ Hook 的选择点:尽量静态变量和单例,因为一旦创建对象,它们不容易变化,非常容易定位。

b. 寻找要hook的对象的持有者,拿到要hook的对象
(持有:B类 的成员变量里有 一个是A的对象,那么B就是A的持有者,如下)

1
2
class B{ A a;}
class A{}

c. 定义“要hook的对象”的代理类,并且创建该类的对象
d. 使用上一步创建出来的对象,替换掉要hook的对象

b

举个栗子

1
2
3
4
5
6
7
View v = findViewById(R.id.tv);
v.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "hello",Toast.LENGTH_SHORT).show();
}
});

view的点击事件,toast了一段话,现在要求,不允许改动这个OnClickListener,要在toast之前添加日志打印 Log.d(...)

  • 第一步:根据需求确定 要hook的对象;
    我们的目的是在OnClickListener中,插入自己的逻辑.所以,确定要hook的,是v.setOnClickListener()方法的实参。

  • 第二步:寻找要hook的对象的持有者,拿到要hook的对象\
    进入v.setOnClickListener源码:发现我们创建的OnClickListener对象被赋值给了getListenerInfo().mOnClickListener

    1
    2
    3
    4
    5
    6
    public void setOnClickListener(@Nullable OnClickListener l) {
    if (!isClickable()) {
    setClickable(true);
    }
    getListenerInfo().mOnClickListener = l;
    }

    getListenInfo()代码如下:

    1
    2
    3
    4
    5
    6
    7
    ListenerInfo getListenerInfo() {
    if (mListenerInfo != null) {
    return mListenerInfo;
    }
    mListenerInfo = new ListenerInfo();
    return mListenerInfo;
    }

    一个View对象中只存在一个ListenerInfo对象,进入ListenerInfo内部:发现OnClickListener对象 被ListenerInfo所持有.

    1
    2
    3
    4
    5
    static class ListenerInfo {
    ...
    public OnClickListener mOnClickListener;
    ...
    }

    到这里为止,完成第二步,找到了点击事件的实际持有者:ListenerInfo .

1
2
3
4
5
6
7
8
// 得到view的mListenerInfo对象,这个对象就是点击事件的持有者
Method method = View.class.getDeclaredMethod("getListenerInfo");
//getDeclaredMethod函数:获得该类某个方法
method.setAccessible(true);
//由于getListenerInfo()方法并不是public的,所以要加这个代码来保证访问权限
Object mListenerInfo = method.invoke(v);
//invoke函数:传递object对象及参数调用该对象对应的方法
//这里拿到的就是mListenerInfo对象,也就是点击事件的持有者
1
2
3
4
5
6
//要从这里面拿到当前的点击事件对象,得到原始的 mOnClickListener 对象
Class<?> listenerInfoClz = Class.forName("android.view.View$ListenerInfo");
// forname函数:根据类名返回类的对象。这是内部类的表示方法
Field field = listenerInfoClz.getDeclaredField("mOnClickListener");
//获得类中某个属性对象
final View.OnClickListener onClickListenerInstance = (View.OnClickListener) field.get(mListenerInfo);//取得真实的mOnClickListener对象
  • 第三步:定义“要hook的对象”的代理类,并且创建该类的对象

我们要hook的是View.OnClickListener对象,所以创建一个类 实现View.OnClickListener接口.

1
2
3
4
5
6
7
8
9
10
11
12
13
static class ProxyOnClickListener implements View.OnClickListener {
View.OnClickListener oriLis;
public ProxyOnClickListener(View.OnClickListener oriLis) {
this.oriLis = oriLis;
}
@Override
public void onClick(View v) {
Log.d("HookSetOnClickListener", "点击事件被hook到了");
if (oriLis != null) {
oriLis.onClick(v);
}
}
}

然后,new出它的对象待用。

1
ProxyOnClickListener proxyOnClickListener = new ProxyOnClickListener(onClickListenerInstance);
  • 第四步:使用上一步创建出来的对象,替换掉要hook的对象,达成 偷梁换柱的最终目的.
    利用反射,将我们创建的代理点击事件对象,传给这个view
    field.set(mListenerInfo, proxyOnClickListener);
4.使用XPosed进行hook

a. 首先第一步先进行配置,在清单文件AndroidManifest里 Application作用域里加上如下配置:

1
2
3
4
5
6
7
8
9
<meta-data        
android:name="xposedmodule"
android:value="true" />
<meta-data
android:name="xposeddescription"
android:value="hello xposed" />
<meta-data
android:name="xposedminversion"
android:value="82" />

b. 第二步,在main目录下(java、res同级目录)创建assets文件夹,在该文件夹下新建一个xposed_init文件(该文件名称固定为xposed_init),该文件用于放置hook的入口,里面是一个路径(比如我的是com.blues.cracktest.XposedInit,XposedInit就是我hook的入口,这个类后面会提及)。

c. 第三步,新建一个类,这里就叫它XposedInit好了,让它实现(implements) IXposedHookLoadPackage 这个接口 ,在handleLoadPackage回调方法中进行拦截操作即可,而具体的拦截操作是借助XposedHelpers.findAndHookMethod方法和XposedBridge.hookMethod方法实现的,这两个方法也是比较简单的,从参数含义可以看到,主要是Hook的类名和方法名,然后还有一个就是拦截的回调方法,一般是拦截之前做什么的一个beforeHookedMethod方法和拦截之后做什么的一个afterHookedMethod方法。

c

参考:

https://www.jianshu.com/p/74c12164ffca?tdsourcetag=s_pcqq_aiomsg

https://www.jianshu.com/p/4f6d20076922

https://www.jianshu.com/p/9be58ee20dee

https://blog.csdn.net/bpk_2/article/details/107909154?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param

https://www.cnblogs.com/ichunqiu/p/8575173.html

https://blog.csdn.net/qq_36676433/article/details/87934138