吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 65|回复: 1
收起左侧

[会员申请] 申请会员ID:孤木落【申请通过,未报到】

[复制链接]
吾爱游客  发表于 2026-2-28 23:37
1、申 请 I D:孤木落
2、个人邮箱:1359640178@qq.com
3、原创技术文章:
https://ggggmllll.github.io/2025/12/14/SRpatch%E5%8E%9F%E7%90%86%E5%88%86%E6%9E%90/

好奇一些常见的java层签名校验实现思路,于是研究了一下SRpatch这一优秀的工具,学到了不少知识
<!--more-->

SRpatch入口

通过观察Manifest.xml,观察到app入口被改为了com.srp.patch.Init类,发现其被混淆(事实上,SRpatch的核心代码均使用Milk混淆,以增加分析难度)
于是进行了初步的反混淆,得到了大致执行流程:

public class AppInfo {

    // 配置JSON文件中的键名常量
    public static final String KEY_PACKAGE_NAME = "packageName";
    public static final String KEY_SIGNATURE = "signature";
    public static final String KEY_SIGNATURE_STRENGTH = "signatureStrength";
    public static final String KEY_APK_SIZE = "apkSize";
    public static final String KEY_ORIGINAL_APPLICATION_NAME = "originalApplicationName";
    public static final String KEY_PMS_PROXY_METHOD = "pmsProxyMethod";
    public static final String KEY_PATH_REDIRECTION_ENABLED = "pathRedirectionEnabled";

    // 目标应用的包名(要被伪装的应用)
    public static String packageName;

    // 伪造的签名数据(Base64编码的签名)
    public static String signature;

    // 签名绕过强度等级(0-4,数值越大绕过能力越强)
    public static int signatureStrength;

    // 原始APK文件大小,用于大小校验绕过
    public static long apkSize;

    // 原始应用的Application类名,用于应用名伪装
    public static String originalApplicationName;

    // PMS代理方法类型("IBINDER_PROXY" 或 "CREATOR_REPLACE")
    public static String pmsProxyMethod;

    // 是否启用APK路径重定向
    public static boolean pathRedirectionEnabled;
}

AppInfo类中保存从SRPatch_config.json中解析到的原app信息及配置

//自定义application实现优先加载
public class Init extends Application {

    /**
     * 异常处理工具类 - 提供Throwable.addSuppressed的兼容性支持
     * 用于在try-with-resources中正确处理异常链
     */
    public static final class ExceptionCompat {
        /**
         * 安全地添加被抑制的异常
         * 在低版本Android上捕获可能的异常
         */
        public static void addSuppressedSafely(Throwable mainThrowable, Throwable suppressedThrowable) {
            try {
                mainThrowable.addSuppressed(suppressedThrowable);
            } catch (Exception ignored) {
                // 在低版本Android上可能不支持addSuppressed方法
                // 忽略异常,不影响主要功能
            }
        }
    }

    // 配置文件名称
    private static final String CONFIG_FILE_NAME = "SRPatch_config.json";

    // Native库名称
    private static final String NATIVE_LIB_NAME = "libSRPatch.so";

    // 日志标签
    private static final String LOG_TAG = "SRPatch.Init";

    // 原始Instrumentation对象引用
    private Instrumentation originalInstrumentation;

    // 原始Application对象引用
    private static Application originalApplication;

    /**
     * 应用初始化入口 - 在应用创建时最早被调用
     * 执行所有必要的Hook和伪装操作
     */
    @Override
    protected void attachBaseContext(Context context) {
        super.attachBaseContext(context);

        try {
            Log.i(LOG_TAG, "开始初始化签名绕过工具...");

            // 步骤1: 解析配置文件
            parseAndStoreConfig(context);

            // 步骤2: 加载Native库
            loadNativeLibrary(context);

            // 步骤3: 如果需要路径重定向或高强度签名绕过,确保基础APK存在
            if (AppInfo.pathRedirectionEnabled || AppInfo.signatureStrength >= 2) {
                ensureBaseApkExists(context);
            }

            // 步骤4: 执行应用名称伪装
            ApplicationNameSpoofing.spoofApplicationName(context);

            // 步骤5: 初始化Patch模块
            Patch.init(context);

            // 步骤6: 伪装当前类名
            disguiseClassName(this.getClass(), AppInfo.originalApplicationName);

            // 步骤7: 创建原始Application实例
            createOriginalApplication(context);

            Log.i(LOG_TAG, "签名绕过工具初始化完成");

        } catch (Exception e) {
            Log.e(LOG_TAG, "初始化过程中发生异常", e);
            // 注意:这里捕获异常但不抛出,确保应用即使Hook失败也能正常启动
        }
    }

    /**
     * 创建原始Application实例
     * 通过反射创建并替换原始Application,保持应用正常功能
     */
    private void createOriginalApplication(Context context) throws Exception {
        if (AppInfo.originalApplicationName == null) {
            Log.w(LOG_TAG, "未配置原始应用名,跳过创建原始Application");
            return;
        }

        // 获取当前ActivityThread实例
        ActivityThread activityThread = ActivityThread.currentActivityThread();

        // 获取并修改Instrumentation字段
        Field instrumentationField = ActivityThread.class.getDeclaredField("mInstrumentation");
        instrumentationField.setAccessible(true);
        this.originalInstrumentation = (Instrumentation) instrumentationField.get(activityThread);

        // 创建原始Application实例
        Class<?> originalAppClass = context.getClassLoader().loadClass(AppInfo.originalApplicationName);
        Init.originalApplication = Instrumentation.newApplication(originalAppClass, context);

        // 替换ActivityThread中的初始Application
        Field initialAppField = ActivityThread.class.getDeclaredField("mInitialApplication");
        initialAppField.setAccessible(true);
        activityThread.mInitialApplication = Init.originalApplication;

        // 修改应用名称信息
        modifyApplicationName(context);

        Log.i(LOG_TAG, "原始Application实例创建完成: " + AppInfo.originalApplicationName);
    }

    /**
     * 伪装类名 - 通过Unsafe直接修改Class对象中的名称字段
     * 这是一种深度Hook技术,可以改变类的身份标识
     */
    private static void disguiseClassName(Class<?> targetClass, String newClassName) throws Exception {
        if (newClassName == null) {
            return;
        }

        // 获取Unsafe实例
        Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
        unsafeField.setAccessible(true);
        Unsafe unsafe = (Unsafe) unsafeField.get(null);

        // 修改类的name字段
        Field nameField = Class.class.getDeclaredField("name");
        unsafe.putObject(targetClass, unsafe.objectFieldOffset(nameField), newClassName);

        // 清空类加载器引用,增加伪装效果
        Field classLoaderField = Class.class.getDeclaredField("classLoader");
        unsafe.putObject(targetClass, unsafe.objectFieldOffset(classLoaderField), null);

        Log.i(LOG_TAG, "类名伪装完成: " + targetClass + " -> " + newClassName);
    }

    /**
     * 确保基础APK文件存在
     * 如果不存在则从assets中复制,用于路径重定向
     */
    private void ensureBaseApkExists(Context context) {
        File patchDirectory = new File(context.getFilesDir().getParentFile(), "srpatch");

        // 创建目录(如果不存在)
        if (!patchDirectory.exists()) {
            boolean dirsCreated = patchDirectory.mkdirs();
            Log.i(LOG_TAG, "创建patch目录: " + dirsCreated + ", 路径: " + patchDirectory.getAbsolutePath());
        }

        File baseApkFile = new File(patchDirectory, "base.apk");

        if (!baseApkFile.exists()) {
            Log.i(LOG_TAG, "base.apk不存在,从assets复制...");
            copyBaseApkFromAssets(context, baseApkFile);
        } else {
            Log.i(LOG_TAG, "base.apk已存在: " + baseApkFile.getAbsolutePath());
        }
    }

    /**
     * 从assets复制基础APK文件
     */
    private void copyBaseApkFromAssets(Context context, File targetFile) {
        try (InputStream inputStream = context.getAssets().open("base.apk");
             FileOutputStream outputStream = new FileOutputStream(targetFile)) {

            byte[] buffer = new byte[8192]; // 8KB缓冲区
            int bytesRead;

            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }

            Log.i(LOG_TAG, "成功复制base.apk到: " + targetFile.getAbsolutePath());

            // 设置文件权限 (0x100 = 256, 对应rw-r--r--)
            Os.chmod(targetFile.getAbsolutePath(), 0x100);

        } catch (Exception e) {
            Log.e(LOG_TAG, "复制base.apk失败", e);
        }
    }

    /**
     * 查找已加载的APK信息对象
     * 通过多种方式尝试获取LoadedApk实例
     */
    private Object findLoadedApk(Context context) throws Exception {
        Object loadedApk = null;

        // 方式1: 尝试从Context获取mPackageInfo字段
        try {
            loadedApk = getFieldValue(context, "mPackageInfo");
            if (loadedApk != null) {
                return loadedApk;
            }
        } catch (NoSuchFieldException e) {
            // 字段不存在,继续尝试其他方式
        }

        // 方式2: 尝试从Context获取mLoadedApk字段
        try {
            loadedApk = getFieldValue(context, "mLoadedApk");
            if (loadedApk != null) {
                return loadedApk;
            }
        } catch (NoSuchFieldException e) {
            // 字段不存在,继续尝试其他方式
        }

        // 方式3: 从ActivityThread的包管理器中查找
        Object activityThread = ActivityThread.currentActivityThread();
        Map<String, WeakReference<?>> packagesMap = (Map<String, WeakReference<?>>) 
                getFieldValue(activityThread, ActivityThread.class, "mPackages");

        if (packagesMap != null) {
            WeakReference<?> weakRef = packagesMap.get("com.example.app");
            if (weakRef != null) {
                loadedApk = weakRef.get();
            }
        }

        return loadedApk;
    }

    /**
     * 通用的字段获取方法(带Class参数)
     */
    private static Object getFieldValue(Object target, Class<?> targetClass, String fieldName) throws Exception {
        Field field = targetClass.getDeclaredField(fieldName);
        field.setAccessible(true);
        return field.get(target);
    }

    /**
     * 通用的字段获取方法
     */
    private static Object getFieldValue(Object target, String fieldName) throws Exception {
        return getFieldValue(target, target.getClass(), fieldName);
    }

    /**
     * 加载Native库
     * 从assets中提取并加载native so库
     */
    private void loadNativeLibrary(Context context) {
        if (context == null) {
            Log.e(LOG_TAG, "Context为null,无法加载Native库");
            return;
        }

        try {
            File filesDir = context.getFilesDir();
            if (filesDir == null) {
                Log.e(LOG_TAG, "filesDir为null,无法加载Native库");
                return;
            }

            File soFile = new File(filesDir, NATIVE_LIB_NAME);

            // 如果so文件不存在或为空,从assets中提取
            if (!soFile.exists() || soFile.length() == 0) {
                extractSoFromAssets(context, soFile);
            }

            // 加载Native库
            System.load(soFile.getAbsolutePath());
            Log.i(LOG_TAG, "Native库加载成功: " + soFile.getAbsolutePath());

        } catch (Throwable t) {
            Log.e(LOG_TAG, "加载Native库失败", t);
        }
    }

    /**
     * 从assets中提取so文件
     */
    private void extractSoFromAssets(Context context, File targetSoFile) {
        String assetPath = "patch/lib/arm64-v8a/" + NATIVE_LIB_NAME;

        try (InputStream inputStream = context.getAssets().open(assetPath);
             FileOutputStream outputStream = new FileOutputStream(targetSoFile)) {

            byte[] buffer = new byte[8192];
            int bytesRead;

            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }

            outputStream.flush();

            // 设置文件权限为755 (rwxr-xr-x)
            try {
                Os.chmod(targetSoFile.getAbsolutePath(), 493); // 493 = 0755 in octal
            } catch (Throwable unused) {
                // 权限设置失败不影响主要功能
            }

            Log.i(LOG_TAG, "成功提取so文件到: " + targetSoFile.getAbsolutePath());

        } catch (Exception e) {
            Log.e(LOG_TAG, "提取so文件失败,asset: " + assetPath, e);
        }
    }

    /**
     * 修改应用名称信息
     * 在多个位置更新应用名称,确保伪装效果
     */
    private void modifyApplicationName(Context context) throws Exception {
        if (context == null) {
            return;
        }

        // 修改当前Context中的应用信息
        ApplicationInfo currentAppInfo = context.getApplicationInfo();
        currentAppInfo.name = AppInfo.originalApplicationName;

        // 修改LoadedApk中的应用信息
        Object loadedApk = findLoadedApk(context);
        if (loadedApk != null) {
            ApplicationInfo loadedApkAppInfo = (ApplicationInfo) getFieldValue(loadedApk, "mApplicationInfo");
            loadedApkAppInfo.className = AppInfo.originalApplicationName;
            loadedApkAppInfo.name = AppInfo.originalApplicationName;
        }
    }

    /**
     * 应用创建完成回调
     * 替换应用实例并调用原始Application的onCreate方法
     */
    @Override
    public void onCreate() {
        super.onCreate();

        if (Init.originalApplication != null && this.originalInstrumentation != null) {
            try {
                replaceApplicationInstance();
                this.originalInstrumentation.callApplicationOnCreate(Init.originalApplication);
                Log.i(LOG_TAG, "原始Application onCreate调用完成");
            } catch (Exception e) {
                throw new RuntimeException("替换应用实例失败", e);
            }
        }
    }

    /**
     * 解析并存储配置信息
     * 从assets中的JSON配置文件读取各种Hook参数
     */
    private void parseAndStoreConfig(Context context) throws Exception {
        StringBuilder configContent = new StringBuilder();

        try (InputStream inputStream = context.getAssets().open("patch/" + CONFIG_FILE_NAME);
             BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {

            String line;
            while ((line = reader.readLine()) != null) {
                configContent.append(line);
            }
        }

        JSONObject configJson = new JSONObject(configContent.toString());

        // 解析各项配置参数
        AppInfo.packageName = configJson.getString("packageName");
        AppInfo.signature = configJson.getString("signature");
        AppInfo.apkSize = configJson.getLong("apkSize");
        AppInfo.signatureStrength = configJson.getInt("signatureStrength");
        AppInfo.originalApplicationName = configJson.optString("originalApplicationName", null);
        AppInfo.pmsProxyMethod = configJson.getString("pmsProxyMethod");
        AppInfo.pathRedirectionEnabled = configJson.getBoolean("pathRedirectionEnabled");

        Log.i(LOG_TAG, "配置解析完成,目标包名: " + AppInfo.packageName);
    }

    /**
     * 替换应用实例
     * 在ActivityThread中完全替换当前应用实例为原始应用
     */
    private void replaceApplicationInstance() throws Exception {
        // 获取当前ActivityThread实例
        ActivityThread activityThread = ActivityThread.currentActivityThread();

        // 替换mAllApplications列表中的应用实例
        Field allApplicationsField = ActivityThread.class.getDeclaredField("mAllApplications");
        allApplicationsField.setAccessible(true);

        List<Application> allApplications = activityThread.mAllApplications;
        allApplications.remove(this);
        allApplications.add(Init.originalApplication);

        // 修改LoadedApk中的mApplication字段
        Object loadedApk = findLoadedApk(this);
        if (loadedApk != null) {
            setFieldValue(loadedApk, "mApplication", Init.originalApplication);

            // 修改ApplicationInfo中的类名和名称
            ApplicationInfo appInfo = (ApplicationInfo) getFieldValue(loadedApk, "mApplicationInfo");
            if (appInfo != null) {
                appInfo.className = AppInfo.originalApplicationName;
                appInfo.name = AppInfo.originalApplicationName;
            }
        }

        Log.i(LOG_TAG, "应用实例替换完成");
    }

    /**
     * 通用的字段设置方法(带Class参数)
     */
    private static void setFieldValue(Object target, Class<?> targetClass, String fieldName, Object value) throws Exception {
        Field field = targetClass.getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(target, value);
    }

    /**
     * 通用的字段设置方法
     */
    private static void setFieldValue(Object target, String fieldName, Object value) throws Exception {
        setFieldValue(target, target.getClass(), fieldName, value);
    }
}
/**
 * 应用名称伪装工具类
 * 通过修改ApplicationInfo中的名称和类名字段,伪装应用身份
 */
public class ApplicationNameSpoofing {

    // 目标应用的包名常量
    private static final String TARGET_PACKAGE_NAME = "com.example.app";

    // 获取应用信息的标志位(0x80 = 128,通常用于获取元数据)
    private static final int APPLICATION_INFO_FLAGS = 0x80;

    /**
     * 执行应用名称伪装
     * 修改目标应用的ApplicationInfo中的名称和类名字段
     * 
     * @Param context Android上下文对象,用于获取PackageManager
     * @throws PackageManager.NameNotFoundException 如果目标包名不存在
     */
    public static void spoofApplicationName(Context context) throws PackageManager.NameNotFoundException {
        // 获取目标包名的ApplicationInfo对象
        // 使用GET_META_DATA标志获取包含元数据的应用信息
        ApplicationInfo targetAppInfo = context.getPackageManager()
                .getApplicationInfo(TARGET_PACKAGE_NAME, APPLICATION_INFO_FLAGS);

        // 修改应用显示名称
        targetAppInfo.name = AppInfo.originalApplicationName;

        // 修改应用类名
        targetAppInfo.className = AppInfo.originalApplicationName;
    }
}

我们发现入口的主要功能是解析配置、Patch初始化和伪装Application

Patch类分析

public class Patch {

    // 日志标签
    private static final String LOG_TAG = "SRPatch";

    // PMS代理方法常量
    private static final String PMS_PROXY_METHOD_IBINDER = "IBINDER_PROXY";

    // 伪造APK文件路径
    public static String FakeApkPath = null;

    // 原始Parcelable.Creator引用
    public static Parcelable.Creator ORIGINAL_APP_INFO_CREATOR = null;
    public static Parcelable.Creator ORIGINAL_CREATOR = null;

    // 配置参数
    public static long sApkSize;
    public static Signature sFakeSignature;
    public static boolean sPathRedirectionEnabled;
    public static String sPmsProxyMethod;
    public static int sSignatureStrength;
    public static String sSourceDir;
    public static String sTargetPackageName;

    /**
     * 初始化Patch模块(已弃用,使用init方法替代)
     * 保持向后兼容性
     * 
     * @param context Android上下文对象
     */
    @Deprecated
    public static void HookInit(Context context) {
        init(context);
    }

    /**
     * 应用Native层绕过方法
     * 根据签名绕过强度等级选择不同的Native绕过策略
     * 
     * @param fakeApkPath 伪造APK文件路径
     */
    private static void applyNativeBypass(String fakeApkPath) {
        int signatureStrength = sSignatureStrength;

        // 根据签名绕过强度等级选择不同的Native绕过方法
        switch (signatureStrength) {
            case 2:
            case 3:
                // 标准签名绕过 + 大小绕过
                SigBypass.SigBypass(sSourceDir, fakeApkPath);
                SigBypass.SizeBypass(sApkSize);
                break;

            case 4:
                //SVC Hook实现绕过
                SigBypass.SvcHookSigna(sSourceDir, fakeApkPath, AppInfo.apkSize);
                break;

            default:
                // 默认情况:使用标准签名绕过
                SigBypass.SigBypass(sSourceDir, fakeApkPath);
                SigBypass.SizeBypass(sApkSize);
                break;
        }

        Log.i(LOG_TAG, "Native绕过方法应用完成,强度等级: " + signatureStrength);
    }

    /**
     * 应用路径重定向
     * 修改APK路径指向伪造的APK文件
     * 
     * @param context Android上下文对象
     * @param fakeApkPath 伪造APK文件路径
     */
    private static void applyPathRedirection(Context context, String fakeApkPath) {
        if (sPathRedirectionEnabled) {
            try {
                ApkPathHook.ApkPathSpoofing(context, fakeApkPath);
                Log.i(LOG_TAG, "APK路径重定向完成: " + fakeApkPath);
            } catch (Throwable throwable) {
                Log.e(LOG_TAG, "APK路径重定向失败", throwable);
            }
        }
    }

    /**
     * 初始化Patch模块
     * 主要的初始化方法,执行所有必要的Hook和伪装操作
     * 
     * @param context Android上下文对象
     */
    public static void init(Context context) {
        Log.i(LOG_TAG, "开始初始化Patch模块...");

        // 初始化配置数据
        initPatchData(context);

        // 如果签名绕过强度大于0,执行java层Hook
        if (sSignatureStrength > 0) {
            try {
                startjavaSignatureReplace();
            } catch (Throwable throwable) {
                Log.e(LOG_TAG, "java层签名替换失败", throwable);
            }

            // 构建伪造APK路径并应用各种绕过技术
            String fakeApkPath = PathUtils.buildFakeApkPath(context);
            FakeApkPath = fakeApkPath;

            applyPathRedirection(context, fakeApkPath);
            applyNativeBypass(fakeApkPath);
        }

        Log.i(LOG_TAG, "Patch模块初始化完成");
    }

    /**
     * 初始化Patch配置数据
     * 从AppInfo中读取配置参数
     * 
     * @param context Android上下文对象
     */
    private static void initPatchData(Context context) {
        sTargetPackageName = AppInfo.packageName;
        sFakeSignature = new Signature(AppInfo.signature);
        sSourceDir = context.getApplicationInfo().sourceDir;
        sPmsProxyMethod = AppInfo.pmsProxyMethod;
        sSignatureStrength = AppInfo.signatureStrength;
        sApkSize = AppInfo.apkSize;
        sPathRedirectionEnabled = AppInfo.pathRedirectionEnabled;

        Log.i(LOG_TAG, "Patch数据初始化完成 - 目标包名: " + sTargetPackageName);
    }

    /**
     * 启动java层签名替换
     * 根据配置选择Binder代理或PMS代理方式
     * 
     * @throws Throwable 如果Hook过程中发生异常
     */
    private static void startjavaSignatureReplace() throws Throwable {
        Log.i(LOG_TAG, "开始java层签名替换,代理方法: " + sPmsProxyMethod);

        // 根据配置选择不同的Hook实现方式
        if (PMS_PROXY_METHOD_IBINDER.equals(sPmsProxyMethod)) {
            // 使用Binder代理方式进行Hook
            FakeIBinder.installBinderHook();
        } else {
            // 使用PMS代理方式进行Hook
            PMSAgent.replaceParcelableCreators();
        }

        Log.i(LOG_TAG, "java层签名替换完成");
    }
}

在Patch类中,SRpatch主要进行了io重定向,代理Binder或代理PMS,分别研究这两部分

java层IO重定向

/**
 * 路径工具类
 * 用于构建和管理伪造的APK文件路径,支持路径重定向功能
 * 这是签名绕过工具中路径欺骗功能的核心组件
 */
public class PathUtils {

    // 伪造APK存储目录名称
    private static final String FAKE_APK_DIRECTORY = "srpatch";

    // 伪造APK文件名称
    private static final String FAKE_APK_FILENAME = "base.apk";

    /**
     * 构建伪造APK文件路径
     * 在应用的私有数据目录下创建特定的目录结构来存储伪造的APK文件
     * 
     * @param context Android上下文对象,用于获取应用文件目录
     * @Return 伪造APK文件的绝对路径
     * 
     * 路径结构示例:
     * /data/data/[package_name]/srpatch/base.apk
     */
    public static String buildFakeApkPath(Context context) {
        // 获取应用的文件目录(/data/data/[package_name]/files)
        File filesDir = context.getFilesDir();

        // 获取文件目录的父目录(/data/data/[package_name])
        File dataDir = filesDir.getParentFile();

        // 在数据目录下创建伪造APK存储目录
        File fakeApkDirectory = new File(dataDir, FAKE_APK_DIRECTORY);

        // 创建伪造APK文件对象
        File fakeApkFile = new File(fakeApkDirectory, FAKE_APK_FILENAME);

        // 返回伪造APK文件的绝对路径
        return fakeApkFile.getAbsolutePath();
    }

    /**
     * 获取伪造APK存储目录路径
     * 
     * @param context Android上下文对象
     * @return 伪造APK存储目录的绝对路径
     */
    public static String getFakeApkDirectoryPath(Context context) {
        File filesDir = context.getFilesDir();
        File dataDir = filesDir.getParentFile();
        File fakeApkDirectory = new File(dataDir, FAKE_APK_DIRECTORY);
        return fakeApkDirectory.getAbsolutePath();
    }

    /**
     * 检查伪造APK文件是否存在
     * 
     * @param context Android上下文对象
     * @return 如果伪造APK文件存在返回true,否则返回false
     */
    public static boolean isFakeApkExists(Context context) {
        String fakeApkPath = buildFakeApkPath(context);
        File fakeApkFile = new File(fakeApkPath);
        return fakeApkFile.exists() && fakeApkFile.length() > 0;
    }

    /**
     * 获取伪造APK文件对象
     * 
     * @param context Android上下文对象
     * @return 伪造APK文件对象
     */
    public static File getFakeApkFile(Context context) {
        String fakeApkPath = buildFakeApkPath(context);
        return new File(fakeApkPath);
    }

    /**
     * 清理伪造APK文件
     * 用于在卸载或重置时清理相关文件
     * 
     * @param context Android上下文对象
     * @return 如果成功删除返回true,否则返回false
     */
    public static boolean cleanupFakeApk(Context context) {
        try {
            File fakeApkFile = getFakeApkFile(context);
            File fakeApkDirectory = fakeApkFile.getParentFile();

            boolean fileDeleted = fakeApkFile.delete();
            boolean dirDeleted = fakeApkDirectory.delete();

            return fileDeleted || dirDeleted;
        } catch (Exception e) {
            return false;
        }
    }
}

PathUtils类主要用于构造重定向目标app及其所在文件夹

/**
 * APK路径Hook工具类
 * 通过修改ApplicationInfo和Context内部字段,将APK路径指向伪造的文件
 * 这是路径重定向功能的核心实现,用于绕过基于APK路径的校验
 */
public class ApkPathHook {

    // 目标应用包名(会在修补时写入)
    private static final String TARGET_PACKAGE_NAME = "com.example.app";

    // 获取应用信息的标志位(0x80 = GET_META_DATA,用于获取包含元数据的应用信息)
    private static final int APPLICATION_INFO_FLAGS = 0x80;

    /**
     * 执行APK路径欺骗
     * 修改多个位置的APK路径指向,确保路径重定向完全生效
     * 
     * @param context Android上下文对象
     * @param fakeApkPath 伪造的APK文件路径
     * @throws PackageManager.NameNotFoundException 如果目标包名不存在
     */
    public static void spoofApkPath(Context context, String fakeApkPath) 
            throws PackageManager.NameNotFoundException {

        // 步骤1: 修改当前应用的应用信息中的路径
        modifyCurrentApplicationInfo(context, fakeApkPath);

        // 步骤2: 修改目标包名的应用信息中的路径
        modifyTargetApplicationInfo(context, fakeApkPath);

        // 步骤3: 修改Context内部字段中的路径
        modifyContextInternalFields(context, fakeApkPath);

        // 步骤4: 强制刷新资源管理器
        refreshResources(context);
    }

    /**
     * 修改当前应用的应用信息路径
     */
    private static void modifyCurrentApplicationInfo(Context context, String fakeApkPath) {
        ApplicationInfo currentAppInfo = context.getApplicationInfo();
        currentAppInfo.sourceDir = fakeApkPath;
        currentAppInfo.publicSourceDir = fakeApkPath;
    }

    /**
     * 修改目标包名的应用信息路径
     */
    private static void modifyTargetApplicationInfo(Context context, String fakeApkPath) 
            throws PackageManager.NameNotFoundException {
        ApplicationInfo targetAppInfo = context.getPackageManager()
                .getApplicationInfo(TARGET_PACKAGE_NAME, APPLICATION_INFO_FLAGS);
        targetAppInfo.sourceDir = fakeApkPath;
        targetAppInfo.publicSourceDir = fakeApkPath;
    }

    /**
     * 修改Context内部字段中的路径
     * 通过反射修改ContextImpl中的mPackageInfo字段相关路径
     */
    private static void modifyContextInternalFields(Context context, String fakeApkPath) {
        Context baseContext = getBaseContext(context);

        if (baseContext == null) {
            return;
        }

        try {
            // 获取mPackageInfo字段
            Field packageInfoField = baseContext.getClass().getDeclaredField("mPackageInfo");
            packageInfoField.setAccessible(true);
            Object packageInfoObject = packageInfoField.get(baseContext);

            if (packageInfoObject != null) {
                // 修改mAppDir字段(APK目录)
                modifyPackageInfoField(packageInfoObject, "mAppDir", fakeApkPath);

                // 尝试修改mResDir字段(资源目录)
                modifyPackageInfoField(packageInfoObject, "mResDir", fakeApkPath);
            }

        } catch (Throwable throwable) {
            // 记录异常但不中断执行
            throwable.printStackTrace();
        }
    }

    /**
     * 获取最底层的Base Context
     * 遍历ContextWrapper链直到找到非包装的Context
     */
    private static Context getBaseContext(Context context) {
        Context currentContext = context;

        while (currentContext instanceof ContextWrapper) {
            Context baseContext = ((ContextWrapper) currentContext).getBaseContext();
            if (baseContext == null) {
                break;
            }
            currentContext = baseContext;
        }

        return currentContext;
    }

    /**
     * 修改PackageInfo对象中的字段
     */
    private static void modifyPackageInfoField(Object packageInfoObject, String fieldName, String newValue) {
        try {
            Field field = packageInfoObject.getClass().getDeclaredField(fieldName);
            field.setAccessible(true);
            field.set(packageInfoObject, newValue);
        } catch (NoSuchFieldException ignored) {
            // 字段不存在,忽略
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }

    /**
     * 强制刷新资源管理器
     * 通过访问Resources触发重新加载,确保路径修改生效
     */
    private static void refreshResources(Context context) {
        try {
            // 访问Resources会触发重新加载,应用路径修改
            context.getResources();
        } catch (Throwable ignored) {
            // 忽略资源加载异常
        }
    }

    /**
     * 重载方法:使用指定的包名进行路径欺骗
     * 
     * @param context Android上下文
     * @param fakeApkPath 伪造的APK文件路径
     * @param targetPackageName 目标包名
     * @throws PackageManager.NameNotFoundException 如果目标包名不存在
     */
    public static void spoofApkPath(Context context, String fakeApkPath, String targetPackageName) 
            throws PackageManager.NameNotFoundException {

        modifyCurrentApplicationInfo(context, fakeApkPath);

        ApplicationInfo targetAppInfo = context.getPackageManager()
                .getApplicationInfo(targetPackageName, APPLICATION_INFO_FLAGS);
        targetAppInfo.sourceDir = fakeApkPath;
        targetAppInfo.publicSourceDir = fakeApkPath;

        modifyContextInternalFields(context, fakeApkPath);
        refreshResources(context);
    }

    /**
     * 检查APK路径欺骗是否生效
     * 
     * @param context Android上下文
     * @return 如果当前应用路径已被修改返回true,否则返回false
     */
    public static boolean isApkPathSpoofed(Context context) {
        ApplicationInfo appInfo = context.getApplicationInfo();
        return appInfo.sourceDir != null && 
               !appInfo.sourceDir.equals(context.getPackageCodePath());
    }
}

代理IBinder

/**
 * Binder代理Hook工具类
 * 通过动态代理Hook PackageManager服务的Binder通信,拦截并修改包信息查询结果
 * 这是签名绕过工具中最高级的Hook技术之一
 */
public class FakeIBinder {

    private static final String LOG_TAG = "FakeIBinder";

    /**
     * Binder调用拦截处理器
     * 负责拦截PackageManager服务的transact调用并修改返回数据
     */
    private static class BinderInvocationHandler implements InvocationHandler {
        private final IBinder originalBinder;
        private final Set<Integer> packageInfoTransactionCodes;
        private final Set<Integer> applicationInfoTransactionCodes;

        public BinderInvocationHandler(IBinder originalBinder, Set<Integer> packageInfoTransactions, 
                                     Set<Integer> applicationInfoTransactions) {
            this.originalBinder = originalBinder;
            this.packageInfoTransactionCodes = packageInfoTransactions;
            this.applicationInfoTransactionCodes = applicationInfoTransactions;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            return handleBinderTransaction(originalBinder, packageInfoTransactionCodes, 
                                         applicationInfoTransactionCodes, proxy, method, args);
        }
    }

    /**
     * Binder死亡监听器
     * 当原始Binder死亡时重新安装Hook
     */
    private static class BinderDeathRecipient implements IBinder.DeathRecipient {
        @Override
        public void binderDied() {
            try {
                reinstallBinderHook();
            } catch (RemoteException | ClassNotFoundException | IllegalAccessException |
                     NoSuchFieldException e) {
                Log.e(LOG_TAG, "Binder死亡后重新安装Hook失败", e);
                throw new RuntimeException("重新安装Binder Hook失败", e);
            }
        }
    }

    /**
     * 安装Binder代理Hook
     * 替换系统的PackageManager服务Binder代理,拦截所有包信息查询请求
     */
    public static void installBinderHook() throws IllegalAccessException, ClassNotFoundException, 
                                                 RemoteException, NoSuchFieldException {
        Log.i(LOG_TAG, "开始安装Binder代理Hook...");

        // 获取当前ActivityThread实例
        ActivityThread activityThread = ActivityThread.currentActivityThread();

        // 获取sPackageManager字段
        Field packageManagerField = ActivityThread.class.getDeclaredField("sPackageManager");
        packageManagerField.setAccessible(true);
        Object packageManagerInstance = packageManagerField.get(null);

        if (packageManagerInstance == null) {
            Log.w(LOG_TAG, "sPackageManager为null,无法安装Hook");
            return;
        }

        // 查找IBinder类型的字段
        Field binderField = findBinderField(packageManagerInstance);
        if (binderField == null) {
            Log.e(LOG_TAG, "未找到IBinder类型字段");
            return;
        }

        binderField.setAccessible(true);
        IBinder originalBinder = (IBinder) binderField.get(packageManagerInstance);

        if (originalBinder == null) {
            Log.w(LOG_TAG, "原始Binder为null,无法安装Hook");
            return;
        }

        // 收集需要拦截的Transaction Code
        Set<Integer> packageInfoTransactions = new HashSet<>();
        Set<Integer> applicationInfoTransactions = new HashSet<>();
        collectTransactionCodes(packageInfoTransactions, applicationInfoTransactions);

        // 创建动态代理
        ClassLoader classLoader = originalBinder.getClass().getClassLoader();
        BinderInvocationHandler handler = new BinderInvocationHandler(
                originalBinder, packageInfoTransactions, applicationInfoTransactions);

        IBinder proxyBinder = (IBinder) Proxy.newProxyInstance(
                classLoader, new Class[]{IBinder.class}, handler);

        // 替换原始Binder
        binderField.set(packageManagerInstance, proxyBinder);

        // 清理缓存
        CacheHandling.clearCaches();

        // 注册Binder死亡监听
        originalBinder.linkToDeath(new BinderDeathRecipient(), 0);

        Log.i(LOG_TAG, "Binder代理Hook安装完成");
    }

    /**
     * 查找IBinder类型的字段
     */
    private static Field findBinderField(Object targetInstance) {
        Field[] fields = targetInstance.getClass().getDeclaredFields();
        for (Field field : fields) {
            Class<?> fieldType = field.getType();
            if (IBinder.class.isAssignableFrom(fieldType)) {
                return field;
            }
        }
        return null;
    }

    /**
     * 收集需要拦截的Transaction Code
     * 通过反射获取IPackageManager中定义的所有TRANSACTION常量
     */
    private static void collectTransactionCodes(Set<Integer> packageInfoTransactions, 
                                              Set<Integer> applicationInfoTransactions) 
            throws ClassNotFoundException {
        Class<?> stubClass = Class.forName("android.content.pm.IPackageManager$Stub");
        Field[] fields = stubClass.getDeclaredFields();

        for (Field field : fields) {
            if (Modifier.isStatic(field.getModifiers()) && field.getType() == int.class) {
                field.setAccessible(true);
                String fieldName = field.getName();

                try {
                    int transactionCode = field.getInt(null);

                    if (fieldName.startsWith("TRANSACTION_getPackageInfo")) {
                        packageInfoTransactions.add(transactionCode);
                    } else if (fieldName.startsWith("TRANSACTION_getApplicationInfo")) {
                        applicationInfoTransactions.add(transactionCode);
                    }
                } catch (IllegalAccessException ignored) {
                    // 忽略无法访问的字段
                }
            }
        }

        Log.i(LOG_TAG, "收集到PackageInfo Transactions: " + packageInfoTransactions.size());
        Log.i(LOG_TAG, "收集到ApplicationInfo Transactions: " + applicationInfoTransactions.size());
    }

    /**
     * 处理Binder事务拦截
     * 核心拦截逻辑,修改PackageManager服务返回的数据
     */
    private static Object handleBinderTransaction(IBinder originalBinder, 
                                                Set<Integer> packageInfoTransactions,
                                                Set<Integer> applicationInfoTransactions,
                                                Object proxy, Method method, Object[] args) 
            throws Throwable {

        // 只拦截transact方法
        if (!"transact".equals(method.getName())) {
            return method.invoke(originalBinder, args);
        }

        // 检查参数有效性
        if (args == null || args.length < 4) {
            return method.invoke(originalBinder, args);
        }

        Integer transactionCode = (Integer) args[0];
        Parcel replyParcel = (Parcel) args[2];

        // 调用原始方法
        Object result = method.invoke(originalBinder, args);

        // 根据Transaction Code处理返回数据
        if (packageInfoTransactions.contains(transactionCode)) {
            patchPackageInfoReply(replyParcel);
        } else if (applicationInfoTransactions.contains(transactionCode)) {
            patchApplicationInfoReply(replyParcel);
        }

        return result;
    }

    /**
     * 重新安装Binder Hook
     * 当原始Binder死亡时调用
     */
    private static void reinstallBinderHook() throws RemoteException, NoSuchFieldException, 
                                                    ClassNotFoundException, IllegalAccessException {
        Log.i(LOG_TAG, "检测到Binder死亡,重新安装Hook...");
        installBinderHook();
    }

    /**
     * 修补PackageInfo返回数据
     * 修改签名信息和应用名称
     */
    private static void patchSignatureInfo(PackageInfo packageInfo) {
        if (packageInfo == null || packageInfo.applicationInfo == null) {
            return;
        }

        // 修补应用信息
        if (AppInfo.originalApplicationName != null && 
            !AppInfo.originalApplicationName.isEmpty()) {
            packageInfo.applicationInfo.name = AppInfo.originalApplicationName;
            packageInfo.applicationInfo.className = AppInfo.originalApplicationName;
        }

        // 修补路径重定向
        if (Patch.sPathRedirectionEnabled) {
            packageInfo.applicationInfo.sourceDir = Patch.FakeApkPath;
            packageInfo.applicationInfo.publicSourceDir = Patch.FakeApkPath;
        }

        // 修补签名信息
        Signature fakeSignature = Patch.sFakeSignature;
        if (fakeSignature != null) {
            packageInfo.signatures = new Signature[]{fakeSignature};

            // Android P (API 28) 及以上版本需要额外处理signingInfo
            if (Build.VERSION.SDK_INT >= 28) {
                patchSigningInfoForAndroidP(packageInfo, fakeSignature);
            }
        }
    }

    /**
     * 为Android P及以上版本修补签名信息
     */
    @SuppressLint("PrivateApi")
    private static void patchSigningInfoForAndroidP(PackageInfo packageInfo, Signature fakeSignature) {
        try {
            if (packageInfo.signingInfo == null) {
                // 创建新的SigningInfo
                createNewSigningInfo(packageInfo, fakeSignature);
            } else {
                // 修改现有的SigningInfo
                modifyExistingSigningInfo(packageInfo, fakeSignature);
            }
        } catch (Throwable t) {
            Log.w(LOG_TAG, "修改SigningInfo失败", t);
        }
    }

    /**
     * 创建新的SigningInfo对象
     */
    private static void createNewSigningInfo(PackageInfo packageInfo, Signature fakeSignature) 
            throws Exception {
        Class<?> signingDetailsClass = Class.forName("android.content.pm.SigningDetails");
        Object signingDetails;

        try {
            signingDetails = signingDetailsClass.getConstructor(Signature[].class, int.class, Signature[].class)
                    .newInstance(new Signature[]{fakeSignature}, 2, null);
        } catch (NoSuchMethodException e) {
            signingDetails = signingDetailsClass.getConstructor(Signature[].class, int.class)
                    .newInstance(new Signature[]{fakeSignature}, 2);
        }

        SigningInfo newSigningInfo = (SigningInfo) SigningInfo.class.getConstructor(signingDetailsClass)
                .newInstance(signingDetails);

        Field signingInfoField = PackageInfo.class.getDeclaredField("signingInfo");
        signingInfoField.setAccessible(true);
        packageInfo.signingInfo = newSigningInfo;
    }

    /**
     * 修改现有的SigningInfo对象
     */
    private static void modifyExistingSigningInfo(PackageInfo packageInfo, Signature fakeSignature) {
        try {
            // 修改APK内容签名
            Signature[] apkSigners = packageInfo.signingInfo.getApkContentsSigners();
            if (apkSigners != null && apkSigners.length > 0) {
                apkSigners[0] = fakeSignature;
            }

            // 修改签名证书历史
            Signature[] signingHistory = packageInfo.signingInfo.getSigningCertificateHistory();
            if (signingHistory != null && signingHistory.length > 0) {
                signingHistory[0] = fakeSignature;
            }

            // 通过反射修改内部签名细节
            modifySigningDetails(packageInfo, fakeSignature);
        } catch (Throwable t) {
            Log.w(LOG_TAG, "修改现有SigningInfo失败", t);
        }
    }

    /**
     * 通过反射修改SigningDetails内部字段
     */
    private static void modifySigningDetails(PackageInfo packageInfo, Signature fakeSignature) {
        try {
            Field signingDetailsField = packageInfo.signingInfo.getClass().getDeclaredField("mSigningDetails");
            signingDetailsField.setAccessible(true);
            Object signingDetails = signingDetailsField.get(packageInfo.signingInfo);

            if (signingDetails != null) {
                Field signaturesField = signingDetails.getClass().getDeclaredField("mSignatures");
                signaturesField.setAccessible(true);
                signaturesField.set(signingDetails, new Signature[]{fakeSignature});
            }
        } catch (Throwable t) {
            Log.w(LOG_TAG, "修改SigningDetails失败", t);
        }
    }

    /**
     * 修补ApplicationInfo返回数据
     */
    private static void patchApplicationInfoReply(Parcel replyParcel) {
        if (replyParcel == null) {
            return;
        }

        int originalPosition = replyParcel.dataPosition();
        replyParcel.setDataPosition(0);

        try {
            // 检查Parcel中是否有数据
            if (replyParcel.readInt() != 0) {
                return;
            }

            ApplicationInfo applicationInfo = readApplicationInfoFromParcel(replyParcel);

            // 检查是否需要修补
            if (shouldPatchApplicationInfo(applicationInfo)) {
                patchApplicationInfo(applicationInfo);
                rewriteApplicationInfoToParcel(replyParcel, applicationInfo);
            }

        } catch (Throwable t) {
            Log.w(LOG_TAG, "修补ApplicationInfo返回数据失败", t);
        } finally {
            replyParcel.setDataPosition(originalPosition);
        }
    }

    /**
     * 从Parcel中读取ApplicationInfo
     */
    private static ApplicationInfo readApplicationInfoFromParcel(Parcel parcel) {
        try {
            if (Build.VERSION.SDK_INT >= 26) {
                try {
                    return parcel.readTypedObject(ApplicationInfo.CREATOR);
                } catch (Throwable t) {
                    return (ApplicationInfo) parcel.readParcelable(ApplicationInfo.class.getClassLoader());
                }
            } else {
                return (ApplicationInfo) parcel.readParcelable(ApplicationInfo.class.getClassLoader());
            }
        } catch (Throwable t) {
            return null;
        }
    }

    /**
     * 检查是否需要修补ApplicationInfo
     */
    private static boolean shouldPatchApplicationInfo(ApplicationInfo appInfo) {
        return appInfo != null && 
               appInfo.packageName != null && 
               Patch.sTargetPackageName != null && 
               Patch.sTargetPackageName.equals(appInfo.packageName);
    }

    /**
     * 修补ApplicationInfo对象
     */
    private static void patchApplicationInfo(ApplicationInfo appInfo) {
        // 修补应用名
        if (AppInfo.originalApplicationName != null && 
            !AppInfo.originalApplicationName.isEmpty()) {
            appInfo.name = AppInfo.originalApplicationName;
            appInfo.className = AppInfo.originalApplicationName;
        }

        // 修补路径
        if (Patch.sPathRedirectionEnabled) {
            appInfo.sourceDir = Patch.FakeApkPath;
            appInfo.publicSourceDir = Patch.FakeApkPath;
        }
    }

    /**
     * 重写ApplicationInfo到Parcel
     */
    private static void rewriteApplicationInfoToParcel(Parcel parcel, ApplicationInfo appInfo) {
        parcel.setDataPosition(0);
        parcel.setDataSize(0);
        parcel.writeInt(0);  // 表示有数据
        parcel.writeInt(1);  // 标志位
        appInfo.writeToParcel(parcel, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
    }

    /**
     * 修补PackageInfo返回数据
     */
    private static void patchPackageInfoReply(Parcel replyParcel) {
        if (replyParcel == null) {
            return;
        }

        int originalPosition = replyParcel.dataPosition();
        replyParcel.setDataPosition(0);

        try {
            // 检查Parcel中是否有数据
            if (replyParcel.readInt() != 0) {
                return;
            }

            PackageInfo packageInfo = readPackageInfoFromParcel(replyParcel);

            // 检查是否需要修补
            if (shouldPatchPackageInfo(packageInfo)) {
                patchSignatureInfo(packageInfo);
                rewritePackageInfoToParcel(replyParcel, packageInfo);
            }

        } catch (Throwable t) {
            Log.w(LOG_TAG, "修补PackageInfo返回数据失败", t);
        } finally {
            replyParcel.setDataPosition(originalPosition);
        }
    }

    /**
     * 从Parcel中读取PackageInfo
     */
    private static PackageInfo readPackageInfoFromParcel(Parcel parcel) {
        try {
            if (Build.VERSION.SDK_INT >= 26) {
                try {
                    return parcel.readTypedObject(PackageInfo.CREATOR);
                } catch (Throwable t) {
                    return (PackageInfo) parcel.readParcelable(PackageInfo.class.getClassLoader());
                }
            } else {
                return (PackageInfo) parcel.readParcelable(PackageInfo.class.getClassLoader());
            }
        } catch (Throwable t) {
            return null;
        }
    }

    /**
     * 检查是否需要修补PackageInfo
     */
    private static boolean shouldPatchPackageInfo(PackageInfo packageInfo) {
        return packageInfo != null && 
               packageInfo.packageName != null && 
               Patch.sTargetPackageName != null && 
               Patch.sTargetPackageName.equals(packageInfo.packageName);
    }

    /**
     * 重写PackageInfo到Parcel
     */
    private static void rewritePackageInfoToParcel(Parcel parcel, PackageInfo packageInfo) {
        parcel.setDataPosition(0);
        parcel.setDataSize(0);
        parcel.writeInt(0);  // 表示有数据
        parcel.writeInt(1);  // 标志位
        packageInfo.writeToParcel(parcel, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
    }
}

代理PMS

/**
 * PackageManager服务代理工具类
 * 通过替换Parcelable.Creator来修改PackageManager返回的包信息和应用信息
 * 这是签名绕过工具中另一种重要的Hook技术
 */
public class PMSAgent {

    private static final String LOG_TAG = "PMSAgent";

    /**
     * Parcelable.Creator代理基类
     * 提供通用的Creator代理功能,子类专注于特定类型的修改逻辑
     */
    private static abstract class BaseCreatorProxy<T> implements Parcelable.Creator<T> {

        /**
         * 从Parcel创建对象的具体实现,由子类提供
         */
        protected abstract T doCreateFromParcel(Parcel source);

        /**
         * 创建对象数组的具体实现,由子类提供
         */
        protected abstract T[] doNewArray(int size);

        @Override
        public T createFromParcel(Parcel source) {
            return doCreateFromParcel(source);
        }

        @Override
        public T[] newArray(int size) {
            return doNewArray(size);
        }

        /**
         * 通用的对象修改方法 - 修改应用信息
         */
        protected void modifyApplicationInfo(ApplicationInfo appInfo) {
            if (appInfo == null) return;

            // 修改应用名称
            if (shouldModifyAppName(appInfo)) {
                appInfo.name = AppInfo.originalApplicationName;
                appInfo.className = AppInfo.originalApplicationName;
            }

            // 修改应用路径
            if (Patch.sPathRedirectionEnabled) {
                appInfo.sourceDir = Patch.FakeApkPath;
                appInfo.publicSourceDir = Patch.FakeApkPath;
            }
        }

        /**
         * 检查是否需要修改应用名称
         */
        private boolean shouldModifyAppName(ApplicationInfo appInfo) {
            return appInfo.packageName != null &&
                   Patch.sTargetPackageName != null &&
                   Patch.sTargetPackageName.equals(appInfo.packageName) &&
                   AppInfo.originalApplicationName != null &&
                   !AppInfo.originalApplicationName.isEmpty();
        }

        /**
         * 通用的对象修改方法 - 修改包信息
         */
        protected void modifyPackageInfo(PackageInfo packageInfo) {
            if (packageInfo == null) return;

            // 修改应用信息
            modifyApplicationInfo(packageInfo.applicationInfo);

            // 修改签名信息
            if (shouldModifySignature(packageInfo)) {
                modifySignatureInfo(packageInfo);
            }
        }

        /**
         * 检查是否需要修改签名
         */
        private boolean shouldModifySignature(PackageInfo packageInfo) {
            return packageInfo.packageName != null &&
                   Patch.sTargetPackageName != null &&
                   Patch.sTargetPackageName.equals(packageInfo.packageName) &&
                   packageInfo.signatures != null &&
                   packageInfo.signatures.length > 0;
        }

        /**
         * 修改签名信息
         */
        private void modifySignatureInfo(PackageInfo packageInfo) {
            // 修改基础签名
            packageInfo.signatures[0] = Patch.sFakeSignature;

            // Android P及以上版本需要额外处理signingInfo
            if (Build.VERSION.SDK_INT >= 28 && packageInfo.signingInfo != null) {
                modifySigningInfo(packageInfo);
            }
        }

        /**
         * 修改Android P+的签名信息
         */
        private void modifySigningInfo(PackageInfo packageInfo) {
            try {
                Signature[] apkSigners = packageInfo.signingInfo.getApkContentsSigners();
                if (apkSigners != null && apkSigners.length > 0) {
                    apkSigners[0] = Patch.sFakeSignature;
                }
            } catch (Exception e) {
                Log.w(LOG_TAG, "修改SigningInfo失败", e);
            }
        }
    }

    /**
     * ApplicationInfo Creator代理(Android P以下版本)
     * 用于替换ApplicationInfo.CREATOR,修改返回的应用信息
     */
    private static class ApplicationInfoCreatorProxyLegacy extends BaseCreatorProxy<ApplicationInfo> {

        @Override
        protected ApplicationInfo doCreateFromParcel(Parcel source) {
            // 使用原始Creator创建对象
            ApplicationInfo appInfo = (ApplicationInfo) Patch.ORIGINAL_APP_INFO_CREATOR.createFromParcel(source);

            // 修改应用信息
            modifyApplicationInfo(appInfo);

            return appInfo;
        }

        @Override
        protected ApplicationInfo[] doNewArray(int size) {
            return (ApplicationInfo[]) Patch.ORIGINAL_APP_INFO_CREATOR.newArray(size);
        }

        @Override
        public boolean equals(Object obj) {
            return this == obj;
        }

        @Override
        public int hashCode() {
            return System.identityHashCode(this);
        }
    }

    /**
     * ApplicationInfo Creator代理(Android P及以上版本)
     * 支持ClassLoaderCreator接口
     */
    private static class ApplicationInfoCreatorProxyP extends BaseCreatorProxy<ApplicationInfo> 
            implements Parcelable.ClassLoaderCreator<ApplicationInfo> {

        @Override
        protected ApplicationInfo doCreateFromParcel(Parcel source) {
            // 使用原始Creator创建对象
            ApplicationInfo appInfo = (ApplicationInfo) Patch.ORIGINAL_APP_INFO_CREATOR.createFromParcel(source);

            // 修改应用信息
            modifyApplicationInfo(appInfo);

            return appInfo;
        }

        @Override
        protected ApplicationInfo[] doNewArray(int size) {
            return (ApplicationInfo[]) Patch.ORIGINAL_APP_INFO_CREATOR.newArray(size);
        }

        @Override
        public ApplicationInfo createFromParcel(Parcel source, ClassLoader loader) {
            return doCreateFromParcel(source);
        }
    }

    /**
     * PackageInfo Creator代理(Android P以下版本)
     * 用于替换PackageInfo.CREATOR,修改返回的包信息
     */
    private static class PackageInfoCreatorProxyLegacy extends BaseCreatorProxy<PackageInfo> {

        @Override
        protected PackageInfo doCreateFromParcel(Parcel source) {
            // 使用原始Creator创建对象
            PackageInfo packageInfo = (PackageInfo) Patch.ORIGINAL_CREATOR.createFromParcel(source);

            // 修改包信息
            modifyPackageInfo(packageInfo);

            return packageInfo;
        }

        @Override
        protected PackageInfo[] doNewArray(int size) {
            return (PackageInfo[]) Patch.ORIGINAL_CREATOR.newArray(size);
        }

        @Override
        public boolean equals(Object obj) {
            return this == obj;
        }

        @Override
        public int hashCode() {
            return System.identityHashCode(this);
        }
    }

    /**
     * PackageInfo Creator代理(Android P及以上版本)
     * 支持ClassLoaderCreator接口
     */
    private static class PackageInfoCreatorProxyP extends BaseCreatorProxy<PackageInfo> 
            implements Parcelable.ClassLoaderCreator<PackageInfo> {

        @Override
        protected PackageInfo doCreateFromParcel(Parcel source) {
            // 使用原始Creator创建对象
            PackageInfo packageInfo = (PackageInfo) Patch.ORIGINAL_CREATOR.createFromParcel(source);

            // 修改包信息
            modifyPackageInfo(packageInfo);

            return packageInfo;
        }

        @Override
        protected PackageInfo[] doNewArray(int size) {
            return (PackageInfo[]) Patch.ORIGINAL_CREATOR.newArray(size);
        }

        @Override
        public PackageInfo createFromParcel(Parcel source, ClassLoader loader) {
            return doCreateFromParcel(source);
        }
    }

    /**
     * 获取Unsafe实例
     * 用于直接操作内存,修改final字段
     */
    private static Unsafe getUnsafeInstance() throws Exception {
        Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
        unsafeField.setAccessible(true);
        return (Unsafe) unsafeField.get(null);
    }

    /**
     * 替换Parcelable.Creator
     * 核心方法:通过反射和Unsafe替换PackageInfo和ApplicationInfo的CREATOR字段
     */
    public static void replaceParcelableCreators() throws Exception {
        Log.i(LOG_TAG, "开始替换Parcelable.Creator...");

        // 替换PackageInfo.CREATOR
        replacePackageInfoCreator();

        // 替换ApplicationInfo.CREATOR
        replaceApplicationInfoCreator();

        // 清理缓存
        CacheHandling.clearCaches();

        Log.i(LOG_TAG, "Parcelable.Creator替换完成");
    }

    /**
     * 替换PackageInfo.CREATOR
     */
    private static void replacePackageInfoCreator() throws Exception {
        Field creatorField = PackageInfo.class.getDeclaredField("CREATOR");
        creatorField.setAccessible(true);

        // 保存原始Creator
        Patch.ORIGINAL_CREATOR = (Parcelable.Creator) creatorField.get(null);

        // 根据Android版本选择代理实现
        BaseCreatorProxy<PackageInfo> packageInfoProxy = createPackageInfoProxy();

        // 伪装代理类名
        disguiseProxyClassName(packageInfoProxy, "android.content.pm.PackageInfo$1");

        // 替换CREATOR字段
        replaceFinalField(creatorField, packageInfoProxy);
    }

    /**
     * 替换ApplicationInfo.CREATOR
     */
    private static void replaceApplicationInfoCreator() throws Exception {
        Field creatorField = ApplicationInfo.class.getDeclaredField("CREATOR");
        creatorField.setAccessible(true);

        // 保存原始Creator
        Patch.ORIGINAL_APP_INFO_CREATOR = (Parcelable.Creator) creatorField.get(null);

        // 根据Android版本选择代理实现
        BaseCreatorProxy<ApplicationInfo> appInfoProxy = createApplicationInfoProxy();

        // 伪装代理类名
        disguiseProxyClassName(appInfoProxy, "android.content.pm.ApplicationInfo$1");

        // 替换CREATOR字段
        replaceFinalField(creatorField, appInfoProxy);
    }

    /**
     * 创建PackageInfo代理实例
     */
    private static BaseCreatorProxy<PackageInfo> createPackageInfoProxy() {
        if (Build.VERSION.SDK_INT >= 28) {
            return new PackageInfoCreatorProxyP();
        } else {
            return new PackageInfoCreatorProxyLegacy();
        }
    }

    /**
     * 创建ApplicationInfo代理实例
     */
    private static BaseCreatorProxy<ApplicationInfo> createApplicationInfoProxy() {
        if (Build.VERSION.SDK_INT >= 28) {
            return new ApplicationInfoCreatorProxyP();
        } else {
            return new ApplicationInfoCreatorProxyLegacy();
        }
    }

    /**
     * 伪装代理类名
     * 使用Unsafe直接修改Class对象的name字段,增加隐蔽性
     */
    private static void disguiseProxyClassName(Object proxy, String targetClassName) throws Exception {
        Unsafe unsafe = getUnsafeInstance();
        Field nameField = Class.class.getDeclaredField("name");
        long nameFieldOffset = unsafe.objectFieldOffset(nameField);

        unsafe.putObject(proxy.getClass(), nameFieldOffset, targetClassName);
    }

    /**
     * 替换final字段的值
     * 通过反射修改字段访问标志,然后设置新值
     */
    private static void replaceFinalField(Field field, Object newValue) throws Exception {
        // 获取原始访问标志
        Field modifiersField = Field.class.getDeclaredField("accessFlags");
        modifiersField.setAccessible(true);
        int originalModifiers = field.getModifiers();

        try {
            // 移除final标志
            modifiersField.setInt(field, originalModifiers & ~Modifier.FINAL);

            // 设置新值
            field.set(null, newValue);

        } finally {
            // 恢复final标志
            modifiersField.setInt(field, originalModifiers | Modifier.FINAL);
        }
    }
}

清理缓存

/**
 * 缓存清理工具类
 * 清理PackageManager和Parcel中的各种缓存,确保Hook修改能够立即生效
 * 在修改系统状态后调用,避免缓存导致修改不生效
 */
public class CacheHandling {

    /**
     * 清理所有相关缓存
     * 包括PackageManager的包信息缓存和Parcel的Creator缓存
     * 在修改PackageInfo或ApplicationInfo后必须调用此方法
     */
    public static void clearCaches() {
        clearPackageInfoCache();
        clearParcelCreatorCache();
        clearParcelPairedCreatorCache();
    }

    /**
     * 清理PackageManager的包信息缓存
     * 清除系统对包信息的缓存,确保下次查询时重新加载修改后的信息
     */
    private static void clearPackageInfoCache() {
        try {
            // 获取PackageManager的sPackageInfoCache字段
            Field cacheField = findFieldRecursively(PackageManager.class, "sPackageInfoCache");
            Object cacheInstance = cacheField.get(null);

            if (cacheInstance != null) {
                // 调用缓存对象的clear方法清空缓存
                cacheInstance.getClass().getMethod("clear").invoke(cacheInstance);
            }
        } catch (Throwable ignored) {
            // 忽略清理缓存时的异常,不影响主要功能
        }
    }

    /**
     * 清理Parcel的Creator缓存
     * 清除Parcel对Parcelable.Creator的缓存,确保使用我们替换的Creator
     */
    private static void clearParcelCreatorCache() {
        try {
            // 获取Parcel的mCreators字段
            Field creatorsField = findFieldRecursively(Parcel.class, "mCreators");
            Map<?, ?> creatorsMap = (Map<?, ?>) creatorsField.get(null);

            if (creatorsMap != null) {
                creatorsMap.clear();
            }
        } catch (Throwable ignored) {
            // 忽略清理缓存时的异常
        }
    }

    /**
     * 清理Parcel的配对Creator缓存
     * 清除Parcel的sPairedCreators缓存(某些Android版本特有)
     */
    private static void clearParcelPairedCreatorCache() {
        try {
            // 获取Parcel的sPairedCreators字段
            Field pairedCreatorsField = findFieldRecursively(Parcel.class, "sPairedCreators");
            Map<?, ?> pairedCreatorsMap = (Map<?, ?>) pairedCreatorsField.get(null);

            if (pairedCreatorsMap != null) {
                pairedCreatorsMap.clear();
            }
        } catch (Throwable ignored) {
            // 忽略清理缓存时的异常
        }
    }

    /**
     * 递归查找字段
     * 在当前类及其父类中查找指定字段
     * 
     * @param targetClass 要查找的起始类
     * @param fieldName 要查找的字段名
     * @return 找到的Field对象
     * @throws NoSuchFieldException 如果字段不存在
     */
    private static Field findFieldRecursively(Class<?> targetClass, String fieldName) 
            throws NoSuchFieldException {
        Class<?> currentClass = targetClass;

        // 在当前类及其父类中递归查找字段
        while (currentClass != null && !Object.class.equals(currentClass)) {
            try {
                Field field = currentClass.getDeclaredField(fieldName);
                field.setAccessible(true);
                return field;
            } catch (NoSuchFieldException e) {
                // 在当前类中未找到,继续在父类中查找
                currentClass = currentClass.getSuperclass();
            }
        }

        throw new NoSuchFieldException("字段未找到: " + fieldName);
    }
}

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

Hmily 发表于 2026-3-2 16:31
I D :孤木落
邮箱:1359640178@qq.com

申请通过,欢迎光临吾爱破解论坛,期待吾爱破解有你更加精彩,ID和密码自己通过邮件密码找回功能修改,请即时登陆并修改密码!
登陆后请在一周内在此帖报道,否则将删除ID信息。

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-3-4 16:46

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表