《教我兄弟学Android逆向15 xpose改机开发03-写一款自己的改机软件》

本文是Xpose改机开发教程,介绍了改机优缺点,优点是易上手、成本低,缺点是易被检测且只能操作Java层。给出三种解决方案,还介绍改机点,如硬件、手机卡等信息,说明了寻找改机点的方法及改机代码编写,最后布置了课后作业。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上一篇 《教我兄弟学Android逆向14 xpose改机开发02-改机代码基础编写》我带你熟悉了一下改机的流程,搭建了改机的基础代码,改机参数数据储存方面我们用的是SharedPreferences存储数据,界面方面写了一个一键新机的按钮,点一键新机的时候会随机生成imei数据存储到xml数据中,然后xpose代码hook到了getDeviceId函数会将返回值设置成xml文件读取的值,这样就完成了对imei的修改。

关于界面方面上节课也是粗略的写了一下,你可以根据自己想实现的功能去写自己想要的界面。
前面两节课我们配置了xpose开发的环境并且编写了xpose改机的第一个demo
那么本节课我会给你介绍一下改机的总体,以及改机点的寻找和编写。

要么学!要么不学!学和不学之间没有中间值 不学就放弃,学就要去认真的学!    --致选择

xpose改机的优缺点
优点
易上手,便于使用,所需时间成本比较少。
缺点
很容易被检测,只能在java层去操作,Native层,内核层,C库的一些函数无法被修改。
比如libc的函数open,fopen,access,rename,Unix的popen函数还有一些C层内核层获取设备信息的结构体这些都是无法通过xpose去改的。

那么如果想做一款比较好的改机有什么解决方案呢?
1.用xpose去配合一些可以hook so层函数的工具比如Inlinehook,frida等。
2.针对性修改,逆向出协议数据配合xpose模拟数据发包。
3.自定义安卓系统,全局修改。


一 .改机点介绍
1.硬件信息
手机的唯一标识imei,android,序列号serial,手机品牌,手机机型,制造商,蓝牙名,蓝牙MAC地址,系统版本,系统版本名称,开发代号,源码控制版本号,编译类型,CPU架构,无线电固件版本,设备版本号,主板名称,引导程序版本号,设备参数,设备地址,产品名称,ROM名称,硬件名称,指纹,开发ROM编译用户,设备的ROM生成的时间.....
2.手机卡信息
3.蓝牙信息
4.UA信息
5.电池电量
5.开机时间
6.手机内存的信息
7.屏幕大小
8.传感器
9.位置基站信息
10.wifi信息
11.文件信息
12.环境检测
13.设备信息真实性检测
......


看到这么多信息你应该有疑问了,上面说的这些点都是怎么去找到的?

二.改机点寻找
1.从百度google等搜索引擎去搜索xpose改机代码,github上面也有一些开源的xpose改机代码都可以去参考。
2.逆向一些app去看对方是怎么去获取设备信息的,怎么去检测环境信息的从而针对性的去完善改机代码。
3.研究分析安卓源码,找到一切可以获取设备信息的点,要知道大厂做安全的都是从研究Android源码开始的。

三.改机代码编写
1. 因为改机代码量比较大,所以我们首先写一个抽象类去继承XC_MethodHook后面的hook类都可以去继承这个类。
MethodHook.java

public abstract class MethodHook extends XC_MethodHook {
        protected String mpackageName;
        protected ClassLoader mclassLoader;
        protected DeviceInfoModel deviceInfoModel;
        public MethodHook(XC_LoadPackage.LoadPackageParam paramLoadPackageParam, DeviceInfoModel deviceInfoModel)
        {
            this.mpackageName = paramLoadPackageParam.packageName;
            this.mclassLoader = paramLoadPackageParam.classLoader;
            this.deviceInfoModel = deviceInfoModel;
        }
    @Override
    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
        super.afterHookedMethod(param);
    }
    public void hookMethodByClassMethodName(String paramString, String paramString2)
    {
        try
        {
            for (Method localMethod : XposedHelpers.findClass(paramString, this.mclassLoader).getDeclaredMethods())
                if ((localMethod.getName().equals(paramString2)) && (!Modifier.isAbstract(localMethod.getModifiers())))
                {
                    localMethod.setAccessible(true);
                    XposedBridge.hookMethod(localMethod, this);
                }
        }
        catch (Throwable localThrowable)
        {
            Log.e("xposed-MethodHook", "hookMethodByClassMethodName Exception " + paramString);
        }
    }
    public void hookMethodByClassMethodName(String paramString1, String paramString2, Object[] paramArrayOfObject)
    {
        try
        {
            Object[] arrayOfObject = new Object[1 + paramArrayOfObject.length];
            for (int i = 0; i < arrayOfObject.length; i++)
            {
                if (i == -1 + arrayOfObject.length)
                {
                    arrayOfObject[(-1 + arrayOfObject.length)] = this;
                    XposedHelpers.findAndHookMethod(paramString1, this.mclassLoader, paramString2, arrayOfObject);
                    return;
                }
                arrayOfObject[i] = paramArrayOfObject[i];
            }
        }
        catch (Throwable localThrowable)
        {
            Log.e("xposed-MethodHook", "addHookMethodWithParms Exception " + paramString1);
        }
    }
 
    public void hookMethodByClassMethodName(String paramString, Object[] paramArrayOfObject)
    {
        try
        {
            Object[] arrayOfObject = new Object[1 + paramArrayOfObject.length];
            for (int i = 0; i < arrayOfObject.length; i++)
            {
                if (i == -1 + arrayOfObject.length)
                {
                    arrayOfObject[(-1 + arrayOfObject.length)] = this;
                    XposedHelpers.findAndHookConstructor(paramString, this.mclassLoader, arrayOfObject);
                    return;
                }
                arrayOfObject[i] = paramArrayOfObject[i];
            }
        }
        catch (Throwable localThrowable)
        {
           Log.e("xposed-MethodHook", "addHookConWithParms Exception " + paramString);
        }
    }
 
    public void addHook(String paramString)
    {
        try
        {
            for (Constructor localConstructor : XposedHelpers.findClass(paramString, this.mclassLoader).getDeclaredConstructors())
                if (Modifier.isPublic(localConstructor.getModifiers()))
                    XposedBridge.hookMethod(localConstructor, this);
        }
        catch (Throwable localThrowable)
        {
            Log.e("Xhook", "addHook exception", localThrowable);
        }
    }
    public static Field setAccessible(Object arg4, String arg5) {
        Field[] v4 = arg4.getClass().getDeclaredFields();
        int v0 = v4.length;
        int v1;
        for(v1 = 0; v1 < v0; ++v1) {
            Field v2 = v4[v1];
            v2.setAccessible(true);
            if(v2.getType().toString().endsWith(arg5)) {
                return v2;
            }
        }
        return null;
    }
}

2.BuildHook.java
这里包含手机的一些硬件信息的修改和android系统属性的修改,但是缺点的话SystemProperties的get方法很多大厂都是通过native去调用底层的native_get方法检测,这样就要配合其他方式去修改了。

public class BuildHook extends MethodHook
{
    public BuildHook(XC_LoadPackage.LoadPackageParam paramLoadPackageParam, DeviceInfoModel deviceInfoModel, final Context context) {
        super(paramLoadPackageParam, deviceInfoModel);
        hookMethodByClassMethodName("android.os.SystemProperties", "set");
        hookMethodByClassMethodName("android.os.SystemProperties", "get");
        //hookMethodByClassMethodName("android.os.SystemProperties", "getString");
        hookMethodByClassMethodName(Settings.System.class.getName(), "putStringForUser");
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.CUPCAKE) {
            hookMethodByClassMethodName(Settings.Secure.class.getName(), "putStringForUser");
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            hookMethodByClassMethodName(Settings.Global.class.getName(), "putStringForUser");
        }
        hookMethodByClassMethodName(Settings.System.class.getName(), "getStringForUser");
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.CUPCAKE) {
            hookMethodByClassMethodName(Settings.Secure.class.getName(), "getStringForUser");
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            hookMethodByClassMethodName(Settings.Global.class.getName(), "getStringForUser");
        }
        hookMethodByClassMethodName("android.provider.Settings$NameValueCache", "getStringForUser");
    }
 
    @SuppressLint("SuspiciousIndentation")
    private void setBuilds() {
        XposedHelpers.setStaticObjectField(Build.class, "BOOTLOADER", "unkown");
        if (!TextUtils.isEmpty(this.deviceInfoModel.getBuildBrand()))
            XposedHelpers.setStaticObjectField(Build.class, "BRAND", this.deviceInfoModel.getBuildBrand());
        if (!TextUtils.isEmpty(this.deviceInfoModel.getBuildBoard()))
            XposedHelpers.setStaticObjectField(Build.class, "BOARD", this.deviceInfoModel.getBuildBoard());
        if (!TextUtils.isEmpty(this.deviceInfoModel.getBuildModel()))
            XposedHelpers.setStaticObjectField(Build.class, "MODEL", this.deviceInfoModel.getBuildModel());
        if (!TextUtils.isEmpty(this.deviceInfoModel.getDisplayId()))
            XposedHelpers.setStaticObjectField(Build.class, "DISPLAY", this.deviceInfoModel.getDisplayId());
        if (!TextUtils.isEmpty(this.deviceInfoModel.getBuildProduct()))
            XposedHelpers.setStaticObjectField(Build.class, "PRODUCT", this.deviceInfoModel.getBuildProduct());
        if (!TextUtils.isEmpty(this.deviceInfoModel.getBuildManufacturer()))
            XposedHelpers.setStaticObjectField(Build.class, "MANUFACTURER", this.deviceInfoModel.getBuildManufacturer());
        if (!TextUtils.isEmpty(this.deviceInfoModel.getBuildDevice()))
            XposedHelpers.setStaticObjectField(Build.class, "DEVICE", this.deviceInfoModel.getBuildDevice());
        if (!TextUtils.isEmpty(this.deviceInfoModel.getBuildRelease()))
            XposedHelpers.setStaticObjectField(Build.VERSION.class, "RELEASE", this.deviceInfoModel.getBuildRelease());
        if (!TextUtils.isEmpty(this.deviceInfoModel.getBuildSdk()))
            XposedHelpers.setStaticObjectField(Build.VERSION.class, "SDK", this.deviceInfoModel.getBuildSdk());
        if (!TextUtils.isEmpty(this.deviceInfoModel.getBuildFingerprint()))
            XposedHelpers.setStaticObjectField(Build.class, "FINGERPRINT", this.deviceInfoModel.getBuildFingerprint());
        if (!TextUtils.isEmpty(this.deviceInfoModel.getBuildHardware()))
            XposedHelpers.setStaticObjectField(Build.class, "HARDWARE", this.deviceInfoModel.getBuildHardware());
        if (!TextUtils.isEmpty(this.deviceInfoModel.getBuildCodename()))
            XposedHelpers.setStaticObjectField(Build.VERSION.class, "CODENAME", this.deviceInfoModel.getBuildCodename());
        if (!TextUtils.isEmpty(this.deviceInfoModel.getBuildIncremental()))
            XposedHelpers.setStaticObjectField(Build.VERSION.class, "INCREMENTAL", this.deviceInfoModel.getBuildIncremental());
        if (!TextUtils.isEmpty(this.deviceInfoModel.getBuildHost()))
            XposedHelpers.setStaticObjectField(Build.class, "HOST", this.deviceInfoModel.getBuildHost());
        if (!TextUtils.isEmpty(this.deviceInfoModel.getBuildId()))
            XposedHelpers.setStaticObjectField(Build.class, "ID", this.deviceInfoModel.getBuildId());
        if (!TextUtils.isEmpty(this.deviceInfoModel.getBuildType()))
            XposedHelpers.setStaticObjectField(Build.class, "TYPE", this.deviceInfoModel.getBuildType());
        if (!TextUtils.isEmpty(this.deviceInfoModel.getBuildUser()))
            XposedHelpers.setStaticObjectField(Build.class, "USER", this.deviceInfoModel.getBuildUser());
        if (!TextUtils.isEmpty(this.deviceInfoModel.getBuildSerialno()))
            XposedHelpers.setStaticObjectField(Build.class, "SERIAL", this.deviceInfoModel.getBuildSerialno());
        if (!TextUtils.isEmpty(this.deviceInfoModel.getBuildTags()))
            XposedHelpers.setStaticObjectField(Build.class, "TAGS", this.deviceInfoModel.getBuildTags());
        if (this.deviceInfoModel.getBuildUtc() > 0L)
            XposedHelpers.setStaticObjectField(Build.class, "TIME", Long.valueOf(this.deviceInfoModel.getBuildUtc()));
 
        if (!TextUtils.isEmpty(this.deviceInfoModel.getBuildAbi())){
            XposedHelpers.setStaticObjectField(Build.class, "CPU_ABI", this.deviceInfoModel.getBuildAbi());
        }
 
        if (!TextUtils.isEmpty(this.deviceInfoModel.getBuildAbi2())){
            XposedHelpers.setStaticObjectField(Build.class, "CPU_ABI2", this.deviceInfoModel.getBuildAbi2());
        }
        if (!TextUtils.isEmpty(this.deviceInfoModel.getBuildSdk())){
            if(Integer.parseInt(this.deviceInfoModel.getBuildSdk())<26){
                XposedHelpers.setStaticIntField(Build.VERSION.class, "SDK_INT", Integer.parseInt(this.deviceInfoModel.getBuildSdk()));
            }
        }
        if (!TextUtils.isEmpty(this.deviceInfoModel.getSecurity_patch())){
            XposedHelpers.setStaticObjectField(Build.VERSION.class, "SECURITY_PATCH", this.deviceInfoModel.getSecurity_patch());
        }
    }
 
    public static Object IIl1lIIlll(DeviceInfoModel arg4, String arg5) {
        if("ro.product.model".equals(arg5)) {
            if(!TextUtils.isEmpty(arg4.getBuildModel())) {
                return arg4.getBuildModel();
 
            }
        }
 
        if("ro.boot.serialno".equals(arg5)) {
            if(!TextUtils.isEmpty(arg4.getSerialno())) {
                Log.i("TestYY", "ro.boot.serialno");
                return arg4.getSerialno();
            }
        }
 
 
        else if("ro.build.id".equals(arg5)) {
            if(!TextUtils.isEmpty(arg4.getBuildId())) {
                return arg4.getBuildId();
            }
        }
        else if("ro.build.display.id".equals(arg5)) {
            if(!TextUtils.isEmpty(arg4.getDisplayId())) {
                return arg4.getDisplayId();
            }
        }
        else if("ro.build.type".equals(arg5)) {
            if(!TextUtils.isEmpty(arg4.getBuildType())) {
                return arg4.getBuildType();
            }
        }
        else if("ro.build.user".equals(arg5)) {
            if(!TextUtils.isEmpty(arg4.getBuildUser())) {
                return arg4.getBuildUser();
            }
        }
        else if("ro.build.host".equals(arg5)) {
            if(!TextUtils.isEmpty(arg4.getBuildHost())) {
             
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值