文章目录

  • Android Hook框架介绍
  • Cydia Substrate
  • 插件编写步骤
  • 实例:编写Cydia修改系统字体颜色
  • Xposed
  • 插件编写步骤
  • 实例:Hook获取手机序列号
  • 准备工作
  • 获取hook所需要的数据
  • 编写hook代码
  • 效果测试


Android Hook框架介绍

Android中比较经典的Hook框架有两个

  1. Cydia Substrate,闭源,从苹果开始到Android
  2. xposed,开源,从Android开始到苹果

Cydia Substrate

插件编写步骤

Cydia Substrate插件编写的一般步骤:

  1. 导入substrate-api.jar
  2. 设置权限和入口
  3. 新建一个类实现回调函数
  4. 使用MS.hookClassLoad用于HOOK加载类
  5. 使用MS.hookMethod用于HOOK方法

实例:编写Cydia修改系统字体颜色

安卓system路径在哪 安卓system目录 看不到_android

首先新建一个空的项目

安卓system路径在哪 安卓system目录 看不到_sed_02

将substrate-api.jar复制到libs目录下,jar下载地址如下:

http://asdk.cydiasubstrate.com/zips/cydia_substrate-r2.zip

安卓system路径在哪 安卓system目录 看不到_Android_03

接着右键打开模块设置

安卓system路径在哪 安卓system目录 看不到_android_04

将jar包导入到模块依赖库

接着在清单文件中添加一个自定义的权限

<uses-permission android:name="cydia.permission.SUBSTRATE"></uses-permission>

添加一个meta-data标签,并指定入口类

<meta-data name="com.saurik.substrate.main" android:value=".Main"></meta-data>

安卓system路径在哪 安卓system目录 看不到_安卓system路径在哪_05

然后新建一个入口类,命名为Main

package com.example.cydiademo;

import android.content.res.Resources;
import android.util.Log;

import com.saurik.substrate.MS;

import java.lang.reflect.Method;

public class Main {


    static void initialize() {
        //1.hook指定的类-->android.content.res.Resources
        MS.hookClassLoad("android.content.res.Resources", new MS.ClassLoadHook() {
            @Override
            public void classLoaded(Class<?> aClass) {

                //2.1 获取老的方法对象
                Method method=null;
                try {
                    method=aClass.getMethod("getColor",int.class);
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                }
                if (method==null){
                    Log.d("GuiShou","method==null");
                    return;
                }

                //2.hook指定的方法-->getColor
                //老的方法的指针
                final MS.MethodPointer methodPointer=new MS.MethodPointer();
                MS.hookMethod(aClass, method, new MS.MethodHook() {
                    @Override
                    public Object invoked(Object o, Object... objects) throws Throwable {
                        //hook代码
                        //调用老的方法,获取color
                        int color= (int) methodPointer.invoke(o,objects);
                        //修改color并返回
                        return color&~0x0000ff00|0x00ff0000;
                    }
                },methodPointer);

            }
        });
    }
}

接着实现initialize方法,修改系统字体颜色。到此插件编写完成,这个hook框架需要运行在真机环境下,所以暂时看不到效果。

Xposed

插件编写步骤

Xposed是一个开源的Hook框架,可定制性强;其提供了SDK可以写插件,轻松完成hook。基本步骤如下:

  1. 创建一个无Activity的工程
  2. 设置清单文件信息
  3. 导入Xposed jar包,并设置为privoder(complie only)
  4. 创建一个主类并实现Xposed中的接口
  5. 重新handleLoadPackage方法
  6. 建立xposed_init文件外部声明主类
  7. 在handleLoadPackage中完善Hook代码

实例:Hook获取手机序列号

需要HOOK的目标程序如下:

安卓system路径在哪 安卓system目录 看不到_sed_06

app运行之后,会显示当前的设备ID

准备工作

安卓system路径在哪 安卓system目录 看不到_Android_07

新建一个工程,将XposedBridge-82.jar复制到新建的lib目录下

安卓system路径在哪 安卓system目录 看不到_sed_08

打开模块设置,将jar包导入到模块,并设置Configuration为compileOnly

<meta-data android:name="xposedmodule" android:value="true"></meta-data>
<meta-data android:name="xposeddescription" android:value="XX神器"></meta-data>
<meta-data android:name="xposedminversion" android:value="54"></meta-data>

在清单文件中添加上面的字段

安卓system路径在哪 安卓system目录 看不到_sed_09

接着新建一个类,命名为Main

public class Main implements IXposedHookLoadPackage {
    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
        
    }
}

并实现IXposedHookLoadPackage接口,然后在handleLoadPackage函数内编写Hook代码

安卓system路径在哪 安卓system目录 看不到_安卓system路径在哪_10

接着指定入口类,新建assets/xposed_init文件,然后将入口类写到该文件内。准备工作就已经完成,接着开始编写hook代码。

获取hook所需要的数据

需要对app进行hook需要知道下面几个数据

  1. 包名
  2. 类名
  3. 方法原型

首先来查看一下需要HOOK的目标app代码

安卓system路径在哪 安卓system目录 看不到_安卓_11

显示设备ID的代码在onCreate方法中

public void onCreate(Bundle savedInstanceState) {
        IncrementalChange incrementalChange = $change;
        if (incrementalChange != null) {
            incrementalChange.access$dispatch("onCreate.(Landroid/os/Bundle;)V", this, savedInstanceState);
            return;
        }
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ((TextView) findViewById(R.id.textinfo)).setText("设备ID: " + ((TelephonyManager) getSystemService("phone")).getDeviceId());
    }

需要Hook的类名是TelephonyManager,方法名是getDeviceId

安卓system路径在哪 安卓system目录 看不到_Android_12

接着Android Studio的自动导入功能可以看到完整的类名是

android.telephony.TelephonyManager

安卓system路径在哪 安卓system目录 看不到_安卓system路径在哪_13

然后进入类内搜索方法名,即可获取到完整的方法原型

public String getDeviceId()

然后查看清单文件

安卓system路径在哪 安卓system目录 看不到_android_14

在清单文件中可以查看到包名为com.bluelesson.testphoneinfo

编写hook代码

接着编写hook代码如下:

public class Main implements IXposedHookLoadPackage {
    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam Param) throws Throwable {
        //包名 com.bluelesson.testphoneinfo
        //类名 android.telephony.TelephonyManager
        //方法名 public String getDeviceId()

        String packageName=Param.packageName;
        if (!packageName.equals("com.bluelesson.testphoneinfo"))
            return;
        XposedHelpers.findAndHookMethod(TelephonyManager.class,//类类型
                "getDeviceId",//方法名
                new XC_MethodReplacement() {    //回调
                    @Override
                    protected Object replaceHookedMethod(MethodHookParam methodHookParam) throws Throwable {
                        return "我就是序列号";
                    }
                });
    }
}

替换getDeviceId函数,直接返回序列号

效果测试

安卓system路径在哪 安卓system目录 看不到_android_15

在模拟器中安卓xposed框架

安卓system路径在哪 安卓system目录 看不到_sed_16

第一次进入需要安装更新以激活框架

安卓system路径在哪 安卓system目录 看不到_安卓_17

然后直接安卓app到模拟器,提示Xposed模块未激活

安卓system路径在哪 安卓system目录 看不到_安卓_18

勾选当前模块

安卓system路径在哪 安卓system目录 看不到_安卓_19

返回到Xposed插件主页,点击软重启

安卓system路径在哪 安卓system目录 看不到_Android_20

打开目标app,可以看到当前的设备ID已经被修改了