Xposed插件编写教程(微信自动登陆)

分类 - 技术 共有 0 条评论

Wxautologin

找到包路径

使用当前Activity软件找到登陆提示的包路径->可以得到包路径地址为:com.tencent.mm.plugin.webwx.ui.ExtDeviceWXLoginUI

反编译Apk找到hook方法

首先我们先解压需要hook的apk,将其中的dex文件复制出来,再将dex文件反编译后就能获得java类。

Snipaste_2020-04-22_22-06-25.jpg

使用 dex2jar

这里我们使用dex2jar-2.0工具进行反编译dex,将所有dex文件复制到dex2jar文件夹下(方便使用 .sh)。命令为:./d2j-jar2dex.sh ./*.dex,这个意思就是将所有的dex文件都反编译(如果有多个的话)经过这个操作后,会在当前目录下生成jar文件,这个文件中就包含class类

Snipaste_2020-04-22_22-09-35.jpg

Snipaste_2020-04-22_22-11-12.jpg

使用 jd-gui

使用jd-gui程序查看反编译的jar,并在其中找到要hook的方法。这里需要一点 Android基础,找到了需要Hook的方法以后我们就可以开始写插件啦!
Snipaste_2020-04-22_22-12-25.jpg

ps:这里演示一下微信登陆的分析过程

Snipaste_2020-04-22_22-26-00.jpg

经过分析,找到需要hook的类在第5个dex中,将第五个dex生成的jar文件拖动到jd-gui上,用jd-gui打开它,找到com.tencent.mm.plugin.webwx.ui.ExtDeviceWXLoginUI类,这个xEY 就是手机上被唤起的那个登陆按钮,那么接下来我们只需要找到一个能被hook的方法就行了,经过分析我们可以Hook initview方法

Snipaste_2020-04-22_22-27-56.jpg

Snipaste_2020-04-22_22-33-30.jpg

演示结束

配置Android程序

创建项目

打开Android studio 创建一个空Activity项目。

Snipaste_2020-04-22_22-14-02.jpg

等待gradle sync完成后,修改AndroidManifest.xml,让Xposed框架能够识别到本程序。添加三个meta-data,第一个指示这是一个xposed模块,第二个是模块描述,第三个是最小所能支持到的xposed版本。
Snipaste_2020-04-22_22-15-57.jpg

<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的类

Snipaste_2020-04-22_22-16-57.jpg

文件内容:
cn.lovelywhite.wxautologin.Hook

添加依赖

在app下的build.gradle中添加模块依赖,这是为了导入xposed包。注意需要改为compileOnly,我们不需要把xposed打包进我们的apk

Snipaste_2020-04-22_22-17-58.jpg

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不到方法。
Snipaste_2020-04-22_22-18-48.jpg

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原创,如需转载请附上原文连接。

文章评论