mirror::Object 对象所包含的内容就是 instance field 的内容,因此它的大小和类的 instance field 有关。之所以叫 mirror ,是因为这些 mirror 类中定义的成员和 Java 类的字段(field)是一致的。
一般的类的对象对应的都是 art::mirror::Object ,访问 field 是通过对象地址 + field offset 实现的。如果一个类继承另一个类,则内存布局上子类的 field 排在父类的后面,这和结构体继承的内存布局是一致的。
例如 art::mirror::Object 只有两个成员:
1 2 3 4 5
// art/runtime/mirror/object.h // The Class representing the type of the object. HeapReference<Class> klass_; // Monitor and hash code information. uint32_t monitor_;
// art/runtime/mirror/class.h // 'Class' Object Fields // Order governed by java field ordering. See art::ClassLinker::LinkFieldsHelper::LinkFields.
// Defining class loader, or null for the "bootstrap" system loader. HeapReference<ClassLoader> class_loader_;
// For array classes, the component class object for instanceof/checkcast // (for String[][][], this will be String[][]). null for non-array classes. HeapReference<Class> component_type_;
// DexCache of resolved constant pool entries (will be null for classes generated by the // runtime such as arrays and primitive classes). HeapReference<DexCache> dex_cache_;
// ...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
// libcore/ojluni/src/main/java/java/lang/Class.java /** defining class loader, or null for the "bootstrap" system loader. */ privatetransient ClassLoader classLoader;
/** * For array classes, the component class object for instanceof/checkcast (for String[][][], * this will be String[][]). null for non-array classes. */ privatetransient Class<?> componentType;
/** * DexCache of resolved constant pool entries. Will be null for certain runtime-generated classes * e.g. arrays and primitive classes. */ privatetransient Object dexCache;
// we want a relatively stable order so that adding new fields // minimizes disruption of C++ version such as Class and Method. // // The overall sort order order is: // 1) All object reference fields, sorted alphabetically. // 2) All java long (64-bit) integer fields, sorted alphabetically. // 3) All java double (64-bit) floating point fields, sorted alphabetically. // 4) All java int (32-bit) integer fields, sorted alphabetically. // 5) All java float (32-bit) floating point fields, sorted alphabetically. // 6) All java char (16-bit) integer fields, sorted alphabetically. // 7) All java short (16-bit) integer fields, sorted alphabetically. // 8) All java boolean (8-bit) integer fields, sorted alphabetically. // 9) All java byte (8-bit) integer fields, sorted alphabetically. // // (References are first to increase the chance of reference visiting // being able to take a fast path using a bitmap of references at the // start of the object, see `Class::reference_instance_offsets_`.) // // Once the fields are sorted in this order we will attempt to fill any gaps // that might be present in the memory layout of the structure. // Note that we shall not fill gaps between the superclass fields.
// Collect fields and their "type order index" (see numbered points above).
隐藏 API
隐藏 API 限制是 Android P 引入的。它可以限制通过反射、JNI 和链接方式获取被禁止的 method 或 field 的访问。实际上被限制的就是这几个地方:
Class.get[Declared]Field|Method[s]
JNIEnv::Get{Method|Field}ID
dalvik 指令直接访问 method 或 field ,在 link 阶段,阻止隐藏的 method 或 field 被解析到 dex cache 中。这限制了通过 api stub 的链接方式访问。
值得注意的是,如果得到了 Method 或 Field 对象,然后直接 invoke 或 get/set 是不会有检查的。此外,这个限制也不会阻止访问 Class ,Class.forName 或者在 dalvik 指令访问有隐藏 API 的类都是可以的。可以说这个限制仅阻拦了应用代码以某种形式获取 ArtMethod 或 ArtField 的访问,但并不会在调用时检查。
/** * Gets the unique instance of this class. This is only allowed in * very limited situations. */ publicstatic Unsafe getUnsafe() { Class<?> caller = Reflection.getCallerClass(); /* * Only code on the bootclasspath is allowed to get at the * Unsafe instance. */ ClassLoadercalling= (caller == null) ? null : caller.getClassLoader(); if ((calling != null) && (calling != Unsafe.class.getClassLoader())) { thrownewSecurityException("Unsafe access denied"); }
static hiddenapi::AccessContext GetJniAccessContext(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_){ // Construct AccessContext from the first calling class on stack. // If the calling class cannot be determined, e.g. unattached threads, // we conservatively assume the caller is trusted. ObjPtr<mirror::Class> caller = GetCallingClass(self, /* num_frames= */1); return caller.IsNull() ? hiddenapi::AccessContext(/* is_trusted= */true) : hiddenapi::AccessContext(caller); }
Google 留给开发者的后门。修改系统设置可以在系统范围内给所有进程解除隐藏 API 限制。修改系统设置是不需要 root 的。
解除:
1 2 3
adb shell settings put global hidden_api_policy 1 adb shell settings put global hidden_api_policy_pre_p_apps 1 adb shell settings put global hidden_api_policy_p_apps 1
还原:
1 2 3
adb shell settings delete global hidden_api_policy adb shell settings delete global hidden_api_policy_pre_p_apps adb shell settings delete global hidden_api_policy_p_apps
实质上是让系统服务创建进程的时候改变 runtimeFlags ,关闭隐藏 API 限制。
DexFile.setTrusted
LSPlant 的 MakeDexFileTrusted 可以给某个 dex 解除隐藏 api 限制,其实现是调用 art 内部函数 DexFile::setTrusted 。LSPosed 利用这个方法(1, 2)给自己和模块的 dex 解除限制,因此模块可以正常使用隐藏的 api 。
总结
LSPass 应该是目前功能最为完备的隐藏 api 限制绕过工具了,不仅可以在进程内全局解除 api 限制,也可以在不解除 api 限制的情况下使用隐藏 api ,避免对应用产生影响(LSPatch 的例子)。