问题
unity 版本不同导出函数也有些不同,所以有时候借助导出函数去遍历class或者method就会出问题,但是mscorlib总是有的,也就是说使用反射总是可行的
测试背景
- 这里使用2021.3版本的unity头文件作为示例,具体更多更完整的可以参考 这个git项目
- 环境使用 frida动态调用测试 和 c++静态实现
实现
按照 Perfare大佬的项目 Zygisk-Il2CppDumper 逻辑
- 拿到domain和assemblies
Il2CppDomain* domain = il2cpp_domain_get();
size_t size = 0;
const Il2CppAssembly** assemblies = il2cpp_domain_get_assemblies(domain, &size);
- 我们需要依旧是常规获取 core lib
const Il2CppImage* corlib = il2cpp_get_corlib(); // 拿到 mscorlib
- 然后是常规方式使用导出函数去拿到我们要用到的类方法
// System.Reflection.Assembly → public static Assembly Load(string assemblyString)
// System.Type → public virtual Type[] GetTypes()
Il2CppClass* assemblyClass = il2cpp_class_from_name(corlib, "System.Reflection", "Assembly");
const MethodInfo* assemblyLoad = il2cpp_class_get_method_from_name(assemblyClass, "Load", 1);
const MethodInfo* assemblyGetTypes = il2cpp_class_get_method_from_name(assemblyClass, "GetTypes", 0);
- 两次遍历拿到classtype
foreach assemblies
const Il2CppImage* image = il2cpp_assembly_get_image(assemblies[i]);
const char* image_name = il2cpp_image_get_name(image); // === image->name
Il2CppArray* reflectionTypes = ((Assembly_GetTypes_ftn) assemblyGetTypes->methodPointer)(reflectionAssembly, nullptr)
foreach reflectionTypes
Il2CppClass* klass = il2cpp_class_from_system_type((Il2CppReflectionType *) items[j]);
const Il2CppType* type = il2cpp_class_get_type(klass);
endforeach
endforeach
写了小段代码来验证
- public static Assembly Load(string assemblyString) 返回值为C#中的System.Reflection.Assembly,在内存中实际上为 Il2CppReflectionAssembly*
- public virtual Type[] GetTypes() 返回值为C#中的 System.Type, 实际上为 Il2CppReflectionRuntimeType*
[MI 8::XXX ]-> i()
--------------------------------------------------------------
| List Images { assembly -> image -> classCount -> imageName } |
--------------------------------------------------------------
[*] 0xb637a300 -> 0xc1bdaf10 3 __Generated
[*] 0xb6379080 -> 0xc1bda258 922 Assembly-CSharp
[*] 0xb6379a40 -> 0xc1bda90c 6 Coffee.UIParticle
[*] 0xb6379fc0 -> 0xc1bdacd4 5 DelaunayER
[*] 0xb6379140 -> 0xc1bda2dc 107 EasyRoads3Dv3
[*] 0xb637a000 -> 0xc1bdad00 8 Google.Play.Review
[*] 0xb6379f80 -> 0xc1bdaca8 15 Google.Play.Core
[*] 0xb6379b00 -> 0xc1bda990 12 Google.Play.Common
[*] 0xb6379380 -> 0xc1bda468 85 Mono.Security
[*] 0xb6379000 -> 0xc1bda200 1627 mscorlib
[*] 0xb6379200 -> 0xc1bda360 305 Newtonsoft.Json
...
[MI 8::XXX ]-> callFunction(find_method("mscorlib", "Assembly", "Load", 1), allocUStr("mscorlib"))
"0xc2c9daf0"
[MI 8::XXX ]-> seeHexA(0xc2c9daf0)
0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
c2c9daf0 80 2e b9 c1 00 00 00 00 00 90 37 b6 00 00 00 00 ..........7.....
c2c9db00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c2c9db10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c2c9db20 00 00 00 00 00 00 00 00 00 5f 81 bf 00 00 00 00 ........._......
typedef struct Il2CppReflectionAssembly
{
Il2CppObject object;
const Il2CppAssembly *assembly;
Il2CppObject *resolve_event_holder;
Il2CppObject *evidence;
Il2CppObject *minimum;
Il2CppObject *optional;
Il2CppObject *refuse;
Il2CppObject *granted;
Il2CppObject *denied;
bool from_byte_array;
Il2CppString *name;
} Il2CppReflectionAssembly;
参考上述内容 并结合结构体即可看出Load调用后返回的
*(对比const Il2CppAssembly *assembly的值)*
System.Reflection.Assembly === Il2CppReflectionAssembly*
代码中这个类型 mscorlib.System.Type 是C++中的这个结构体(被强转为这个) Il2CppReflectionType* , 但是实际上它是这个类型 Il2CppReflectionRuntimeType, 是属于 Il2CppReflectionType 的子类,所以这样向上转型也没问题,我这里简单的实现了一个 showTypeParent 来验证这个说法
↓ showTypeParent 的结果 ↓
Object(0xbf2daf60) <--- MemberInfo(0xbf2da920) <--- Type(0xbf2da960) <--- TypeInfo(0xa9a37960) <--- RuntimeType(0xc4224680)
// 参考这两个结构体
// Il2CppReflectionRuntimeType 持有 Il2CppReflectionType 而不是 Il2CppReflectionType*
// 同时补充了一些成员变量,所以这明显就是一个继承关系 ↓
typedef struct Il2CppReflectionType
{
Il2CppObject object;
const Il2CppType *type;
} Il2CppReflectionType;
typedef struct Il2CppReflectionRuntimeType
{
Il2CppReflectionType type;
Il2CppObject* type_info;
Il2CppObject* genericCache;
Il2CppObject* serializationCtor;
} Il2CppReflectionRuntimeType;
typedef struct Il2CppObject
{
union
{
Il2CppClass *klass;
Il2CppVTable *vtable;
};
MonitorData *monitor;
} Il2CppObject;
- 根据目前的信息已经拿到了
这两个类下的方法很多相似的基本就类似于没有复写的虚函数
il2cpp:0115D224 System.Type$$.ctor ; CODE XREF: il2cpp:01058D80↑p
il2cpp:0115D224 ; __unwind {
il2cpp:0115D224 00 10 A0 E3 MOV R1, #0
il2cpp:0115D228 D6 DB FB EA B System.Reflection.MemberInfo$$.ctor
il2cpp:0115D234 System.Type$$GetType
il2cpp:0115D234 00 10 A0 E3 MOV R1, #0
il2cpp:0115D238 10 E8 00 EA B System.Object$$GetType
il2cpp:0115D234 System.Type$$GetType ; CODE XREF: il2cpp:01021D24↑p
il2cpp:0115D234 ; il2cpp:0116F408↓p
il2cpp:0115D234 00 10 A0 E3 MOV R1, #0
il2cpp:0115D238 10 E8 00 EA B System.Object$$GetType
再看看一个比较常使用的方法
public virtual bool get_IsEnum() @ 0x115D9A0