0%

Android逆向:说一说Xposed

在阅读本文之前,假设你的手机已经root,并且已经成功安装好了 XposedInstaller。

什么是Xposed

Xposed 是一个 Android 平台上的动态劫持框架,通过替换手机上的孵化器 zygote 进程为 Xposed 自带的 zygote,使其在启动过程中加载 XposedBridge.jar,模块开发者可以通过 jar 提供的 API 来实现对所有的 Function(这里可以理解为方法) 的劫持,在原 Function 执行的前后加上自定义代码。

1

Xposed框架是一款可以在不修改APK的情况下影响程序运行(修改系统)的框架服务,基于它可以制作出许多功能强大的模块,且在功能不冲突的情况下同时运作。Xposed理论上能够hook到系统任意一个Java进程,由于是从底层hook,所以需要root权限,并且每次更新都要重新启动,否则不生效 。

Xposed 和 Cydia Substrate

这两个框架都是app注入的利器,只是相对来说有各自特点罢了。Cydia Substrate是一个代码修改平台。它可以修改任何主进程的代码,不管是用Java还是C/C++(native代码)编写的。而Xposed只支持 hook system/bin/app_process中的Java函数。其实Cydia Substrate 与xposed 的hook原理是一样的,二者都可以作为Java Hook的框架,看使用习惯了(iOS的越狱用到的便是Cydia Substrate)。笔者最近研究主要以Xposed为主,暂不对Cydia Substrate进行详细的说明,后续有研究会继续以文字形式记录吧。

利用Xposed执行最简单的篡改操作

Xposed的运用太过广泛,作为这个系列的第一篇笔记,这里也介绍一种Xposed最简单的应用场景。

我们修改入门android逆向的项目,将 Hello World 修改为 Hello Xposed!

a. 随意在Android Studio里创建一个项目,在这里我的包名是:com.blues.cracktest 里面没有任何后续添加的代码,编译之后只有屏幕中间最经典的“Hello World!”;
b. 我们需要做的就是通过Xposed去修改这个“Hello World”,让它替换成任何我们想要它显示成为的东西,比如我期望是“Hello Xposed! ”
首先第一步先进行配置,在清单文件AndroidManifest里 Application作用域里加上如下配置:

1
2
3
4
5
6
7
8
9
<meta-data
android:name="xposedmodule"
android:value="true" />
<meta-data
android:name="xposeddescription"
android:value="hello xposed" />
<meta-data
android:name="xposedminversion"
android:value="82" />

第二步,在main目录下(java、res同级目录)创建assets文件夹,在该文件夹下新建一个xposed_init文件(该文件名称固定为xposed_init),该文件用于放置hook的入口,里面是一个路径(比如我的是com.example.androidrefirst.XposedInit,XposedInit就是我hook的入口,这个类后面会提及)。

第三步,新建一个类,这里就叫它XposedInit好了,让它实现(implements) IXposedHookLoadPackage 这个接口 ,重写 handleLoadPackage 方法(该方法用于获取需要hook到的类,里面会用到一个findAndHookMethod 用于hook对应的方法),我就直接show code吧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package com.example.androidrefirst;

import android.os.Bundle;
import android.widget.TextView;

import java.lang.reflect.Field;

import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;

public class XposedInit implements IXposedHookLoadPackage {
@Override
public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam) {
if (lpparam.packageName.equals("com.example.androidrefirst")) {
XposedHelpers.findAndHookMethod("com.example.androidrefirst.MainActivity", lpparam.classLoader, "onCreate", Bundle.class, new XC_MethodHook() {
@Override
protected void afterHookedMethod(XC_MethodHook.MethodHookParam param) throws Throwable {
//不能通过Class.forName()来获取Class ,在跨应用时会失效
Class c = lpparam.classLoader.loadClass("com.example.androidrefirst.MainActivity");
Field field = c.getDeclaredField("textView");
field.setAccessible(true);
//param.thisObject 为执行该方法的对象,在这里指MainActivity
TextView textView = (TextView) field.get(param.thisObject);
textView.setText("Hello Xposed!!!!!!!");
}
});
}
}
}

原来的MainActivity长这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package com.example.androidrefirst;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
private EditText code;
private Button btn_verify;
private TextView textView;

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

private void init() {
code = findViewById(R.id.editText);
btn_verify = findViewById(R.id.button);
btn_verify.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String verifyCode=code.getText().toString().trim();
if(verifyCode.equals("2019")){
Intent intent=new Intent(MainActivity.this,SuccessActivity.class);
startActivity(intent);
}else {
Toast.makeText(MainActivity.this,"验证码错误!", Toast.LENGTH_LONG).show();
}
}
});
textView=findViewById(R.id.textView1);
textView.setText("hello world!!!!!");
}
}

运行之后在 XposedInstaller 中启用我们的xposed模块 重启之后看效果。可以看到Hello Xposed!!!!!!!

参考:

https://blog.csdn.net/micaaa/article/details/82706778