[Xposed]Xposed模块开发入门教程
Xposed开发基础实例
众所周知,Android系统中应用程序进程都是由Zygote
进程孵化出来的,而Zygote
进程是由Init
进程启动的。Zygote
进程在启动时会创建一个Dalvik
虚拟机实例,每当它孵化一个新的应用程序进程时,都会将这个Dalvik
虚拟机实例复制到新的应用程序进程里面去,而一个应用程序进程被Zygote
进程孵化出来的时候,不仅会获得Zygote
进程中的Dalvik
虚拟机实例拷贝,还会与Zygote
一起共享Java运行时
库。
而Xposed
则通过替换app_process
程序来控制Zygote
进程,使得app_process
在启动过程中会加载XposedBridge.jar
这个jar
包,从而完成对Zygote
进程及其创建的Dalvik虚拟机
的劫持。
这里不细讲Zygote
!!!!
实战GoGoGo!
未作说明的话,本例中创建的工程为Empty Activity
构建一个简单的需要被劫持的应用
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical">
<TextView
android:id="@+id/textHello"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
android:textSize="50sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="是否被劫持"/>
</LinearLayout>
用简单的线性布局添加一个按钮即可,毕竟以后不可能自己去开发自己开发的app的模块。
MainActivity.java
package XXX;
// 此为你的包名,AS未作特殊设置的话会自动生成
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button) findViewById(R.id.button);
// 这个是按钮id
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this, getToast(), Toast.LENGTH_SHORT).show();
Log.println(Log.INFO, "Tc", "调用onclick");
}
});
}
public String getToast() {
return "我没有被劫持";
}
}
只是对按钮进行OnClick事件的监听,让其返回未被劫持的提示
安装到真机或是虚拟机上
构建一个简单的需要被劫持的应用
这里建议新建一个工程,分开成2个应用模拟劫持
首先要更改src/main目录下的AndroidManifest.xml,让Xposed识别这是一个Xposed模块
AndroidManifest.xml
可以在 active
标签开始前添加以下信息
<meta-data
android:name="xposedmodule"
android:value="true"
/>
<meta-data
android:name="xposeddescription"
android:value="这是一个Xposed例程"
/>
<meta-data
android:name="xposedminversion"
android:value="53"
/>
xposedmodule 是否为Xposed模块
xposeddescription 描述
xposedminversion 最小支持Xposed版本
导包
这里直接更改src/main目录下的build.gradle即可
在dependencies
添加
compileOnly 'de.robv.android.xposed:api:82'
然后直接选择上方Sync Now
直接同步即可
若网络原因失败,可尝试更换国内仓库源
layout & Main
事实上,如果要开发一个功能强大且需要自定义设置的可以自行编写布局样式与MainActivity类
本实例中无需,但更改了layout中的TextView的内容与布局格式作为展示
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical">
<TextView
android:id="@+id/textHello"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="劫持测试"
android:textSize="50sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</LinearLayout>
MainActivity.java
package XXX;
// 包名
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
这个就是自动生成的,未做更改
编写劫持类
在MainActivity同目录下创建Java类,本例中为HookTest
package XXX;
// 包名
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
public class HookTest implements IXposedHookLoadPackage {
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
if (lpparam.packageName.equals("XXXX"))
// 此处XXXX为被劫持的包名
{
XposedBridge.log("Im on hook");
Class<?> clazz = lpparam.classLoader.loadClass("XXXX.YY");
// 反射
// 此处XXXX为被劫持包名,YY为劫持类
XposedHelpers.findAndHookMethod(clazz, "getToast", new XC_MethodHook()
// 这个getToast即为方法名
{
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
param.setResult("已被劫持,耶斯莫拉");
}
});
}
}
}
让HookTest实现IXposedHookLoadPackage接口并重写handleLoadPackage方法
xposed_init
创建文件夹与文件
在main下New -> Folder -> AssetsFolder创建一个Assets文件夹,并在里面创建一个名为xposed_init的普通文件
写文件
将刚编写的劫持类包名.类写入到这个文件中,本例中类名为HookTest
安装与启用
安装到真机或者模拟器,我用的是LSPOSED,安装后则会直接提示模块未启用,点击进入选择作用域(目标应用)并打开开关
启用&效果
启用模块
检验
杀掉之前打开的目标应用后台,并重新启动
重新点击按钮
发现劫持成功
关闭模块并检验
关闭模块
重新打开
发现已还原
结语
像我们这个例子很简单,没有特意的进行代码混淆
以及程序入口改写
等等,我们寻找还是很简单的,一般市面上的App
都是有很多反Xposed
的行为,我们其实要学习的还有很多,这个小教程就当做个小入门吧。