Android对startActivity方法进行Hook

startActivity 方法的两种形式:

  1. startActivity 有两种写法, 最常见的是下面这种, 使用 Activity 自带的 startActivity
    方法:
//第一个是Activity的startActivity方法
Intent intent= new Intent(MainActivity.this ,,SecondActivity.class) ;
startActivity(intent);
  1. 还有一种写法是使用Context的startActivity 方法,我们使用 getApplicationContext方法获取Context 对象,如下所示:
第二个是Context的startActivity方法
Intent intent= new Intent(MainActivity.this ,,SecondActivity.class) ;
getApplicationContext() .startActivity(intent );

两种写法殊途同归,它们都是在App 进程中通知AMS要启动哪个Activity。Context 内部的 startActivity 方法,其实也是在调用 Instrumentation 的execStartActivity 方法,后面的流程,两种方式就都是一样的了 。

1 Hook Activity的startActivity方法

public class InstrumentationProxy extends Instrumentation {

    private static final String TAG = "InstrumentationProxy";

    Instrumentation mInstrumentation;

    public InstrumentationProxy(Instrumentation instrumentation) {
        mInstrumentation = instrumentation;
    }

    public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {

        Log.d(TAG,  "Hook 成功"  + " who :" + who);

        // 开始调用原始的方法, 调不调用随你,但是不调用的话, 所有的startActivity都失效了.
        // 由于这个方法是隐藏的,因此需要使用反射调用;首先找到这个方法
        Class[] pareTyples = {Context.class, IBinder.class, IBinder.class,
                Activity.class, Intent.class, int.class, Bundle.class};

        Object[] pareVaules = {who, contextThread, token, target,
                intent, requestCode, options};

        String methodName = "execStartActivity";

        try {
            Method execStartActivity = mInstrumentation.getClass().getDeclaredMethod(methodName, pareTyples);
            execStartActivity.setAccessible(true);
            return (ActivityResult) execStartActivity.invoke(mInstrumentation, pareVaules);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }
}
public class Hook51MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_hook51_main);

        Class clazz = Activity.class;

        try {
            Field field = clazz.getDeclaredField("mInstrumentation");
            field.setAccessible(true);
            Instrumentation mInstrumentation = (Instrumentation) field.get(this);
            Instrumentation instrumentationProxy = new InstrumentationProxy(mInstrumentation);
            field.set(this, instrumentationProxy);

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public void toHook51SecondActivity(View view) {
        Intent intent = new Intent(Hook51MainActivity.this,Hook51SecondActivity.class);
        startActivity(intent);
    }
}

调用toHook51SecondActivity()方法后,输出:

InstrumentationProxy: Hook 成功 who :com.hongx.plugin.chapter05.hook51.Hook51MainActivity@410777b0

2 Hook Context 的 startActivity 方法

public class Hook51MainActivity extends AppCompatActivity {

    @Override
    protected void attachBaseContext(Context context) {
        super.attachBaseContext(context);
        try {
            // 在这里进行Hook
            String className = "android.app.ActivityThread";
            String methodName = "currentActivityThread";
            Class[] pareTyples = new Class[]{};
            Object[] pareVaules = new Object[]{};
            Class clazz = Class.forName(className);
            Method method = clazz.getDeclaredMethod(methodName, pareTyples);
            method.setAccessible(true);
            Object currentActivityThread = method.invoke(null, pareVaules);// 先获取到当前的ActivityThread对象

            String filedName = "mInstrumentation";
            Field field = clazz.getDeclaredField(filedName);
            field.setAccessible(true);
            Instrumentation mInstrumentation = (Instrumentation) field.get(currentActivityThread); // 拿到原始的 mInstrumentation字段
            // 创建代理对象
            Instrumentation instrumentationProxy = new InstrumentationProxy(mInstrumentation);
            // 偷梁换柱
            field.set(currentActivityThread, instrumentationProxy);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_hook51_main);
    }

    public void toHook51SecondActivity(View view) {
        Intent intent = new Intent(Hook51MainActivity.this,Hook51SecondActivity.class);
        intent.addFlags(Intent . FLAG_ACTIVITY_NEW_TASK) ;
        getApplicationContext (). startActivity (intent );
    }
}

输出:

InstrumentationProxy: Hook 成功 who :android.app.Application@40ff6850

3 Hook startActivity 总结

Hook Context 的 startActivity 方法和 Hook Activity 的 startActivity 方法最大的区别就是替换的 Instrumentation 不同 , 前者是 ActivityThread 中的 Instrumentation ,后者是 Activity中的Instrumentation。另外有一点需要注意的是,在 MainActivity 的onCreate 方法中进行Instrumentation替换的,未必是最佳的替换时间点 ,所以在 Activity 的 attachBaseContext 方法中进行Instrumentation 替换,因为这个方法要先于 Activity 的 onCreate 方法被调用。讲到这里,我们知道了如何使用代理来 Hook startActivity 方法,简单说就是找到 Hook 点,再用代理对象来替换 Hook 点 。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值