Xposed HOOK入门体验
Xposed框架介绍
Xposed框架是一款开源java层的HOOK框架,其功能是可以在不修改APK的情况下影响程序运行(修改系统)的框架服务,基于它可以制作出许多功能强大的模块,且在功能不冲突的情况下同时运作。自己编写HOOK功能是相当麻烦的所以我们一般使用这些hook框架来做HOOK,这样我们就可以把精力放在业务逻辑上了。常用的Hook框架有Xposed、CydiaSubstrate和ADBI/DDI,这里Xposed感觉是最易用的了。
工作原理
Xposed框架是由rovo89开发的一款针对Android平台的动态劫持项目,是一款可以在不修改APK的情况下影响程序运行(修改系统)的框架服务,通过替换/system/bin/app_process 程序控制 zygote 进程,从而使 app_process 在启动过程中加载XposedBridge.jar 这个jar包,从而完成对Zygote进程及其创建的Dalvik虚拟机的劫持。
Zygote进程在启动过程中,除了创建一个Dalvik虚拟机实例之外,还会将Java运行时库加载到进程中来,同时还会注册一些Android核心类的JNI方法到前面创建的Dalvik虚拟机实例中去。
一个应用程序被孵化出来的时候,其不仅会获得Zygote进程中的Dalvik虚拟机实例,还会与Zygote一起共享Java运行时库,这也是可以将XposedBridge.jar这个jar包加载到每一个Android应用中的原因。
XposedBridge有一个私有的Native方法:hookMethodNative,这个方法也在app_process中使用。该函数提供一个方法对象利用Java的反射机制来对内置的方法覆写。
环境
Android Studio
Android4.4.4
Xposed2.7.apk
Xposed框架的安装
将Xposed2.7.apk安装到你的手机上进入后界面如下
image.png
进入框架
image.png
点击安装/更新
重启之后就安装完成了
目标项目的编写
这里为了更清楚的展示效果这里被HOOK的项目也由我们自己编写
创建项目
image.png
image.png
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="HOOK"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity.java
package com.shark.xposedtarget;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Toast.makeText(MainActivity.this, toastMessage(), Toast.LENGTH_SHORT).show();
}
});
}
public String toastMessage() {
return "我未被劫持";
}
}
项目运行效果如下
image.png
HOOK模块的编写
同上创建项目后
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.shark.hookmodle">
<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">
<!--告诉Xposed框架这个是Xposed模块-->
<meta-data
android:name="xposedmodule"
android:value="true" />
<!--模块的描述信息-->
<meta-data
android:name="xposeddescription"
android:value="这是一个Xposed例程" />
<!--模块支持的最低版本-->
<meta-data
android:name="xposedminversion"
android:value="53" />
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
主要添加了meta-data等信息上面的注释已经说明
接下来在build.gradle添加XposedBridgeApi-xx.jar
找到build.gradle,加上:
repositories {
jcenter()
}
以及
compileOnly 'de.robv.android.xposed:api:82'
compileOnly 'de.robv.android.xposed:api:82:sources'
这句代码是告诉AndroidStuido使用jcenter作为代码仓库,从这个仓库里远程寻找 de.robv.android.xposed:api:82 这个API。这个网上很少有Xposed教程介绍它的!(我们不用自己找XposedBridgeApi.jar了。注意!此处要用compileOnly这个修饰符!网上有些写的是provide ,现在已经停用了!)
apply plugin: 'com.android.application'
android {
compileSdkVersion 29
buildToolsVersion "29.0.2"
defaultConfig {
applicationId "com.shark.hookmodle"
minSdkVersion 19
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
repositories {
jcenter()
}
dependencies {
compileOnly 'de.robv.android.xposed:api:82'
compileOnly 'de.robv.android.xposed:api:82:sources'
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}
新建一个类“HookTest.java”,代码如下:
package com.shark.hookmodle;
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 {
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
if (loadPackageParam.packageName.equals("com.shark.xposedtarget")) {
XposedBridge.log(" has Hooked!");
Class clazz = loadPackageParam.classLoader.loadClass(
"com.shark.xposedtarget.MainActivity");
XposedHelpers.findAndHookMethod(clazz, "toastMessage", new XC_MethodHook() {
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
//XposedBridge.log(" has Hooked!");
}
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
param.setResult("你已被劫持");
}
});
}
}
}
最后一步,添加入口点
右键点击 “main ” 文件夹 , 选择new --> Folder -->Assets Folder,新建assets 文件夹:
然后右键点击 assets文件夹, new--> file,文件名为xposed_init(文件类型选text),并在其中写上入口类的完整路径(就是自己编写的那一个Hook类),这样, Xposed框架就能够从这个 xposed_init 读取信息来找到模块的入口,然后进行Hook操作了:
image.png
将此模块安装到手机上
运行
勾选我们开发的模块
image.png
重启后运行目标app结果如下
image.png