Wxautologin
找到包路径
使用当前Activity
软件找到登陆提示的包路径->可以得到包路径地址为:com.tencent.mm.plugin.webwx.ui.ExtDeviceWXLoginUI
反编译Apk找到hook方法
首先我们先解压需要hook的apk,将其中的dex文件复制出来,再将dex文件反编译后就能获得java类。
使用 dex2jar
这里我们使用dex2jar-2.0工具进行反编译dex,将所有dex文件复制到dex2jar文件夹下(方便使用 .sh)。命令为:./d2j-jar2dex.sh ./*.dex
,这个意思就是将所有的dex文件都反编译(如果有多个的话)经过这个操作后,会在当前目录下生成jar文件,这个文件中就包含class类
使用 jd-gui
使用jd-gui程序查看反编译的jar,并在其中找到要hook的方法。这里需要一点 Android基础,找到了需要Hook的方法以后我们就可以开始写插件啦!
ps:这里演示一下微信登陆的分析过程
经过分析,找到需要hook的类在第5个dex中,将第五个dex生成的jar文件拖动到jd-gui上,用jd-gui打开它,找到com.tencent.mm.plugin.webwx.ui.ExtDeviceWXLoginUI
类,这个xEY 就是手机上被唤起的那个登陆按钮,那么接下来我们只需要找到一个能被hook的方法就行了,经过分析我们可以Hook initview方法
演示结束
配置Android程序
创建项目
打开Android studio 创建一个空Activity项目。
等待gradle sync完成后,修改AndroidManifest.xml
,让Xposed框架能够识别到本程序。添加三个meta-data,第一个指示这是一个xposed模块,第二个是模块描述,第三个是最小所能支持到的xposed版本。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cn.lovelywhite.wxautologin">
<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="This is a plug-in that can stop advertising" />
<meta-data
android:name="xposedminversion"
android:value="82" />
</application>
</manifest>
编辑 xposed_init
接着在assets文件夹下创建一个文件(无后缀),名称为:xposed_init
这个文件里面需要填上加载Hook类包路径,用于提示xposed找到Hook类。我这里就先填上了,待会我会在这个包路径下新创建一个名字为Hook的类
文件内容:cn.lovelywhite.wxautologin.Hook
添加依赖
在app下的build.gradle中添加模块依赖,这是为了导入xposed包。注意需要改为compileOnly,我们不需要把xposed打包进我们的apk
apply plugin: 'com.android.application'
android {
compileSdkVersion 29
buildToolsVersion "29.0.3"
defaultConfig {
applicationId "cn.lovelywhite.wxautologin"
minSdkVersion 22
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'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
//添加下面这一句,82代表版本
compileOnly 'de.robv.android.xposed:api:82'
//添加上面这一句
}
编写Hook代码
我们之前在xposed_init
中添加了Hook类的路径,接下来我们需要创建这个Hook类,名字可以随意取只要和xposed_init里的路径一样就行,这里分两种情况。一种是采用multidex分包机制将Apk分包了,一种是没分包。分包了的话可能Hook不到方法。
Hook 方法在其他包中
第一种情况:没分包,或者分包了且要hook的方法在第一个包当中(参考我另一个项目)这种情况就不用套一层
YxladyWater项目github地址
package cn.lovelywhite.yxladywaterhook;
import android.app.AndroidAppHelper;
import android.widget.Toast;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodReplacement;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
//首先我们需要实现这个接口:IXposedHookLoadPackage
public class Hook implements IXposedHookLoadPackage {
//实现handleLoadPackage方法
public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam){
//lpparam中有当前运行的应用包名,我们需要进行匹配
if(lpparam.packageName.equals("com.yxlady.water")) {
//接着我们就开始写Hook方法了,这个方法在XposedHelpers类下。
//findAndHookMethod hook就是钩子的意思 顾名思义就是 找到并且hook它。
//这个方法接受四个参数
//第一个:要hook的类名
//第二个:classloader
//第三个:要hook的方法
//第四个:用于回调的匿名类,有很多种这里就不一一介绍了。
//这里一共有两种Hook方式,方法之前和方法之后:分别代表在该方法调用之前和调用之后
XposedHelpers.findAndHookMethod("com.yxlady.water.ui.activity.EntryActivity",
lpparam.classLoader,
"k",
//这个匿名类的作用是替换方法内容->我们将k方法的内容替换掉,因为k方法是调用广告的方法。
new XC_MethodReplacement() {
//实现replaceHookedMethod方法,这样k方法就被替换成了
/*
*
* XposedHelpers.callMethod(param.thisObject, "m");
Toast.makeText(
AndroidAppHelper.currentApplication().getApplicationContext(),
"去除广告成功",
Toast.LENGTH_LONG
).show();
*
* */
@Override
protected Object replaceHookedMethod(MethodHookParam param) {
//下面这一行是调用m方法->m方法是开启主界面的方法
XposedHelpers.callMethod(param.thisObject, "m");
Toast.makeText(
AndroidAppHelper.currentApplication().getApplicationContext(),
"去除广告成功",
Toast.LENGTH_LONG
).show();
return null;
}
}
);
}
}
}
Hook 方法在第一个包中
第二种情况:分包了,并且要Hook的方法不在第一个包当中
Wxautologin 项目github地址
package cn.lovelywhite.wxautologin;
import android.app.Application;
import android.content.Context;
import android.widget.Button;
import java.lang.reflect.Field;
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;
//我们需要创建一个实现类,这个实现类实现的是IXposedHookLoadPackage接口
public class Hook implements IXposedHookLoadPackage {
//然后我们需要实现handleLoadPackage方法,这个方法就是程序入口方法
public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam) {
//lpparam中存放了加载程序的包名,我们需要匹配一下,这里我们就匹配com.tencent.mm
if (lpparam.packageName.equals("com.tencent.mm")) {
XposedBridge.log("Wx Loaded!");//当我们打开微信,会在Xposed控制台输出wx Loaded。
//接着我们就开始写Hook方法了,这个方法在XposedHelpers类下。
/* 对于multidex 的代码,我们需要获取到当前上下文才能正确Hook 到非主包中的方法
由于Android在加载Dex文件之后会创建一个Application对象,然后会调用其中的attach方法,所以
我们可以先通过这个方法先获取到上下文对象再来进行进一步hook multidex中的方法。
*/
XposedHelpers.findAndHookMethod(Application.class, "attach", Context.class, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
ClassLoader cl = ((Context) param.args[0]).getClassLoader();
Class<?> hookclass = null;
try {
hookclass = cl.loadClass("com.tencent.mm.plugin.webwx.ui.ExtDeviceWXLoginUI");
} catch (Exception e) {
return;
}
final Class<?> finalHookclass = hookclass;
//接下来就跟没分包是一样的套路了
XposedHelpers.findAndHookMethod(hookclass/*类名*/, "initView"/*方法名*/, new XC_MethodHook() {
//之前调用
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
XposedBridge.log("initView1!");
}
//之后调用
@Override
protected void afterHookedMethod(XC_MethodHook.MethodHookParam param)
throws Throwable {
XposedBridge.log("initView2!");
//获取到xEy 经过反编译解析,这是个按钮也就是接受登陆按钮
Field field = finalHookclass.getDeclaredField("xEY");
//设置可访问性
field.setAccessible(true);
//强制转换为button对象
Button btn = (Button) field.get(param.thisObject);
//模拟点击
btn.performClick();
}
});
}
});
}
}
}
本文由lw原创,如需转载请附上原文连接。
本文由 suxi 创作,采用 知识共享署名4.0 国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为: 2024/03/28 16:31