Xposed介绍
Xposed框架是一款可以在不修改APK的情况下影响程序运行(修改系统)的框架服务,通过替换/system/bin/app_process程序控制zygote进程,使得app_process在启动过程中会加载XposedBridge.jar这个jar包,从而完成对Zygote进程及其创建的Dalvik虚拟机的劫持。
官网地址: http://repo.xposed.info/
源码地址: https://github.com/rovo89
Xposed安装
Android 6.0.x
https://pan.baidu.com/s/1qY7oW36 密码:r3mh
- 设备需要root
- recovery 刷入
xposed-v78-sdk23-arm.zip
- 安装
xposed.apk
Xposed使用
打开Xposed Installer
- 框架——安装、检查框架运行状态
- 模块——列出当前可用模块以及状态
- 下载——框架商店
- 日志——Xposed中日志记录
注意:每次启用或者关闭模块均需要重启设备
Xposed模块开发
Xposed模块的安装包实际上就是一个有着特殊的AndroidManifest.xml和添加了XposedBridgeApi.jar包的apk文件,所以同样可以用Android Studio 来开发。同时我们在开发时需获取的目标(被劫持的)apk的信息有:
- 包名
- 类名
- 函数名
- 函数参数
LoginDemo
package com.example.xuanxuan.myapplication;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private Button bt1;
private EditText name1;
private EditText password1;
private final String ACCOUNT="xuanxuan";
private final String PASSWORD="123456";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bt1 = (Button) findViewById(R.id.id_button);
name1 = (EditText)findViewById(R.id.id_name);
password1 = (EditText)findViewById(R.id.id_password);
bt1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String username = name1.getText().toString();
String password = password1.getText().toString();
if(isOK(username,password)){
Toast.makeText(MainActivity.this,"login success",Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(MainActivity.this,"login failed",Toast.LENGTH_SHORT).show();
}
}
});
}
private boolean isOK (String argc,String argv){
return argc.equals(ACCOUNT)&&argv.equals(PASSWORD);
}
}
HookDemo
- 新建一个不需要Activity的空白工程。
- 在空工程的java文件夹中新建一个类,该类就是一个模块类,这里命名为“Module”。
- 配置AndroidManifest.xml,其中的meta-data内容要照搬。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.xuanxuan.hackdemo">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme" >
<meta-data
android:name="xposedmodule"
android:value="true"/>
<meta-data
android:name="xposeddescription"
android:value="Hook Test!"/>
<meta-data
android:name="xposedminversion"
android:value="54"/>
</application>
</manifest>
- 在main文件夹下创建一个assets文件夹,并在里面创建一个名为“xposed_init”的普通文件,在里面添加一句字符串,即包名+模块类名,如
com.example.xuanxuan.hackdemo.Module
- 新建一个名为
lib
的文件夹,注意不是libs
。然后放入XposedBridgeApi.jar包,并在该jar包上右键Add as Library。
XposedBridgeApi.jar下载地址:
https://forum.xda-developers.com/xposed/xposed-api-changelog-developer-news-t2714067
- 编写模块类Module.java
package com.example.xuanxuan.hackdemo;
import android.util.Log;
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;
/**
* Created by xuanxuan on 2018/1/15.
*/
public class Module implements IXposedHookLoadPackage{
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
if(loadPackageParam.packageName.equals("com.example.xuanxuan.myapplication")){ //包名
XposedHelpers.findAndHookMethod(
"com.example.xuanxuan.myapplication.MainActivity", //类名
loadPackageParam.classLoader,
"isOK", //函数名
String.class,
String.class, //函数参数
new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
XposedBridge.log("账号:"+(String)param.args[0]+" 密码:"+(String)param.args[1]);
Log.d("zz","账号:"+(String)param.args[0]+" 密码:"+(String)param.args[1]);
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Log.d("zz", param.getResult().toString());
}
});
}
}
}
说明:
-
Module继承了IXposedHookLoadPackage接口,当系统加载应用包的时候回调 handleLoadPackage;
-
XposedHelpers的静态方法findAndHookMethod就是hook函数的的方法,其参数对应为:
- 类名,必须要有包名前缀,即“packageName+className”
- loadPackageParam.classLoader(照写)
- 方法名
- 参数类型(根据所hook方法的参数的类型,即有多少个写多少个,加上.class)
- XC_MethodHook回调接口
如果代码被混淆过,即使你明知道代码中要hook的类名和方法名,但都不一定能用,必须以smali中的名字为准,比如:isOk()混淆之后在smali中的函数名为a,那么hook的时候就必须写a,而不是isOK,第一个参数类名同理!
- 参数里有一个监听类XC_MethodHook,该类在hook前后回调,通过回调方法的MethodHookParam可以拦截到函数参数。
- 打包 Build->Generate Signed APK生成一个APK,并安装在手机,重启。即可在Xposed日志中查看到被记录的登录信息。
参考
Android 6.0.x 系统安装xposed框架
http://blog.csdn.net/u011303443/article/details/51031170
XPosed入门与登陆劫持演示
https://www.csdn.net/article/2015-08-14/2825462
Android逆向分析之Xposed的hook技术
http://blog.csdn.net/qq_18870023/article/details/51753587
Xposed模块编写的那些事
http://www.freebuf.com/articles/terminal/114910.html