【VirtualAPP 双开系列01】巧妙的反射框架

目录:

  • 1. 反射类型包装
  • 2. 实例
  • 3. 总结

 

1. 反射类型包装

 

2. 实例分析 

https://wos.58cdn.com.cn/IjGfEdCbIlr/ishare/video_XUU713V9XdWc37XUXU35U5d3VaV95ad1.mp4

看看其反射相关输出:

04-06 10:41:31.722 29160 29160 I kuang   : load mappingClass: mirror.dalvik.system.VMRuntime ,realClass: dalvik.system.VMRuntime
04-06 10:41:31.722 29160 29160 I kuang   : field: TYPE
04-06 10:41:31.722 29160 29160 I kuang   : static field type: class java.lang.Class
04-06 10:41:31.722 29160 29160 I kuang   : field: getCurrentInstructionSet
04-06 10:41:31.722 29160 29160 I kuang   : static field type: class mirror.RefStaticMethod
04-06 10:41:31.722 29160 29160 I kuang   : field: getRuntime
04-06 10:41:31.722 29160 29160 I kuang   : static field type: class mirror.RefStaticMethod
04-06 10:41:31.722 29160 29160 I kuang   : field: is64Bit
04-06 10:41:31.722 29160 29160 I kuang   : static field type: class mirror.RefMethod
04-06 10:41:31.722 29160 29160 I kuang   : field: setTargetSdkVersion
04-06 10:41:31.722 29160 29160 I kuang   : static field type: class mirror.RefMethod
04-06 10:41:31.722 29160 29160 I kuang   : invoke static method: getRuntime
04-06 10:41:31.722 29160 29160 I kuang   : invoke method: dalvik.system.VMRuntime, method: setTargetSdkVersion


...

04-06 10:37:11.534 26426 26448 I kuang   : load mappingClass: mirror.com.android.internal.content.NativeLibraryHelper ,realClass: com.android.internal.content.NativeLibraryHelper
04-06 10:37:11.534 26426 26448 I kuang   : field: TYPE
04-06 10:37:11.534 26426 26448 I kuang   : static field type: class java.lang.Class
04-06 10:37:11.534 26426 26448 I kuang   : field: copyNativeBinaries
04-06 10:37:11.534 26426 26448 I kuang   : static field type: class mirror.RefStaticMethod
04-06 10:37:11.534 26426 26448 I kuang   : field: findSupportedAbi
04-06 10:37:11.534 26426 26448 I kuang   : static field type: class mirror.RefStaticMethod
04-06 10:37:11.534 26426 26448 I kuang   : invoke static method: findSupportedAbi
04-06 10:37:11.556 26426 26448 I kuang   : invoke static method: copyNativeBinaries
04-06 10:37:12.068 26426 26448 I kuang   : invoke method: android.content.res.AssetManager, method: addAssetPath
04-06 10:37:12.075 26426 26448 I kuang   : invoke method: android.content.res.AssetManager, method: addAssetPath

我们来找一个简单的类看一下,NativeLibraryHelper,原始类 (Android 7.0):

package com.android.internal.content;

public class NativeLibraryHelper {
     

     public static int copyNativeBinaries(Handle handle, File sharedLibraryDir, String abi) {
        for (long apkHandle : handle.apkHandles) {
            int res = nativeCopyNativeBinaries(apkHandle, sharedLibraryDir.getPath(), abi,
                    handle.extractNativeLibs, HAS_NATIVE_BRIDGE);
            if (res != INSTALL_SUCCEEDED) {
                return res;
            }
        }
        return INSTALL_SUCCEEDED;
    }

   public static int findSupportedAbi(Handle handle, String[] supportedAbis) {
        int finalRes = NO_NATIVE_LIBRARIES;
        for (long apkHandle : handle.apkHandles) {
            final int res = nativeFindSupportedAbi(apkHandle, supportedAbis);
            if (res == NO_NATIVE_LIBRARIES) {
                // No native code, keep looking through all APKs.
            } else if (res == INSTALL_FAILED_NO_MATCHING_ABIS) {
                // Found some native code, but no ABI match; update our final
                // result if we haven\'t found other valid code.
                if (finalRes < 0) {
                    finalRes = INSTALL_FAILED_NO_MATCHING_ABIS;
                }
            } else if (res >= 0) {
                // Found valid native code, track the best ABI match
                if (finalRes < 0 || res < finalRes) {
                    finalRes = res;
                }
            } else {
                // Unexpected error; bail
                return res;
            }
        }
        return finalRes;
    }

    public static class Handle implements Closeable {

    	public static Handle create(File packageFile) throws IOException {
            try {
                final PackageLite lite = PackageParser.parsePackageLite(packageFile, 0);
                return create(lite);
            } catch (PackageParserException e) {
                throw new IOException("Failed to parse package: " + packageFile, e);
            }
        }
    }
}

 ADocker 镜像类:

package mirror.com.android.internal.content;

public class NativeLibraryHelper {

    // 加载映射 class 
    public static Class<?> TYPE = RefClass.load(NativeLibraryHelper.class, "com.android.internal.content.NativeLibraryHelper");

    // 带参静态方法,参数无需反射
    @MethodParams({Handle.class, File.class, String.class})
    public static RefStaticMethod<Integer> copyNativeBinaries;

    // 带参静态方法,参数无需反射
    @MethodParams({Handle.class, String[].class})
    public static RefStaticMethod<Integer> findSupportedAbi;
    

    // 静态内部类
    public static class Handle {

        // 加载映射 class 
        public static Class<?> TYPE = RefClass.load(Handle.class, "com.android.internal.content.NativeLibraryHelper$Handle");

        // 带参静态方法,参数无需反射
        @MethodParams({File.class})
        public static RefStaticMethod<Object> create;
    }
}

// 封装的工具映射类,属性和方法都是静态,内部实现再通过是否传入 object, 来决定是否是普通方法还是静态方法
public class VMRuntime {
        public static Class<?> TYPE = RefClass.load(VMRuntime.class, "dalvik.system.VMRuntime");        
        // 获取 VMRuntime 对象(单例对象)
        public static RefStaticMethod<Object> getRuntime;
        @MethodParams({int.class})
        public static RefMethod<Void> setTargetSdkVersion;
        public static RefMethod<Boolean> is64Bit;
        public static RefStaticMethod<String> getCurrentInstructionSet;
}

ADocker 调用:

package com.android.dockercore.helper.compat;

public class NativeLibraryHelperCompat {


	@TargetApi(Build.VERSION_CODES.LOLLIPOP)
	private static int copyNativeBinariesAfterL(File apkFile, File sharedLibraryDir) {
		try {
                        // 调用镜像内部类 NativeLibraryHelper.Handle 的静态方法 create() 获取 handle 对象

			Object handle = NativeLibraryHelper.Handle.create.call(apkFile);
			if (handle == null) {
				return -1;
			}

			String abi = null;
			Set<String> abiSet = getABIsFromApk(apkFile.getAbsolutePath());
			if (abiSet == null || abiSet.isEmpty()) {
				return 0;
			}
                        // step1: 调用镜像类 VMRuntime 的静态方法 getRuntime.call() 获取 VMRuntime 单例对象                        // step2: 调用镜像类 vmRuntimeObject 的普通方法 is64Bit.call(vmRuntimeObject)                                                            
			boolean is64Bit = VMRuntime.is64Bit.call(VMRuntime.getRuntime.call());
			if (is64Bit && isVM64(abiSet)) {
				if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
                        // 调用镜像类 NativeLibraryHelper 的静态方法 findSupportedAbi(), 传入参数 handle 对象和常量		                                                          int abiIndex = NativeLibraryHelper.findSupportedAbi.call(handle, Build.SUPPORTED_64_BIT_ABIS);
					if (abiIndex >= 0) {
						abi = Build.SUPPORTED_64_BIT_ABIS[abiIndex];
					}
				}
			} else {
				if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
					int abiIndex = NativeLibraryHelper.findSupportedAbi.call(handle, Build.SUPPORTED_32_BIT_ABIS);
					if (abiIndex >= 0) {
						abi = Build.SUPPORTED_32_BIT_ABIS[abiIndex];
					}
				}
			}

			if (abi == null) {
				VLog.e(TAG, "Not match any abi [%s].", apkFile.getPath());
				return -1;
			}
                        // 调用镜像类 NativeLibraryHelper 的静态方法 copyNativeBinaries(), 传入参数 handle 对象、字符串、常量		
			return NativeLibraryHelper.copyNativeBinaries.call(handle, sharedLibraryDir, abi);
		} catch (Throwable e) {
			VLog.d(TAG, "copyNativeBinaries with error : %s", e.getLocalizedMessage());
			e.printStackTrace();
		}

		return -1;
	}
}

流程图:

变量的调用(设置属性):

// 修改 mBasePackageName 内的值,传输 context 对象(原始反射的对象,一般是单例),hostPkg 参数
ContextImpl.mBasePackageName.set(context, hostPkg);

 

3. 总结

  • 声明式。反射哪个类,哪个成员对象,哪个方法,都是用声明的方式给出的。什么是声明?就是用类定义的方式,直截了当的定义出来。
  • 使用简单,没有胶水代码。在声明里,完全看不到任何和反射API相关的代码,基本隐藏了Java的反射框架,对使用者来说,几乎是无感的。
  • 实现简洁,原理简单。这么一个好用的框架,它的实现却不复杂,源码不多,代码实现很简单,却很好地诠释了什么叫优雅。

 

 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
VirtualApp是一个开源的、提供虚拟化应用的框架,其源码可以帮助我们了解和学习虚拟化技术的实现原理。 VirtualApp的源码中主要包含了以下几个方面的内容: 1. Hook技术:VirtualApp使用了Xposed和Substrate等Hook框架,通过动态修改运行时的Java方法,实现对目标应用的API调用进行拦截和替换。通过Hook技术,VirtualApp能够在虚拟环境中替换目标应用的敏感操作,实现对应用的隔离和保护。 2. 虚拟环境创建:VirtualApp源码实现了一个独立的虚拟环境,可以在这个环境中安装和运行目标应用。这个虚拟环境通过Hook技术对系统运行时的一些特殊API进行拦截和修改,使得目标应用在虚拟环境中运行时能够调用到虚拟环境提供的资源、服务和功能。 3. 进程隔离:VirtualApp使用了Linux的Namespace和Cgroup等技术,实现了进程的隔离。在虚拟环境中运行的应用与宿主系统的应用是完全独立的,互不干扰。这种隔离可以保护宿主系统的安全,同时也可以保护虚拟环境中的应用不受外部环境的干扰。 4. 文件系统隔离:VirtualApp通过Hook技术对文件操作API进行拦截和修改,实现了虚拟环境与宿主系统的文件系统隔离。在虚拟环境中运行的应用只能访问到虚拟环境的文件系统,无法直接访问宿主系统的文件系统,从而保护了宿主系统的文件安全。 总的来说,VirtualApp的源码实现了虚拟化应用的关键功能,如Hook技术、虚拟环境创建、进程隔离和文件系统隔离等。通过阅读和学习VirtualApp的源码,我们可以深入了解和掌握虚拟化技术的实现原理。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值