GKLBB

当你经历了暴风雨,你也就成为了暴风雨

导航

应用安全 --- apk加固 之 强制升级

// 定义包名,这个类属于com.iran.SmaliHelper包
package com.iran.SmaliHelper;

// 导入Android应用程序基类
import android.app.Application;
// 导入Android应用程序测试工具类
import android.app.Instrumentation;
// 导入Android上下文类
import android.content.Context;
// 导入应用程序信息类
import android.content.pm.ApplicationInfo;
// 导入包信息类
import android.content.pm.PackageInfo;
// 导入包管理器类
import android.content.pm.PackageManager;
// 导入Java反射相关的字段类
import java.lang.reflect.Field;
// 导入Java动态代理调用处理器接口
import java.lang.reflect.InvocationHandler;
// 导入Java反射方法类
import java.lang.reflect.Method;
// 导入Java动态代理类
import java.lang.reflect.Proxy;
// 导入Java数组列表类
import java.util.ArrayList;

// 定义一个最终类RemoveUpdate,继承自Application并实现InvocationHandler接口
// 这个类的主要作用是拦截和修改系统包管理器的行为
public final class RemoveUpdate extends Application implements InvocationHandler {
    
    // 存储应用程序类名的私有字段
    private String appClassName;
    // 存储数据的私有字段
    private String data;
    // 存储系统包管理器对象的私有字段
    private Object sPackageManager;
    // 存储签名信息的二维字节数组
    private byte[][] sign;
    // 存储类型标识的私有字段
    private String type;
    
    // 构造函数,初始化各个字段的默认值
    public RemoveUpdate() {
        // 设置应用程序类名为"GKLBB"
        this.appClassName = "GKLBB";
        // 设置类型为"1",用于控制不同的拦截策略
        this.type = "1";
        // 初始化数据字段为空字符串
        this.data = "";
    }
    
    // 重写attachBaseContext方法,在应用程序上下文附加时执行
    @Override
    protected void attachBaseContext(Context base) {
        // 调用父类的attachBaseContext方法
        super.attachBaseContext(base);
        
        try {
            // 通过反射获取ActivityThread类
            Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
            // 获取当前ActivityThread实例
            Object currentActivityThread = activityThreadClass.getDeclaredMethod("currentActivityThread", new Class[0])
                    .invoke(null, new Object[0]);
            // 获取ActivityThread类中的sPackageManager字段
            Field sPackageManagerField = activityThreadClass.getDeclaredField("sPackageManager");
            // 设置字段可访问(绕过private限制)
            sPackageManagerField.setAccessible(true);
            // 保存原始的包管理器对象
            this.sPackageManager = sPackageManagerField.get(currentActivityThread);
            
            // 获取IPackageManager接口类
            Class<?> iPackageManagerInterface = Class.forName("android.content.pm.IPackageManager");
            // 创建动态代理对象,用当前对象作为调用处理器
            Object proxy = Proxy.newProxyInstance(
                    iPackageManagerInterface.getClassLoader(),
                    new Class[]{iPackageManagerInterface},
                    this
            );
            // 将代理对象设置到ActivityThread的sPackageManager字段中
            sPackageManagerField.set(currentActivityThread, proxy);
            
            // 获取PackageManager实例
            PackageManager pm = base.getPackageManager();
            // 获取PackageManager中的mPM字段
            Field mPmField = pm.getClass().getDeclaredField("mPM");
            // 设置字段可访问
            mPmField.setAccessible(true);
            // 将代理对象也设置到PackageManager的mPM字段中
            mPmField.set(pm, proxy);
        } catch (Exception e) {
            // 如果出现异常,打印堆栈跟踪信息
            e.printStackTrace();
        }
    }
    
    // 重写onCreate方法,在应用程序创建时执行
    @Override
    public void onCreate() {
        // 调用父类的onCreate方法
        super.onCreate();
        
        try {
            // 获取当前ActivityThread实例
            Object currentActivityThread = invokeStaticMethod("android.app.ActivityThread", "currentActivityThread", new Class[0], new Object[0]);
            // 获取绑定的应用程序数据对象
            Object mBoundApplication = getFieldObject("android.app.ActivityThread", currentActivityThread, "mBoundApplication");
            // 从AppBindData中获取应用程序信息
            ApplicationInfo appinfo_In_AppBindData = (ApplicationInfo) getFieldObject("android.app.ActivityThread$AppBindData", mBoundApplication, "appInfo");
            // 获取已加载的APK信息
            Object loadedApkInfo = getFieldObject("android.app.ActivityThread", currentActivityThread, "mPackages");
            
            // 修改AppBindData中的应用程序类名
            appinfo_In_AppBindData.className = this.appClassName;
            // 获取LoadedApk中的应用程序信息
            ApplicationInfo appinfo_In_LoadedApk = (ApplicationInfo) getFieldObject("android.app.LoadedApk", loadedApkInfo, "mApplicationInfo");
            // 修改LoadedApk中的应用程序类名
            appinfo_In_LoadedApk.className = this.appClassName;
            
            // 获取旧的应用程序实例
            Application oldApplication = (Application) getFieldObject("android.app.ActivityThread", currentActivityThread, "mInitialApplication");
            // 获取所有应用程序列表
            ArrayList<Application> mAllApplications = (ArrayList<Application>) getFieldObject("android.app.ActivityThread", currentActivityThread, "mAllApplications");
            // 从列表中移除旧的应用程序实例
            mAllApplications.remove(oldApplication);
            
            // 再次获取LoadedApk中的应用程序信息(用于创建新应用程序)
            ApplicationInfo appinfo_In_LoadedApk2 = (ApplicationInfo) getFieldObject("android.app.LoadedApk", loadedApkInfo, "mApplicationInfo");
            // 创建新的应用程序实例
            Application app = (Application) invokeMethod("android.app.LoadedApk", "makeApplication", loadedApkInfo, 
                    new Class[]{boolean.class, Instrumentation.class}, 
                    new Object[]{false, null});
            
            // 设置新的应用程序实例为初始应用程序
            setFieldObject("android.app.ActivityThread", "mInitialApplication", currentActivityThread, app);
            // 如果新应用程序实例不为空,调用其onCreate方法
            if (app != null) {
                app.onCreate();
            }
        } catch (Exception e) {
            // 如果出现异常,打印堆栈跟踪信息
            e.printStackTrace();
        }
    }
    
    // 通过反射获取指定对象的字段值
    public Object getFieldObject(String className, Object obj, String fieldName) {
        try {
            // 根据类名获取Class对象
            Class<?> objClass = Class.forName(className);
            // 获取指定名称的字段
            Field field = objClass.getDeclaredField(fieldName);
            // 设置字段可访问(绕过private等访问限制)
            field.setAccessible(true);
            // 返回字段的值
            return field.get(obj);
        } catch (SecurityException | NoSuchFieldException | IllegalArgumentException | 
                 IllegalAccessException | ClassNotFoundException e) {
            // 捕获各种可能的异常并打印堆栈信息
            e.printStackTrace();
            // 异常时返回null
            return null;
        }
    }
    
    // 通过反射获取指定类的静态字段值
    public Object getStaticFieldObject(String className, String fieldName) {
        try {
            // 根据类名获取Class对象
            Class<?> objClass = Class.forName(className);
            // 获取指定名称的字段
            Field field = objClass.getDeclaredField(fieldName);
            // 设置字段可访问
            field.setAccessible(true);
            // 获取静态字段的值(传入null表示静态字段)
            return field.get(null);
        } catch (SecurityException | NoSuchFieldException | IllegalArgumentException | 
                 IllegalAccessException | ClassNotFoundException e) {
            // 捕获异常并打印堆栈信息
            e.printStackTrace();
            // 异常时返回null
            return null;
        }
    }
    
    // 通过反射设置指定对象的字段值
    public void setFieldObject(String className, String fieldName, Object obj, Object fieldValue) {
        try {
            // 根据类名获取Class对象
            Class<?> objClass = Class.forName(className);
            // 获取指定名称的字段
            Field field = objClass.getDeclaredField(fieldName);
            // 设置字段可访问
            field.setAccessible(true);
            // 设置字段的值
            field.set(obj, fieldValue);
        } catch (SecurityException | NoSuchFieldException | IllegalArgumentException | 
                 IllegalAccessException | ClassNotFoundException e) {
            // 捕获异常并打印堆栈信息
            e.printStackTrace();
        }
    }
    
    // 通过反射设置指定类的静态字段值
    public void setStaticObject(String className, String fieldName, Object fieldValue) {
        try {
            // 根据类名获取Class对象
            Class<?> objClass = Class.forName(className);
            // 获取指定名称的字段
            Field field = objClass.getDeclaredField(fieldName);
            // 设置字段可访问
            field.setAccessible(true);
            // 设置静态字段的值(传入null表示静态字段)
            field.set(null, fieldValue);
        } catch (SecurityException | NoSuchFieldException | IllegalArgumentException | 
                 IllegalAccessException | ClassNotFoundException e) {
            // 捕获异常并打印堆栈信息
            e.printStackTrace();
        }
    }
    
    // 通过反射调用指定对象的方法
    public Object invokeMethod(String className, String methodName, Object obj, Class<?>[] paramTypes, Object[] params) {
        try {
            // 根据类名获取Class对象
            Class<?> objClass = Class.forName(className);
            // 根据方法名和参数类型获取Method对象
            Method method = objClass.getDeclaredMethod(methodName, paramTypes);
            // 设置方法可访问
            method.setAccessible(true);
            // 调用方法并返回结果
            return method.invoke(obj, params);
        } catch (Exception e) {
            // 捕获异常并打印堆栈信息
            e.printStackTrace();
            // 异常时返回null
            return null;
        }
    }
    
    // 通过反射调用指定类的静态方法
    public Object invokeStaticMethod(String className, String methodName, Class<?>[] paramTypes, Object[] params) {
        try {
            // 根据类名获取Class对象
            Class<?> objClass = Class.forName(className);
            // 根据方法名和参数类型获取Method对象
            Method method = objClass.getDeclaredMethod(methodName, paramTypes);
            // 设置方法可访问
            method.setAccessible(true);
            // 调用静态方法并返回结果(传入null表示静态方法)
            return method.invoke(null, params);
        } catch (Exception e) {
            // 捕获异常并打印堆栈信息
            e.printStackTrace();
            // 异常时返回null
            return null;
        }
    }
    
    // 实现InvocationHandler接口的invoke方法,用于拦截包管理器的方法调用
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 初始化返回结果
        Object result = null;
        
        // 如果类型为"1",执行版本码修改策略
        if ("1".equals(this.type)) {
            // 如果调用的是getPackageInfo方法且查询的是当前应用包名
            if ("getPackageInfo".equals(method.getName()) && 
                args[0].equals(getPackageName())) {
                // 调用原始包管理器的方法
                result = method.invoke(this.sPackageManager, args);
                // 将返回的包信息转换为PackageInfo对象
                PackageInfo info = (PackageInfo) result;
                // 将版本码设置为最大整数值,用于绕过版本检查
                info.versionCode = Integer.MAX_VALUE;
            } else {
                // 对于其他方法调用,直接转发给原始包管理器
                result = method.invoke(this.sPackageManager, args);
            }
        } else if ("2".equals(this.type)) {
            // 如果类型为"2",执行隐藏应用策略
            if ("getInstalledPackages".equals(method.getName())) {
                // 如果查询已安装包列表,返回空列表(隐藏所有应用)
                result = new ArrayList<>();
            } else if ("getPackageInfo".equals(method.getName())) {
                // 如果查询包信息
                if (!args[0].equals(getPackageName())) {
                    // 如果不是查询当前应用,将包名替换为"ccc"(不存在的包名)
                    args[0] = "ccc";
                    result = method.invoke(this.sPackageManager, args);
                } else {
                    // 如果是查询当前应用,正常处理
                    result = method.invoke(this.sPackageManager, args);
                }
            } else if ("getApplicationInfo".equals(method.getName()) ||
                      "getPackageUid".equals(method.getName()) ||
                      "getPackageGids".equals(method.getName()) ||
                      "getApplicationEnabledSetting".equals(method.getName()) ||
                      "getText".equals(method.getName()) ||
                      "getResourcesForApplication".equals(method.getName())) {
                // 对于这些应用信息相关的方法
                if (!args[0].equals(getPackageName())) {
                    // 如果不是查询当前应用,将包名替换为"ccc"
                    args[0] = "ccc";
                    result = method.invoke(this.sPackageManager, args);
                } else {
                    // 如果是查询当前应用,正常处理
                    result = method.invoke(this.sPackageManager, args);
                }
            } else if ("getApplicationBanner".equals(method.getName())) {
                // 如果是获取应用横幅图标的方法
                if (args[0] instanceof String && !args[0].equals(getPackageName())) {
                    // 如果参数是字符串且不是当前应用包名,替换为"ccc"
                    args[0] = "ccc";
                    result = method.invoke(this.sPackageManager, args);
                } else {
                    // 否则正常处理
                    result = method.invoke(this.sPackageManager, args);
                }
            } else {
                // 对于其他方法,直接转发给原始包管理器
                result = method.invoke(this.sPackageManager, args);
            }
        } else {
            // 如果类型不是"1"或"2",直接转发所有方法调用
            result = method.invoke(this.sPackageManager, args);
        }
        
        // 返回处理结果
        return result;
    }
}
}

 

posted on 2025-09-09 00:31  GKLBB  阅读(11)  评论(0)    收藏  举报