理论知识参考:activity的启动流程(一)
hook activity
下载反射使用代码RefInvoke.java
hook思路:
- 获取实例中的mInstrumentation区域
- 创建MyInstrumentation对象
- 使用MyInstrumentation对象替换掉实例中的mInstrumentation区域
核心代码如下:
// hook实现静态代理
// hook本MainActivity实例的mInstrumentation
// 替换为myInstrumentation
Object mInstrumentation = RefInvoke.getFieldOjbect(Activity.class.getName(), this, "mInstrumentation");
Instrumentation myInstrumentation = new MyInstrumentation((Instrumentation)mInstrumentation);
RefInvoke.setFieldOjbect(Activity.class.getName(), "mInstrumentation", this, myInstrumentation);
实战代码
MainActivity.java:
package com.exmple.hookactivity;
import androidx.appcompat.app.AppCompatActivity;
import android.app.Activity;
import android.app.Instrumentation;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import com.exmple.hookactivity.hook.MyInstrumentation;
import com.exmple.hookactivity.hook.RefInvoke;
/**
* @author Lee
* @date 20/12/10
*/
public class MainActivity extends AppCompatActivity {
Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// hook实现静态代理
// hook本MainActivity实例的mInstrumentation
// 替换为myInstrumentation
Object mInstrumentation = RefInvoke.getFieldOjbect(Activity.class.getName(), this, "mInstrumentation");
Instrumentation myInstrumentation = new MyInstrumentation((Instrumentation)mInstrumentation);
RefInvoke.setFieldOjbect(Activity.class.getName(), "mInstrumentation", this, myInstrumentation);
button = (Button)findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setClass(MainActivity.this, Second.class);
startActivity(intent);
}
});
}
}
Second.java:
package com.exmple.hookactivity;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
/**
* @author Lee
* @date 20/12/10
*/
public class Second extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
}
}
RefInvoke.java:
package com.exmple.hookactivity.hook;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class RefInvoke {
public static Object invokeStaticMethod(String class_name, String method_name, Class[] pareTyple, Object[] pareVaules){
try {
Class<?> obj_class = Class.forName(class_name);
Method method = obj_class.getMethod(method_name,pareTyple);
return method.invoke(null, pareVaules);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static Object invokeMethod(String class_name, String method_name, Object obj ,Class[] pareTyple, Object[] pareVaules){
try {
Class<?> obj_class = Class.forName(class_name);
Method method = obj_class.getMethod(method_name,pareTyple);
return method.invoke(obj, pareVaules);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static Object getFieldOjbect(String class_name,Object obj, String filedName){
try {
Class<?> obj_class = Class.forName(class_name);
Field field = obj_class.getDeclaredField(filedName);
field.setAccessible(true);
return field.get(obj);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static Object getStaticFieldOjbect(String class_name, String filedName){
try {
Class<?> obj_class = Class.forName(class_name);
Field field = obj_class.getDeclaredField(filedName);
field.setAccessible(true);
return field.get(null);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static void setFieldOjbect(String classname, String filedName, Object obj, Object filedVaule){
try {
Class<?> obj_class = Class.forName(classname);
Field field = obj_class.getDeclaredField(filedName);
field.setAccessible(true);
field.set(obj, filedVaule);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void setStaticOjbect(String class_name, String filedName, Object filedVaule){
try {
Class<?> obj_class = Class.forName(class_name);
Field field = obj_class.getDeclaredField(filedName);
field.setAccessible(true);
field.set(null, filedVaule);
} catch (Exception e) {
e.printStackTrace();
}
}
}
MyInstrumentation.java:
package com.exmple.hookactivity.hook;
import android.app.Activity;
import android.app.Instrumentation;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import java.lang.reflect.Method;
/**
* @author weishu
* @date 16/1/28
*/
public class MyInstrumentation extends Instrumentation {
private static final String TAG = "MyInstrumentation";
// ActivityThread中原始的对象, 保存起来
Instrumentation mBase;
public MyInstrumentation(Instrumentation base) {
mBase = base;
}
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
// Hook之前, XXX到此一游!
Log.e(TAG, "\n执行了startActivity, 参数如下: \n" + "who = [" + who + "], " +
"\ncontextThread = [" + contextThread + "], \ntoken = [" + token + "], " +
"\ntarget = [" + target + "], \nintent = [" + intent +
"], \nrequestCode = [" + requestCode + "], \noptions = [" + options + "]");
// 开始调用原始的方法, 调不调用随你,但是不调用的话, 所有的startActivity都失效了.
// 由于这个方法是隐藏的,因此需要使用反射调用;首先找到这个方法
try {
Method execStartActivity = Instrumentation.class.getDeclaredMethod(
"execStartActivity",
Context.class, IBinder.class, IBinder.class, Activity.class,
Intent.class, int.class, Bundle.class);
execStartActivity.setAccessible(true);
return (ActivityResult) execStartActivity.invoke(mBase, who,
contextThread, token, target, intent, requestCode, options);
} catch (Exception e) {
// 某该死的rom修改了 需要手动适配
throw new RuntimeException("do not support!!! pls adapt it");
}
}
}
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start Second"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
activity_second.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Second">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello Second Activity"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
执行效果:
image.png
网友评论