写在前面:今天自己动手实现了Xposed模块的编写,又费了很大劲,之前一直在搞crypto(对于我这个没学过数论的菜鸡,确实好难),这次把很多丢了的东西又捡回来了,所以在这里做个记录,下次再丢可以来这里看看。其实关于Xposed模块编写,网上有很多文章,都可以拿来借鉴,但自己写的才是最好的!
一、准备
- 一只安装Xposed框架的Android手机
- 基本的Android的开发环境(-.-)
XposedBridgeApi-54.jar (这里我不提供链接了,自己网上找找)
准备差不多这么多
二、编写被Hook的app
注意:XposedBridgeApi-54.jar
这个包必须是要使用provided 进行编译的,否则会重复包含,导致错误。这里提供两种方案:
方案一:将jar包导入到libs目录下(当然这里也可以直接复制粘贴进来),修改build.gradle文件。修改前后如下:
修改前:compile fileTree(include: ['*.jar'], dir: 'libs')
修改后:provided fileTree(include: ['*.jar'], dir: 'libs')
注意:在添加jar包后在同步gradle,否则会加载不出来-2018/3/7注
也可以这么做provided files(‘libs/XposedBridgeApi-54.jar’) 总之是要将jar包利用provided方式进行加载-2018/3/8注
方案二:在app目录下新建lib目录和libs目录同一级,将jar包导入到lib目录中,同样修改build.gradle文件。如下:
在原有的dependences块中增加一行:provided files('lib/XposedBridgeApi-54.jar')
这样修改后就不有编译错误了。
具体案例的代码如下,写得比较简单,就不解释了。
private ImageView imageView;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
imageView=(ImageView) findViewById(R.id.picture);
Resources resources=this.getResources();
Bitmap bitmap = BitmapFactory.decodeResource(resources,R.drawable.image1);//给你个眼神自行体会
imageView.setImageBitmap(bitmap);
Button buttonHook = (Button) findViewById(R.id.buttonHook);
Button buttonRecover = (Button) findViewById(R.id.buttonRecover);
buttonHook.setOnClickListener(this);
buttonRecover.setOnClickListener(this);
}
public void onClick(View v){
switch (v.getId()){
case R.id.buttonHook:
if(check()){
//Toast.makeText(MainActivity.this, "Congratulation!", Toast.LENGTH_SHORT).show();
imageView.setImageResource(R.drawable.image2);
}
break;
case R.id.buttonRecover:
imageView.setImageResource(R.drawable.image1);
break;
}
}
private boolean check() {
Toast.makeText(MainActivity.this, "This is test!", Toast.LENGTH_SHORT).show();
return false;
}
其实我最开始是想Hook Toast的,但是尝试失败,无奈之下写了check。那接下来我们就来Xposed模块咯。
三、编写Xposed模块:
Xposed模块通常是没有界面的,当然你也可以提供一个界面,在文末我会贴上有界面的图和代码。
新建一个项目,修改build.gradle,在app->src->main下新建assets目录,在assets目录下新建xposed_init文件,并添加com.code.jsk.xposedhook.MainCtf
包名+类名 用于xposed的初始化,它会执行该目录下的代码。接着只要编写Hook类,并重写handleLoadPackage即可。
public class MainCtf implements IXposedHookLoadPackage {
//包加载时回调
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
if (!loadPackageParam.packageName.equals("com.code.jsk.xposedexampleapp")) return;
XposedBridge.log("Load app" + loadPackageParam.packageName); //在日志中记录我hook了哪个包
//findAndHookMethod("android.widget.Toast", loadPackageParam.classLoader, "makeText", new XC_MethodReplacement() {
findAndHookMethod("com.code.jsk.xposedexampleapp.MainActivity",loadPackageParam.classLoader, "check", new XC_MethodReplacement() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
XposedBridge.log("This is beforeHookedMethod!");
}
@Override
protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {
//Toast.makeText(, "Hacked!", Toast.LENGTH_SHORT).show();
XposedBridge.log("Hacked check");
return true;
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
XposedBridge.log("This is the afterHookedMethod!");
}
});
}
}
代码中我都加了关键注释,主要就是处理beforeHookedMethod,replaceHookedMethod,afterHookedMethod 这三个函数
基本的过程就是先找到相应的包,之后再匹配需要hook的方法,之后就是replace方法。
我个人比较喜欢用adb进行操作:
adb install -r hook.apk 进行安装 -r是强制覆盖安装
adb reboot 重启
之前有一段代码写错了。这里记录这个错误就不做修改了。
findAndHookMethod(“com.code.jsk.xposedexampleapp.MainActivity”,loadPackageParam.classLoader, “check”, new XC_MethodReplacement() {})
他有两种写法,一种是
findAndHookMethod(String className,
ClassLoader classLoader,
String methodName,
Object... parameter TypesAndCallback)
还有一种:
findAndHookMethod(Class<?> clazz,
String methodName,
Object... parameter TypesAndCallback)
最后一个参数new的对象也有不同如果仅仅是replaceMethoed,那么使用new XC_MethodReplacement() {
即可,如果需要使用beforeHookedMethod和afterHookedMethod 这两个函数那么就需要 new XC_MethodHook() {
修改后的代码如下:
findAndHookMethod("com.code.jsk.xposedexampleapp.MainActivity",loadPackageParam.classLoader, "check", new XC_MethodReplacement() {
@Override
protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {
//Toast.makeText(, "Hacked!", Toast.LENGTH_SHORT).show();
XposedBridge.log("Hacked check");
return true;
}
});
findAndHookMethod("com.code.jsk.xposedexampleapp.MainActivity", loadPackageParam.classLoader, "check", new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
XposedBridge.log("This is the beforeHookedMethod!");
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
XposedBridge.log("This is the afterHookedMethod!");
}
});
最后并没有执行afterHookedMethod 这部分代码,我也不带清楚为什么。
最后在贴上带界面的Xposed模块的图
简单的增加一个主活动,并添加界面即可。
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
ImageView imageView = (ImageView) findViewById(R.id.imageview);
imageView.setImageResource(R.drawable.image3);
}
}