diff --git a/O&Z_IL2CPP_Security/JsonManager.cs b/O&Z_IL2CPP_Security/JsonManager.cs
index 1ffbfde..e1e8466 100644
--- a/O&Z_IL2CPP_Security/JsonManager.cs
+++ b/O&Z_IL2CPP_Security/JsonManager.cs
@@ -19,11 +19,13 @@ public class ObfusConfig
         public int NumObfus { get; set; }
         public int LocalVariables2Field { get; set; }
         public int StrCrypter { get; set; }
+        public int Obfusfunc { get; set; }
     }
     public class JsonManager
     {
         public JsonIndex index;
         public string path;
+        public static string origin = "ewogICAgImtleSI6MTE0NTE0LAogICAgIlZlcnNpb24iOiIyNC40IiwKICAgICIvLyI6IuaUr+aMgTI4IDI0LjQiLAogICAgIk9iZnVzIjoKICAgIHsKICAgICAgICAiQ29udHJvbEZsb3ciOjEsCiAgICAgICAgIk51bU9iZnVzIjoxLAogICAgICAgICJMb2NhbFZhcmlhYmxlczJGaWVsZCI6MSwKICAgICAgICAiU3RyQ3J5cHRlciI6MSwKICAgICAgICAiT2JmdXNmdW5jIjoxLAogICAgICAgICIvLyI6IjA95YWz6ZetIDE95byA5ZCvIiwKICAgICAgICAiLy8iOiJDb250cm9sRmxvd++8muaOp+WItua1geeoi+a3t+a3hiIsCiAgICAgICAgIi8vIjoiTnVtT2JmdXPvvJrmlbDlrZfmt7fmt4YiLAogICAgICAgICIvLyI6IkxvY2FsVmFyaWFibGVzMkZpZWxk77ya5bGA6YOo5Y+Y6YeP6L2s5o2i5Li65a2X5q61IiwKICAgICAgICAiLy8iOiJTdHJDcnlwdGVy77ya5a2X56ym5Liy5Yqg5a+GIiwKICAgICAgICAiLy8iOiJPYmZ1c2Z1bmPvvJroh6rlrprkuYnmt7fmt4bnsbvlkozmlrnms5XlkI3np7As5Y+v5Lul5Zyoa2V5ZnVuY+S4reiHquWumuS5iea3t+a3huaooeW8jyjlpoLnlKjliLDkuoblj43lsITnrYnnsbvlnospIgoKICAgIH0KfQ==";
         public JsonManager(string _path)
         {
             path = _path;
diff --git a/O&Z_IL2CPP_Security/Progarm.cs b/O&Z_IL2CPP_Security/Progarm.cs
index 860fac9..ed5271a 100644
--- a/O&Z_IL2CPP_Security/Progarm.cs
+++ b/O&Z_IL2CPP_Security/Progarm.cs
@@ -16,22 +16,13 @@
 Console.WriteLine("O&Z_IL2CPP_Security");
 if (!File.Exists("Config.json"))
 {
+    Console.ForegroundColor = ConsoleColor.Red;
     Console.WriteLine("Config.json not found!");
-    Console.WriteLine("正在生成默认配置文件...");
-    JsonIndex index = new JsonIndex()
-    {
-        key = 114514,
-        Version = "24.4",
-        Obfus = new ObfusConfig()
-        {
-            ControlFlow = 1,
-            NumObfus = 1,
-            LocalVariables2Field = 1,
-            StrCrypter = 1
-        }
-    };
-    File.WriteAllText("Config.json", JsonMapper.ToJson(index));
+    Console.ForegroundColor = ConsoleColor.Yellow;
+    Console.WriteLine("正在生成默认配置文件..."); 
+    File.WriteAllBytes("Config.json", Convert.FromBase64String(JsonManager.origin));
     if (File.Exists("Config.json")) Console.WriteLine("已重新生成默认配置文件...\nDone!");
+    Console.ForegroundColor = ConsoleColor.White;
 }
 if (args.Length == 0)
 {
@@ -193,7 +184,10 @@ bool CheckMetadataFile()
 }
 void _Test()
 {
-    Console.WriteLine(XXTEA.EncryptToBase64String("HelloWorld", "123456"));
+    AssemblyLoader loader = new AssemblyLoader(OpenFilePath);
+    ObfusFunc obfusFunc = new ObfusFunc(loader.Module);
+    obfusFunc.Excute();
+    loader.Save();
 }
 void CheckVersion()
 {
@@ -220,6 +214,11 @@ void MonoObfus()
         ControlFlow controlFlow = new ControlFlow(loader.Module);
         controlFlow.Execute();
     }
+    if (jsonManager.index.Obfus.Obfusfunc == 1)
+    {
+        ObfusFunc obfusFunc = new ObfusFunc(loader.Module);
+        obfusFunc.Excute();
+    }
     if (jsonManager.index.Obfus.NumObfus == 1)
     {
         NumObfus numObfus = new NumObfus(loader.Module);
diff --git a/O&Z_IL2CPP_Security/Properties/launchSettings.json b/O&Z_IL2CPP_Security/Properties/launchSettings.json
index 4b7c6ef..747e55d 100644
--- a/O&Z_IL2CPP_Security/Properties/launchSettings.json
+++ b/O&Z_IL2CPP_Security/Properties/launchSettings.json
@@ -10,7 +10,7 @@
     },
     "Test": {
       "commandName": "Project",
-      "commandLineArgs": "\"global-metadata.dat\" Test"
+      "commandLineArgs": "\"C:\\Users\\22864\\Desktop\\2019Testbuild\\O&Z_2019_4_32_f1_Data\\Managed\\Assembly-CSharp - 副本.dll\" Test"
     },
     "Generate": {
       "commandName": "Project",
@@ -18,7 +18,7 @@
     },
     "Obfus": {
       "commandName": "Project",
-      "commandLineArgs": "\"C:\\Users\\22864\\Desktop\\END_AUTO V2\\END_Data\\Managed\\Assembly-CSharp.dll.bak\" MonoObfus"
+      "commandLineArgs": "\"C:\\Users\\22864\\Desktop\\2019Testbuild\\O&Z_2019_4_32_f1_Data\\Managed\\Assembly-CSharp - 副本.dll\" MonoObfus"
     }
   }
 }
\ No newline at end of file
diff --git a/O&Z_IL2CPP_Security/resource/Config.json b/O&Z_IL2CPP_Security/resource/Config.json
new file mode 100644
index 0000000..62c7848
--- /dev/null
+++ b/O&Z_IL2CPP_Security/resource/Config.json
@@ -0,0 +1,19 @@
+{
+    "key":114514,
+    "Version":"24.4",
+    "//":"支持28 24.4",
+    "Obfus":
+    {
+        "ControlFlow":1,
+        "NumObfus":1,
+        "LocalVariables2Field":1,
+        "StrCrypter":1,
+        "StrObfus":1,
+        "//":"0=关闭 1=开启",
+        "//":"ControlFlow:控制流程混淆",
+        "//":"NumObfus:数字混淆",
+        "//":"LocalVariables2Field:局部变量转换为字段",
+        "//":"StrCrypter:字符串加密",
+        "//":"StrObfus:方法加密混淆,可以在keyfunc中添加自定义需要排除的方法(如用到了反射等类型)"
+    }
+}
\ No newline at end of file
diff --git a/O&Z_IL2CPP_Security/resource/keyfunc.json b/O&Z_IL2CPP_Security/resource/keyfunc.json
new file mode 100644
index 0000000..7494ca9
--- /dev/null
+++ b/O&Z_IL2CPP_Security/resource/keyfunc.json
@@ -0,0 +1,126 @@
+{
+    "ignoreMethod": [
+        "Awake",
+        "OnEnable",
+        "Start",
+        "FixedUpdate",
+        "Update",
+        "OnDisable",
+        "LateUpdate",
+        "Reset",
+        "OnValidate",
+        "FixedUpdate",
+        "OnTriggerEnter",
+        "OnTriggerEnter2D",
+        "OnTriggerExit",
+        "OnTriggerExit2D",
+        "OnTriggerStay2D",
+        "OnCollisionEnter",
+        "OnCollisionEnter2D",
+        "OnCollisionExit",
+        "OnCollisionExit2D",
+        "OnCollisionStay",
+        "OnCollisionStay2D",
+        "OnMouseDown",
+        "OnMouseDrag",
+        "OnMouseEnter",
+        "OnMouseExit",
+        "OnMouseOver",
+        "OnMouseUp",
+        "OnMouseUpAsButton",
+        "OnPreCull",
+        "OnBecameVisible",
+        "OnBecameInvisible",
+        "OnWillRenderObject",
+        "OnPreRender",
+        "OnRenderObject",
+        "OnPostRender",
+        "OnRenderImage",
+        "OnGUI",
+        "OnDrawGizmos",
+        "OnDrawGizmosSelected",
+        "OnApplicationFocus",
+        "OnApplicationPause",
+        "OnApplicationQuit",
+        "OnDisable",
+        "OnDestory",
+        "OnLevelWasLoaded",
+        "OnAnimatorIK",
+        "OnAnimatorMove",
+        "OnApplicationFocus",
+        "OnApplicationPause",
+        "OnApplicationQuit",
+        "OnAudioFilterRead",
+        "OnBecameInvisible",
+        "OnBecameVisible",
+        "OnConnectedToServer",
+        "OnControllerColliderHit",
+        "OnEnable",
+        "OnFailedToConnect",
+        "OnDisconnectedFromServer",
+        "OnDrawGizmos",
+        "OnDrawGizmosSelected",
+        "OnEnable",
+        "OnFailedToConnect",
+        "OnFailedToConnectToMasterServer",
+        "OnJointBreak",
+        "OnJointBreak2D",
+        "OnMasterServerEvent",
+        "OnNetworkInstantiate",
+        "OnParticleCollision",
+        "OnParticleSystemStopped",
+        "OnParticleTrigger",
+        "OnParticleUpdateJobScheduled",
+        "OnPlayerConnected",
+        "OnPlayerDisconnected",
+        "OnPostRender",
+        "OnPreCull",
+        "OnPreRender",
+        "OnRenderImage",
+        "OnRenderObject",
+        "OnSerializeNetworkView",
+        "OnServerInitialized",
+        "OnTransformChildrenChanged",
+        "OnTransformParentChanged",
+        "OnValidate",
+        "OnWillRenderObject",
+        "Reset",
+        "__",
+        "incontrol",
+        "stop",
+        "option",
+        "pausemanager",
+        "fallingrock",
+        "postfix",
+        "prefix",
+        "transpiler"
+    ],
+    "ignoreField":[
+        "incontrol",
+        "enum",
+        "optional",
+        "__"
+    ],
+    "//":"以上为默认忽略列表,默认包含全部的Unity关键方法,建议不要修改,以下为自定义忽略列表,可以根据需要自行添加(如果需要用到反射或者动态调用的方法,建议添加到这里))",
+
+    "//":"关于如何是使用自定义忽略列表,这里有几点建议",
+    "//":"1.在Unity中,GameObject或者prefabs初始绑定了脚本,则该脚本的类名不可混淆,方法名和字段名可以混淆",
+    "//":"2.在Unity中,GameObject或者prefabs初始没有绑定脚本,但是在代码中动态添加了脚本,则该脚本的类名、方法名和字段名都可以混淆",
+    "//":"3.如果该脚本中涉及到了UI的事件响应(如Button.OnClick),则该脚本的类名和该方法名都不可混淆,字段名可以混淆",
+    "//":"4.Unity的生命周期方法和回调方法不能混淆,上方的忽略列表包含了大多数常用的生命周期和回调方法,如果有遗漏,可以自行添加",
+    "//":"5.Unity中的Invoke等特殊方法所调用的函数方法不可混淆,同理协程类的方法也不可混淆,请自行添加到自定义忽略列表",
+    "//":"6.部分涉及反射类的代码不能混淆,如System.Reflection(GetField,GetMethod,Invoke等),请自行添加到自定义忽略列表",
+    "//":"7.Native层里直接调用C#或通过Unity内置API发送事件到C#的类和方法不可混淆(大多数在移动平台中)",
+    "//":"8.一些特殊插件对应的脚本不可混淆,例如xLua和与之绑定的C#脚本",
+
+    
+    "//":"对于方法名的混淆采用的是白名单模式,即默认混淆,如果不需要混淆,可以添加到这里",
+    "customignoreMethod":[
+    ],
+    "//":"对于字段名的混淆采用的是白名单模式,即默认混淆,如果不需要混淆,可以添加到这里",
+    "customignoreField":[
+    ],
+    "//":"对于类名的混淆采用的是黑名单模式,即默认不混淆,如果需要混淆,可以添加到这里",
+    "customignoreClass":[
+    ]
+}
\ No newline at end of file
diff --git a/O&Z_IL2CPP_Security/resource/src-res/24.4/MetadataCache.cpp b/O&Z_IL2CPP_Security/resource/src-res/24.4/MetadataCache.cpp
new file mode 100644
index 0000000..933dca0
--- /dev/null
+++ b/O&Z_IL2CPP_Security/resource/src-res/24.4/MetadataCache.cpp
@@ -0,0 +1,1725 @@
+#include "il2cpp-config.h"
+#include "MetadataCache.h"
+
+#include <map>
+#include <limits>
+#include "il2cpp-class-internals.h"
+#include "il2cpp-tabledefs.h"
+#include "il2cpp-runtime-stats.h"
+#include "gc/GarbageCollector.h"
+#include "metadata/ArrayMetadata.h"
+#include "metadata/GenericMetadata.h"
+#include "metadata/GenericMethod.h"
+#include "metadata/Il2CppTypeCompare.h"
+#include "metadata/Il2CppTypeHash.h"
+#include "metadata/Il2CppTypeVector.h"
+#include "metadata/Il2CppGenericContextCompare.h"
+#include "metadata/Il2CppGenericContextHash.h"
+#include "metadata/Il2CppGenericInstCompare.h"
+#include "metadata/Il2CppGenericInstHash.h"
+#include "metadata/Il2CppGenericMethodCompare.h"
+#include "metadata/Il2CppGenericMethodHash.h"
+#include "metadata/Il2CppSignatureCompare.h"
+#include "metadata/Il2CppSignatureHash.h"
+#include "os/Atomic.h"
+#include "os/Mutex.h"
+#include "utils/CallOnce.h"
+#include "utils/Collections.h"
+#include "utils/HashUtils.h"
+#include "utils/Il2CppHashMap.h"
+#include "utils/Il2CppHashSet.h"
+#include "utils/Memory.h"
+#include "utils/StringUtils.h"
+#include "utils/PathUtils.h"
+#include "vm/Assembly.h"
+#include "vm/Class.h"
+#include "vm/ClassInlines.h"
+#include "vm/GenericClass.h"
+#include "vm/MetadataAlloc.h"
+#include "vm/MetadataLoader.h"
+#include "vm/MetadataLock.h"
+#include "vm/Method.h"
+#include "vm/Object.h"
+#include "vm/String.h"
+#include "vm/Type.h"
+#include "mono-runtime/il2cpp-mapping.h"
+#include "vm-utils/NativeSymbol.h"
+#include "vm-utils/VmStringUtils.h"
+#include "vm/xxtea.h"
+typedef std::map<Il2CppClass*, Il2CppClass*> PointerTypeMap;
+typedef Il2CppHashMap<const char*, Il2CppClass*, il2cpp::utils::StringUtils::StringHasher<const char*>, il2cpp::utils::VmStringUtils::CaseSensitiveComparer> WindowsRuntimeTypeNameToClassMap;
+typedef Il2CppHashMap<const Il2CppClass*, const char*, il2cpp::utils::PointerHash<Il2CppClass> > ClassToWindowsRuntimeTypeNameMap;
+
+typedef Il2CppHashSet<const Il2CppGenericMethod*, il2cpp::metadata::Il2CppGenericMethodHash, il2cpp::metadata::Il2CppGenericMethodCompare> Il2CppGenericMethodSet;
+typedef Il2CppGenericMethodSet::const_iterator Il2CppGenericMethodSetIter;
+static Il2CppGenericMethodSet s_GenericMethodSet;
+
+struct Il2CppMetadataCache
+{
+    il2cpp::os::FastMutex m_CacheMutex;
+    PointerTypeMap m_PointerTypes;
+};
+
+static Il2CppMetadataCache s_MetadataCache;
+static Il2CppClass** s_TypeInfoTable = NULL;
+static Il2CppClass** s_TypeInfoDefinitionTable = NULL;
+static const MethodInfo** s_MethodInfoDefinitionTable = NULL;
+static Il2CppString** s_StringLiteralTable = NULL;
+static const Il2CppGenericMethod** s_GenericMethodTable = NULL;
+static int32_t s_ImagesCount = 0;
+static Il2CppImage* s_ImagesTable = NULL;
+static int32_t s_AssembliesCount = 0;
+static Il2CppAssembly* s_AssembliesTable = NULL;
+
+
+typedef Il2CppHashSet<const Il2CppGenericInst*, il2cpp::metadata::Il2CppGenericInstHash, il2cpp::metadata::Il2CppGenericInstCompare> Il2CppGenericInstSet;
+static Il2CppGenericInstSet s_GenericInstSet;
+
+typedef Il2CppHashMap<const Il2CppGenericMethod*, const Il2CppGenericMethodIndices*, il2cpp::metadata::Il2CppGenericMethodHash, il2cpp::metadata::Il2CppGenericMethodCompare> Il2CppMethodTableMap;
+typedef Il2CppMethodTableMap::const_iterator Il2CppMethodTableMapIter;
+static Il2CppMethodTableMap s_MethodTableMap;
+
+typedef Il2CppHashMap<il2cpp::utils::dynamic_array<const Il2CppType*>, Il2CppMethodPointer, il2cpp::metadata::Il2CppSignatureHash, il2cpp::metadata::Il2CppSignatureCompare> Il2CppUnresolvedSignatureMap;
+typedef Il2CppUnresolvedSignatureMap::const_iterator Il2CppUnresolvedSignatureMapIter;
+static Il2CppUnresolvedSignatureMap *s_pUnresolvedSignatureMap;
+
+typedef Il2CppHashMap<FieldInfo*, int32_t, il2cpp::utils::PointerHash<FieldInfo> > Il2CppThreadLocalStaticOffsetHashMap;
+typedef Il2CppThreadLocalStaticOffsetHashMap::iterator Il2CppThreadLocalStaticOffsetHashMapIter;
+static Il2CppThreadLocalStaticOffsetHashMap s_ThreadLocalStaticOffsetMap;
+
+static const Il2CppCodeRegistration * s_Il2CppCodeRegistration;
+static const Il2CppMetadataRegistration * s_Il2CppMetadataRegistration;
+static const Il2CppCodeGenOptions* s_Il2CppCodeGenOptions;
+static CustomAttributesCache** s_CustomAttributesCaches;
+
+static WindowsRuntimeTypeNameToClassMap s_WindowsRuntimeTypeNameToClassMap;
+static ClassToWindowsRuntimeTypeNameMap s_ClassToWindowsRuntimeTypeNameMap;
+
+struct InteropDataToTypeConverter
+{
+    inline const Il2CppType* operator()(const Il2CppInteropData& interopData) const
+    {
+        return interopData.type;
+    }
+};
+
+typedef il2cpp::utils::collections::ArrayValueMap<const Il2CppType*, Il2CppInteropData, InteropDataToTypeConverter, il2cpp::metadata::Il2CppTypeLess, il2cpp::metadata::Il2CppTypeEqualityComparer> InteropDataMap;
+static InteropDataMap s_InteropData;
+
+struct WindowsRuntimeFactoryTableEntryToTypeConverter
+{
+    inline const Il2CppType* operator()(const Il2CppWindowsRuntimeFactoryTableEntry& entry) const
+    {
+        return entry.type;
+    }
+};
+
+typedef il2cpp::utils::collections::ArrayValueMap<const Il2CppType*, Il2CppWindowsRuntimeFactoryTableEntry, WindowsRuntimeFactoryTableEntryToTypeConverter, il2cpp::metadata::Il2CppTypeLess, il2cpp::metadata::Il2CppTypeEqualityComparer> WindowsRuntimeFactoryTable;
+static WindowsRuntimeFactoryTable s_WindowsRuntimeFactories;
+
+template<typename K, typename V>
+struct PairToKeyConverter
+{
+    inline const K& operator()(const std::pair<K, V>& pair) const
+    {
+        return pair.first;
+    }
+};
+
+typedef il2cpp::utils::collections::ArrayValueMap<const Il2CppGuid*, std::pair<const Il2CppGuid*, Il2CppClass*>, PairToKeyConverter<const Il2CppGuid*, Il2CppClass*> > GuidToClassMap;
+static GuidToClassMap s_GuidToNonImportClassMap;
+
+template<typename T>
+static T MetadataOffset(void* metadata, size_t sectionOffset, size_t itemIndex)
+{
+    return reinterpret_cast<T>(reinterpret_cast<uint8_t*>(metadata) + sectionOffset) + itemIndex;
+}
+
+void il2cpp::vm::MetadataCache::Register(const Il2CppCodeRegistration* const codeRegistration, const Il2CppMetadataRegistration* const metadataRegistration, const Il2CppCodeGenOptions* const codeGenOptions)
+{
+    s_Il2CppCodeRegistration = codeRegistration;
+    s_Il2CppMetadataRegistration = metadataRegistration;
+    s_Il2CppCodeGenOptions = codeGenOptions;
+
+    for (int32_t j = 0; j < metadataRegistration->genericClassesCount; j++)
+        if (metadataRegistration->genericClasses[j]->typeDefinitionIndex != kTypeIndexInvalid)
+            il2cpp::metadata::GenericMetadata::RegisterGenericClass(metadataRegistration->genericClasses[j]);
+
+    for (int32_t i = 0; i < metadataRegistration->genericInstsCount; i++)
+        s_GenericInstSet.insert(metadataRegistration->genericInsts[i]);
+
+    s_InteropData.assign_external(codeRegistration->interopData, codeRegistration->interopDataCount);
+    s_WindowsRuntimeFactories.assign_external(codeRegistration->windowsRuntimeFactoryTable, codeRegistration->windowsRuntimeFactoryCount);
+}
+
+static void* s_GlobalMetadata;
+static const Il2CppGlobalMetadataHeader* s_GlobalMetadataHeader;
+static const FrontHeader* frontHeader;
+bool il2cpp::vm::MetadataCache::Initialize()
+{
+    char _metadataName[19] = {53,62,61,48,51,62,127,63,55,38,51,54,51,38,51,124,54,51,38}; //global-metadata.dat
+    for(int i=0;i<strlen(_metadataName);i++)
+    {
+        _metadataName[i] ^= 114514;
+    }
+    s_GlobalMetadata = vm::MetadataLoader::LoadMetadataFile(_metadataName);
+    if (!s_GlobalMetadata)
+        return false;
+
+    il2cpp::metadata::GenericMetadata::SetMaximumRuntimeGenericDepth(s_Il2CppCodeGenOptions->maximumRuntimeGenericDepth);
+    //还原头部
+    frontHeader = (FrontHeader *)s_GlobalMetadata;
+    char *Headerdata = (char *)malloc(frontHeader->legnth);
+    size_t Headerlen;
+    memcpy(Headerdata, (char*)s_GlobalMetadata + frontHeader->offset, frontHeader->legnth);
+    char *Header = (char *)xxtea_decrypt(Headerdata, frontHeader->legnth, frontHeader->key, &Headerlen);
+    s_GlobalMetadataHeader = (const Il2CppGlobalMetadataHeader*)Header;
+
+    //s_GlobalMetadataHeader = (const Il2CppGlobalMetadataHeader*)s_GlobalMetadata;
+
+    IL2CPP_ASSERT(s_GlobalMetadataHeader->sanity == 0xFAB11BAF);
+    IL2CPP_ASSERT(s_GlobalMetadataHeader->version == 24);
+
+    // Pre-allocate these arrays so we don't need to lock when reading later.
+    // These arrays hold the runtime metadata representation for metadata explicitly
+    // referenced during conversion. There is a corresponding table of same size
+    // in the converted metadata, giving a description of runtime metadata to construct.
+    s_TypeInfoTable = (Il2CppClass**)IL2CPP_CALLOC(s_Il2CppMetadataRegistration->typesCount, sizeof(Il2CppClass*));
+    s_TypeInfoDefinitionTable = (Il2CppClass**)IL2CPP_CALLOC(s_GlobalMetadataHeader->typeDefinitionsCount / sizeof(Il2CppTypeDefinition), sizeof(Il2CppClass*));
+    s_MethodInfoDefinitionTable = (const MethodInfo**)IL2CPP_CALLOC(s_GlobalMetadataHeader->methodsCount / sizeof(Il2CppMethodDefinition), sizeof(MethodInfo*));
+    s_GenericMethodTable = (const Il2CppGenericMethod**)IL2CPP_CALLOC(s_Il2CppMetadataRegistration->methodSpecsCount, sizeof(Il2CppGenericMethod*));
+    s_ImagesCount = s_GlobalMetadataHeader->imagesCount / sizeof(Il2CppImageDefinition);
+    s_ImagesTable = (Il2CppImage*)IL2CPP_CALLOC(s_ImagesCount, sizeof(Il2CppImage));
+    s_AssembliesCount = s_GlobalMetadataHeader->assembliesCount / sizeof(Il2CppAssemblyDefinition);
+    s_AssembliesTable = (Il2CppAssembly*)IL2CPP_CALLOC(s_AssembliesCount, sizeof(Il2CppAssembly));
+    // setup all the Il2CppImages. There are not many and it avoid locks later on
+    const Il2CppImageDefinition* imagesDefinitions = (const Il2CppImageDefinition*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->imagesOffset);
+    for (int32_t imageIndex = 0; imageIndex < s_ImagesCount; imageIndex++)
+    {
+        const Il2CppImageDefinition* imageDefinition = imagesDefinitions + imageIndex;
+        Il2CppImage* image = s_ImagesTable + imageIndex;
+        image->name = GetStringFromIndex(imageDefinition->nameIndex);
+
+        std::string nameNoExt = il2cpp::utils::PathUtils::PathNoExtension(image->name);
+        image->nameNoExt = (char*)IL2CPP_CALLOC(nameNoExt.size() + 1, sizeof(char));
+        strcpy(const_cast<char*>(image->nameNoExt), nameNoExt.c_str());
+
+        image->assembly = const_cast<Il2CppAssembly*>(GetAssemblyFromIndex(imageDefinition->assemblyIndex));
+        image->typeStart = imageDefinition->typeStart;
+        image->typeCount = imageDefinition->typeCount;
+        image->exportedTypeStart = imageDefinition->exportedTypeStart;
+        image->exportedTypeCount = imageDefinition->exportedTypeCount;
+        image->entryPointIndex = imageDefinition->entryPointIndex;
+        image->token = imageDefinition->token;
+        image->customAttributeStart = imageDefinition->customAttributeStart;
+        image->customAttributeCount = imageDefinition->customAttributeCount;
+        for (uint32_t codeGenModuleIndex = 0; codeGenModuleIndex < s_Il2CppCodeRegistration->codeGenModulesCount; ++codeGenModuleIndex)
+        {
+            if (strcmp(image->name, s_Il2CppCodeRegistration->codeGenModules[codeGenModuleIndex]->moduleName) == 0)
+                image->codeGenModule = s_Il2CppCodeRegistration->codeGenModules[codeGenModuleIndex];
+        }
+        IL2CPP_ASSERT(image->codeGenModule);
+        image->dynamic = false;
+    }
+
+    // setup all the Il2CppAssemblies.
+    const Il2CppAssemblyDefinition* assemblyDefinitions = (const Il2CppAssemblyDefinition*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->assembliesOffset);
+    for (int32_t assemblyIndex = 0; assemblyIndex < s_ImagesCount; assemblyIndex++)
+    {
+        const Il2CppAssemblyDefinition* assemblyDefinition = assemblyDefinitions + assemblyIndex;
+        Il2CppAssembly* assembly = s_AssembliesTable + assemblyIndex;
+
+        assembly->image = il2cpp::vm::MetadataCache::GetImageFromIndex(assemblyDefinition->imageIndex);
+        assembly->token = assemblyDefinition->token;
+        assembly->referencedAssemblyStart = assemblyDefinition->referencedAssemblyStart;
+        assembly->referencedAssemblyCount = assemblyDefinition->referencedAssemblyCount;
+
+        Il2CppAssemblyName* assemblyName = &assembly->aname;
+        const Il2CppAssemblyNameDefinition* assemblyNameDefinition = &assemblyDefinition->aname;
+
+        assemblyName->name = GetStringFromIndex(assemblyNameDefinition->nameIndex);
+        assemblyName->culture = GetStringFromIndex(assemblyNameDefinition->cultureIndex);
+        assemblyName->public_key = (const uint8_t*)GetStringFromIndex(assemblyNameDefinition->publicKeyIndex);
+        assemblyName->hash_alg = assemblyNameDefinition->hash_alg;
+        assemblyName->hash_len = assemblyNameDefinition->hash_len;
+        assemblyName->flags = assemblyNameDefinition->flags;
+        assemblyName->major = assemblyNameDefinition->major;
+        assemblyName->minor = assemblyNameDefinition->minor;
+        assemblyName->build = assemblyNameDefinition->build;
+        assemblyName->revision = assemblyNameDefinition->revision;
+        memcpy(assemblyName->public_key_token, assemblyNameDefinition->public_key_token, sizeof(assemblyNameDefinition->public_key_token));
+
+        il2cpp::vm::Assembly::Register(assembly);
+    }
+
+    InitializeUnresolvedSignatureTable();
+
+#if IL2CPP_ENABLE_NATIVE_STACKTRACES
+    std::vector<MethodDefinitionKey> managedMethods;
+
+
+    const Il2CppTypeDefinition* typeDefinitions = (const Il2CppTypeDefinition*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->typeDefinitionsOffset);
+    for (int32_t i = 0; i < s_AssembliesCount; i++)
+    {
+        const Il2CppImage* image = s_AssembliesTable[i].image;
+
+        for (size_t j = 0; j < image->typeCount; j++)
+        {
+            const Il2CppTypeDefinition* type = typeDefinitions + image->typeStart + j;
+
+            for (uint16_t u = 0; u < type->method_count; u++)
+            {
+                const Il2CppMethodDefinition* methodDefinition = GetMethodDefinitionFromIndex(type->methodStart + u);
+                MethodDefinitionKey currentMethodList;
+                currentMethodList.methodIndex = type->methodStart + u;
+                currentMethodList.method = GetMethodPointer(image, methodDefinition->token);
+                if (currentMethodList.method)
+                    managedMethods.push_back(currentMethodList);
+            }
+        }
+    }
+
+    for (int32_t i = 0; i < s_Il2CppMetadataRegistration->genericMethodTableCount; i++)
+    {
+        const Il2CppGenericMethodFunctionsDefinitions* genericMethodIndices = s_Il2CppMetadataRegistration->genericMethodTable + i;
+
+        MethodDefinitionKey currentMethodList;
+
+        GenericMethodIndex genericMethodIndex = genericMethodIndices->genericMethodIndex;
+
+        IL2CPP_ASSERT(genericMethodIndex < s_Il2CppMetadataRegistration->methodSpecsCount);
+        const Il2CppMethodSpec* methodSpec = s_Il2CppMetadataRegistration->methodSpecs + genericMethodIndex;
+
+        currentMethodList.methodIndex = methodSpec->methodDefinitionIndex;
+
+        IL2CPP_ASSERT(genericMethodIndices->indices.methodIndex < static_cast<int32_t>(s_Il2CppCodeRegistration->genericMethodPointersCount));
+        currentMethodList.method = s_Il2CppCodeRegistration->genericMethodPointers[genericMethodIndices->indices.methodIndex];
+
+        managedMethods.push_back(currentMethodList);
+    }
+
+    il2cpp::utils::NativeSymbol::RegisterMethods(managedMethods);
+#endif
+    return true;
+}
+void il2cpp::vm::MetadataCache::InitializeStringLiteralTable()
+{
+    s_StringLiteralTable = (Il2CppString**)il2cpp::gc::GarbageCollector::AllocateFixed(s_GlobalMetadataHeader->stringLiteralCount / sizeof(Il2CppStringLiteral) * sizeof(Il2CppString*), NULL);
+}
+
+void il2cpp::vm::MetadataCache::InitializeGenericMethodTable()
+{
+    for (int32_t i = 0; i < s_Il2CppMetadataRegistration->genericMethodTableCount; i++)
+    {
+        const Il2CppGenericMethodFunctionsDefinitions* genericMethodIndices = s_Il2CppMetadataRegistration->genericMethodTable + i;
+        const Il2CppGenericMethod* genericMethod = GetGenericMethodFromIndex(genericMethodIndices->genericMethodIndex);
+        s_MethodTableMap.insert(std::make_pair(genericMethod, &genericMethodIndices->indices));
+    }
+}
+
+void il2cpp::vm::MetadataCache::InitializeWindowsRuntimeTypeNamesTables()
+{
+    int32_t typeCount = s_GlobalMetadataHeader->windowsRuntimeTypeNamesSize / sizeof(Il2CppWindowsRuntimeTypeNamePair);
+    const Il2CppWindowsRuntimeTypeNamePair* windowsRuntimeTypeNames = MetadataOffset<Il2CppWindowsRuntimeTypeNamePair*>(s_GlobalMetadata, s_GlobalMetadataHeader->windowsRuntimeTypeNamesOffset, 0);
+
+    for (int32_t i = 0; i < typeCount; i++)
+    {
+        Il2CppWindowsRuntimeTypeNamePair typeNamePair = windowsRuntimeTypeNames[i];
+        const char* name = GetStringFromIndex(typeNamePair.nameIndex);
+        const Il2CppType* type = GetIl2CppTypeFromIndex(typeNamePair.typeIndex);
+        Il2CppClass* klass = il2cpp::vm::Class::FromIl2CppType(type);
+
+        if (!Class::IsNullable(klass))
+        {
+            // Don't add nullable types to name -> klass map because IReference`1<T> and Nullable`1<T>
+            // share windows runtime type names, and that would cause a collision.
+            s_WindowsRuntimeTypeNameToClassMap.insert(std::make_pair(name, klass));
+        }
+
+        s_ClassToWindowsRuntimeTypeNameMap.insert(std::make_pair(klass, name));
+    }
+}
+
+void il2cpp::vm::MetadataCache::InitializeGuidToClassTable()
+{
+    Il2CppInteropData* interopData = s_Il2CppCodeRegistration->interopData;
+    uint32_t interopDataCount = s_Il2CppCodeRegistration->interopDataCount;
+    std::vector<std::pair<const Il2CppGuid*, Il2CppClass*> > guidToNonImportClassMap;
+    guidToNonImportClassMap.reserve(interopDataCount);
+
+    for (uint32_t i = 0; i < interopDataCount; i++)
+    {
+        // It's important to check for non-import types because type projections will have identical GUIDs (e.g. IEnumerable<T> and IIterable<T>)
+        if (interopData[i].guid != NULL)
+        {
+            Il2CppClass* klass = Class::FromIl2CppType(interopData[i].type);
+            if (!klass->is_import_or_windows_runtime)
+                guidToNonImportClassMap.push_back(std::make_pair(interopData[i].guid, klass));
+        }
+    }
+
+    s_GuidToNonImportClassMap.assign(guidToNonImportClassMap);
+}
+
+// this is called later in the intialization cycle with more systems setup like GC
+void il2cpp::vm::MetadataCache::InitializeGCSafe()
+{
+    InitializeStringLiteralTable();
+    InitializeGenericMethodTable();
+    InitializeWindowsRuntimeTypeNamesTables();
+    InitializeGuidToClassTable();
+}
+
+void il2cpp::vm::MetadataCache::InitializeUnresolvedSignatureTable()
+{
+    s_pUnresolvedSignatureMap = new Il2CppUnresolvedSignatureMap();
+
+    for (uint32_t i = 0; i < s_Il2CppCodeRegistration->unresolvedVirtualCallCount; ++i)
+    {
+        const Il2CppRange* range = MetadataOffset<Il2CppRange*>(s_GlobalMetadata, s_GlobalMetadataHeader->unresolvedVirtualCallParameterRangesOffset, i);
+        il2cpp::utils::dynamic_array<const Il2CppType*> signature;
+
+        for (int j = 0; j < range->length; ++j)
+        {
+            TypeIndex typeIndex = *MetadataOffset<TypeIndex*>(s_GlobalMetadata, s_GlobalMetadataHeader->unresolvedVirtualCallParameterTypesOffset, range->start + j);
+            const Il2CppType* type = il2cpp::vm::MetadataCache::GetIl2CppTypeFromIndex(typeIndex);
+            signature.push_back(type);
+        }
+
+        (*s_pUnresolvedSignatureMap)[signature] = s_Il2CppCodeRegistration->unresolvedVirtualCallPointers[i];
+    }
+}
+
+Il2CppClass* il2cpp::vm::MetadataCache::GetGenericInstanceType(Il2CppClass* genericTypeDefinition, const il2cpp::metadata::Il2CppTypeVector& genericArgumentTypes)
+{
+    const Il2CppGenericInst* inst = il2cpp::vm::MetadataCache::GetGenericInst(genericArgumentTypes);
+    Il2CppGenericClass* genericClass = il2cpp::metadata::GenericMetadata::GetGenericClass(genericTypeDefinition, inst);
+    return il2cpp::vm::GenericClass::GetClass(genericClass);
+}
+
+const MethodInfo* il2cpp::vm::MetadataCache::GetGenericInstanceMethod(const MethodInfo* genericMethodDefinition, const Il2CppGenericContext* context)
+{
+    const MethodInfo* method = genericMethodDefinition;
+    const Il2CppGenericInst* classInst = context->class_inst;
+    const Il2CppGenericInst* methodInst = context->method_inst;
+    if (genericMethodDefinition->is_inflated)
+    {
+        IL2CPP_ASSERT(genericMethodDefinition->klass->generic_class);
+        classInst = genericMethodDefinition->klass->generic_class->context.class_inst;
+        method = genericMethodDefinition->genericMethod->methodDefinition;
+    }
+
+    const Il2CppGenericMethod* gmethod = GetGenericMethod(method, classInst, methodInst);
+    return il2cpp::metadata::GenericMethod::GetMethod(gmethod);
+}
+
+const MethodInfo* il2cpp::vm::MetadataCache::GetGenericInstanceMethod(const MethodInfo* genericMethodDefinition, const il2cpp::metadata::Il2CppTypeVector& genericArgumentTypes)
+{
+    Il2CppGenericContext context = { NULL, GetGenericInst(genericArgumentTypes) };
+
+    return GetGenericInstanceMethod(genericMethodDefinition, &context);
+}
+
+const Il2CppGenericContext* il2cpp::vm::MetadataCache::GetMethodGenericContext(const MethodInfo* method)
+{
+    if (!method->is_inflated)
+    {
+        IL2CPP_NOT_IMPLEMENTED(Image::GetMethodGenericContext);
+        return NULL;
+    }
+
+    return &method->genericMethod->context;
+}
+
+const MethodInfo* il2cpp::vm::MetadataCache::GetGenericMethodDefinition(const MethodInfo* method)
+{
+    if (!method->is_inflated)
+    {
+        IL2CPP_NOT_IMPLEMENTED(Image::GetGenericMethodDefinition);
+        return NULL;
+    }
+
+    return method->genericMethod->methodDefinition;
+}
+
+const Il2CppGenericContainer* il2cpp::vm::MetadataCache::GetMethodGenericContainer(const MethodInfo* method)
+{
+    return method->genericContainer;
+}
+
+Il2CppClass* il2cpp::vm::MetadataCache::GetPointerType(Il2CppClass* type)
+{
+    il2cpp::os::FastAutoLock lock(&s_MetadataCache.m_CacheMutex);
+
+    PointerTypeMap::const_iterator i = s_MetadataCache.m_PointerTypes.find(type);
+    if (i == s_MetadataCache.m_PointerTypes.end())
+        return NULL;
+
+    return i->second;
+}
+
+Il2CppClass* il2cpp::vm::MetadataCache::GetWindowsRuntimeClass(const char* fullName)
+{
+    WindowsRuntimeTypeNameToClassMap::iterator it = s_WindowsRuntimeTypeNameToClassMap.find(fullName);
+    if (it != s_WindowsRuntimeTypeNameToClassMap.end())
+        return it->second;
+
+    return NULL;
+}
+
+const char* il2cpp::vm::MetadataCache::GetWindowsRuntimeClassName(const Il2CppClass* klass)
+{
+    ClassToWindowsRuntimeTypeNameMap::iterator it = s_ClassToWindowsRuntimeTypeNameMap.find(klass);
+    if (it != s_ClassToWindowsRuntimeTypeNameMap.end())
+        return it->second;
+
+    return NULL;
+}
+
+Il2CppMethodPointer il2cpp::vm::MetadataCache::GetWindowsRuntimeFactoryCreationFunction(const char* fullName)
+{
+    Il2CppClass* klass = GetWindowsRuntimeClass(fullName);
+    if (klass == NULL)
+        return NULL;
+
+    WindowsRuntimeFactoryTable::iterator factoryEntry = s_WindowsRuntimeFactories.find_first(&klass->byval_arg);
+    if (factoryEntry == s_WindowsRuntimeFactories.end())
+        return NULL;
+
+    return factoryEntry->createFactoryFunction;
+}
+
+Il2CppClass* il2cpp::vm::MetadataCache::GetClassForGuid(const Il2CppGuid* guid)
+{
+    IL2CPP_ASSERT(guid != NULL);
+
+    GuidToClassMap::iterator it = s_GuidToNonImportClassMap.find_first(guid);
+    if (it != s_GuidToNonImportClassMap.end())
+        return it->second;
+
+    return NULL;
+}
+
+void il2cpp::vm::MetadataCache::AddPointerType(Il2CppClass* type, Il2CppClass* pointerType)
+{
+    il2cpp::os::FastAutoLock lock(&s_MetadataCache.m_CacheMutex);
+    s_MetadataCache.m_PointerTypes.insert(std::make_pair(type, pointerType));
+}
+
+const Il2CppGenericInst* il2cpp::vm::MetadataCache::GetGenericInst(const Il2CppType* const* types, uint32_t typeCount)
+{
+    // temporary inst to lookup a permanent one that may already exist
+    Il2CppGenericInst inst;
+    inst.type_argc = typeCount;
+    inst.type_argv = (const Il2CppType**)alloca(inst.type_argc * sizeof(Il2CppType*));
+
+    size_t index = 0;
+    const Il2CppType* const* typesEnd = types + typeCount;
+    for (const Il2CppType* const* iter = types; iter != typesEnd; ++iter, ++index)
+        inst.type_argv[index] = *iter;
+
+    {
+        // Acquire lock to check if inst has already been cached.
+        il2cpp::os::FastAutoLock lock(&s_MetadataCache.m_CacheMutex);
+        Il2CppGenericInstSet::const_iterator iter = s_GenericInstSet.find(&inst);
+        if (iter != s_GenericInstSet.end())
+            return *iter;
+    }
+
+    Il2CppGenericInst* newInst = NULL;
+    {
+        il2cpp::os::FastAutoLock lock(&g_MetadataLock);
+        newInst  = (Il2CppGenericInst*)MetadataMalloc(sizeof(Il2CppGenericInst));
+        newInst->type_argc = typeCount;
+        newInst->type_argv = (const Il2CppType**)MetadataMalloc(newInst->type_argc * sizeof(Il2CppType*));
+    }
+
+    index = 0;
+    for (const Il2CppType* const* iter = types; iter != typesEnd; ++iter, ++index)
+        newInst->type_argv[index] = *iter;
+
+    {
+        // Acquire lock agains to attempt to cache inst.
+        il2cpp::os::FastAutoLock lock(&s_MetadataCache.m_CacheMutex);
+        // Another thread may have already added this inst or we may be the first.
+        // In either case, the iterator returned from 'insert' points to the item
+        // cached within the set. We can always return this. In the case of another
+        // thread beating us, the only downside is an extra allocation in the
+        // metadata memory pool that lives for life of process anyway.
+        auto result = s_GenericInstSet.insert(newInst);
+        if (result.second)
+            ++il2cpp_runtime_stats.generic_instance_count;
+
+        return *(result.first);
+    }
+}
+
+const Il2CppGenericInst* il2cpp::vm::MetadataCache::GetGenericInst(const il2cpp::metadata::Il2CppTypeVector& types)
+{
+    return GetGenericInst(&types[0], static_cast<uint32_t>(types.size()));
+}
+
+static il2cpp::os::FastMutex s_GenericMethodMutex;
+const Il2CppGenericMethod* il2cpp::vm::MetadataCache::GetGenericMethod(const MethodInfo* methodDefinition, const Il2CppGenericInst* classInst, const Il2CppGenericInst* methodInst)
+{
+    Il2CppGenericMethod method = { 0 };
+    method.methodDefinition = methodDefinition;
+    method.context.class_inst = classInst;
+    method.context.method_inst = methodInst;
+
+    il2cpp::os::FastAutoLock lock(&s_GenericMethodMutex);
+    Il2CppGenericMethodSet::const_iterator iter = s_GenericMethodSet.find(&method);
+    if (iter != s_GenericMethodSet.end())
+        return *iter;
+
+    Il2CppGenericMethod* newMethod = MetadataAllocGenericMethod();
+    newMethod->methodDefinition = methodDefinition;
+    newMethod->context.class_inst = classInst;
+    newMethod->context.method_inst = methodInst;
+
+    s_GenericMethodSet.insert(newMethod);
+
+    return newMethod;
+}
+
+static bool IsShareableEnum(const Il2CppType* type)
+{
+    // Base case for recursion - we've found an enum.
+    if (il2cpp::vm::Type::IsEnum(type))
+        return true;
+
+    if (il2cpp::vm::Type::IsGenericInstance(type))
+    {
+        // Recursive case - look "inside" the generic instance type to see if this is a nested enum.
+        Il2CppClass* definition = il2cpp::vm::GenericClass::GetTypeDefinition(type->data.generic_class);
+        return IsShareableEnum(il2cpp::vm::Class::GetType(definition));
+    }
+
+    // Base case for recurion - this is not an enum or a generic instance type.
+    return false;
+}
+
+// this logic must match the C# logic in GenericSharingAnalysis.GetSharedTypeForGenericParameter
+static const Il2CppGenericInst* GetSharedInst(const Il2CppGenericInst* inst)
+{
+    if (inst == NULL)
+        return NULL;
+
+    il2cpp::metadata::Il2CppTypeVector types;
+    for (uint32_t i = 0; i < inst->type_argc; ++i)
+    {
+        if (il2cpp::vm::Type::IsReference(inst->type_argv[i]))
+            types.push_back(&il2cpp_defaults.object_class->byval_arg);
+        else
+        {
+            const Il2CppType* type = inst->type_argv[i];
+            if (s_Il2CppCodeGenOptions->enablePrimitiveValueTypeGenericSharing)
+            {
+                if (IsShareableEnum(type))
+                {
+                    const Il2CppType* underlyingType = il2cpp::vm::Type::GetUnderlyingType(type);
+                    switch (underlyingType->type)
+                    {
+                        case IL2CPP_TYPE_I1:
+                            type = &il2cpp_defaults.sbyte_shared_enum->byval_arg;
+                            break;
+                        case IL2CPP_TYPE_I2:
+                            type = &il2cpp_defaults.int16_shared_enum->byval_arg;
+                            break;
+                        case IL2CPP_TYPE_I4:
+                            type = &il2cpp_defaults.int32_shared_enum->byval_arg;
+                            break;
+                        case IL2CPP_TYPE_I8:
+                            type = &il2cpp_defaults.int64_shared_enum->byval_arg;
+                            break;
+                        case IL2CPP_TYPE_U1:
+                            type = &il2cpp_defaults.byte_shared_enum->byval_arg;
+                            break;
+                        case IL2CPP_TYPE_U2:
+                            type = &il2cpp_defaults.uint16_shared_enum->byval_arg;
+                            break;
+                        case IL2CPP_TYPE_U4:
+                            type = &il2cpp_defaults.uint32_shared_enum->byval_arg;
+                            break;
+                        case IL2CPP_TYPE_U8:
+                            type = &il2cpp_defaults.uint64_shared_enum->byval_arg;
+                            break;
+                        default:
+                            IL2CPP_ASSERT(0 && "Invalid enum underlying type");
+                            break;
+                    }
+                }
+            }
+
+            if (il2cpp::vm::Type::IsGenericInstance(type))
+            {
+                const Il2CppGenericInst* sharedInst = GetSharedInst(type->data.generic_class->context.class_inst);
+                Il2CppGenericClass* gklass = il2cpp::metadata::GenericMetadata::GetGenericClass(type->data.generic_class->typeDefinitionIndex, sharedInst);
+                Il2CppClass* klass = il2cpp::vm::GenericClass::GetClass(gklass);
+                type = &klass->byval_arg;
+            }
+            types.push_back(type);
+        }
+    }
+
+    const Il2CppGenericInst* sharedInst = il2cpp::vm::MetadataCache::GetGenericInst(types);
+
+    return sharedInst;
+}
+
+InvokerMethod il2cpp::vm::MetadataCache::GetInvokerMethodPointer(const MethodInfo* methodDefinition, const Il2CppGenericContext* context)
+{
+    Il2CppGenericMethod method = { 0 };
+    method.methodDefinition = const_cast<MethodInfo*>(methodDefinition);
+    method.context.class_inst = context->class_inst;
+    method.context.method_inst = context->method_inst;
+
+    Il2CppMethodTableMapIter iter = s_MethodTableMap.find(&method);
+    if (iter != s_MethodTableMap.end())
+    {
+        IL2CPP_ASSERT(iter->second->invokerIndex >= 0);
+        if (static_cast<uint32_t>(iter->second->invokerIndex) < s_Il2CppCodeRegistration->invokerPointersCount)
+            return s_Il2CppCodeRegistration->invokerPointers[iter->second->invokerIndex];
+        return NULL;
+    }
+    // get the shared version if it exists
+    method.context.class_inst = GetSharedInst(context->class_inst);
+    method.context.method_inst = GetSharedInst(context->method_inst);
+
+    iter = s_MethodTableMap.find(&method);
+    if (iter != s_MethodTableMap.end())
+    {
+        IL2CPP_ASSERT(iter->second->invokerIndex >= 0);
+        if (static_cast<uint32_t>(iter->second->invokerIndex) < s_Il2CppCodeRegistration->invokerPointersCount)
+            return s_Il2CppCodeRegistration->invokerPointers[iter->second->invokerIndex];
+        return NULL;
+    }
+
+    return NULL;
+}
+
+Il2CppMethodPointer il2cpp::vm::MetadataCache::GetMethodPointer(const MethodInfo* methodDefinition, const Il2CppGenericContext* context)
+{
+    Il2CppGenericMethod method = { 0 };
+    method.methodDefinition = const_cast<MethodInfo*>(methodDefinition);
+    method.context.class_inst = context->class_inst;
+    method.context.method_inst = context->method_inst;
+
+    Il2CppMethodTableMapIter iter = s_MethodTableMap.find(&method);
+    if (iter != s_MethodTableMap.end())
+    {
+        IL2CPP_ASSERT(iter->second->invokerIndex >= 0);
+        if (iter->second->adjustorThunkIndex != -1)
+            return s_Il2CppCodeRegistration->genericAdjustorThunks[iter->second->adjustorThunkIndex];
+
+        if (static_cast<uint32_t>(iter->second->methodIndex) < s_Il2CppCodeRegistration->genericMethodPointersCount)
+            return s_Il2CppCodeRegistration->genericMethodPointers[iter->second->methodIndex];
+        return NULL;
+    }
+
+    method.context.class_inst = GetSharedInst(context->class_inst);
+    method.context.method_inst = GetSharedInst(context->method_inst);
+
+    iter = s_MethodTableMap.find(&method);
+    if (iter != s_MethodTableMap.end())
+    {
+        IL2CPP_ASSERT(iter->second->invokerIndex >= 0);
+        if (iter->second->adjustorThunkIndex != -1)
+            return s_Il2CppCodeRegistration->genericAdjustorThunks[iter->second->adjustorThunkIndex];
+
+        if (static_cast<uint32_t>(iter->second->methodIndex) < s_Il2CppCodeRegistration->genericMethodPointersCount)
+            return s_Il2CppCodeRegistration->genericMethodPointers[iter->second->methodIndex];
+        return NULL;
+    }
+
+    return NULL;
+}
+
+Il2CppClass* il2cpp::vm::MetadataCache::GetTypeInfoFromTypeIndex(TypeIndex index, bool throwOnError)
+{
+    if (index == kTypeIndexInvalid)
+        return NULL;
+
+    IL2CPP_ASSERT(index < s_Il2CppMetadataRegistration->typesCount && "Invalid type index ");
+
+    if (s_TypeInfoTable[index])
+        return s_TypeInfoTable[index];
+
+    const Il2CppType* type = s_Il2CppMetadataRegistration->types[index];
+    Il2CppClass *klass = il2cpp::vm::Class::FromIl2CppType(type, throwOnError);
+    if (klass)
+    {
+        il2cpp::vm::ClassInlines::InitFromCodegen(klass);
+        s_TypeInfoTable[index] = klass;
+    }
+
+    return s_TypeInfoTable[index];
+}
+
+const Il2CppType* il2cpp::vm::MetadataCache::GetIl2CppTypeFromIndex(TypeIndex index)
+{
+    if (index == kTypeIndexInvalid)
+        return NULL;
+
+    IL2CPP_ASSERT(index < s_Il2CppMetadataRegistration->typesCount && "Invalid type index ");
+
+    return s_Il2CppMetadataRegistration->types[index];
+}
+
+const MethodInfo* il2cpp::vm::MetadataCache::GetMethodInfoFromIndex(EncodedMethodIndex methodIndex)
+{
+    uint32_t index = GetDecodedMethodIndex(methodIndex);
+
+    if (index == 0)
+        return NULL;
+
+    if (GetEncodedIndexType(methodIndex) == kIl2CppMetadataUsageMethodRef)
+        return il2cpp::metadata::GenericMethod::GetMethod(GetGenericMethodFromIndex(index));
+    else
+        return il2cpp::vm::MetadataCache::GetMethodInfoFromMethodDefinitionIndex(index);
+}
+
+const Il2CppGenericMethod* il2cpp::vm::MetadataCache::GetGenericMethodFromIndex(GenericMethodIndex index)
+{
+    IL2CPP_ASSERT(index < s_Il2CppMetadataRegistration->methodSpecsCount);
+    if (s_GenericMethodTable[index])
+        return s_GenericMethodTable[index];
+
+    const Il2CppMethodSpec* methodSpec = s_Il2CppMetadataRegistration->methodSpecs + index;
+    const MethodInfo* methodDefinition = GetMethodInfoFromMethodDefinitionIndex(methodSpec->methodDefinitionIndex);
+    const Il2CppGenericInst* classInst = NULL;
+    const Il2CppGenericInst* methodInst = NULL;
+    if (methodSpec->classIndexIndex != -1)
+    {
+        IL2CPP_ASSERT(methodSpec->classIndexIndex < s_Il2CppMetadataRegistration->genericInstsCount);
+        classInst = s_Il2CppMetadataRegistration->genericInsts[methodSpec->classIndexIndex];
+    }
+    if (methodSpec->methodIndexIndex != -1)
+    {
+        IL2CPP_ASSERT(methodSpec->methodIndexIndex < s_Il2CppMetadataRegistration->genericInstsCount);
+        methodInst = s_Il2CppMetadataRegistration->genericInsts[methodSpec->methodIndexIndex];
+    }
+    s_GenericMethodTable[index] = GetGenericMethod(methodDefinition, classInst, methodInst);
+
+    return s_GenericMethodTable[index];
+}
+
+static int CompareIl2CppTokenAdjustorThunkPair(const void* pkey, const void* pelem)
+{
+    return (int)(((Il2CppTokenAdjustorThunkPair*)pkey)->token - ((Il2CppTokenAdjustorThunkPair*)pelem)->token);
+}
+
+Il2CppMethodPointer il2cpp::vm::MetadataCache::GetAdjustorThunk(const Il2CppImage* image, uint32_t token)
+{
+    if (image->codeGenModule->adjustorThunkCount == 0)
+        return NULL;
+
+    Il2CppTokenAdjustorThunkPair key;
+    memset(&key, 0, sizeof(Il2CppTokenAdjustorThunkPair));
+    key.token = token;
+
+    const Il2CppTokenAdjustorThunkPair* result = (const Il2CppTokenAdjustorThunkPair*)bsearch(&key, image->codeGenModule->adjustorThunks,
+        image->codeGenModule->adjustorThunkCount, sizeof(Il2CppTokenAdjustorThunkPair), CompareIl2CppTokenAdjustorThunkPair);
+
+    if (result == NULL)
+        return NULL;
+
+    return result->adjustorThunk;
+}
+
+Il2CppMethodPointer il2cpp::vm::MetadataCache::GetMethodPointer(const Il2CppImage* image, uint32_t token)
+{
+    uint32_t rid = GetTokenRowId(token);
+    uint32_t table =  GetTokenType(token);
+    if (rid == 0)
+        return NULL;
+
+    IL2CPP_ASSERT(rid <= image->codeGenModule->methodPointerCount);
+
+    return image->codeGenModule->methodPointers[rid - 1];
+}
+
+InvokerMethod il2cpp::vm::MetadataCache::GetMethodInvoker(const Il2CppImage* image, uint32_t token)
+{
+    uint32_t rid = GetTokenRowId(token);
+    uint32_t table = GetTokenType(token);
+    if (rid == 0)
+        return NULL;
+
+    int32_t index = image->codeGenModule->invokerIndices[rid - 1];
+
+    if (index == kMethodIndexInvalid)
+        return NULL;
+
+    IL2CPP_ASSERT(index >= 0 && static_cast<uint32_t>(index) < s_Il2CppCodeRegistration->invokerPointersCount);
+    return s_Il2CppCodeRegistration->invokerPointers[index];
+}
+
+const Il2CppInteropData* il2cpp::vm::MetadataCache::GetInteropDataForType(const Il2CppType* type)
+{
+    IL2CPP_ASSERT(type != NULL);
+    InteropDataMap::iterator interopData = s_InteropData.find_first(type);
+    if (interopData == s_InteropData.end())
+        return NULL;
+
+    return interopData;
+}
+
+static bool MatchTokens(Il2CppTokenIndexMethodTuple key, Il2CppTokenIndexMethodTuple element)
+{
+    return key.token < element.token;
+}
+
+Il2CppMethodPointer il2cpp::vm::MetadataCache::GetReversePInvokeWrapper(const Il2CppImage* image, const MethodInfo* method)
+{
+    if (image->codeGenModule->reversePInvokeWrapperCount == 0)
+        return NULL;
+
+    // For each image (i.e. assembly), the reverse pinvoke wrapper indices are in an array sorted by
+    // metadata token. Each entry also might have the method metadata pointer, which is used to further
+    // find methods that have a matching metadata token.
+
+    Il2CppTokenIndexMethodTuple key;
+    memset(&key, 0, sizeof(Il2CppTokenIndexMethodTuple));
+    key.token = method->token;
+
+    // Binary search for a range which matches the metadata token.
+    auto begin = image->codeGenModule->reversePInvokeWrapperIndices;
+    auto end = image->codeGenModule->reversePInvokeWrapperIndices + image->codeGenModule->reversePInvokeWrapperCount;
+    auto matchingRange = std::equal_range(begin, end, key, &MatchTokens);
+
+    int32_t index = -1;
+    auto numberOfMatches = std::distance(matchingRange.first, matchingRange.second);
+    if (numberOfMatches == 1)
+    {
+        // Normal case - we found one non-generic method.
+        index = matchingRange.first->index;
+    }
+    else if (numberOfMatches > 1)
+    {
+        // Multiple generic instance methods share the same token, since it is from the generic method definition.
+        // To find the proper method, look for the one with a matching method metadata pointer.
+        const Il2CppTokenIndexMethodTuple* currentMatch = matchingRange.first;
+        const Il2CppTokenIndexMethodTuple* lastMatch = matchingRange.second;
+        while (currentMatch != lastMatch)
+        {
+            // First, check the method metadata, and use it if it has been initialized.
+            // If not, let's fall back to the generic method.
+            const MethodInfo* possibleMatch = (const MethodInfo*)*currentMatch->method;
+            if (possibleMatch == NULL)
+                possibleMatch = il2cpp::metadata::GenericMethod::GetMethod(GetGenericMethodFromIndex(currentMatch->genericMethodIndex));
+            if (possibleMatch == method)
+            {
+                index = currentMatch->index;
+                break;
+            }
+            currentMatch++;
+        }
+    }
+
+    if (index == -1)
+        return NULL;
+
+    IL2CPP_ASSERT(index >= 0 && static_cast<uint32_t>(index) < s_Il2CppCodeRegistration->reversePInvokeWrapperCount);
+    return s_Il2CppCodeRegistration->reversePInvokeWrappers[index];
+}
+
+static const Il2CppType* GetReducedType(const Il2CppType* type)
+{
+    if (type->byref)
+        return &il2cpp_defaults.object_class->byval_arg;
+
+    if (il2cpp::vm::Type::IsEnum(type))
+        type = il2cpp::vm::Type::GetUnderlyingType(type);
+
+    switch (type->type)
+    {
+        case IL2CPP_TYPE_BOOLEAN:
+            return &il2cpp_defaults.sbyte_class->byval_arg;
+        case IL2CPP_TYPE_CHAR:
+            return &il2cpp_defaults.int16_class->byval_arg;
+        case IL2CPP_TYPE_BYREF:
+        case IL2CPP_TYPE_CLASS:
+        case IL2CPP_TYPE_OBJECT:
+        case IL2CPP_TYPE_STRING:
+        case IL2CPP_TYPE_ARRAY:
+        case IL2CPP_TYPE_SZARRAY:
+            return &il2cpp_defaults.object_class->byval_arg;
+        case IL2CPP_TYPE_GENERICINST:
+            if (il2cpp::vm::Type::GenericInstIsValuetype(type))
+                return type;
+            else
+                return &il2cpp_defaults.object_class->byval_arg;
+        default:
+            return type;
+    }
+}
+
+Il2CppMethodPointer il2cpp::vm::MetadataCache::GetUnresolvedVirtualCallStub(const MethodInfo* method)
+{
+    il2cpp::utils::dynamic_array<const Il2CppType*> signature;
+
+    signature.push_back(GetReducedType(method->return_type));
+    for (int i = 0; i < method->parameters_count; ++i)
+        signature.push_back(GetReducedType(method->parameters[i].parameter_type));
+
+    Il2CppUnresolvedSignatureMapIter it = s_pUnresolvedSignatureMap->find(signature);
+    if (it != s_pUnresolvedSignatureMap->end())
+        return it->second;
+
+    return NULL;
+}
+
+static const Il2CppImage* GetImageForTypeDefinitionIndex(TypeDefinitionIndex index)
+{
+    for (int32_t imageIndex = 0; imageIndex < s_ImagesCount; imageIndex++)
+    {
+        const Il2CppImage* image = s_ImagesTable + imageIndex;
+        IL2CPP_ASSERT(index >= 0);
+        if (index >= image->typeStart && static_cast<uint32_t>(index) < (image->typeStart + image->typeCount))
+            return image;
+    }
+
+    IL2CPP_ASSERT(0 && "Failed to find owning image for type");
+    return NULL;
+}
+
+enum PackingSize
+{
+    Zero,
+    One,
+    Two,
+    Four,
+    Eight,
+    Sixteen,
+    ThirtyTwo,
+    SixtyFour,
+    OneHundredTwentyEight
+};
+
+static uint8_t ConvertPackingSizeEnumToValue(PackingSize packingSize)
+{
+    switch (packingSize)
+    {
+        case Zero:
+            return 0;
+        case One:
+            return 1;
+        case Two:
+            return 2;
+        case Four:
+            return 4;
+        case Eight:
+            return 8;
+        case Sixteen:
+            return 16;
+        case ThirtyTwo:
+            return 32;
+        case SixtyFour:
+            return 64;
+        case OneHundredTwentyEight:
+            return 128;
+        default:
+            Assert(0 && "Invalid packing size!");
+            return 0;
+    }
+}
+
+static const int kBitIsValueType = 1;
+static const int kBitIsEnum = 2;
+static const int kBitHasFinalizer = 3;
+static const int kBitHasStaticConstructor = 4;
+static const int kBitIsBlittable = 5;
+static const int kBitIsImportOrWindowsRuntime = 6;
+static const int kPackingSize = 7; // This uses 4 bits from bit 7 to bit 10
+static const int kPackingSizeIsDefault = 11;
+static const int kClassSizeIsDefault = 12;
+static const int kSpecifiedPackingSize = 13; // This uses 4 bits from bit 13 to bit 16
+
+int32_t il2cpp::vm::MetadataCache::StructLayoutPack(TypeDefinitionIndex index)
+{
+    const Il2CppTypeDefinition* typeDefinition = GetTypeDefinitionFromIndex(index);
+    return ConvertPackingSizeEnumToValue(static_cast<PackingSize>((typeDefinition->bitfield >> (kSpecifiedPackingSize - 1)) & 0xF));
+}
+
+bool il2cpp::vm::MetadataCache::StructLayoutPackIsDefault(TypeDefinitionIndex index)
+{
+    const Il2CppTypeDefinition* typeDefinition = GetTypeDefinitionFromIndex(index);
+    return (typeDefinition->bitfield >> (kPackingSizeIsDefault - 1)) & 0x1;
+}
+
+bool il2cpp::vm::MetadataCache::StructLayoutSizeIsDefault(TypeDefinitionIndex index)
+{
+    const Il2CppTypeDefinition* typeDefinition = GetTypeDefinitionFromIndex(index);
+    return (typeDefinition->bitfield >> (kClassSizeIsDefault - 1)) & 0x1;
+}
+
+static Il2CppClass* FromTypeDefinition(TypeDefinitionIndex index)
+{
+    IL2CPP_ASSERT(index >= 0 && static_cast<uint32_t>(index) < s_GlobalMetadataHeader->typeDefinitionsCount / sizeof(Il2CppTypeDefinition));
+    const Il2CppTypeDefinition* typeDefinitions = (const Il2CppTypeDefinition*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->typeDefinitionsOffset);
+    const Il2CppTypeDefinition* typeDefinition = typeDefinitions + index;
+    const Il2CppTypeDefinitionSizes* typeDefinitionSizes = s_Il2CppMetadataRegistration->typeDefinitionsSizes[index];
+    Il2CppClass* typeInfo = (Il2CppClass*)IL2CPP_CALLOC(1, sizeof(Il2CppClass) + (sizeof(VirtualInvokeData) * typeDefinition->vtable_count));
+    typeInfo->klass = typeInfo;
+    typeInfo->image = GetImageForTypeDefinitionIndex(index);
+    typeInfo->name = il2cpp::vm::MetadataCache::GetStringFromIndex(typeDefinition->nameIndex);
+    typeInfo->namespaze = il2cpp::vm::MetadataCache::GetStringFromIndex(typeDefinition->namespaceIndex);
+    typeInfo->byval_arg = *il2cpp::vm::MetadataCache::GetIl2CppTypeFromIndex(typeDefinition->byvalTypeIndex);
+    typeInfo->this_arg = *il2cpp::vm::MetadataCache::GetIl2CppTypeFromIndex(typeDefinition->byrefTypeIndex);
+    typeInfo->typeDefinition = typeDefinition;
+    typeInfo->genericContainerIndex = typeDefinition->genericContainerIndex;
+    typeInfo->instance_size = typeDefinitionSizes->instance_size;
+    typeInfo->actualSize = typeDefinitionSizes->instance_size; // actualySize is instance_size for compiler generated values
+    typeInfo->native_size = typeDefinitionSizes->native_size;
+    typeInfo->static_fields_size = typeDefinitionSizes->static_fields_size;
+    typeInfo->thread_static_fields_size = typeDefinitionSizes->thread_static_fields_size;
+    typeInfo->thread_static_fields_offset = -1;
+    typeInfo->flags = typeDefinition->flags;
+    typeInfo->valuetype = (typeDefinition->bitfield >> (kBitIsValueType - 1)) & 0x1;
+    typeInfo->enumtype = (typeDefinition->bitfield >> (kBitIsEnum - 1)) & 0x1;
+    typeInfo->is_generic = typeDefinition->genericContainerIndex != kGenericContainerIndexInvalid; // generic if we have a generic container
+    typeInfo->has_finalize = (typeDefinition->bitfield >> (kBitHasFinalizer - 1)) & 0x1;
+    typeInfo->has_cctor = (typeDefinition->bitfield >> (kBitHasStaticConstructor - 1)) & 0x1;
+    typeInfo->is_blittable = (typeDefinition->bitfield >> (kBitIsBlittable - 1)) & 0x1;
+    typeInfo->is_import_or_windows_runtime = (typeDefinition->bitfield >> (kBitIsImportOrWindowsRuntime - 1)) & 0x1;
+    typeInfo->packingSize = ConvertPackingSizeEnumToValue(static_cast<PackingSize>((typeDefinition->bitfield >> (kPackingSize - 1)) & 0xF));
+    typeInfo->method_count = typeDefinition->method_count;
+    typeInfo->property_count = typeDefinition->property_count;
+    typeInfo->field_count = typeDefinition->field_count;
+    typeInfo->event_count = typeDefinition->event_count;
+    typeInfo->nested_type_count = typeDefinition->nested_type_count;
+    typeInfo->vtable_count = typeDefinition->vtable_count;
+    typeInfo->interfaces_count = typeDefinition->interfaces_count;
+    typeInfo->interface_offsets_count = typeDefinition->interface_offsets_count;
+    typeInfo->token = typeDefinition->token;
+    typeInfo->interopData = il2cpp::vm::MetadataCache::GetInteropDataForType(&typeInfo->byval_arg);
+
+    if (typeDefinition->parentIndex != kTypeIndexInvalid)
+        typeInfo->parent = il2cpp::vm::Class::FromIl2CppType(il2cpp::vm::MetadataCache::GetIl2CppTypeFromIndex(typeDefinition->parentIndex));
+
+    if (typeDefinition->declaringTypeIndex != kTypeIndexInvalid)
+        typeInfo->declaringType = il2cpp::vm::Class::FromIl2CppType(il2cpp::vm::MetadataCache::GetIl2CppTypeFromIndex(typeDefinition->declaringTypeIndex));
+
+    typeInfo->castClass = typeInfo->element_class = typeInfo;
+    if (typeInfo->enumtype)
+        typeInfo->castClass = typeInfo->element_class = il2cpp::vm::Class::FromIl2CppType(il2cpp::vm::MetadataCache::GetIl2CppTypeFromIndex(typeDefinition->elementTypeIndex));
+
+    return typeInfo;
+}
+
+const Il2CppAssembly* il2cpp::vm::MetadataCache::GetAssemblyFromIndex(AssemblyIndex index)
+{
+    if (index == kGenericContainerIndexInvalid)
+        return NULL;
+
+    IL2CPP_ASSERT(index <= s_AssembliesCount);
+    return s_AssembliesTable + index;
+}
+
+const Il2CppAssembly* il2cpp::vm::MetadataCache::GetAssemblyByName(const char* nameToFind)
+{
+    for (int i = 0; i < s_AssembliesCount; i++)
+    {
+        const Il2CppAssembly* assembly = s_AssembliesTable + i;
+
+        const char* assemblyName = assembly->aname.name;
+
+        if (strcmp(assemblyName, nameToFind) == 0)
+            return assembly;
+    }
+
+    return NULL;
+}
+
+Il2CppImage* il2cpp::vm::MetadataCache::GetImageFromIndex(ImageIndex index)
+{
+    if (index == kGenericContainerIndexInvalid)
+        return NULL;
+
+    IL2CPP_ASSERT(index <= s_ImagesCount);
+    return s_ImagesTable + index;
+}
+
+Il2CppClass* il2cpp::vm::MetadataCache::GetTypeInfoFromTypeDefinitionIndex(TypeDefinitionIndex index)
+{
+    if (index == kTypeIndexInvalid)
+        return NULL;
+
+    IL2CPP_ASSERT(index >= 0 && static_cast<uint32_t>(index) < s_GlobalMetadataHeader->typeDefinitionsCount / sizeof(Il2CppTypeDefinition));
+
+    if (!s_TypeInfoDefinitionTable[index])
+    {
+        // we need to use the metadata lock, since we may need to retrieve other Il2CppClass's when setting. Our parent may be a generic instance for example
+        il2cpp::os::FastAutoLock lock(&g_MetadataLock);
+        // double checked locking
+        if (!s_TypeInfoDefinitionTable[index])
+            s_TypeInfoDefinitionTable[index] = FromTypeDefinition(index);
+    }
+
+    return s_TypeInfoDefinitionTable[index];
+}
+
+const Il2CppTypeDefinition* il2cpp::vm::MetadataCache::GetTypeDefinitionFromIndex(TypeDefinitionIndex index)
+{
+    if (index == kTypeDefinitionIndexInvalid)
+        return NULL;
+
+    IL2CPP_ASSERT(index >= 0 && static_cast<uint32_t>(index) < s_GlobalMetadataHeader->typeDefinitionsCount / sizeof(Il2CppTypeDefinition));
+    const Il2CppTypeDefinition* typeDefinitions = (const Il2CppTypeDefinition*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->typeDefinitionsOffset);
+    return typeDefinitions + index;
+}
+
+TypeDefinitionIndex il2cpp::vm::MetadataCache::GetExportedTypeFromIndex(TypeDefinitionIndex index)
+{
+    if (index == kTypeDefinitionIndexInvalid)
+        return kTypeDefinitionIndexInvalid;
+
+    IL2CPP_ASSERT(index >= 0 && static_cast<uint32_t>(index) < s_GlobalMetadataHeader->exportedTypeDefinitionsCount / sizeof(TypeDefinitionIndex));
+    TypeDefinitionIndex* exportedTypes = (TypeDefinitionIndex*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->exportedTypeDefinitionsOffset);
+    return *(exportedTypes + index);
+}
+
+const Il2CppGenericContainer* il2cpp::vm::MetadataCache::GetGenericContainerFromIndex(GenericContainerIndex index)
+{
+    if (index == kGenericContainerIndexInvalid)
+        return NULL;
+
+    IL2CPP_ASSERT(index >= 0 && static_cast<uint32_t>(index) <= s_GlobalMetadataHeader->genericContainersCount / sizeof(Il2CppGenericContainer));
+    const Il2CppGenericContainer* genericContainers = (const Il2CppGenericContainer*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->genericContainersOffset);
+    return genericContainers + index;
+}
+
+const Il2CppGenericParameter* il2cpp::vm::MetadataCache::GetGenericParameterFromIndex(GenericParameterIndex index)
+{
+    if (index == kGenericParameterIndexInvalid)
+        return NULL;
+
+    IL2CPP_ASSERT(index >= 0 && static_cast<uint32_t>(index) <= s_GlobalMetadataHeader->genericParametersCount / sizeof(Il2CppGenericParameter));
+    const Il2CppGenericParameter* genericParameters = (const Il2CppGenericParameter*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->genericParametersOffset);
+    return genericParameters + index;
+}
+
+const Il2CppType* il2cpp::vm::MetadataCache::GetGenericParameterConstraintFromIndex(GenericParameterConstraintIndex index)
+{
+    IL2CPP_ASSERT(index >= 0 && static_cast<uint32_t>(index) <= s_GlobalMetadataHeader->genericParameterConstraintsCount / sizeof(TypeIndex));
+    const TypeIndex* constraintIndices = (const TypeIndex*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->genericParameterConstraintsOffset);
+
+    return GetIl2CppTypeFromIndex(constraintIndices[index]);
+}
+
+Il2CppClass* il2cpp::vm::MetadataCache::GetNestedTypeFromIndex(NestedTypeIndex index)
+{
+    IL2CPP_ASSERT(index >= 0 && static_cast<uint32_t>(index) <= s_GlobalMetadataHeader->nestedTypesCount / sizeof(TypeDefinitionIndex));
+    const TypeDefinitionIndex* nestedTypeIndices = (const TypeDefinitionIndex*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->nestedTypesOffset);
+
+    return GetTypeInfoFromTypeDefinitionIndex(nestedTypeIndices[index]);
+}
+
+const Il2CppType* il2cpp::vm::MetadataCache::GetInterfaceFromIndex(InterfacesIndex index)
+{
+    IL2CPP_ASSERT(index >= 0 && static_cast<uint32_t>(index) <= s_GlobalMetadataHeader->interfacesCount / sizeof(TypeIndex));
+    const TypeIndex* interfaceIndices = (const TypeIndex*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->interfacesOffset);
+
+    return GetIl2CppTypeFromIndex(interfaceIndices[index]);
+}
+
+EncodedMethodIndex il2cpp::vm::MetadataCache::GetVTableMethodFromIndex(VTableIndex index)
+{
+    IL2CPP_ASSERT(index >= 0 && static_cast<uint32_t>(index) <= s_GlobalMetadataHeader->vtableMethodsCount / sizeof(EncodedMethodIndex));
+    const EncodedMethodIndex* methodReferences = (const EncodedMethodIndex*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->vtableMethodsOffset);
+
+    return methodReferences[index];
+}
+
+Il2CppInterfaceOffsetPair il2cpp::vm::MetadataCache::GetInterfaceOffsetIndex(InterfaceOffsetIndex index)
+{
+    IL2CPP_ASSERT(index >= 0 && static_cast<uint32_t>(index) <= s_GlobalMetadataHeader->interfaceOffsetsCount / sizeof(Il2CppInterfaceOffsetPair));
+    const Il2CppInterfaceOffsetPair* interfaceOffsets = (const Il2CppInterfaceOffsetPair*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->interfaceOffsetsOffset);
+
+    return interfaceOffsets[index];
+}
+
+static int CompareIl2CppTokenRangePair(const void* pkey, const void* pelem)
+{
+    return (int)(((Il2CppTokenRangePair*)pkey)->token - ((Il2CppTokenRangePair*)pelem)->token);
+}
+
+il2cpp::vm::RGCTXCollection il2cpp::vm::MetadataCache::GetRGCTXs(const Il2CppImage* image, uint32_t token)
+{
+    il2cpp::vm::RGCTXCollection collection = { 0, NULL };
+    if (image->codeGenModule->rgctxRangesCount == 0)
+        return collection;
+
+    Il2CppTokenRangePair key;
+    memset(&key, 0, sizeof(Il2CppTokenRangePair));
+    key.token = token;
+
+    const Il2CppTokenRangePair* res = (const Il2CppTokenRangePair*)bsearch(&key, image->codeGenModule->rgctxRanges, image->codeGenModule->rgctxRangesCount, sizeof(Il2CppTokenRangePair), CompareIl2CppTokenRangePair);
+
+    if (res == NULL)
+        return collection;
+
+    collection.count = res->range.length;
+    collection.items = image->codeGenModule->rgctxs + res->range.start;
+
+    return collection;
+}
+
+const Il2CppEventDefinition* il2cpp::vm::MetadataCache::GetEventDefinitionFromIndex(EventIndex index)
+{
+    IL2CPP_ASSERT(index >= 0 && static_cast<uint32_t>(index) <= s_GlobalMetadataHeader->eventsCount / sizeof(Il2CppEventDefinition));
+    const Il2CppEventDefinition* events = (const Il2CppEventDefinition*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->eventsOffset);
+    return events + index;
+}
+
+const Il2CppFieldDefinition* il2cpp::vm::MetadataCache::GetFieldDefinitionFromIndex(FieldIndex index)
+{
+    IL2CPP_ASSERT(index >= 0 && static_cast<uint32_t>(index) <= s_GlobalMetadataHeader->fieldsCount / sizeof(Il2CppFieldDefinition));
+    const Il2CppFieldDefinition* fields = (const Il2CppFieldDefinition*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->fieldsOffset);
+    return fields + index;
+}
+
+const Il2CppFieldDefaultValue* il2cpp::vm::MetadataCache::GetFieldDefaultValueFromIndex(FieldIndex index)
+{
+    IL2CPP_ASSERT(index >= 0 && static_cast<uint32_t>(index) <= s_GlobalMetadataHeader->fieldDefaultValuesCount / sizeof(Il2CppFieldDefaultValue));
+    const Il2CppFieldDefaultValue* defaultValues = (const Il2CppFieldDefaultValue*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->fieldDefaultValuesOffset);
+    return defaultValues + index;
+}
+
+const uint8_t* il2cpp::vm::MetadataCache::GetFieldDefaultValueDataFromIndex(FieldIndex index)
+{
+    IL2CPP_ASSERT(index >= 0 && static_cast<uint32_t>(index) <= s_GlobalMetadataHeader->fieldAndParameterDefaultValueDataCount / sizeof(uint8_t));
+    const uint8_t* defaultValuesData = (const uint8_t*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->fieldAndParameterDefaultValueDataOffset);
+    return defaultValuesData + index;
+}
+
+const Il2CppFieldDefaultValue* il2cpp::vm::MetadataCache::GetFieldDefaultValueForField(const FieldInfo* field)
+{
+    Il2CppClass* parent = field->parent;
+    size_t fieldIndex = (field - parent->fields);
+    if (il2cpp::vm::Type::IsGenericInstance(&parent->byval_arg))
+        fieldIndex += il2cpp::vm::GenericClass::GetTypeDefinition(parent->generic_class)->typeDefinition->fieldStart;
+    else
+        fieldIndex += parent->typeDefinition->fieldStart;
+    const Il2CppFieldDefaultValue *start = (const Il2CppFieldDefaultValue*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->fieldDefaultValuesOffset);
+    const Il2CppFieldDefaultValue *entry = start;
+    while (entry < start + s_GlobalMetadataHeader->fieldDefaultValuesCount)
+    {
+        if (fieldIndex == entry->fieldIndex)
+        {
+            return entry;
+        }
+        entry++;
+    }
+    IL2CPP_ASSERT(0);
+    return NULL;
+}
+
+const Il2CppParameterDefaultValue * il2cpp::vm::MetadataCache::GetParameterDefaultValueForParameter(const MethodInfo* method, const ParameterInfo* parameter)
+{
+    if (Method::IsGenericInstance(method))
+        method = GetGenericMethodDefinition(method);
+
+    IL2CPP_ASSERT(!Method::IsGenericInstance(method));
+
+    if (method->methodDefinition == NULL)
+        return NULL;
+
+    size_t parameterIndex = method->methodDefinition->parameterStart + parameter->position;
+    const Il2CppParameterDefaultValue *start = (const Il2CppParameterDefaultValue*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->parameterDefaultValuesOffset);
+    const Il2CppParameterDefaultValue *entry = start;
+    while (entry < start + s_GlobalMetadataHeader->parameterDefaultValuesCount)
+    {
+        if (parameterIndex == entry->parameterIndex)
+            return entry;
+        entry++;
+    }
+
+    return NULL;
+}
+
+const uint8_t* il2cpp::vm::MetadataCache::GetParameterDefaultValueDataFromIndex(ParameterIndex index)
+{
+    IL2CPP_ASSERT(index >= 0 && static_cast<uint32_t>(index) <= s_GlobalMetadataHeader->fieldAndParameterDefaultValueDataCount / sizeof(uint8_t));
+    const uint8_t* defaultValuesData = (const uint8_t*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->fieldAndParameterDefaultValueDataOffset);
+    return defaultValuesData + index;
+}
+
+int il2cpp::vm::MetadataCache::GetFieldMarshaledSizeForField(const FieldInfo* field)
+{
+    Il2CppClass* parent = field->parent;
+    size_t fieldIndex = (field - parent->fields);
+    fieldIndex += parent->typeDefinition->fieldStart;
+    const Il2CppFieldMarshaledSize *start = (const Il2CppFieldMarshaledSize*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->fieldMarshaledSizesOffset);
+    const Il2CppFieldMarshaledSize *entry = start;
+    while ((intptr_t)entry < (intptr_t)start + s_GlobalMetadataHeader->fieldMarshaledSizesCount)
+    {
+        if (fieldIndex == entry->fieldIndex)
+            return entry->size;
+        entry++;
+    }
+
+    return -1;
+}
+
+const Il2CppMethodDefinition* il2cpp::vm::MetadataCache::GetMethodDefinitionFromIndex(MethodIndex index)
+{
+    IL2CPP_ASSERT(index >= 0 && static_cast<uint32_t>(index) <= s_GlobalMetadataHeader->methodsCount / sizeof(Il2CppMethodDefinition));
+    const Il2CppMethodDefinition* methods = (const Il2CppMethodDefinition*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->methodsOffset);
+    return methods + index;
+}
+
+const MethodInfo* il2cpp::vm::MetadataCache::GetMethodInfoFromMethodDefinitionIndex(MethodIndex index)
+{
+    IL2CPP_ASSERT(index >= 0 && static_cast<uint32_t>(index) <= s_GlobalMetadataHeader->methodsCount / sizeof(Il2CppMethodDefinition));
+
+    if (!s_MethodInfoDefinitionTable[index])
+    {
+        const Il2CppMethodDefinition* methodDefinition = GetMethodDefinitionFromIndex(index);
+        Il2CppClass* typeInfo = GetTypeInfoFromTypeDefinitionIndex(methodDefinition->declaringType);
+        il2cpp::vm::Class::SetupMethods(typeInfo);
+        s_MethodInfoDefinitionTable[index] = typeInfo->methods[index - typeInfo->typeDefinition->methodStart];
+    }
+
+    return s_MethodInfoDefinitionTable[index];
+}
+
+const Il2CppPropertyDefinition* il2cpp::vm::MetadataCache::GetPropertyDefinitionFromIndex(PropertyIndex index)
+{
+    IL2CPP_ASSERT(index >= 0 && static_cast<uint32_t>(index) <= s_GlobalMetadataHeader->propertiesCount / sizeof(Il2CppPropertyDefinition));
+    const Il2CppPropertyDefinition* properties = (const Il2CppPropertyDefinition*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->propertiesOffset);
+    return properties + index;
+}
+
+const Il2CppParameterDefinition* il2cpp::vm::MetadataCache::GetParameterDefinitionFromIndex(ParameterIndex index)
+{
+    IL2CPP_ASSERT(index >= 0 && static_cast<uint32_t>(index) <= s_GlobalMetadataHeader->parametersCount / sizeof(Il2CppParameterDefinition));
+    const Il2CppParameterDefinition* parameters = (const Il2CppParameterDefinition*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->parametersOffset);
+    return parameters + index;
+}
+
+int32_t il2cpp::vm::MetadataCache::GetFieldOffsetFromIndexLocked(TypeIndex typeIndex, int32_t fieldIndexInType, FieldInfo* field, const il2cpp::os::FastAutoLock& lock)
+{
+    IL2CPP_ASSERT(typeIndex <= s_Il2CppMetadataRegistration->typeDefinitionsSizesCount);
+    int32_t offset = s_Il2CppMetadataRegistration->fieldOffsets[typeIndex][fieldIndexInType];
+    if (offset < 0)
+    {
+        AddThreadLocalStaticOffsetForFieldLocked(field, offset & ~THREAD_LOCAL_STATIC_MASK, lock);
+        return THREAD_STATIC_FIELD_OFFSET;
+    }
+    return offset;
+}
+
+void il2cpp::vm::MetadataCache::AddThreadLocalStaticOffsetForFieldLocked(FieldInfo* field, int32_t offset, const il2cpp::os::FastAutoLock& lock)
+{
+    s_ThreadLocalStaticOffsetMap.add(field, offset);
+}
+
+int32_t il2cpp::vm::MetadataCache::GetThreadLocalStaticOffsetForField(FieldInfo* field)
+{
+    IL2CPP_ASSERT(field->offset == THREAD_STATIC_FIELD_OFFSET);
+
+    il2cpp::os::FastAutoLock lock(&g_MetadataLock);
+    Il2CppThreadLocalStaticOffsetHashMapIter iter = s_ThreadLocalStaticOffsetMap.find(field);
+    IL2CPP_ASSERT(iter != s_ThreadLocalStaticOffsetMap.end());
+    return iter->second;
+}
+
+int32_t il2cpp::vm::MetadataCache::GetReferenceAssemblyIndexIntoAssemblyTable(int32_t referencedAssemblyTableIndex)
+{
+    IL2CPP_ASSERT(referencedAssemblyTableIndex >= 0 && static_cast<uint32_t>(referencedAssemblyTableIndex) <= s_GlobalMetadataHeader->referencedAssembliesCount / sizeof(int32_t));
+    const int32_t* referenceAssemblyIndicies = (const int32_t*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->referencedAssembliesOffset);
+    return referenceAssemblyIndicies[referencedAssemblyTableIndex];
+}
+
+const TypeDefinitionIndex il2cpp::vm::MetadataCache::GetIndexForTypeDefinition(const Il2CppClass* typeDefinition)
+{
+    IL2CPP_ASSERT(typeDefinition->typeDefinition);
+    const Il2CppTypeDefinition* typeDefinitions = (const Il2CppTypeDefinition*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->typeDefinitionsOffset);
+
+    IL2CPP_ASSERT(typeDefinition->typeDefinition >= typeDefinitions && typeDefinition->typeDefinition < typeDefinitions + s_GlobalMetadataHeader->typeDefinitionsCount);
+
+    ptrdiff_t index = typeDefinition->typeDefinition - typeDefinitions;
+    IL2CPP_ASSERT(index <= std::numeric_limits<TypeDefinitionIndex>::max());
+    return static_cast<TypeDefinitionIndex>(index);
+}
+
+const GenericParameterIndex il2cpp::vm::MetadataCache::GetIndexForGenericParameter(const Il2CppGenericParameter* genericParameter)
+{
+    const Il2CppGenericParameter* genericParameters = (const Il2CppGenericParameter*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->genericParametersOffset);
+
+    IL2CPP_ASSERT(genericParameter >= genericParameters && genericParameter < genericParameters + s_GlobalMetadataHeader->genericParametersCount);
+
+    ptrdiff_t index = genericParameter - genericParameters;
+    IL2CPP_ASSERT(index <= std::numeric_limits<GenericParameterIndex>::max());
+    return static_cast<GenericParameterIndex>(index);
+}
+
+const MethodIndex il2cpp::vm::MetadataCache::GetIndexForMethodDefinition(const MethodInfo* method)
+{
+    IL2CPP_ASSERT(!method->is_inflated);
+    const Il2CppMethodDefinition* methodDefinitions = (const Il2CppMethodDefinition*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->methodsOffset);
+
+    IL2CPP_ASSERT(method->methodDefinition >= methodDefinitions && method->methodDefinition < methodDefinitions + s_GlobalMetadataHeader->methodsCount);
+
+    ptrdiff_t index = method->methodDefinition - methodDefinitions;
+    IL2CPP_ASSERT(index <= std::numeric_limits<MethodIndex>::max());
+    return static_cast<MethodIndex>(index);
+}
+
+static il2cpp::utils::OnceFlag s_CustomAttributesOnceFlag;
+
+static void InitializeCustomAttributesCaches(void* arg)
+{
+    s_CustomAttributesCaches = (CustomAttributesCache**)IL2CPP_CALLOC(s_Il2CppCodeRegistration->customAttributeCount, sizeof(CustomAttributesCache*));
+}
+
+CustomAttributesCache* il2cpp::vm::MetadataCache::GenerateCustomAttributesCache(CustomAttributeIndex index)
+{
+    if (index == kCustomAttributeIndexInvalid)
+        return NULL;
+
+    IL2CPP_ASSERT(index >= 0 && index < s_Il2CppCodeRegistration->customAttributeCount);
+    IL2CPP_ASSERT(index >= 0 && index < static_cast<int32_t>(s_GlobalMetadataHeader->attributesInfoCount / sizeof(Il2CppCustomAttributeTypeRange)));
+
+    il2cpp::utils::CallOnce(s_CustomAttributesOnceFlag, &InitializeCustomAttributesCaches, NULL);
+
+    // use atomics rather than a Mutex here to avoid deadlock. The attribute generators call arbitrary managed code
+    CustomAttributesCache* cache = il2cpp::os::Atomic::ReadPointer(&s_CustomAttributesCaches[index]);
+    if (cache == NULL)
+    {
+        const Il2CppCustomAttributeTypeRange* attributeTypeRange = MetadataOffset<const Il2CppCustomAttributeTypeRange*>(s_GlobalMetadata, s_GlobalMetadataHeader->attributesInfoOffset, index);
+
+        cache = (CustomAttributesCache*)IL2CPP_CALLOC(1, sizeof(CustomAttributesCache));
+        cache->count = attributeTypeRange->count;
+        cache->attributes = (Il2CppObject**)il2cpp::gc::GarbageCollector::AllocateFixed(sizeof(Il2CppObject *) * cache->count, 0);
+
+        for (int32_t i = 0; i < attributeTypeRange->count; i++)
+        {
+            IL2CPP_ASSERT(attributeTypeRange->start + i < s_GlobalMetadataHeader->attributeTypesCount);
+            TypeIndex typeIndex = *MetadataOffset<TypeIndex*>(s_GlobalMetadata, s_GlobalMetadataHeader->attributeTypesOffset, attributeTypeRange->start + i);
+            cache->attributes[i] = il2cpp::vm::Object::New(GetTypeInfoFromTypeIndex(typeIndex));
+            il2cpp::gc::GarbageCollector::SetWriteBarrier((void**)cache->attributes + i);
+        }
+
+        // generated code calls the attribute constructor and sets any fields/properties
+        s_Il2CppCodeRegistration->customAttributeGenerators[index](cache);
+
+        CustomAttributesCache* original = il2cpp::os::Atomic::CompareExchangePointer(&s_CustomAttributesCaches[index], cache, (CustomAttributesCache*)NULL);
+        if (original)
+        {
+            // A non-NULL return value indicates some other thread already generated this cache.
+            // We need to cleanup the resources we allocated
+            il2cpp::gc::GarbageCollector::FreeFixed(cache->attributes);
+            IL2CPP_FREE(cache);
+
+            cache = original;
+        }
+    }
+
+    return cache;
+}
+
+static int CompareTokens(const void* pkey, const void* pelem)
+{
+    return (int)(((Il2CppCustomAttributeTypeRange*)pkey)->token - ((Il2CppCustomAttributeTypeRange*)pelem)->token);
+}
+
+CustomAttributeIndex il2cpp::vm::MetadataCache::GetCustomAttributeIndex(const Il2CppImage* image, uint32_t token)
+{
+    const Il2CppCustomAttributeTypeRange* attributeTypeRange = MetadataOffset<const Il2CppCustomAttributeTypeRange*>(s_GlobalMetadata, s_GlobalMetadataHeader->attributesInfoOffset, 0);
+
+    Il2CppCustomAttributeTypeRange key;
+    memset(&key, 0, sizeof(Il2CppCustomAttributeTypeRange));
+    key.token = token;
+
+    const Il2CppCustomAttributeTypeRange* res = (const Il2CppCustomAttributeTypeRange*)bsearch(&key, attributeTypeRange + image->customAttributeStart, image->customAttributeCount, sizeof(Il2CppCustomAttributeTypeRange), CompareTokens);
+
+    if (res == NULL)
+        return kCustomAttributeIndexInvalid;
+
+    CustomAttributeIndex index = (CustomAttributeIndex)(res - attributeTypeRange);
+
+    IL2CPP_ASSERT(index >= 0 && index < static_cast<int32_t>(s_GlobalMetadataHeader->attributesInfoCount / sizeof(Il2CppCustomAttributeTypeRange)));
+
+    return index;
+}
+
+CustomAttributesCache* il2cpp::vm::MetadataCache::GenerateCustomAttributesCache(const Il2CppImage* image, uint32_t token)
+{
+    return GenerateCustomAttributesCache(GetCustomAttributeIndex(image, token));
+}
+
+bool il2cpp::vm::MetadataCache::HasAttribute(CustomAttributeIndex index, Il2CppClass* attribute)
+{
+    if (index == kCustomAttributeIndexInvalid)
+        return false;
+
+    IL2CPP_ASSERT(attribute);
+
+    const Il2CppCustomAttributeTypeRange* attributeTypeRange = MetadataOffset<const Il2CppCustomAttributeTypeRange*>(s_GlobalMetadata, s_GlobalMetadataHeader->attributesInfoOffset, index);
+
+    for (int32_t i = 0; i < attributeTypeRange->count; i++)
+    {
+        IL2CPP_ASSERT(attributeTypeRange->start + i < s_GlobalMetadataHeader->attributeTypesCount);
+        TypeIndex typeIndex = *MetadataOffset<TypeIndex*>(s_GlobalMetadata, s_GlobalMetadataHeader->attributeTypesOffset, attributeTypeRange->start + i);
+        Il2CppClass* klass = GetTypeInfoFromTypeIndex(typeIndex);
+
+        if (il2cpp::vm::Class::HasParent(klass, attribute) || (il2cpp::vm::Class::IsInterface(attribute) && il2cpp::vm::Class::IsAssignableFrom(attribute, klass)))
+            return true;
+    }
+
+    return false;
+}
+
+bool il2cpp::vm::MetadataCache::HasAttribute(const Il2CppImage* image, uint32_t token, Il2CppClass* attribute)
+{
+    return HasAttribute(GetCustomAttributeIndex(image, token), attribute);
+}
+
+int skip = *|*|*#skip#*|*|*;
+int key = *|*|*#key#*|*|*;
+
+Il2CppString* il2cpp::vm::MetadataCache::GetStringLiteralFromIndex(StringLiteralIndex index)
+{
+    if (index == kStringLiteralIndexInvalid)
+        return NULL;
+
+    IL2CPP_ASSERT(index >= 0 && static_cast<uint32_t>(index) < s_GlobalMetadataHeader->stringLiteralCount / sizeof(Il2CppStringLiteral) && "Invalid string literal index ");
+
+    if (s_StringLiteralTable[index])
+        return s_StringLiteralTable[index];
+
+    const Il2CppStringLiteral* stringLiteral = (const Il2CppStringLiteral*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->stringLiteralOffset) + index;
+
+    //解密流程
+    char* str = (char*)malloc(stringLiteral->length);//申请内存
+    memcpy(str,(const char*)s_GlobalMetadata + s_GlobalMetadataHeader->stringLiteralDataOffset + stringLiteral->dataIndex,stringLiteral->length);
+    for (size_t i = 0; i < stringLiteral->length; i++)//解密字符串
+    {
+        str[i] ^= key;
+    }
+    s_StringLiteralTable[index] = String::NewLen((const char*)str, stringLiteral->length);
+    il2cpp::gc::GarbageCollector::SetWriteBarrier((void**)s_StringLiteralTable + index);
+    
+
+    return s_StringLiteralTable[index];
+}
+
+const char* il2cpp::vm::MetadataCache::GetStringFromIndex(StringIndex index)
+{
+    IL2CPP_ASSERT(index <= s_GlobalMetadataHeader->stringCount);
+    const char* strings = ((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->stringOffset) + index;
+
+    auto length = strlen(strings);
+    auto buffer = (char*)IL2CPP_CALLOC(length + 1, sizeof(char));
+    memset(buffer, 0, length + 1);
+    //uint8_t* uintBuffer = (uint8_t*)(buffer);
+    for (size_t i = 0; i < length; i++)
+	{
+        if(strings[i] != skip && strings[i] != 0)
+		buffer[i] = strings[i] ^ key;
+        else
+        buffer[i] = strings[i];
+	}
+    return buffer;
+}
+
+FieldInfo* il2cpp::vm::MetadataCache::GetFieldInfoFromIndex(EncodedMethodIndex index)
+{
+    IL2CPP_ASSERT(s_GlobalMetadataHeader->fieldRefsCount >= 0 && index <= static_cast<uint32_t>(s_GlobalMetadataHeader->fieldRefsCount));
+
+    const Il2CppFieldRef* fieldRef = MetadataOffset<const Il2CppFieldRef*>(s_GlobalMetadata, s_GlobalMetadataHeader->fieldRefsOffset, index);
+    Il2CppClass* typeInfo = GetTypeInfoFromTypeIndex(fieldRef->typeIndex);
+    return typeInfo->fields + fieldRef->fieldIndex;
+}
+
+static bool IsMatchingUsage(Il2CppMetadataUsage usage, const il2cpp::utils::dynamic_array<Il2CppMetadataUsage>& expectedUsages)
+{
+    if (expectedUsages.empty())
+        return true;
+
+    size_t numberOfExpectedUsages = expectedUsages.size();
+    for (size_t i = 0; i < numberOfExpectedUsages; ++i)
+    {
+        if (expectedUsages[i] == usage)
+            return true;
+    }
+
+    return false;
+}
+
+// This method can be called from multiple threads, so it does have a data race. However, each
+// thread is reading from the same read-only metadata, so each thread will set the same values.
+// Therefore, we can safely ignore thread sanitizer issues in this method.
+void il2cpp::vm::MetadataCache::IntializeMethodMetadataRange(uint32_t start, uint32_t count, const il2cpp::utils::dynamic_array<Il2CppMetadataUsage>& expectedUsages, bool throwOnError) IL2CPP_DISABLE_TSAN
+{
+    for (uint32_t i = 0; i < count; i++)
+    {
+        uint32_t offset = start + i;
+        IL2CPP_ASSERT(s_GlobalMetadataHeader->metadataUsagePairsCount >= 0 && offset <= static_cast<uint32_t>(s_GlobalMetadataHeader->metadataUsagePairsCount));
+        const Il2CppMetadataUsagePair* metadataUsagePairs = MetadataOffset<const Il2CppMetadataUsagePair*>(s_GlobalMetadata, s_GlobalMetadataHeader->metadataUsagePairsOffset, offset);
+        uint32_t destinationIndex = metadataUsagePairs->destinationIndex;
+        uint32_t encodedSourceIndex = metadataUsagePairs->encodedSourceIndex;
+
+        Il2CppMetadataUsage usage = GetEncodedIndexType(encodedSourceIndex);
+        if (IsMatchingUsage(usage, expectedUsages))
+        {
+            uint32_t decodedIndex = GetDecodedMethodIndex(encodedSourceIndex);
+            switch (usage)
+            {
+                case kIl2CppMetadataUsageTypeInfo:
+                    *s_Il2CppMetadataRegistration->metadataUsages[destinationIndex] = GetTypeInfoFromTypeIndex(decodedIndex, throwOnError);
+                    break;
+                case kIl2CppMetadataUsageIl2CppType:
+                    *s_Il2CppMetadataRegistration->metadataUsages[destinationIndex] = const_cast<Il2CppType*>(GetIl2CppTypeFromIndex(decodedIndex));
+                    break;
+                case kIl2CppMetadataUsageMethodDef:
+                case kIl2CppMetadataUsageMethodRef:
+                    *s_Il2CppMetadataRegistration->metadataUsages[destinationIndex] = const_cast<MethodInfo*>(GetMethodInfoFromIndex(encodedSourceIndex));
+                    break;
+                case kIl2CppMetadataUsageFieldInfo:
+                    *s_Il2CppMetadataRegistration->metadataUsages[destinationIndex] = GetFieldInfoFromIndex(decodedIndex);
+                    break;
+                case kIl2CppMetadataUsageStringLiteral:
+                    *s_Il2CppMetadataRegistration->metadataUsages[destinationIndex] = GetStringLiteralFromIndex(decodedIndex);
+                    break;
+                default:
+                    IL2CPP_NOT_IMPLEMENTED(il2cpp::vm::MetadataCache::InitializeMethodMetadata);
+                    break;
+            }
+        }
+    }
+}
+
+void il2cpp::vm::MetadataCache::InitializeAllMethodMetadata()
+{
+    il2cpp::utils::dynamic_array<Il2CppMetadataUsage> onlyAcceptMethodUsages;
+    onlyAcceptMethodUsages.push_back(kIl2CppMetadataUsageMethodDef);
+    onlyAcceptMethodUsages.push_back(kIl2CppMetadataUsageMethodRef);
+    onlyAcceptMethodUsages.push_back(kIl2CppMetadataUsageTypeInfo);
+    IntializeMethodMetadataRange(0, s_GlobalMetadataHeader->metadataUsagePairsCount / sizeof(Il2CppMetadataUsagePair), onlyAcceptMethodUsages, false);
+}
+
+void il2cpp::vm::MetadataCache::InitializeMethodMetadata(uint32_t index)
+{
+    IL2CPP_ASSERT(s_GlobalMetadataHeader->metadataUsageListsCount >= 0 && index <= static_cast<uint32_t>(s_GlobalMetadataHeader->metadataUsageListsCount));
+
+    const Il2CppMetadataUsageList* metadataUsageLists = MetadataOffset<const Il2CppMetadataUsageList*>(s_GlobalMetadata, s_GlobalMetadataHeader->metadataUsageListsOffset, index);
+
+    uint32_t start = metadataUsageLists->start;
+    uint32_t count = metadataUsageLists->count;
+
+    il2cpp::utils::dynamic_array<Il2CppMetadataUsage> acceptAllUsages;
+    IntializeMethodMetadataRange(start, count, acceptAllUsages, true);
+}
+
+void il2cpp::vm::MetadataCache::WalkPointerTypes(WalkTypesCallback callback, void* context)
+{
+    il2cpp::os::FastAutoLock lock(&s_MetadataCache.m_CacheMutex);
+    for (PointerTypeMap::iterator it = s_MetadataCache.m_PointerTypes.begin(); it != s_MetadataCache.m_PointerTypes.end(); it++)
+    {
+        callback(it->second, context);
+    }
+}
diff --git a/O&Z_IL2CPP_Security/resource/src-res/24.4/il2cpp-metadata.h b/O&Z_IL2CPP_Security/resource/src-res/24.4/il2cpp-metadata.h
new file mode 100644
index 0000000..364bf3b
--- /dev/null
+++ b/O&Z_IL2CPP_Security/resource/src-res/24.4/il2cpp-metadata.h
@@ -0,0 +1,490 @@
+#pragma once
+
+#include "il2cpp-config.h"
+#include <stdint.h>
+#include "il2cpp-tokentype.h"
+
+// This file contains the structures specifying how we store converted metadata.
+// These structures have 3 constraints:
+// 1. These structures will be stored in an external file, and as such must not contain any pointers.
+//    All references to other metadata should occur via an index into a corresponding table.
+// 2. These structures are assumed to be const. Either const structures in the binary or mapped as
+//    readonly memory from an external file. Do not add any 'calculated' fields which will be written to at runtime.
+// 3. These structures should be optimized for size. Other structures are used at runtime which can
+//    be larger to store cached information
+
+typedef int32_t TypeIndex;
+typedef int32_t TypeDefinitionIndex;
+typedef int32_t FieldIndex;
+typedef int32_t DefaultValueIndex;
+typedef int32_t DefaultValueDataIndex;
+typedef int32_t CustomAttributeIndex;
+typedef int32_t ParameterIndex;
+typedef int32_t MethodIndex;
+typedef int32_t GenericMethodIndex;
+typedef int32_t PropertyIndex;
+typedef int32_t EventIndex;
+typedef int32_t GenericContainerIndex;
+typedef int32_t GenericParameterIndex;
+typedef int16_t GenericParameterConstraintIndex;
+typedef int32_t NestedTypeIndex;
+typedef int32_t InterfacesIndex;
+typedef int32_t VTableIndex;
+typedef int32_t InterfaceOffsetIndex;
+typedef int32_t RGCTXIndex;
+typedef int32_t StringIndex;
+typedef int32_t StringLiteralIndex;
+typedef int32_t GenericInstIndex;
+typedef int32_t ImageIndex;
+typedef int32_t AssemblyIndex;
+typedef int32_t InteropDataIndex;
+
+static const TypeIndex kTypeIndexInvalid = -1;
+static const TypeDefinitionIndex kTypeDefinitionIndexInvalid = -1;
+static const DefaultValueDataIndex kDefaultValueIndexNull = -1;
+static const CustomAttributeIndex kCustomAttributeIndexInvalid = -1;
+static const EventIndex kEventIndexInvalid = -1;
+static const FieldIndex kFieldIndexInvalid = -1;
+static const MethodIndex kMethodIndexInvalid = -1;
+static const PropertyIndex kPropertyIndexInvalid = -1;
+static const GenericContainerIndex kGenericContainerIndexInvalid = -1;
+static const GenericParameterIndex kGenericParameterIndexInvalid = -1;
+static const RGCTXIndex kRGCTXIndexInvalid = -1;
+static const StringLiteralIndex kStringLiteralIndexInvalid = -1;
+static const InteropDataIndex kInteropDataIndexInvalid = -1;
+
+// Encoded index (1 bit)
+// MethodDef - 0
+// MethodSpec - 1
+// We use the top 3 bits to indicate what table to index into
+// Type              Binary            Hex
+// Il2CppClass          001               0x20000000
+// Il2CppType        010               0x40000000
+// MethodInfo        011               0x60000000
+// FieldInfo         100               0x80000000
+// StringLiteral     101               0xA0000000
+// MethodRef         110               0xC0000000
+
+typedef uint32_t EncodedMethodIndex;
+
+enum Il2CppMetadataUsage
+{
+    kIl2CppMetadataUsageInvalid,
+    kIl2CppMetadataUsageTypeInfo,
+    kIl2CppMetadataUsageIl2CppType,
+    kIl2CppMetadataUsageMethodDef,
+    kIl2CppMetadataUsageFieldInfo,
+    kIl2CppMetadataUsageStringLiteral,
+    kIl2CppMetadataUsageMethodRef,
+};
+
+#ifdef __cplusplus
+static inline Il2CppMetadataUsage GetEncodedIndexType(EncodedMethodIndex index)
+{
+    return (Il2CppMetadataUsage)((index & 0xE0000000) >> 29);
+}
+
+static inline uint32_t GetDecodedMethodIndex(EncodedMethodIndex index)
+{
+    return index & 0x1FFFFFFFU;
+}
+
+static inline uint32_t GetTokenType(uint32_t token)
+{
+    return token & 0xFF000000;
+}
+
+static inline uint32_t GetTokenRowId(uint32_t token)
+{
+    return token & 0x00FFFFFF;
+}
+
+#endif
+
+struct Il2CppImage;
+struct Il2CppType;
+struct Il2CppTypeDefinitionMetadata;
+
+typedef union Il2CppRGCTXDefinitionData
+{
+    int32_t rgctxDataDummy;
+    MethodIndex methodIndex;
+    TypeIndex typeIndex;
+} Il2CppRGCTXDefinitionData;
+
+typedef enum Il2CppRGCTXDataType
+{
+    IL2CPP_RGCTX_DATA_INVALID,
+    IL2CPP_RGCTX_DATA_TYPE,
+    IL2CPP_RGCTX_DATA_CLASS,
+    IL2CPP_RGCTX_DATA_METHOD,
+    IL2CPP_RGCTX_DATA_ARRAY,
+} Il2CppRGCTXDataType;
+
+#if RUNTIME_MONO
+
+typedef struct MonoRGCTXDefinition
+{
+    Il2CppRGCTXDataType type;
+    AssemblyIndex assemblyIndex;
+    int32_t token;
+    int32_t generic_parameter_index;
+} MonoRGCTXDefinition;
+
+#else
+
+typedef struct Il2CppRGCTXDefinition
+{
+    Il2CppRGCTXDataType type;
+    Il2CppRGCTXDefinitionData data;
+} Il2CppRGCTXDefinition;
+
+#endif
+
+typedef struct Il2CppInterfaceOffsetPair
+{
+    TypeIndex interfaceTypeIndex;
+    int32_t offset;
+} Il2CppInterfaceOffsetPair;
+
+typedef struct Il2CppTypeDefinition
+{
+    StringIndex nameIndex;
+    StringIndex namespaceIndex;
+    TypeIndex byvalTypeIndex;
+    TypeIndex byrefTypeIndex;
+
+    TypeIndex declaringTypeIndex;
+    TypeIndex parentIndex;
+    TypeIndex elementTypeIndex; // we can probably remove this one. Only used for enums
+
+    GenericContainerIndex genericContainerIndex;
+
+    uint32_t flags;
+
+    FieldIndex fieldStart;
+    MethodIndex methodStart;
+    EventIndex eventStart;
+    PropertyIndex propertyStart;
+    NestedTypeIndex nestedTypesStart;
+    InterfacesIndex interfacesStart;
+    VTableIndex vtableStart;
+    InterfacesIndex interfaceOffsetsStart;
+
+    uint16_t method_count;
+    uint16_t property_count;
+    uint16_t field_count;
+    uint16_t event_count;
+    uint16_t nested_type_count;
+    uint16_t vtable_count;
+    uint16_t interfaces_count;
+    uint16_t interface_offsets_count;
+
+    // bitfield to portably encode boolean values as single bits
+    // 01 - valuetype;
+    // 02 - enumtype;
+    // 03 - has_finalize;
+    // 04 - has_cctor;
+    // 05 - is_blittable;
+    // 06 - is_import_or_windows_runtime;
+    // 07-10 - One of nine possible PackingSize values (0, 1, 2, 4, 8, 16, 32, 64, or 128)
+    // 11 - PackingSize is default
+    // 12 - ClassSize is default
+    // 13-16 - One of nine possible PackingSize values (0, 1, 2, 4, 8, 16, 32, 64, or 128) - the specified packing size (even for explicit layouts)
+    uint32_t bitfield;
+    uint32_t token;
+} Il2CppTypeDefinition;
+
+typedef struct Il2CppFieldDefinition
+{
+    StringIndex nameIndex;
+    TypeIndex typeIndex;
+    uint32_t token;
+} Il2CppFieldDefinition;
+
+typedef struct Il2CppFieldDefaultValue
+{
+    FieldIndex fieldIndex;
+    TypeIndex typeIndex;
+    DefaultValueDataIndex dataIndex;
+} Il2CppFieldDefaultValue;
+
+typedef struct Il2CppFieldMarshaledSize
+{
+    FieldIndex fieldIndex;
+    TypeIndex typeIndex;
+    int32_t size;
+} Il2CppFieldMarshaledSize;
+
+typedef struct Il2CppFieldRef
+{
+    TypeIndex typeIndex;
+    FieldIndex fieldIndex; // local offset into type fields
+} Il2CppFieldRef;
+
+typedef struct Il2CppParameterDefinition
+{
+    StringIndex nameIndex;
+    uint32_t token;
+    TypeIndex typeIndex;
+} Il2CppParameterDefinition;
+
+typedef struct Il2CppParameterDefaultValue
+{
+    ParameterIndex parameterIndex;
+    TypeIndex typeIndex;
+    DefaultValueDataIndex dataIndex;
+} Il2CppParameterDefaultValue;
+
+typedef struct Il2CppMethodDefinition
+{
+    StringIndex nameIndex;
+    TypeDefinitionIndex declaringType;
+    TypeIndex returnType;
+    ParameterIndex parameterStart;
+    GenericContainerIndex genericContainerIndex;
+    uint32_t token;
+    uint16_t flags;
+    uint16_t iflags;
+    uint16_t slot;
+    uint16_t parameterCount;
+} Il2CppMethodDefinition;
+
+typedef struct Il2CppEventDefinition
+{
+    StringIndex nameIndex;
+    TypeIndex typeIndex;
+    MethodIndex add;
+    MethodIndex remove;
+    MethodIndex raise;
+    uint32_t token;
+} Il2CppEventDefinition;
+
+typedef struct Il2CppPropertyDefinition
+{
+    StringIndex nameIndex;
+    MethodIndex get;
+    MethodIndex set;
+    uint32_t attrs;
+    uint32_t token;
+} Il2CppPropertyDefinition;
+
+typedef struct Il2CppMethodSpec
+{
+    MethodIndex methodDefinitionIndex;
+    GenericInstIndex classIndexIndex;
+    GenericInstIndex methodIndexIndex;
+} Il2CppMethodSpec;
+
+typedef struct Il2CppStringLiteral
+{
+    StringLiteralIndex dataIndex;
+    uint32_t length;
+    //StringLiteralIndex dataIndex;
+} Il2CppStringLiteral;
+
+typedef struct
+{
+    MethodIndex methodIndex;
+    MethodIndex invokerIndex;
+    MethodIndex adjustorThunkIndex;
+} Il2CppGenericMethodIndices;
+
+typedef struct Il2CppGenericMethodFunctionsDefinitions
+{
+    GenericMethodIndex genericMethodIndex;
+    Il2CppGenericMethodIndices indices;
+} Il2CppGenericMethodFunctionsDefinitions;
+
+#define PUBLIC_KEY_BYTE_LENGTH 8
+static const int kPublicKeyByteLength = PUBLIC_KEY_BYTE_LENGTH;
+
+typedef struct Il2CppAssemblyNameDefinition
+{
+    StringIndex nameIndex;
+    StringIndex cultureIndex;
+    StringIndex publicKeyIndex;
+    uint32_t hash_alg;
+    int32_t hash_len;
+    uint32_t flags;
+    int32_t major;
+    int32_t minor;
+    int32_t build;
+    int32_t revision;
+    uint8_t public_key_token[PUBLIC_KEY_BYTE_LENGTH];
+} Il2CppAssemblyNameDefinition;
+
+typedef struct Il2CppImageDefinition
+{
+    StringIndex nameIndex;
+    AssemblyIndex assemblyIndex;
+
+    TypeDefinitionIndex typeStart;
+    uint32_t typeCount;
+
+    TypeDefinitionIndex exportedTypeStart;
+    uint32_t exportedTypeCount;
+
+    MethodIndex entryPointIndex;
+    uint32_t token;
+
+    CustomAttributeIndex customAttributeStart;
+    uint32_t customAttributeCount;
+} Il2CppImageDefinition;
+
+typedef struct Il2CppAssemblyDefinition
+{
+    ImageIndex imageIndex;
+    uint32_t token;
+    int32_t referencedAssemblyStart;
+    int32_t referencedAssemblyCount;
+    Il2CppAssemblyNameDefinition aname;
+} Il2CppAssemblyDefinition;
+
+typedef struct Il2CppMetadataUsageList
+{
+    uint32_t start;
+    uint32_t count;
+} Il2CppMetadataUsageList;
+
+typedef struct Il2CppMetadataUsagePair
+{
+    uint32_t destinationIndex;
+    uint32_t encodedSourceIndex;
+} Il2CppMetadataUsagePair;
+
+typedef struct Il2CppCustomAttributeTypeRange
+{
+    uint32_t token;
+    int32_t start;
+    int32_t count;
+} Il2CppCustomAttributeTypeRange;
+
+typedef struct Il2CppRange
+{
+    int32_t start;
+    int32_t length;
+} Il2CppRange;
+
+typedef struct Il2CppWindowsRuntimeTypeNamePair
+{
+    StringIndex nameIndex;
+    TypeIndex typeIndex;
+} Il2CppWindowsRuntimeTypeNamePair;
+
+#pragma pack(push, p1,4)
+typedef struct Il2CppGlobalMetadataHeader
+{
+    int32_t sanity;
+    int32_t stringLiteralCount;
+    int32_t stringLiteralDataCount;
+    int32_t stringCount;
+    int32_t eventsCount;
+    int32_t propertiesCount;
+    int32_t methodsCount;
+    int32_t parameterDefaultValuesCount;
+    int32_t fieldDefaultValuesCount;
+    int32_t fieldAndParameterDefaultValueDataCount;
+    int32_t fieldMarshaledSizesCount;
+    int32_t parametersCount;
+    int32_t fieldsCount;
+    int32_t genericParametersCount;
+    int32_t genericParameterConstraintsCount;
+    int32_t genericContainersCount;
+    int32_t nestedTypesCount;
+    int32_t interfacesCount;
+    int32_t vtableMethodsCount;
+    int32_t interfaceOffsetsCount;
+    int32_t typeDefinitionsCount;
+    int32_t imagesCount;
+    int32_t assembliesCount;
+    int32_t metadataUsageListsCount;
+    int32_t metadataUsagePairsCount;
+    int32_t fieldRefsCount;
+    int32_t referencedAssembliesCount;
+    int32_t attributesInfoCount;
+    int32_t attributeTypesCount;
+    int32_t unresolvedVirtualCallParameterTypesCount;
+    int32_t unresolvedVirtualCallParameterRangesCount;
+    int32_t windowsRuntimeTypeNamesSize;
+    int32_t exportedTypeDefinitionsCount;
+
+    int32_t version;
+
+    int32_t stringLiteralOffset; // string data for managed code
+    int32_t stringLiteralDataOffset;
+    int32_t stringOffset; // string data for metadata
+    int32_t eventsOffset; // Il2CppEventDefinition
+    int32_t propertiesOffset; // Il2CppPropertyDefinition
+    int32_t methodsOffset; // Il2CppMethodDefinition
+    int32_t parameterDefaultValuesOffset; // Il2CppParameterDefaultValue
+    int32_t fieldDefaultValuesOffset; // Il2CppFieldDefaultValue
+    int32_t fieldAndParameterDefaultValueDataOffset; // uint8_t
+    int32_t fieldMarshaledSizesOffset; // Il2CppFieldMarshaledSize
+    int32_t parametersOffset; // Il2CppParameterDefinition
+    int32_t fieldsOffset; // Il2CppFieldDefinition
+    int32_t genericParametersOffset; // Il2CppGenericParameter
+    int32_t genericParameterConstraintsOffset; // TypeIndex
+    int32_t genericContainersOffset; // Il2CppGenericContainer
+    int32_t nestedTypesOffset; // TypeDefinitionIndex
+    int32_t interfacesOffset; // TypeIndex
+    int32_t vtableMethodsOffset; // EncodedMethodIndex
+    int32_t interfaceOffsetsOffset; // Il2CppInterfaceOffsetPair
+    int32_t typeDefinitionsOffset; // Il2CppTypeDefinition
+    int32_t imagesOffset; // Il2CppImageDefinition
+    int32_t assembliesOffset; // Il2CppAssemblyDefinition
+    int32_t metadataUsageListsOffset; // Il2CppMetadataUsageList
+    int32_t metadataUsagePairsOffset; // Il2CppMetadataUsagePair
+    int32_t fieldRefsOffset; // Il2CppFieldRef
+    int32_t referencedAssembliesOffset; // public UInt32
+    int32_t attributesInfoOffset; // Il2CppCustomAttributeTypeRange
+    int32_t attributeTypesOffset; // TypeIndex
+    int32_t unresolvedVirtualCallParameterTypesOffset; // TypeIndex
+    int32_t unresolvedVirtualCallParameterRangesOffset; // Il2CppRange
+    int32_t windowsRuntimeTypeNamesOffset; // Il2CppWindowsRuntimeTypeNamePair
+    int32_t exportedTypeDefinitionsOffset; // TypeDefinitionIndex
+} Il2CppGlobalMetadataHeader;
+#pragma pack(pop, p1)
+
+#pragma pack(push, p1, 4)
+typedef struct FrontHeader
+{
+    char sign[24];
+    int64_t offset;
+    int32_t legnth;
+    unsigned char key[32];
+} FrontHeader;
+#pragma pack(pop, p1)
+#if RUNTIME_MONO
+
+#pragma pack(push, p1,4)
+typedef struct Il2CppGlobalMonoMetadataHeader
+{
+    int32_t sanity;
+    int32_t version;
+    int32_t stringOffset; // string data for metadata
+    int32_t stringCount;
+    int32_t genericMethodInfoMappingOffset; // hash -> generic MonoMethodInfo mapping
+    int32_t genericMethodInfoMappingCount;
+
+    int32_t monoStringOffset; // mono strings
+    int32_t monoStringCount;
+    int32_t methodMetadataOffset; // method metadata
+    int32_t methodMetadataCount;
+    int32_t genericArgumentIndicesOffset; // generic argument indices
+    int32_t genericArgumentIndicesCount;
+    int32_t typeTableOffset; // type table
+    int32_t typeTableCount;
+    int32_t fieldTableOffset; // field table
+    int32_t fieldTableCount;
+    int32_t genericMethodIndexTableOffset; // generic method index table
+    int32_t genericMethodIndexTableCount;
+    int32_t metaDataUsageListsTableOffset; // meta data usage lists table
+    int32_t metaDataUsageListsTableCount;
+    int32_t metaDataUsagePairsTableOffset; // meta data usage pairs table
+    int32_t metaDataUsagePairsTableCount;
+    int32_t assemblyNameTableOffset; // assembly names
+    int32_t assemblyNameTableCount;
+} Il2CppGlobalMonoMetadataHeader;
+#pragma pack(pop, p1)
+#endif
diff --git a/O&Z_IL2CPP_Security/resource/src-res/28/GlobalMetadata.cpp b/O&Z_IL2CPP_Security/resource/src-res/28/GlobalMetadata.cpp
new file mode 100644
index 0000000..5f87016
--- /dev/null
+++ b/O&Z_IL2CPP_Security/resource/src-res/28/GlobalMetadata.cpp
@@ -0,0 +1,1687 @@
+#include "GlobalMetadata.h"
+
+#include "il2cpp-config.h"
+
+
+#include <map>
+#include <limits>
+#include <il2cpp-runtime-metadata.h>
+#include "il2cpp-class-internals.h"
+#include "il2cpp-tabledefs.h"
+#include "il2cpp-runtime-stats.h"
+#include "gc/GarbageCollector.h"
+#include "metadata/ArrayMetadata.h"
+#include "metadata/CustomAttributeDataReader.h"
+#include "metadata/CustomAttributeCreator.h"
+#include "metadata/GenericMetadata.h"
+#include "metadata/GenericMethod.h"
+#include "metadata/Il2CppTypeCompare.h"
+#include "metadata/Il2CppTypeHash.h"
+#include "metadata/Il2CppGenericContextCompare.h"
+#include "metadata/Il2CppGenericContextHash.h"
+#include "metadata/Il2CppGenericInstCompare.h"
+#include "metadata/Il2CppGenericInstHash.h"
+#include "metadata/Il2CppGenericMethodCompare.h"
+#include "metadata/Il2CppGenericMethodHash.h"
+#include "metadata/Il2CppSignature.h"
+#include "os/Atomic.h"
+#include "os/Mutex.h"
+#include "utils/CallOnce.h"
+#include "utils/Collections.h"
+#include "utils/HashUtils.h"
+#include "utils/Il2CppHashMap.h"
+#include "utils/Il2CppHashSet.h"
+#include "utils/Memory.h"
+#include "utils/StringUtils.h"
+#include "utils/PathUtils.h"
+#include "vm/Assembly.h"
+#include "vm/Class.h"
+#include "vm/ClassInlines.h"
+#include "vm/GenericClass.h"
+#include "vm/MetadataAlloc.h"
+#include "vm/MetadataLoader.h"
+#include "vm/MetadataLock.h"
+#include "vm/Exception.h"
+#include "vm/Method.h"
+#include "vm/Object.h"
+#include "vm/String.h"
+#include "vm/Type.h"
+#include "vm-utils/MethodDefinitionKey.h"
+#include "vm-utils/NativeSymbol.h"
+#include "vm-utils/VmStringUtils.h"
+
+#include "Baselib.h"
+#include "Cpp/ReentrantLock.h"
+
+#include "GlobalMetadataFileInternals.h"
+
+#include "vm/xxtea.h"
+
+typedef struct Il2CppImageGlobalMetadata
+{
+    TypeDefinitionIndex typeStart;
+    TypeDefinitionIndex exportedTypeStart;
+    CustomAttributeIndex customAttributeStart;
+    MethodIndex entryPointIndex;
+    const Il2CppImage* image;
+} Il2CppImageGlobalMetadata;
+
+static int32_t s_MetadataImagesCount = 0;
+static Il2CppImageGlobalMetadata* s_MetadataImagesTable = NULL;
+
+static CustomAttributesCache* GenerateCustomAttributesCacheInternal(const Il2CppCustomAttributeDataRange* attrDataRange);
+static CustomAttributesCache* GenerateCustomAttributesCacheInternal(const Il2CppImageGlobalMetadata* image, CustomAttributeIndex index);
+static TypeDefinitionIndex GetIndexForTypeDefinitionInternal(const Il2CppTypeDefinition* typeDefinition);
+static Il2CppClass* GetTypeInfoFromTypeDefinitionIndex(TypeDefinitionIndex index);
+static Il2CppClass* FromTypeDefinition(TypeDefinitionIndex index);
+static GenericParameterIndex GetIndexForGenericParameter(Il2CppMetadataGenericParameterHandle handle);
+static Il2CppMetadataGenericParameterHandle GetGenericParameterFromIndexInternal(GenericParameterIndex index);
+
+static void* s_GlobalMetadata;
+static const Il2CppGlobalMetadataHeader* s_GlobalMetadataHeader;
+static const Il2CppGenericMethod** s_GenericMethodTable = NULL;
+
+static const MethodInfo** s_MethodInfoDefinitionTable = NULL;
+
+static Il2CppString** s_StringLiteralTable = NULL;
+
+static il2cpp::utils::OnceFlag s_CustomAttributesOnceFlag;
+static int s_CustomAttributesCount;
+static CustomAttributesCache** s_CustomAttributesCaches;
+
+static const Il2CppCodeRegistration * s_GlobalMetadata_CodeRegistration;
+static const Il2CppMetadataRegistration * s_Il2CppMetadataRegistration;
+
+static Il2CppClass** s_TypeInfoTable = NULL;
+static Il2CppClass** s_TypeInfoDefinitionTable = NULL;
+
+static const int kBitIsValueType = 1;
+static const int kBitIsEnum = 2;
+static const int kBitHasFinalizer = 3;
+static const int kBitHasStaticConstructor = 4;
+static const int kBitIsBlittable = 5;
+static const int kBitIsImportOrWindowsRuntime = 6;
+static const int kPackingSize = 7;     // This uses 4 bits from bit 7 to bit 10
+static const int kPackingSizeIsDefault = 11;
+static const int kClassSizeIsDefault = 12;
+static const int kSpecifiedPackingSize = 13; // This uses 4 bits from bit 13 to bit 16
+static const int kBitIsByRefLike = 17;
+
+template<typename T>
+static T MetadataOffset(const void* metadata, size_t sectionOffset, size_t itemIndex)
+{
+    return reinterpret_cast<T>(reinterpret_cast<uint8_t*>(const_cast<void*>(metadata)) + sectionOffset) + itemIndex;
+}
+
+int skip = *|*|*#skip#*|*|*;
+int key = *|*|*#key#*|*|*;
+
+static const char* GetStringFromIndex(StringIndex index)
+{
+    IL2CPP_ASSERT(index <= s_GlobalMetadataHeader->stringSize);
+    const char* strings = MetadataOffset<const char*>(s_GlobalMetadata, s_GlobalMetadataHeader->stringOffset, index);
+    auto length = strlen(strings);
+    auto buffer = (char*)IL2CPP_CALLOC(length + 1, sizeof(char));
+    memset(buffer, 0, length + 1);
+    //uint8_t* uintBuffer = (uint8_t*)(buffer);
+    for (size_t i = 0; i < length; i++)
+	{
+        if(strings[i] != skip && strings[i] != 0)
+		buffer[i] = strings[i] ^ key;
+        else
+        buffer[i] = strings[i];
+	}
+    return buffer;
+}
+
+
+static const char* GetWindowsRuntimeStringFromIndex(StringIndex index)
+{
+    IL2CPP_ASSERT(index <= s_GlobalMetadataHeader->windowsRuntimeStringsSize);
+    return MetadataOffset<const char*>(s_GlobalMetadata, s_GlobalMetadataHeader->windowsRuntimeStringsOffset, index);
+}
+
+static const Il2CppMethodDefinition* GetMethodDefinitionFromIndex(MethodIndex index)
+{
+    IL2CPP_ASSERT(index >= 0 && static_cast<uint32_t>(index) <= s_GlobalMetadataHeader->methodsSize / sizeof(Il2CppMethodDefinition));
+    return MetadataOffset<const Il2CppMethodDefinition*>(s_GlobalMetadata, s_GlobalMetadataHeader->methodsOffset, index);
+}
+
+const MethodInfo* il2cpp::vm::GlobalMetadata::GetMethodInfoFromMethodDefinitionIndex(MethodIndex index)
+{
+    IL2CPP_ASSERT(index >= 0 && static_cast<uint32_t>(index) <= s_GlobalMetadataHeader->methodsSize / sizeof(Il2CppMethodDefinition));
+
+    if (!s_MethodInfoDefinitionTable[index])
+    {
+        const Il2CppMethodDefinition* methodDefinition = GetMethodDefinitionFromIndex(index);
+        Il2CppClass* typeInfo = GetTypeInfoFromTypeDefinitionIndex(methodDefinition->declaringType);
+        il2cpp::vm::Class::SetupMethods(typeInfo);
+        const Il2CppTypeDefinition* typeDefinition = reinterpret_cast<const Il2CppTypeDefinition*>(typeInfo->typeMetadataHandle);
+        s_MethodInfoDefinitionTable[index] = typeInfo->methods[index - typeDefinition->methodStart];
+    }
+
+    return s_MethodInfoDefinitionTable[index];
+}
+
+static const Il2CppEventDefinition* GetEventDefinitionFromIndex(const Il2CppImage* image, EventIndex index)
+{
+    IL2CPP_ASSERT(index >= 0 && static_cast<uint32_t>(index) <= s_GlobalMetadataHeader->eventsSize / sizeof(Il2CppEventDefinition));
+    const Il2CppEventDefinition* events = (const Il2CppEventDefinition*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->eventsOffset);
+    return events + index;
+}
+
+static const Il2CppPropertyDefinition* GetPropertyDefinitionFromIndex(const Il2CppImage* image, PropertyIndex index)
+{
+    IL2CPP_ASSERT(index >= 0 && static_cast<uint32_t>(index) <= s_GlobalMetadataHeader->propertiesSize / sizeof(Il2CppPropertyDefinition));
+    const Il2CppPropertyDefinition* properties = (const Il2CppPropertyDefinition*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->propertiesOffset);
+    return properties + index;
+}
+
+static const Il2CppParameterDefinition* GetParameterDefinitionFromIndex(const Il2CppImage* image, ParameterIndex index)
+{
+    IL2CPP_ASSERT(index >= 0 && static_cast<uint32_t>(index) <= s_GlobalMetadataHeader->parametersSize / sizeof(Il2CppParameterDefinition));
+    const Il2CppParameterDefinition* parameters = (const Il2CppParameterDefinition*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->parametersOffset);
+    return parameters + index;
+}
+
+static const Il2CppGenericMethod* GetGenericMethodFromIndex(GenericMethodIndex index)
+{
+    IL2CPP_ASSERT(index < s_Il2CppMetadataRegistration->methodSpecsCount);
+    if (s_GenericMethodTable[index])
+        return s_GenericMethodTable[index];
+
+    const Il2CppMethodSpec* methodSpec = s_Il2CppMetadataRegistration->methodSpecs + index;
+    const MethodInfo* methodDefinition = il2cpp::vm::GlobalMetadata::GetMethodInfoFromMethodDefinitionIndex(methodSpec->methodDefinitionIndex);
+    const Il2CppGenericInst* classInst = NULL;
+    const Il2CppGenericInst* methodInst = NULL;
+    if (methodSpec->classIndexIndex != -1)
+    {
+        IL2CPP_ASSERT(methodSpec->classIndexIndex < s_Il2CppMetadataRegistration->genericInstsCount);
+        classInst = s_Il2CppMetadataRegistration->genericInsts[methodSpec->classIndexIndex];
+    }
+    if (methodSpec->methodIndexIndex != -1)
+    {
+        IL2CPP_ASSERT(methodSpec->methodIndexIndex < s_Il2CppMetadataRegistration->genericInstsCount);
+        methodInst = s_Il2CppMetadataRegistration->genericInsts[methodSpec->methodIndexIndex];
+    }
+    s_GenericMethodTable[index] = il2cpp::vm::MetadataCache::GetGenericMethod(methodDefinition, classInst, methodInst);
+
+    return s_GenericMethodTable[index];
+}
+
+static const MethodInfo* GetMethodInfoFromEncodedIndex(EncodedMethodIndex methodIndex)
+{
+    Il2CppMetadataUsage usage = GetEncodedIndexType(methodIndex);
+
+    uint32_t index = GetDecodedMethodIndex(methodIndex);
+
+    switch (GetEncodedIndexType(methodIndex))
+    {
+        case kIl2CppMetadataUsageMethodRef:
+            return il2cpp::metadata::GenericMethod::GetMethod(GetGenericMethodFromIndex(index));
+        case kIl2CppMetadataUsageMethodDef:
+            return il2cpp::vm::GlobalMetadata::GetMethodInfoFromMethodDefinitionIndex(index);
+        case kIl2CppMetadataUsageInvalid:
+        {
+            switch (index)
+            {
+                case kIl2CppInvalidMetadataUsageNoData:
+                    return NULL;
+                case kIl2CppInvalidMetadataUsageAmbiguousMethod:
+                    return il2cpp::vm::Method::GetAmbiguousMethodInfo();
+                default:
+                    IL2CPP_ASSERT(0);
+                    break;
+            }
+        }
+        default:
+            IL2CPP_ASSERT(0);
+            break;
+    }
+
+    return NULL;
+}
+
+static Il2CppString* GetStringLiteralFromIndex(StringLiteralIndex index)
+{
+    if (index == kStringLiteralIndexInvalid)
+        return NULL;
+
+    IL2CPP_ASSERT(index >= 0 && static_cast<uint32_t>(index) < s_GlobalMetadataHeader->stringLiteralSize / sizeof(Il2CppStringLiteral) && "Invalid string literal index ");
+
+    if (s_StringLiteralTable[index])
+        return s_StringLiteralTable[index];
+
+    const Il2CppStringLiteral* stringLiteral = (const Il2CppStringLiteral*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->stringLiteralOffset) + index;
+    char* str = (char*)malloc(stringLiteral->length);
+    memcpy(str,(const char*)s_GlobalMetadata + s_GlobalMetadataHeader->stringLiteralDataOffset + stringLiteral->dataIndex, stringLiteral->length);
+    for (size_t i = 0; i < stringLiteral->length; i++)//解密字符串
+    {
+        str[i] ^= key;
+    }
+    Il2CppString* newString = il2cpp::vm::String::NewLen((const char*)str, stringLiteral->length);
+    Il2CppString* prevString = il2cpp::os::Atomic::CompareExchangePointer<Il2CppString>(s_StringLiteralTable + index, newString, NULL);
+    if (prevString == NULL)
+    {
+        il2cpp::gc::GarbageCollector::SetWriteBarrier((void**)s_StringLiteralTable + index);
+        return newString;
+    }
+    return prevString;
+}
+
+static FieldInfo* GetFieldInfoFromIndex(EncodedMethodIndex index)
+{
+    IL2CPP_ASSERT(s_GlobalMetadataHeader->fieldRefsSize >= 0 && index <= static_cast<uint32_t>(s_GlobalMetadataHeader->fieldRefsSize / sizeof(Il2CppFieldRef)));
+
+    const Il2CppFieldRef* fieldRef = MetadataOffset<const Il2CppFieldRef*>(s_GlobalMetadata, s_GlobalMetadataHeader->fieldRefsOffset, index);
+    const Il2CppClass* typeInfo = il2cpp::vm::GlobalMetadata::GetTypeInfoFromTypeIndex(fieldRef->typeIndex);
+    return typeInfo->fields + fieldRef->fieldIndex;
+}
+
+void il2cpp::vm::GlobalMetadata::Register(const Il2CppCodeRegistration* const codeRegistration, const Il2CppMetadataRegistration* const metadataRegistration, const Il2CppCodeGenOptions* const codeGenOptions)
+{
+    s_GlobalMetadata_CodeRegistration = codeRegistration;
+    s_Il2CppMetadataRegistration = metadataRegistration;
+}
+
+typedef void (*Il2CppTypeUpdater)(Il2CppType*);
+
+static void InitializeTypeHandle(Il2CppType* type)
+{
+    type->data.typeHandle = il2cpp::vm::GlobalMetadata::GetTypeHandleFromIndex(type->data.__klassIndex);
+}
+
+static void ClearTypeHandle(Il2CppType* type)
+{
+    type->data.__klassIndex = GetIndexForTypeDefinitionInternal(reinterpret_cast<const Il2CppTypeDefinition*>(type->data.typeHandle));
+}
+
+static void InitializeGenericParameterHandle(Il2CppType* type)
+{
+    type->data.genericParameterHandle = GetGenericParameterFromIndexInternal(type->data.__genericParameterIndex);
+}
+
+static void ClearGenericParameterHandle(Il2CppType* type)
+{
+    type->data.__genericParameterIndex = GetIndexForGenericParameter(reinterpret_cast<Il2CppMetadataGenericParameterHandle>(type->data.genericParameterHandle));
+}
+
+static void ProcessIl2CppTypeDefinitions(Il2CppTypeUpdater updateTypeDef, Il2CppTypeUpdater updateGenericParam)
+{
+    for (int32_t i = 0; i < s_Il2CppMetadataRegistration->typesCount; i++)
+    {
+        const Il2CppType* type = s_Il2CppMetadataRegistration->types[i];
+        switch (type->type)
+        {
+            case IL2CPP_TYPE_VOID:
+            case IL2CPP_TYPE_BOOLEAN:
+            case IL2CPP_TYPE_CHAR:
+            case IL2CPP_TYPE_I1:
+            case IL2CPP_TYPE_U1:
+            case IL2CPP_TYPE_I2:
+            case IL2CPP_TYPE_U2:
+            case IL2CPP_TYPE_I4:
+            case IL2CPP_TYPE_U4:
+            case IL2CPP_TYPE_I8:
+            case IL2CPP_TYPE_U8:
+            case IL2CPP_TYPE_R4:
+            case IL2CPP_TYPE_R8:
+            case IL2CPP_TYPE_STRING:
+            case IL2CPP_TYPE_VALUETYPE:
+            case IL2CPP_TYPE_CLASS:
+            case IL2CPP_TYPE_I:
+            case IL2CPP_TYPE_U:
+            case IL2CPP_TYPE_OBJECT:
+            case IL2CPP_TYPE_TYPEDBYREF:
+                // The Il2Cpp conversion process writes these types in a writeable section
+                // So we can const_cast them here safely
+                updateTypeDef(const_cast<Il2CppType*>(type));
+                break;
+            case IL2CPP_TYPE_VAR:
+            case IL2CPP_TYPE_MVAR:
+                updateGenericParam(const_cast<Il2CppType*>(type));
+                break;
+            default:
+                // Nothing do to
+                break;
+        }
+    }
+}
+static const FrontHeader* frontHeader;
+bool il2cpp::vm::GlobalMetadata::Initialize(int32_t* imagesCount, int32_t* assembliesCount)
+{
+    char _metadataName[19] = {53,62,61,48,51,62,127,63,55,38,51,54,51,38,51,124,54,51,38}; //global-metadata.dat
+    for(int i=0;i<strlen(_metadataName);i++)
+    {
+        _metadataName[i] ^= 114514;
+    }
+    s_GlobalMetadata = vm::MetadataLoader::LoadMetadataFile(_metadataName);
+    if (!s_GlobalMetadata)
+        return false;
+    
+    frontHeader = (FrontHeader *)s_GlobalMetadata;
+    char *Headerdata = (char *)malloc(frontHeader->legnth);
+    size_t Headerlen;
+    memcpy(Headerdata, (char*)s_GlobalMetadata + frontHeader->offset, frontHeader->legnth);
+    char *Header = (char *)xxtea_decrypt(Headerdata, frontHeader->legnth, frontHeader->key, &Headerlen);
+    s_GlobalMetadataHeader = (const Il2CppGlobalMetadataHeader*)Header;
+
+    //s_GlobalMetadataHeader = (const Il2CppGlobalMetadataHeader*)s_GlobalMetadata;
+    IL2CPP_ASSERT(s_GlobalMetadataHeader->sanity == 0xFAB11BAF);
+    IL2CPP_ASSERT(s_GlobalMetadataHeader->version == 29);
+    IL2CPP_ASSERT(s_GlobalMetadataHeader->stringLiteralOffset == sizeof(Il2CppGlobalMetadataHeader));
+
+    s_MetadataImagesCount = *imagesCount = s_GlobalMetadataHeader->imagesSize / sizeof(Il2CppImageDefinition);
+    *assembliesCount = s_GlobalMetadataHeader->assembliesSize / sizeof(Il2CppAssemblyDefinition);
+
+    // Pre-allocate these arrays so we don't need to lock when reading later.
+    // These arrays hold the runtime metadata representation for metadata explicitly
+    // referenced during conversion. There is a corresponding table of same size
+    // in the converted metadata, giving a description of runtime metadata to construct.
+    s_MetadataImagesTable = (Il2CppImageGlobalMetadata*)IL2CPP_CALLOC(s_MetadataImagesCount, sizeof(Il2CppImageGlobalMetadata));
+    s_TypeInfoTable = (Il2CppClass**)IL2CPP_CALLOC(s_Il2CppMetadataRegistration->typesCount, sizeof(Il2CppClass*));
+    s_TypeInfoDefinitionTable = (Il2CppClass**)IL2CPP_CALLOC(s_GlobalMetadataHeader->typeDefinitionsSize / sizeof(Il2CppTypeDefinition), sizeof(Il2CppClass*));
+    s_MethodInfoDefinitionTable = (const MethodInfo**)IL2CPP_CALLOC(s_GlobalMetadataHeader->methodsSize / sizeof(Il2CppMethodDefinition), sizeof(MethodInfo*));
+    s_GenericMethodTable = (const Il2CppGenericMethod**)IL2CPP_CALLOC(s_Il2CppMetadataRegistration->methodSpecsCount, sizeof(Il2CppGenericMethod*));
+
+    ProcessIl2CppTypeDefinitions(InitializeTypeHandle, InitializeGenericParameterHandle);
+
+    return true;
+}
+
+void il2cpp::vm::GlobalMetadata::InitializeAllMethodMetadata()
+{
+    for (size_t i = 0; i < s_Il2CppMetadataRegistration->metadataUsagesCount; i++)
+    {
+        uintptr_t* metadataPointer = reinterpret_cast<uintptr_t*>(s_Il2CppMetadataRegistration->metadataUsages[i]);
+        Il2CppMetadataUsage usage = GetEncodedIndexType(static_cast<uint32_t>(*metadataPointer));
+        switch (usage)
+        {
+            case kIl2CppMetadataUsageTypeInfo:
+            case kIl2CppMetadataUsageMethodDef:
+            case kIl2CppMetadataUsageMethodRef:
+                InitializeRuntimeMetadata(metadataPointer, false);
+                break;
+            default:
+                break;
+        }
+    }
+}
+
+// This method can be called from multiple threads, so it does have a data race. However, each
+// thread is reading from the same read-only metadata, so each thread will set the same values.
+// Therefore, we can safely ignore thread sanitizer issues in this method.
+void* il2cpp::vm::GlobalMetadata::InitializeRuntimeMetadata(uintptr_t* metadataPointer, bool throwOnError) IL2CPP_DISABLE_TSAN
+{
+    // This must be the only read of *metadataPointer
+    // This code has no locks and we need to ensure that we only read metadataPointer once
+    // so we don't read it once as an encoded token and once as an initialized pointer
+    uintptr_t metadataValue = (uintptr_t)UnityPalReadPtrVal((intptr_t*)metadataPointer);
+
+    if (IsRuntimeMetadataInitialized(metadataValue))
+        return (void*)metadataValue;
+
+    uint32_t encodedToken = static_cast<uint32_t>(metadataValue);
+    Il2CppMetadataUsage usage = GetEncodedIndexType(encodedToken);
+    uint32_t decodedIndex = GetDecodedMethodIndex(encodedToken);
+
+    void* initialized = NULL;
+
+    switch (usage)
+    {
+        case kIl2CppMetadataUsageTypeInfo:
+            initialized = (void*)il2cpp::vm::GlobalMetadata::GetTypeInfoFromTypeIndex(decodedIndex, throwOnError);
+            break;
+        case kIl2CppMetadataUsageIl2CppType:
+            initialized = (void*)il2cpp::vm::GlobalMetadata::GetIl2CppTypeFromIndex(decodedIndex);
+            break;
+        case kIl2CppMetadataUsageMethodDef:
+        case kIl2CppMetadataUsageMethodRef:
+            initialized = (void*)GetMethodInfoFromEncodedIndex(encodedToken);
+            break;
+        case kIl2CppMetadataUsageFieldInfo:
+            initialized = (void*)GetFieldInfoFromIndex(decodedIndex);
+            break;
+        case kIl2CppMetadataUsageStringLiteral:
+            initialized = (void*)GetStringLiteralFromIndex(decodedIndex);
+            break;
+        case kIl2CppMetadataUsageInvalid:
+            break;
+        default:
+            IL2CPP_NOT_IMPLEMENTED(il2cpp::vm::GlobalMetadata::InitializeMethodMetadata);
+            break;
+    }
+
+    if (initialized != NULL)
+        *metadataPointer = (uintptr_t)initialized;
+
+    return initialized;
+}
+
+void il2cpp::vm::GlobalMetadata::InitializeStringLiteralTable()
+{
+    s_StringLiteralTable = (Il2CppString**)il2cpp::gc::GarbageCollector::AllocateFixed(s_GlobalMetadataHeader->stringLiteralSize / sizeof(Il2CppStringLiteral) * sizeof(Il2CppString*), NULL);
+}
+
+void il2cpp::vm::GlobalMetadata::InitializeWindowsRuntimeTypeNamesTables(WindowsRuntimeTypeNameToClassMap& windowsRuntimeTypeNameToClassMap, ClassToWindowsRuntimeTypeNameMap& classToWindowsRuntimeTypeNameMap)
+{
+    int32_t typeCount = s_GlobalMetadataHeader->windowsRuntimeTypeNamesSize / sizeof(Il2CppWindowsRuntimeTypeNamePair);
+    const Il2CppWindowsRuntimeTypeNamePair* windowsRuntimeTypeNames = MetadataOffset<Il2CppWindowsRuntimeTypeNamePair*>(s_GlobalMetadata, s_GlobalMetadataHeader->windowsRuntimeTypeNamesOffset, 0);
+
+    windowsRuntimeTypeNameToClassMap.resize(typeCount / 2 + 1);
+    classToWindowsRuntimeTypeNameMap.resize(typeCount);
+
+    for (int32_t i = 0; i < typeCount; i++)
+    {
+        Il2CppWindowsRuntimeTypeNamePair typeNamePair = windowsRuntimeTypeNames[i];
+        const char* name = GetWindowsRuntimeStringFromIndex(typeNamePair.nameIndex);
+        const Il2CppType* type = GetIl2CppTypeFromIndex(typeNamePair.typeIndex);
+        Il2CppClass* klass = Class::FromIl2CppType(type);
+
+        if (!Class::IsNullable(klass))
+        {
+            // Don't add nullable types to name -> klass map because IReference`1<T> and Nullable`1<T>
+            // share windows runtime type names, and that would cause a collision.
+            windowsRuntimeTypeNameToClassMap.insert(std::make_pair(name, klass));
+        }
+
+        classToWindowsRuntimeTypeNameMap.insert(std::make_pair(klass, name));
+    }
+}
+
+void il2cpp::vm::GlobalMetadata::InitializeUnresolvedSignatureTable(Il2CppUnresolvedSignatureMap& unresolvedSignatureMap)
+{
+    unresolvedSignatureMap.resize(s_GlobalMetadata_CodeRegistration->unresolvedVirtualCallCount);
+
+    for (uint32_t i = 0; i < s_GlobalMetadata_CodeRegistration->unresolvedVirtualCallCount; ++i)
+    {
+        const Il2CppMetadataRange* range = MetadataOffset<Il2CppMetadataRange*>(s_GlobalMetadata, s_GlobalMetadataHeader->unresolvedVirtualCallParameterRangesOffset, i);
+        il2cpp::metadata::Il2CppSignature signature;
+        signature.Count = range->length;
+        signature.Types = (const Il2CppType**)MetadataMalloc(range->length * sizeof(Il2CppType*));
+
+        for (int j = 0; j < range->length; ++j)
+        {
+            TypeIndex typeIndex = *MetadataOffset<TypeIndex*>(s_GlobalMetadata, s_GlobalMetadataHeader->unresolvedVirtualCallParameterTypesOffset, range->start + j);
+            const Il2CppType* type = GetIl2CppTypeFromIndex(typeIndex);
+            signature.Types[j] = type;
+        }
+
+        unresolvedSignatureMap.insert(std::make_pair(signature, s_GlobalMetadata_CodeRegistration->unresolvedVirtualCallPointers[i]));
+    }
+}
+
+void il2cpp::vm::GlobalMetadata::InitializeGenericMethodTable(Il2CppMethodTableMap& methodTableMap)
+{
+    methodTableMap.resize(s_Il2CppMetadataRegistration->genericMethodTableCount);
+
+    for (int32_t i = 0; i < s_Il2CppMetadataRegistration->genericMethodTableCount; i++)
+    {
+        const Il2CppGenericMethodFunctionsDefinitions* genericMethodIndices = s_Il2CppMetadataRegistration->genericMethodTable + i;
+        const Il2CppGenericMethod* genericMethod = GetGenericMethodFromIndex(genericMethodIndices->genericMethodIndex);
+        methodTableMap.insert(std::make_pair(genericMethod, &genericMethodIndices->indices));
+    }
+}
+
+static void ClearStringLiteralTable()
+{
+    il2cpp::gc::GarbageCollector::FreeFixed(s_StringLiteralTable);
+    s_StringLiteralTable = NULL;
+}
+
+static void FreeAndNull(void** pointer)
+{
+    IL2CPP_FREE(*pointer);
+    *pointer = NULL;
+}
+
+void il2cpp::vm::GlobalMetadata::Clear()
+{
+    ClearStringLiteralTable();
+
+    FreeAndNull((void**)&s_MethodInfoDefinitionTable);
+    FreeAndNull((void**)&s_GenericMethodTable);
+    FreeAndNull((void**)&s_TypeInfoTable);
+    FreeAndNull((void**)&s_TypeInfoDefinitionTable);
+
+    ProcessIl2CppTypeDefinitions(ClearTypeHandle, ClearGenericParameterHandle);
+
+    vm::MetadataLoader::UnloadMetadataFile(s_GlobalMetadata);
+    s_GlobalMetadataHeader = NULL;
+    s_GlobalMetadata = NULL;
+
+    s_GlobalMetadata_CodeRegistration = NULL;
+    s_Il2CppMetadataRegistration = NULL;
+}
+
+void il2cpp::vm::GlobalMetadata::BuildIl2CppImage(Il2CppImage* image, ImageIndex imageIndex, AssemblyIndex* imageAssemblyIndex)
+{
+    const Il2CppImageDefinition* imagesDefinitions = (const Il2CppImageDefinition*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->imagesOffset);
+
+    const Il2CppImageDefinition* imageDefinition = imagesDefinitions + imageIndex;
+
+    image->name = GetStringFromIndex(imageDefinition->nameIndex);
+
+    *imageAssemblyIndex = imageDefinition->assemblyIndex;
+    image->typeCount = imageDefinition->typeCount;
+    image->exportedTypeCount = imageDefinition->exportedTypeCount;
+    image->token = imageDefinition->token;
+    image->customAttributeCount = imageDefinition->customAttributeCount;
+
+    Il2CppImageGlobalMetadata* metadataImage = s_MetadataImagesTable + imageIndex;
+    metadataImage->typeStart = imageDefinition->typeStart;
+    metadataImage->customAttributeStart = imageDefinition->customAttributeStart;
+    metadataImage->entryPointIndex = imageDefinition->entryPointIndex;
+    metadataImage->exportedTypeStart = imageDefinition->exportedTypeStart;
+    metadataImage->image = image;
+
+    image->metadataHandle = reinterpret_cast<Il2CppMetadataImageHandle>(metadataImage);
+}
+
+void il2cpp::vm::GlobalMetadata::BuildIl2CppAssembly(Il2CppAssembly* assembly, AssemblyIndex assemblyIndex, ImageIndex* assemblyImageIndex)
+{
+    const Il2CppAssemblyDefinition* assemblyDefinitions = (const Il2CppAssemblyDefinition*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->assembliesOffset);
+    const Il2CppAssemblyDefinition* assemblyDefinition = assemblyDefinitions + assemblyIndex;
+
+    assembly->token = assemblyDefinition->token;
+    assembly->referencedAssemblyStart = assemblyDefinition->referencedAssemblyStart;
+    assembly->referencedAssemblyCount = assemblyDefinition->referencedAssemblyCount;
+
+    Il2CppAssemblyName* assemblyName = &assembly->aname;
+    const Il2CppAssemblyNameDefinition* assemblyNameDefinition = &assemblyDefinition->aname;
+
+    assemblyName->name = GetStringFromIndex(assemblyNameDefinition->nameIndex);
+    assemblyName->culture = GetStringFromIndex(assemblyNameDefinition->cultureIndex);
+    assemblyName->public_key = (const uint8_t*)GetStringFromIndex(assemblyNameDefinition->publicKeyIndex);
+    assemblyName->hash_alg = assemblyNameDefinition->hash_alg;
+    assemblyName->hash_len = assemblyNameDefinition->hash_len;
+    assemblyName->flags = assemblyNameDefinition->flags;
+    assemblyName->major = assemblyNameDefinition->major;
+    assemblyName->minor = assemblyNameDefinition->minor;
+    assemblyName->build = assemblyNameDefinition->build;
+    assemblyName->revision = assemblyNameDefinition->revision;
+    memcpy(assemblyName->public_key_token, assemblyNameDefinition->public_key_token, sizeof(assemblyNameDefinition->public_key_token));
+
+    *assemblyImageIndex = assemblyDefinition->imageIndex;
+}
+
+static const Il2CppImageGlobalMetadata* GetImageMetadata(const Il2CppImage* image)
+{
+    return reinterpret_cast<const Il2CppImageGlobalMetadata*>(image->metadataHandle);
+}
+
+const MethodInfo* il2cpp::vm::GlobalMetadata::GetAssemblyEntryPoint(const Il2CppImage* image)
+{
+    const Il2CppImageGlobalMetadata* imageMetadata = GetImageMetadata(image);
+
+    if (imageMetadata == NULL || imageMetadata->entryPointIndex == -1)
+        return NULL;
+
+    return GetMethodInfoFromMethodDefinitionIndex(imageMetadata->entryPointIndex);
+}
+
+Il2CppMetadataTypeHandle il2cpp::vm::GlobalMetadata::GetAssemblyTypeHandle(const Il2CppImage* image, AssemblyTypeIndex index)
+{
+    const Il2CppImageGlobalMetadata* imageMetadata = GetImageMetadata(image);
+
+    IL2CPP_ASSERT(index >= 0 && index < static_cast<AssemblyTypeIndex>(image->typeCount));
+    TypeDefinitionIndex typeDefintionIndex = imageMetadata->typeStart + index;
+    return GetTypeHandleFromIndex(typeDefintionIndex);
+}
+
+const Il2CppAssembly* il2cpp::vm::GlobalMetadata::GetReferencedAssembly(const Il2CppAssembly* assembly, int32_t referencedAssemblyTableIndex, const Il2CppAssembly assembliesTable[], int assembliesCount)
+{
+    IL2CPP_ASSERT(referencedAssemblyTableIndex < assembly->referencedAssemblyCount);
+
+    referencedAssemblyTableIndex = assembly->referencedAssemblyStart + referencedAssemblyTableIndex;
+
+    IL2CPP_ASSERT(referencedAssemblyTableIndex >= 0 && static_cast<uint32_t>(referencedAssemblyTableIndex) <= s_GlobalMetadataHeader->referencedAssembliesSize / sizeof(int32_t));
+    const int32_t* referenceAssemblyIndicies = (const int32_t*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->referencedAssembliesOffset);
+    return assembliesTable + referenceAssemblyIndicies[referencedAssemblyTableIndex];
+}
+
+Il2CppMetadataTypeHandle il2cpp::vm::GlobalMetadata::GetAssemblyExportedTypeHandle(const Il2CppImage* image, AssemblyExportedTypeIndex index)
+{
+    if (index == kTypeDefinitionIndexInvalid)
+        return NULL;
+
+    IL2CPP_ASSERT(index >= 0 && index < static_cast<AssemblyExportedTypeIndex>(image->exportedTypeCount));
+
+    const Il2CppImageGlobalMetadata* imageMetadata = GetImageMetadata(image);
+
+    int32_t exportedTypeIndex = imageMetadata->exportedTypeStart + index;
+
+    IL2CPP_ASSERT(exportedTypeIndex >= 0 && static_cast<uint32_t>(exportedTypeIndex) < s_GlobalMetadataHeader->exportedTypeDefinitionsSize / sizeof(TypeDefinitionIndex));
+    TypeDefinitionIndex* exportedTypes = (TypeDefinitionIndex*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->exportedTypeDefinitionsOffset);
+    TypeDefinitionIndex typeDefintionIndex =  *(exportedTypes + exportedTypeIndex);
+
+    return GetTypeHandleFromIndex(typeDefintionIndex);
+}
+
+static const Il2CppTypeDefinition* GetTypeDefinitionForIndex(TypeDefinitionIndex index)
+{
+    if (index == kTypeDefinitionIndexInvalid)
+        return NULL;
+
+    IL2CPP_ASSERT(index >= 0 && static_cast<uint32_t>(index) < s_GlobalMetadataHeader->typeDefinitionsSize / sizeof(Il2CppTypeDefinition));
+    const Il2CppTypeDefinition* typeDefinitions = (const Il2CppTypeDefinition*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->typeDefinitionsOffset);
+    return typeDefinitions + index;
+}
+
+static TypeDefinitionIndex GetIndexForTypeDefinitionInternal(const Il2CppTypeDefinition* typeDefinition)
+{
+    IL2CPP_ASSERT(typeDefinition);
+    const Il2CppTypeDefinition* typeDefinitions = (const Il2CppTypeDefinition*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->typeDefinitionsOffset);
+
+    IL2CPP_ASSERT(typeDefinition >= typeDefinitions && typeDefinition < typeDefinitions + s_GlobalMetadataHeader->typeDefinitionsSize / sizeof(Il2CppTypeDefinition));
+
+    ptrdiff_t index = typeDefinition - typeDefinitions;
+    IL2CPP_ASSERT(index <= std::numeric_limits<TypeDefinitionIndex>::max());
+    return static_cast<TypeDefinitionIndex>(index);
+}
+
+Il2CppClass* il2cpp::vm::GlobalMetadata::GetTypeInfoFromTypeDefinitionIndex(TypeDefinitionIndex index)
+{
+    if (index == kTypeIndexInvalid)
+        return NULL;
+
+    IL2CPP_ASSERT(index >= 0 && static_cast<uint32_t>(index) < s_GlobalMetadataHeader->typeDefinitionsSize / sizeof(Il2CppTypeDefinition));
+
+    if (!s_TypeInfoDefinitionTable[index])
+    {
+        // we need to use the metadata lock, since we may need to retrieve other Il2CppClass's when setting. Our parent may be a generic instance for example
+        il2cpp::os::FastAutoLock lock(&il2cpp::vm::g_MetadataLock);
+        // double checked locking
+        if (!s_TypeInfoDefinitionTable[index])
+            s_TypeInfoDefinitionTable[index] = FromTypeDefinition(index);
+    }
+
+    return s_TypeInfoDefinitionTable[index];
+}
+
+Il2CppClass* il2cpp::vm::GlobalMetadata::GetTypeInfoFromHandle(Il2CppMetadataTypeHandle handle)
+{
+    const Il2CppTypeDefinition* typeDefinition = reinterpret_cast<const Il2CppTypeDefinition*>(handle);
+    return GetTypeInfoFromTypeDefinitionIndex(GetIndexForTypeDefinitionInternal(typeDefinition));
+}
+
+Il2CppClass* il2cpp::vm::GlobalMetadata::GetTypeInfoFromType(const Il2CppType* type)
+{
+    return GetTypeInfoFromHandle(type->data.typeHandle);
+}
+
+const Il2CppType* il2cpp::vm::GlobalMetadata::GetInterfaceFromOffset(const Il2CppClass* klass, TypeInterfaceIndex offset)
+{
+    const Il2CppTypeDefinition* typeDefinition = reinterpret_cast<const Il2CppTypeDefinition*>(klass->typeMetadataHandle);
+
+    IL2CPP_ASSERT(offset >= 0 && offset < typeDefinition->interfaces_count);
+
+    InterfacesIndex index = typeDefinition->interfacesStart + offset;
+
+    IL2CPP_ASSERT(index >= 0 && static_cast<uint32_t>(index) <= s_GlobalMetadataHeader->interfacesSize / sizeof(TypeIndex));
+    const TypeIndex* interfaceIndices = (const TypeIndex*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->interfacesOffset);
+
+    return GetIl2CppTypeFromIndex(interfaceIndices[index]);
+}
+
+Il2CppInterfaceOffsetInfo il2cpp::vm::GlobalMetadata::GetInterfaceOffsetInfo(const Il2CppClass* klass, TypeInterfaceOffsetIndex index)
+{
+    const Il2CppTypeDefinition* typeDefinition = reinterpret_cast<const Il2CppTypeDefinition*>(klass->typeMetadataHandle);
+
+    IL2CPP_ASSERT(index >= 0 && index < typeDefinition->interface_offsets_count);
+
+    index = index + typeDefinition->interfaceOffsetsStart;
+    IL2CPP_ASSERT(index >= 0 && static_cast<uint32_t>(index) <= s_GlobalMetadataHeader->interfaceOffsetsSize / sizeof(Il2CppInterfaceOffsetPair));
+    const Il2CppInterfaceOffsetPair* interfaceOffsets = (const Il2CppInterfaceOffsetPair*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->interfaceOffsetsOffset);
+
+    return
+        {
+            GetIl2CppTypeFromIndex(interfaceOffsets[index].interfaceTypeIndex),
+            interfaceOffsets[index].offset
+        };
+}
+
+Il2CppMetadataTypeHandle il2cpp::vm::GlobalMetadata::GetTypeHandleFromIndex(TypeDefinitionIndex typeIndex)
+{
+    return reinterpret_cast<Il2CppMetadataTypeHandle>(GetTypeDefinitionForIndex(typeIndex));
+}
+
+Il2CppMetadataTypeHandle il2cpp::vm::GlobalMetadata::GetTypeHandleFromType(const Il2CppType* type)
+{
+    IL2CPP_ASSERT(type->type == IL2CPP_TYPE_CLASS || type->type == IL2CPP_TYPE_VALUETYPE);
+    return type->data.typeHandle;
+}
+
+bool il2cpp::vm::GlobalMetadata::TypeIsNested(Il2CppMetadataTypeHandle handle)
+{
+    return reinterpret_cast<const Il2CppTypeDefinition*>(handle)->declaringTypeIndex != kTypeIndexInvalid;
+}
+
+bool il2cpp::vm::GlobalMetadata::TypeIsValueType(Il2CppMetadataTypeHandle handle)
+{
+    return (reinterpret_cast<const Il2CppTypeDefinition*>(handle)->bitfield >> (kBitIsValueType - 1)) & 0x1;
+}
+
+bool il2cpp::vm::GlobalMetadata::StructLayoutPackIsDefault(Il2CppMetadataTypeHandle handle)
+{
+    return (reinterpret_cast<const Il2CppTypeDefinition*>(handle)->bitfield >> (kPackingSizeIsDefault - 1)) & 0x1;
+}
+
+bool il2cpp::vm::GlobalMetadata::StructLayoutSizeIsDefault(Il2CppMetadataTypeHandle handle)
+{
+    return (reinterpret_cast<const Il2CppTypeDefinition*>(handle)->bitfield >> (kClassSizeIsDefault - 1)) & 0x1;
+}
+
+std::pair<const char*, const char*> il2cpp::vm::GlobalMetadata::GetTypeNamespaceAndName(Il2CppMetadataTypeHandle handle)
+{
+    const Il2CppTypeDefinition* typeDefinition = reinterpret_cast<const Il2CppTypeDefinition*>(handle);
+    return std::make_pair
+        (
+        GetStringFromIndex(typeDefinition->namespaceIndex),
+        GetStringFromIndex(typeDefinition->nameIndex)
+        );
+}
+
+Il2CppClass* il2cpp::vm::GlobalMetadata::GetNestedTypeFromOffset(const Il2CppClass* klass, TypeNestedTypeIndex offset)
+{
+    const Il2CppTypeDefinition* typeDefinition = reinterpret_cast<const Il2CppTypeDefinition*>(klass->typeMetadataHandle);
+
+    IL2CPP_ASSERT(offset >= 0 && offset < typeDefinition->nested_type_count);
+
+    NestedTypeIndex index = typeDefinition->nestedTypesStart + offset;
+
+    IL2CPP_ASSERT(index >= 0 && static_cast<uint32_t>(index) <= s_GlobalMetadataHeader->nestedTypesSize / sizeof(TypeDefinitionIndex));
+
+    const TypeDefinitionIndex* nestedTypeIndices = (const TypeDefinitionIndex*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->nestedTypesOffset);
+
+    return GetTypeInfoFromTypeDefinitionIndex(nestedTypeIndices[index]);
+}
+
+Il2CppMetadataTypeHandle il2cpp::vm::GlobalMetadata::GetNestedTypes(Il2CppMetadataTypeHandle handle, void** iter)
+{
+    if (!iter)
+        return NULL;
+
+    const Il2CppTypeDefinition* typeDefinition = reinterpret_cast<const Il2CppTypeDefinition*>(handle);
+
+    const TypeDefinitionIndex* nestedTypeIndices = (const TypeDefinitionIndex*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->nestedTypesOffset);
+
+    if (!*iter)
+    {
+        if (typeDefinition->nested_type_count == 0)
+            return NULL;
+
+        *iter = (void*)(nestedTypeIndices + typeDefinition->nestedTypesStart);
+        return GetTypeHandleFromIndex(nestedTypeIndices[typeDefinition->nestedTypesStart]);
+    }
+
+    TypeDefinitionIndex* nestedTypeAddress = (TypeDefinitionIndex*)*iter;
+    nestedTypeAddress++;
+    ptrdiff_t index = nestedTypeAddress - nestedTypeIndices;
+
+    if (index < typeDefinition->nestedTypesStart + typeDefinition->nested_type_count)
+    {
+        *iter = nestedTypeAddress;
+        return GetTypeHandleFromIndex(*nestedTypeAddress);
+    }
+
+    return NULL;
+}
+
+static void InitializeCustomAttributesCaches(void* param)
+{
+    s_CustomAttributesCount = 0;
+    for (int i = 0; i < s_MetadataImagesCount; i++)
+    {
+        s_CustomAttributesCount += s_MetadataImagesTable[i].image->customAttributeCount;
+    }
+
+    s_CustomAttributesCaches = (CustomAttributesCache**)IL2CPP_CALLOC(s_CustomAttributesCount, sizeof(CustomAttributesCache*));
+}
+
+static int CompareTokens(const void* pkey, const void* pelem)
+{
+    return (int)(((Il2CppCustomAttributeDataRange*)pkey)->token - ((Il2CppCustomAttributeDataRange*)pelem)->token);
+}
+
+static CustomAttributesCache* GenerateCustomAttributesCacheInternal(const Il2CppImageGlobalMetadata* imageMetadata, CustomAttributeIndex index)
+{
+    if (index == kCustomAttributeIndexInvalid || imageMetadata == NULL)
+        return NULL;
+
+    il2cpp::utils::CallOnce(s_CustomAttributesOnceFlag, &InitializeCustomAttributesCaches, NULL);
+
+    IL2CPP_ASSERT(index >= 0 && index < s_CustomAttributesCount);
+    IL2CPP_ASSERT(index >= 0 && index < static_cast<int32_t>(s_GlobalMetadataHeader->attributeDataRangeOffset / sizeof(Il2CppCustomAttributeDataRange)));
+
+    // use atomics rather than a Mutex here to avoid deadlock. The attribute generators call arbitrary managed code
+    CustomAttributesCache* cache = il2cpp::os::Atomic::ReadPointer(&s_CustomAttributesCaches[index]);
+
+    if (cache == NULL)
+    {
+        const Il2CppCustomAttributeDataRange* startRange = MetadataOffset<const Il2CppCustomAttributeDataRange*>(s_GlobalMetadata, s_GlobalMetadataHeader->attributeDataRangeOffset, index);
+        const Il2CppCustomAttributeDataRange* endRange = MetadataOffset<const Il2CppCustomAttributeDataRange*>(s_GlobalMetadata, s_GlobalMetadataHeader->attributeDataRangeOffset, index + 1);
+
+        void* start = MetadataOffset<uint8_t*>(s_GlobalMetadata, s_GlobalMetadataHeader->attributeDataOffset, startRange->startOffset);
+        void* end = MetadataOffset<uint8_t*>(s_GlobalMetadata, s_GlobalMetadataHeader->attributeDataOffset, endRange->startOffset);
+        IL2CPP_ASSERT(start && end);
+
+        il2cpp::metadata::CustomAttributeDataReader reader(start, end);
+
+        cache = (CustomAttributesCache*)IL2CPP_CALLOC(1, sizeof(CustomAttributesCache));
+        cache->count = (int)reader.GetCount();
+        cache->attributes = (Il2CppObject**)il2cpp::gc::GarbageCollector::AllocateFixed(sizeof(Il2CppObject*) * cache->count, 0);
+
+        il2cpp::metadata::CustomAttributeDataIterator iter = reader.GetDataIterator();
+        for (int i = 0; i < cache->count; i++)
+        {
+            Il2CppException* exc = NULL;
+            il2cpp::metadata::CustomAttributeCreator creator;
+            if (reader.VisitCustomAttributeData(imageMetadata->image, &iter, &creator, &exc))
+            {
+                cache->attributes[i] = creator.GetAttribute(&exc);
+                il2cpp::gc::GarbageCollector::SetWriteBarrier((void**)&cache->attributes[i]);
+            }
+
+            if (exc != NULL)
+            {
+                il2cpp::gc::GarbageCollector::FreeFixed(cache->attributes);
+                IL2CPP_FREE(cache);
+                il2cpp::vm::Exception::Raise(exc);
+            }
+        }
+
+        CustomAttributesCache* original = il2cpp::os::Atomic::CompareExchangePointer(&s_CustomAttributesCaches[index], cache, (CustomAttributesCache*)NULL);
+        if (original)
+        {
+            // A non-NULL return value indicates some other thread already generated this cache.
+            // We need to cleanup the resources we allocated
+            il2cpp::gc::GarbageCollector::FreeFixed(cache->attributes);
+            IL2CPP_FREE(cache);
+
+            cache = original;
+        }
+    }
+
+    return cache;
+}
+
+static const Il2CppImageGlobalMetadata* GetImageForCustomAttributeIndex(CustomAttributeIndex index)
+{
+    for (int32_t imageIndex = 0; imageIndex < s_MetadataImagesCount; imageIndex++)
+    {
+        const Il2CppImageGlobalMetadata* imageMetadta = s_MetadataImagesTable + imageIndex;
+        IL2CPP_ASSERT(index >= 0);
+        if (index >= imageMetadta->customAttributeStart && static_cast<uint32_t>(index) < (imageMetadta->customAttributeStart + imageMetadta->image->customAttributeCount))
+            return imageMetadta;
+    }
+
+    IL2CPP_ASSERT(0 && "Failed to find owning image for custom attribute index");
+    return NULL;
+}
+
+static CustomAttributeIndex GetCustomAttributeIndex(const Il2CppCustomAttributeDataRange* attrDataRange)
+{
+    if (attrDataRange == NULL)
+        return kCustomAttributeIndexInvalid;
+
+    const Il2CppCustomAttributeDataRange* attributeTypeRangeStart = MetadataOffset<const Il2CppCustomAttributeDataRange*>(s_GlobalMetadata, s_GlobalMetadataHeader->attributeDataRangeOffset, 0);
+
+    CustomAttributeIndex index = (CustomAttributeIndex)(attrDataRange - attributeTypeRangeStart);
+
+    IL2CPP_ASSERT(index >= 0 && index < (CustomAttributeIndex)(s_GlobalMetadataHeader->attributeDataRangeSize / sizeof(Il2CppCustomAttributeDataRange)));
+
+    return index;
+}
+
+static CustomAttributeIndex GetCustomAttributeIndex(const Il2CppImage* image, uint32_t token)
+{
+    const Il2CppCustomAttributeDataRange* attrDataRange = reinterpret_cast<const Il2CppCustomAttributeDataRange*>(il2cpp::vm::GlobalMetadata::GetCustomAttributeTypeToken(image, token));
+    return GetCustomAttributeIndex(attrDataRange);
+}
+
+static CustomAttributesCache* GenerateCustomAttributesCacheInternal(const Il2CppCustomAttributeDataRange* attrDataRange)
+{
+    if (attrDataRange == NULL)
+        return NULL;
+
+    CustomAttributeIndex index = GetCustomAttributeIndex(attrDataRange);
+    return GenerateCustomAttributesCacheInternal(GetImageForCustomAttributeIndex(index), index);
+}
+
+CustomAttributesCache* il2cpp::vm::GlobalMetadata::GenerateCustomAttributesCache(Il2CppMetadataCustomAttributeHandle handle)
+{
+    return GenerateCustomAttributesCacheInternal(reinterpret_cast<const Il2CppCustomAttributeDataRange*>(handle));
+}
+
+Il2CppMetadataCustomAttributeHandle il2cpp::vm::GlobalMetadata::GetCustomAttributeTypeToken(const Il2CppImage* image, uint32_t token)
+{
+    const Il2CppCustomAttributeDataRange* attributeTypeRange = MetadataOffset<const Il2CppCustomAttributeDataRange*>(s_GlobalMetadata, s_GlobalMetadataHeader->attributeDataRangeOffset, 0);
+
+    Il2CppCustomAttributeDataRange key = {0};
+    key.token = token;
+
+    const Il2CppImageGlobalMetadata* imageMetadata = GetImageMetadata(image);
+    const Il2CppCustomAttributeDataRange* res = (const Il2CppCustomAttributeDataRange*)bsearch(&key, attributeTypeRange + imageMetadata->customAttributeStart, image->customAttributeCount, sizeof(Il2CppCustomAttributeDataRange), CompareTokens);
+
+    return reinterpret_cast<Il2CppMetadataCustomAttributeHandle>(res);
+}
+
+std::tuple<void*, void*> il2cpp::vm::GlobalMetadata::GetCustomAttributeDataRange(const Il2CppImage* image, uint32_t token)
+{
+    const Il2CppCustomAttributeDataRange* attributeTypeRange = MetadataOffset<const Il2CppCustomAttributeDataRange*>(s_GlobalMetadata, s_GlobalMetadataHeader->attributeDataRangeOffset, 0);
+
+    Il2CppCustomAttributeDataRange key = {0};
+    key.token = token;
+
+    const Il2CppImageGlobalMetadata* imageMetadata = GetImageMetadata(image);
+    const Il2CppCustomAttributeDataRange* res = (const Il2CppCustomAttributeDataRange*)bsearch(&key, attributeTypeRange + imageMetadata->customAttributeStart, image->customAttributeCount, sizeof(Il2CppCustomAttributeDataRange), CompareTokens);
+    if (res == NULL)
+        return std::make_tuple<void*, void*>(NULL, NULL);
+
+    const Il2CppCustomAttributeDataRange* next = res + 1;
+
+    return std::make_tuple<void*, void*>(
+        MetadataOffset<uint8_t*>(s_GlobalMetadata, s_GlobalMetadataHeader->attributeDataOffset, res->startOffset),
+        MetadataOffset<uint8_t*>(s_GlobalMetadata, s_GlobalMetadataHeader->attributeDataOffset, next->startOffset)
+    );
+}
+
+CustomAttributesCache* il2cpp::vm::GlobalMetadata::GenerateCustomAttributesCache(const Il2CppImage* image, uint32_t token)
+{
+    return GenerateCustomAttributesCacheInternal(GetImageMetadata(image), GetCustomAttributeIndex(image, token));
+}
+
+static bool HasAttributeFromTypeRange(const Il2CppImage* image, const Il2CppCustomAttributeDataRange* dataRange, Il2CppClass* attribute)
+{
+    void* start = MetadataOffset<uint8_t*>(s_GlobalMetadata, s_GlobalMetadataHeader->attributeDataOffset, dataRange->startOffset);
+    void* end = MetadataOffset<uint8_t*>(s_GlobalMetadata, s_GlobalMetadataHeader->attributeDataOffset, (dataRange + 1)->startOffset);
+
+    il2cpp::metadata::CustomAttributeDataReader reader(start, end);
+
+    const MethodInfo* ctor;
+    il2cpp::metadata::CustomAttributeCtorIterator iter = reader.GetCtorIterator();
+    while (reader.IterateAttributeCtors(image, &ctor, &iter))
+    {
+        Il2CppClass* klass = ctor->klass;
+        if (il2cpp::vm::Class::HasParent(klass, attribute) || (il2cpp::vm::Class::IsInterface(attribute) && il2cpp::vm::Class::IsAssignableFrom(attribute, klass)))
+            return true;
+    }
+
+    return false;
+}
+
+bool il2cpp::vm::GlobalMetadata::HasAttribute(Il2CppMetadataCustomAttributeHandle token, Il2CppClass* attribute)
+{
+    if (token == NULL)
+        return false;
+
+    const Il2CppCustomAttributeDataRange* dataRange = reinterpret_cast<const Il2CppCustomAttributeDataRange*>(token);
+
+    CustomAttributeIndex index = GetCustomAttributeIndex(dataRange);
+    const Il2CppImageGlobalMetadata* imageMetadata = GetImageForCustomAttributeIndex(index);
+    if (imageMetadata == NULL)
+        return false;
+
+    return HasAttributeFromTypeRange(imageMetadata->image, dataRange, attribute);
+}
+
+bool il2cpp::vm::GlobalMetadata::HasAttribute(const Il2CppImage* image, uint32_t token, Il2CppClass* attribute)
+{
+    CustomAttributeIndex index = GetCustomAttributeIndex(image, token);
+    if (index == kCustomAttributeIndexInvalid)
+        return false;
+
+    IL2CPP_ASSERT(attribute);
+
+    const Il2CppCustomAttributeDataRange* attributeTypeRange = MetadataOffset<const Il2CppCustomAttributeDataRange*>(s_GlobalMetadata, s_GlobalMetadataHeader->attributeDataRangeOffset, index);
+    return HasAttributeFromTypeRange(image, attributeTypeRange, attribute);
+}
+
+const MethodInfo* il2cpp::vm::GlobalMetadata::GetMethodInfoFromVTableSlot(const Il2CppClass* klass, int32_t vTableSlot)
+{
+    const Il2CppTypeDefinition* typeDefinition = reinterpret_cast<const Il2CppTypeDefinition*>(klass->typeMetadataHandle);
+
+    uint32_t index = typeDefinition->vtableStart + vTableSlot;
+    IL2CPP_ASSERT(index >= 0 && index <= s_GlobalMetadataHeader->vtableMethodsSize / sizeof(EncodedMethodIndex));
+    const EncodedMethodIndex* vTableMethodReferences = (const EncodedMethodIndex*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->vtableMethodsOffset);
+    EncodedMethodIndex vTableMethodReference = vTableMethodReferences[index];
+    return GetMethodInfoFromEncodedIndex(vTableMethodReference);
+}
+
+static const Il2CppFieldDefaultValue* GetFieldDefaultValueEntry(const FieldInfo* field)
+{
+    Il2CppClass* parent = field->parent;
+    size_t fieldIndex = (field - parent->fields);
+
+    if (il2cpp::vm::Type::IsGenericInstance(&parent->byval_arg))
+        parent = il2cpp::vm::GenericClass::GetTypeDefinition(parent->generic_class);
+
+    fieldIndex += reinterpret_cast<const Il2CppTypeDefinition*>(parent->typeMetadataHandle)->fieldStart;
+
+    const Il2CppFieldDefaultValue *start = (const Il2CppFieldDefaultValue*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->fieldDefaultValuesOffset);
+    const Il2CppFieldDefaultValue *entry = start;
+    while (entry < start + s_GlobalMetadataHeader->fieldDefaultValuesSize / sizeof(Il2CppFieldDefaultValue))
+    {
+        if (fieldIndex == entry->fieldIndex)
+        {
+            return entry;
+        }
+        entry++;
+    }
+    IL2CPP_ASSERT(0);
+    return NULL;
+}
+
+static const uint8_t* GetFieldOrParameterDefalutValue(uint32_t index)
+{
+    if (index == kDefaultValueIndexNull)
+        return NULL;
+
+    IL2CPP_ASSERT(index >= 0 && index <= s_GlobalMetadataHeader->fieldAndParameterDefaultValueDataSize / sizeof(uint8_t));
+    const uint8_t* defaultValuesData =  (const uint8_t*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->fieldAndParameterDefaultValueDataOffset);
+    return defaultValuesData + index;
+}
+
+const uint8_t* il2cpp::vm::GlobalMetadata::GetFieldDefaultValue(const FieldInfo* field, const Il2CppType** type)
+{
+    const Il2CppFieldDefaultValue* entry = GetFieldDefaultValueEntry(field);
+
+    if (entry != NULL)
+    {
+        *type = GetIl2CppTypeFromIndex(entry->typeIndex);
+        return GetFieldOrParameterDefalutValue(entry->dataIndex);
+    }
+
+    return NULL;
+}
+
+static const Il2CppParameterDefaultValue * GetParameterDefaultValueEntry(const MethodInfo* method, int32_t parameterPosition)
+{
+    if (il2cpp::vm::Method::IsGenericInstance(method))
+        method = il2cpp::vm::MetadataCache::GetGenericMethodDefinition(method);
+
+    IL2CPP_ASSERT(!il2cpp::vm::Method::IsGenericInstance(method));
+
+    const Il2CppMethodDefinition* methodDefinition = reinterpret_cast<const Il2CppMethodDefinition*>(method->methodMetadataHandle);
+
+    if (methodDefinition == NULL)
+        return NULL;
+
+    size_t parameterIndex = methodDefinition->parameterStart + parameterPosition;
+    const Il2CppParameterDefaultValue *start = (const Il2CppParameterDefaultValue*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->parameterDefaultValuesOffset);
+    const Il2CppParameterDefaultValue *entry = start;
+    while (entry < start + s_GlobalMetadataHeader->parameterDefaultValuesSize / sizeof(Il2CppParameterDefaultValue))
+    {
+        if (parameterIndex == entry->parameterIndex)
+            return entry;
+        entry++;
+    }
+
+    return NULL;
+}
+
+const uint8_t* il2cpp::vm::GlobalMetadata::GetParameterDefaultValue(const MethodInfo* method, int32_t parameterPosition, const Il2CppType** type, bool* isExplicitySetNullDefaultValue)
+{
+    *isExplicitySetNullDefaultValue = false;
+    const Il2CppParameterDefaultValue* parameterDefaultValue = GetParameterDefaultValueEntry(method, parameterPosition);
+
+    if (parameterDefaultValue != NULL)
+    {
+        *type = GetIl2CppTypeFromIndex(parameterDefaultValue->typeIndex);
+        *isExplicitySetNullDefaultValue = parameterDefaultValue->dataIndex == kDefaultValueIndexNull;
+        return GetFieldOrParameterDefalutValue(parameterDefaultValue->dataIndex);
+    }
+
+    return NULL;
+}
+
+static TypeDefinitionIndex GetIndexForTypeDefinition(const Il2CppClass* klass)
+{
+    const Il2CppTypeDefinition* typeDefinition = reinterpret_cast<const Il2CppTypeDefinition*>(klass->typeMetadataHandle);
+    return GetIndexForTypeDefinitionInternal(typeDefinition);
+}
+
+uint32_t il2cpp::vm::GlobalMetadata::GetFieldOffset(const Il2CppClass* klass, int32_t fieldIndexInType, FieldInfo* field)
+{
+    uint32_t typeIndex = GetIndexForTypeDefinition(klass);
+    IL2CPP_ASSERT(typeIndex <= static_cast<uint32_t>(s_Il2CppMetadataRegistration->typeDefinitionsSizesCount));
+    int32_t offset = s_Il2CppMetadataRegistration->fieldOffsets[typeIndex][fieldIndexInType];
+    return offset;
+}
+
+int il2cpp::vm::GlobalMetadata::GetFieldMarshaledSizeForField(const FieldInfo* field)
+{
+    Il2CppClass* parent = field->parent;
+    size_t fieldIndex = (field - parent->fields);
+    fieldIndex += reinterpret_cast<const Il2CppTypeDefinition*>(parent->typeMetadataHandle)->fieldStart;
+
+    const Il2CppFieldMarshaledSize *start = (const Il2CppFieldMarshaledSize*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->fieldMarshaledSizesOffset);
+    const Il2CppFieldMarshaledSize *entry = start;
+    while (entry < start + s_GlobalMetadataHeader->fieldMarshaledSizesSize / sizeof(Il2CppFieldMarshaledSize))
+    {
+        if (fieldIndex == entry->fieldIndex)
+            return entry->size;
+        entry++;
+    }
+
+    return -1;
+}
+
+static const Il2CppFieldDefinition* GetFieldDefinitionFromIndex(const Il2CppImage* image, FieldIndex index)
+{
+    IL2CPP_ASSERT(index >= 0 && static_cast<uint32_t>(index) <= s_GlobalMetadataHeader->fieldsSize / sizeof(Il2CppFieldDefinition));
+    const Il2CppFieldDefinition* fields = (const Il2CppFieldDefinition*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->fieldsOffset);
+    return fields + index;
+}
+
+Il2CppMetadataFieldInfo il2cpp::vm::GlobalMetadata::GetFieldInfo(const Il2CppClass* klass, TypeFieldIndex fieldIndex)
+{
+    const Il2CppTypeDefinition* typeDefinition = reinterpret_cast<const Il2CppTypeDefinition*>(klass->typeMetadataHandle);
+
+    IL2CPP_ASSERT(typeDefinition != NULL);
+    IL2CPP_ASSERT(fieldIndex >= 0 && fieldIndex < typeDefinition->field_count);
+    IL2CPP_ASSERT(typeDefinition->fieldStart != kFieldIndexInvalid);
+
+    const Il2CppFieldDefinition* fieldDefinition = GetFieldDefinitionFromIndex(klass->image, typeDefinition->fieldStart + fieldIndex);
+
+    return {
+            GetIl2CppTypeFromIndex(fieldDefinition->typeIndex),
+            GetStringFromIndex(fieldDefinition->nameIndex),
+            fieldDefinition->token
+    };
+}
+
+Il2CppMetadataMethodInfo il2cpp::vm::GlobalMetadata::GetMethodInfo(const Il2CppClass* klass, TypeMethodIndex index)
+{
+    const Il2CppTypeDefinition* typeDefinition = reinterpret_cast<const Il2CppTypeDefinition*>(klass->typeMetadataHandle);
+
+    IL2CPP_ASSERT(typeDefinition != NULL);
+    IL2CPP_ASSERT(index >= 0 && index < typeDefinition->method_count);
+    IL2CPP_ASSERT(typeDefinition->methodStart != kMethodIndexInvalid);
+
+    const Il2CppMethodDefinition* methodDefinition = GetMethodDefinitionFromIndex(typeDefinition->methodStart + index);
+
+    return {
+            reinterpret_cast<Il2CppMetadataMethodDefinitionHandle>(methodDefinition),
+            GetStringFromIndex(methodDefinition->nameIndex),
+            GetIl2CppTypeFromIndex(methodDefinition->returnType),
+            methodDefinition->token,
+            methodDefinition->flags,
+            methodDefinition->iflags,
+            methodDefinition->slot,
+            methodDefinition->parameterCount,
+    };
+}
+
+Il2CppMetadataParameterInfo il2cpp::vm::GlobalMetadata::GetParameterInfo(const Il2CppClass* klass, Il2CppMetadataMethodDefinitionHandle handle, MethodParameterIndex paramIndex)
+{
+    const Il2CppMethodDefinition* methodDefinition = reinterpret_cast<const Il2CppMethodDefinition*>(handle);
+
+    IL2CPP_ASSERT(methodDefinition != NULL);
+    IL2CPP_ASSERT(paramIndex >= 0 && paramIndex < methodDefinition->parameterCount);
+
+    const Il2CppParameterDefinition* parameterDefinition = GetParameterDefinitionFromIndex(klass->image, methodDefinition->parameterStart + paramIndex);
+
+    return {
+            GetStringFromIndex(parameterDefinition->nameIndex),
+            parameterDefinition->token,
+            GetIl2CppTypeFromIndex(parameterDefinition->typeIndex),
+    };
+}
+
+Il2CppMetadataPropertyInfo il2cpp::vm::GlobalMetadata::GetPropertyInfo(const Il2CppClass* klass, TypePropertyIndex index)
+{
+    const Il2CppTypeDefinition* typeDefintion = reinterpret_cast<const Il2CppTypeDefinition*>(klass->typeMetadataHandle);
+
+    IL2CPP_ASSERT(typeDefintion != NULL);
+    IL2CPP_ASSERT(index >= 0 && index < typeDefintion->property_count);
+    IL2CPP_ASSERT(typeDefintion->propertyStart != kPropertyIndexInvalid);
+
+    const Il2CppPropertyDefinition* propertyDefintion = GetPropertyDefinitionFromIndex(klass->image, typeDefintion->propertyStart + index);
+
+    return {
+            GetStringFromIndex(propertyDefintion->nameIndex),
+            propertyDefintion->get != kMethodIndexInvalid ? klass->methods[propertyDefintion->get] : NULL,
+            propertyDefintion->set != kMethodIndexInvalid ? klass->methods[propertyDefintion->set] : NULL,
+            propertyDefintion->attrs,
+            propertyDefintion->token,
+    };
+}
+
+Il2CppMetadataEventInfo il2cpp::vm::GlobalMetadata::GetEventInfo(const Il2CppClass* klass, TypeEventIndex index)
+{
+    const Il2CppTypeDefinition* typeDefintion = reinterpret_cast<const Il2CppTypeDefinition*>(klass->typeMetadataHandle);
+
+    IL2CPP_ASSERT(typeDefintion != NULL);
+    IL2CPP_ASSERT(index >= 0 && index < typeDefintion->event_count);
+
+    const Il2CppEventDefinition* eventDefintion = GetEventDefinitionFromIndex(klass->image, typeDefintion->eventStart + index);
+
+    return {
+            GetStringFromIndex(eventDefintion->nameIndex),
+            GetIl2CppTypeFromIndex(eventDefintion->typeIndex),
+            eventDefintion->add != kMethodIndexInvalid ? klass->methods[eventDefintion->add] : NULL,
+            eventDefintion->remove != kMethodIndexInvalid ? klass->methods[eventDefintion->remove] : NULL,
+            eventDefintion->raise != kMethodIndexInvalid ? klass->methods[eventDefintion->raise] : NULL,
+            eventDefintion->token,
+    };
+}
+
+static const Il2CppGenericContainer* GetGenericContainerFromIndexInternal(GenericContainerIndex index)
+{
+    if (index == kGenericContainerIndexInvalid)
+        return NULL;
+
+    IL2CPP_ASSERT(index >= 0 && static_cast<uint32_t>(index) <= s_GlobalMetadataHeader->genericContainersSize / sizeof(Il2CppGenericContainer));
+    const Il2CppGenericContainer* genericContainers = (const Il2CppGenericContainer*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->genericContainersOffset);
+    return genericContainers + index;
+}
+
+static Il2CppMetadataGenericContainerHandle GetGenericContainerFromIndex(GenericContainerIndex index)
+{
+    const Il2CppGenericContainer* container = GetGenericContainerFromIndexInternal(index);
+    return reinterpret_cast<Il2CppMetadataGenericContainerHandle>(container);
+}
+
+Il2CppMetadataGenericContainerHandle il2cpp::vm::GlobalMetadata::GetGenericContainerFromGenericClass(const Il2CppGenericClass* genericClass)
+{
+    const Il2CppTypeDefinition* genericType = reinterpret_cast<const Il2CppTypeDefinition*>(GetTypeHandleFromType(genericClass->type));
+    return GetGenericContainerFromIndex(genericType->genericContainerIndex);
+}
+
+Il2CppMetadataGenericContainerHandle il2cpp::vm::GlobalMetadata::GetGenericContainerFromMethod(Il2CppMetadataMethodDefinitionHandle handle)
+{
+    const Il2CppMethodDefinition* methodDefinition = reinterpret_cast<const Il2CppMethodDefinition*>(handle);
+    return GetGenericContainerFromIndex(methodDefinition->genericContainerIndex);
+}
+
+const Il2CppGenericMethod* il2cpp::vm::GlobalMetadata::GetGenericMethodFromTokenMethodTuple(const Il2CppTokenIndexMethodTuple* tuple)
+{
+    return GetGenericMethodFromIndex(tuple->__genericMethodIndex);
+}
+
+static Il2CppMetadataGenericParameterHandle GetGenericParameterFromIndexInternal(GenericParameterIndex index)
+{
+    if (index == kGenericParameterIndexInvalid)
+        return NULL;
+
+    IL2CPP_ASSERT(index >= 0 && static_cast<uint32_t>(index) <= s_GlobalMetadataHeader->genericParametersSize / sizeof(Il2CppGenericParameter));
+    const Il2CppGenericParameter* genericParameters = (const Il2CppGenericParameter*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->genericParametersOffset);
+    return reinterpret_cast<Il2CppMetadataGenericParameterHandle>(genericParameters + index);
+}
+
+Il2CppMetadataGenericParameterHandle il2cpp::vm::GlobalMetadata::GetGenericParameterFromType(const Il2CppType* type)
+{
+    IL2CPP_ASSERT(type->type == IL2CPP_TYPE_VAR || type->type == IL2CPP_TYPE_MVAR);
+    return type->data.genericParameterHandle;
+}
+
+Il2CppClass* il2cpp::vm::GlobalMetadata::GetContainerDeclaringType(Il2CppMetadataGenericContainerHandle handle)
+{
+    const Il2CppGenericContainer* genericContainer = reinterpret_cast<const Il2CppGenericContainer*>(handle);
+
+    if (genericContainer->is_method)
+        return GetMethodInfoFromMethodDefinitionIndex(genericContainer->ownerIndex)->klass;
+
+    return GetTypeInfoFromTypeDefinitionIndex(genericContainer->ownerIndex);
+}
+
+Il2CppClass* il2cpp::vm::GlobalMetadata::GetParameterDeclaringType(Il2CppMetadataGenericParameterHandle handle)
+{
+    const Il2CppGenericParameter* genericParameter = reinterpret_cast<const Il2CppGenericParameter*>(handle);
+
+    const Il2CppGenericContainer* genericContainer =  GetGenericContainerFromIndexInternal(genericParameter->ownerIndex);
+
+    if (genericContainer->is_method)
+        return GetMethodInfoFromMethodDefinitionIndex(genericContainer->ownerIndex)->klass;
+
+    return GetTypeInfoFromTypeDefinitionIndex(genericContainer->ownerIndex);
+}
+
+Il2CppMetadataGenericParameterHandle il2cpp::vm::GlobalMetadata::GetGenericParameterFromIndex(Il2CppMetadataGenericContainerHandle handle, GenericContainerParameterIndex index)
+{
+    const Il2CppGenericContainer* genericContainer = reinterpret_cast<const Il2CppGenericContainer*>(handle);
+
+    IL2CPP_ASSERT(index >= 0 && index < genericContainer->type_argc);
+
+    return GetGenericParameterFromIndexInternal(genericContainer->genericParameterStart + index);
+}
+
+const Il2CppType* il2cpp::vm::GlobalMetadata::GetGenericParameterConstraintFromIndex(Il2CppMetadataGenericParameterHandle handle, GenericParameterConstraintIndex index)
+{
+    const Il2CppGenericParameter* genericParameter = reinterpret_cast<const Il2CppGenericParameter*>(handle);
+
+    IL2CPP_ASSERT(index >= 0 && index < genericParameter->constraintsCount);
+
+    index = genericParameter->constraintsStart + index;
+
+    IL2CPP_ASSERT(index >= 0 && static_cast<uint32_t>(index) <= s_GlobalMetadataHeader->genericParameterConstraintsSize / sizeof(TypeIndex));
+    const TypeIndex* constraintIndices = (const TypeIndex*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->genericParameterConstraintsOffset);
+
+    return GetIl2CppTypeFromIndex(constraintIndices[index]);
+}
+
+static GenericParameterIndex GetIndexForGenericParameter(Il2CppMetadataGenericParameterHandle handle)
+{
+    const Il2CppGenericParameter* genericParameter = reinterpret_cast<const Il2CppGenericParameter*>(handle);
+    const Il2CppGenericParameter* genericParameters = (const Il2CppGenericParameter*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->genericParametersOffset);
+
+    IL2CPP_ASSERT(genericParameter >= genericParameters && genericParameter < genericParameters + s_GlobalMetadataHeader->genericParametersSize / sizeof(Il2CppGenericParameter));
+
+    ptrdiff_t index = genericParameter - genericParameters;
+    IL2CPP_ASSERT(index <= std::numeric_limits<GenericParameterIndex>::max());
+    return static_cast<GenericParameterIndex>(index);
+}
+
+const MethodInfo* il2cpp::vm::GlobalMetadata::GetGenericInstanceMethod(const MethodInfo* genericMethodDefinition, const Il2CppGenericContext* context)
+{
+    const MethodInfo* method = genericMethodDefinition;
+    const Il2CppGenericInst* classInst = context->class_inst;
+    const Il2CppGenericInst* methodInst = context->method_inst;
+    if (genericMethodDefinition->is_inflated)
+    {
+        IL2CPP_ASSERT(genericMethodDefinition->klass->generic_class);
+        classInst = genericMethodDefinition->klass->generic_class->context.class_inst;
+        method = genericMethodDefinition->genericMethod->methodDefinition;
+    }
+
+    return il2cpp::metadata::GenericMethod::GetMethod(method, classInst, methodInst);
+}
+
+const Il2CppType* il2cpp::vm::GlobalMetadata::GetTypeFromRgctxDefinition(const Il2CppRGCTXDefinition* rgctxDef)
+{
+    IL2CPP_ASSERT(rgctxDef->type == IL2CPP_RGCTX_DATA_TYPE || rgctxDef->type == IL2CPP_RGCTX_DATA_CLASS);
+    return GetIl2CppTypeFromIndex(((const Il2CppRGCTXDefinitionData*)rgctxDef->data)->__typeIndex);
+}
+
+const Il2CppGenericMethod* il2cpp::vm::GlobalMetadata::GetGenericMethodFromRgctxDefinition(const Il2CppRGCTXDefinition* rgctxDef)
+{
+    IL2CPP_ASSERT(rgctxDef->type == IL2CPP_RGCTX_DATA_METHOD);
+    return GetGenericMethodFromIndex(((const Il2CppRGCTXDefinitionData*)rgctxDef->data)->__methodIndex);
+}
+
+std::pair<const Il2CppType*, const MethodInfo*> il2cpp::vm::GlobalMetadata::GetConstrainedCallFromRgctxDefinition(const Il2CppRGCTXDefinition* rgctxDef)
+{
+    IL2CPP_ASSERT(rgctxDef->type == IL2CPP_RGCTX_DATA_CONSTRAINED);
+
+    const Il2CppRGCTXConstrainedData* constrainedData = (const Il2CppRGCTXConstrainedData*)rgctxDef->data;
+
+    const Il2CppType* type = GetIl2CppTypeFromIndex(constrainedData->__typeIndex);
+    const MethodInfo* method = GetMethodInfoFromEncodedIndex(constrainedData->__encodedMethodIndex);
+    return std::make_pair(type, method);
+}
+
+enum PackingSize
+{
+    Zero,
+    One,
+    Two,
+    Four,
+    Eight,
+    Sixteen,
+    ThirtyTwo,
+    SixtyFour,
+    OneHundredTwentyEight
+};
+
+static uint8_t ConvertPackingSizeEnumToValue(PackingSize packingSize)
+{
+    switch (packingSize)
+    {
+        case Zero:
+            return 0;
+        case One:
+            return 1;
+        case Two:
+            return 2;
+        case Four:
+            return 4;
+        case Eight:
+            return 8;
+        case Sixteen:
+            return 16;
+        case ThirtyTwo:
+            return 32;
+        case SixtyFour:
+            return 64;
+        case OneHundredTwentyEight:
+            return 128;
+        default:
+            Assert(0 && "Invalid packing size!");
+            return 0;
+    }
+}
+
+int32_t il2cpp::vm::GlobalMetadata::StructLayoutPack(Il2CppMetadataTypeHandle handle)
+{
+    return ConvertPackingSizeEnumToValue(static_cast<PackingSize>((reinterpret_cast<const Il2CppTypeDefinition*>(handle)->bitfield >> (kSpecifiedPackingSize - 1)) & 0xF));
+}
+
+static const Il2CppImage* GetImageForTypeDefinitionIndex(TypeDefinitionIndex index)
+{
+    for (int32_t imageIndex = 0; imageIndex < s_MetadataImagesCount; imageIndex++)
+    {
+        const Il2CppImageGlobalMetadata* imageMetadata = s_MetadataImagesTable + imageIndex;
+        IL2CPP_ASSERT(index >= 0);
+        if (index >= imageMetadata->typeStart && static_cast<uint32_t>(index) < (imageMetadata->typeStart + imageMetadata->image->typeCount))
+            return imageMetadata->image;
+    }
+
+    IL2CPP_ASSERT(0 && "Failed to find owning image for type defintion index");
+    return NULL;
+}
+
+static Il2CppClass* FromTypeDefinition(TypeDefinitionIndex index)
+{
+    IL2CPP_ASSERT(index >= 0 && static_cast<uint32_t>(index) < s_GlobalMetadataHeader->typeDefinitionsSize / sizeof(Il2CppTypeDefinition));
+    const Il2CppTypeDefinition* typeDefinitions = (const Il2CppTypeDefinition*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->typeDefinitionsOffset);
+    const Il2CppTypeDefinition* typeDefinition = typeDefinitions + index;
+    const Il2CppTypeDefinitionSizes* typeDefinitionSizes = s_Il2CppMetadataRegistration->typeDefinitionsSizes[index];
+    Il2CppClass* typeInfo = (Il2CppClass*)IL2CPP_CALLOC(1, sizeof(Il2CppClass) + (sizeof(VirtualInvokeData) * typeDefinition->vtable_count));
+    typeInfo->klass = typeInfo;
+    typeInfo->image = GetImageForTypeDefinitionIndex(index);
+    typeInfo->name = GetStringFromIndex(typeDefinition->nameIndex);
+    typeInfo->namespaze = GetStringFromIndex(typeDefinition->namespaceIndex);
+    typeInfo->byval_arg = *il2cpp::vm::GlobalMetadata::GetIl2CppTypeFromIndex(typeDefinition->byvalTypeIndex);
+    typeInfo->this_arg = typeInfo->byval_arg;
+    typeInfo->this_arg.byref = true;
+    typeInfo->this_arg.valuetype = 0;
+    typeInfo->typeMetadataHandle = reinterpret_cast<const Il2CppMetadataTypeHandle>(typeDefinition);
+    typeInfo->genericContainerHandle = GetGenericContainerFromIndex(typeDefinition->genericContainerIndex);
+    typeInfo->instance_size = typeDefinitionSizes->instance_size;
+    typeInfo->actualSize = typeDefinitionSizes->instance_size;     // actualySize is instance_size for compiler generated values
+    typeInfo->native_size = typeDefinitionSizes->native_size;
+    typeInfo->static_fields_size = typeDefinitionSizes->static_fields_size;
+    typeInfo->thread_static_fields_size = typeDefinitionSizes->thread_static_fields_size;
+    typeInfo->thread_static_fields_offset = -1;
+    typeInfo->flags = typeDefinition->flags;
+    typeInfo->enumtype = (typeDefinition->bitfield >> (kBitIsEnum - 1)) & 0x1;
+    typeInfo->is_generic = typeDefinition->genericContainerIndex != kGenericContainerIndexInvalid;     // generic if we have a generic container
+    typeInfo->has_finalize = (typeDefinition->bitfield >> (kBitHasFinalizer - 1)) & 0x1;
+    typeInfo->has_cctor = (typeDefinition->bitfield >> (kBitHasStaticConstructor - 1)) & 0x1;
+    typeInfo->cctor_finished_or_no_cctor = !typeInfo->has_cctor;
+    typeInfo->is_blittable = (typeDefinition->bitfield >> (kBitIsBlittable - 1)) & 0x1;
+    typeInfo->is_import_or_windows_runtime = (typeDefinition->bitfield >> (kBitIsImportOrWindowsRuntime - 1)) & 0x1;
+    typeInfo->packingSize = ConvertPackingSizeEnumToValue(static_cast<PackingSize>((typeDefinition->bitfield >> (kPackingSize - 1)) & 0xF));
+    typeInfo->is_byref_like = (typeDefinition->bitfield >> (kBitIsByRefLike - 1)) & 0x1;
+    typeInfo->method_count = typeDefinition->method_count;
+    typeInfo->property_count = typeDefinition->property_count;
+    typeInfo->field_count = typeDefinition->field_count;
+    typeInfo->event_count = typeDefinition->event_count;
+    typeInfo->nested_type_count = typeDefinition->nested_type_count;
+    typeInfo->vtable_count = typeDefinition->vtable_count;
+    typeInfo->interfaces_count = typeDefinition->interfaces_count;
+    typeInfo->interface_offsets_count = typeDefinition->interface_offsets_count;
+    typeInfo->token = typeDefinition->token;
+    typeInfo->interopData = il2cpp::vm::MetadataCache::GetInteropDataForType(&typeInfo->byval_arg);
+
+    if (typeDefinition->parentIndex != kTypeIndexInvalid)
+        typeInfo->parent = il2cpp::vm::Class::FromIl2CppType(il2cpp::vm::GlobalMetadata::GetIl2CppTypeFromIndex(typeDefinition->parentIndex));
+
+    if (typeDefinition->declaringTypeIndex != kTypeIndexInvalid)
+        typeInfo->declaringType = il2cpp::vm::Class::FromIl2CppType(il2cpp::vm::GlobalMetadata::GetIl2CppTypeFromIndex(typeDefinition->declaringTypeIndex));
+
+    typeInfo->castClass = typeInfo->element_class = typeInfo;
+    if (typeInfo->enumtype)
+        typeInfo->castClass = typeInfo->element_class = il2cpp::vm::Class::FromIl2CppType(il2cpp::vm::GlobalMetadata::GetIl2CppTypeFromIndex(typeDefinition->elementTypeIndex));
+
+    return typeInfo;
+}
+
+const Il2CppType* il2cpp::vm::GlobalMetadata::GetIl2CppTypeFromIndex(TypeIndex index)
+{
+    if (index == kTypeIndexInvalid)
+        return NULL;
+
+    IL2CPP_ASSERT(index < s_Il2CppMetadataRegistration->typesCount && "Invalid type index ");
+
+    return s_Il2CppMetadataRegistration->types[index];
+}
+
+uint32_t il2cpp::vm::GlobalMetadata::GetGenericContainerCount(Il2CppMetadataGenericContainerHandle handle)
+{
+    const Il2CppGenericContainer* container = reinterpret_cast<const Il2CppGenericContainer*>(handle);
+    return container != NULL ? container->type_argc : 0;
+}
+
+void il2cpp::vm::GlobalMetadata::MakeGenericArgType(Il2CppMetadataGenericContainerHandle containerHandle, Il2CppMetadataGenericParameterHandle paramHandle, Il2CppType* arg)
+{
+    const Il2CppGenericContainer* container = reinterpret_cast<const Il2CppGenericContainer*>(containerHandle);
+
+    arg->type = container->is_method ? IL2CPP_TYPE_MVAR : IL2CPP_TYPE_VAR;
+    arg->data.genericParameterHandle = paramHandle;
+}
+
+bool il2cpp::vm::GlobalMetadata::GetGenericContainerIsMethod(Il2CppMetadataGenericContainerHandle handle)
+{
+    const Il2CppGenericContainer* container = reinterpret_cast<const Il2CppGenericContainer*>(handle);
+    IL2CPP_ASSERT(container != NULL);
+    return container != NULL ? container->is_method : false;
+}
+
+int16_t il2cpp::vm::GlobalMetadata::GetGenericConstraintCount(Il2CppMetadataGenericParameterHandle handle)
+{
+    const Il2CppGenericParameter* genericParameter = reinterpret_cast<const Il2CppGenericParameter*>(handle);
+    return genericParameter->constraintsCount;
+}
+
+const char* il2cpp::vm::GlobalMetadata::GetGenericParameterName(Il2CppMetadataGenericParameterHandle handle)
+{
+    const Il2CppGenericParameter* genericParameter = reinterpret_cast<const Il2CppGenericParameter*>(handle);
+    return GetStringFromIndex(genericParameter->nameIndex);
+}
+
+Il2CppGenericParameterInfo il2cpp::vm::GlobalMetadata::GetGenericParameterInfo(Il2CppMetadataGenericParameterHandle handle)
+{
+    const Il2CppGenericParameter* genericParameter = reinterpret_cast<const Il2CppGenericParameter*>(handle);
+
+    return {
+            reinterpret_cast<Il2CppMetadataGenericContainerHandle>(GetGenericContainerFromIndexInternal(genericParameter->ownerIndex)),
+            GetStringFromIndex(genericParameter->nameIndex),
+            genericParameter->num,
+            genericParameter->flags
+    };
+}
+
+uint16_t il2cpp::vm::GlobalMetadata::GetGenericParameterFlags(Il2CppMetadataGenericParameterHandle handle)
+{
+    const Il2CppGenericParameter* genericParameter = reinterpret_cast<const Il2CppGenericParameter*>(handle);
+    return genericParameter->flags;
+}
+
+const MethodInfo* il2cpp::vm::GlobalMetadata::GetMethodInfoFromCatchPoint(const Il2CppCatchPoint* cp)
+{
+    return GetMethodInfoFromMethodDefinitionIndex(cp->__methodDefinitionIndex);
+}
+
+const MethodInfo* il2cpp::vm::GlobalMetadata::GetMethodInfoFromSequencePoint(const Il2CppSequencePoint* seqPoint)
+{
+    return GetMethodInfoFromMethodDefinitionIndex(seqPoint->__methodDefinitionIndex);
+}
+
+Il2CppClass* il2cpp::vm::GlobalMetadata::GetTypeInfoFromTypeSourcePair(const Il2CppTypeSourceFilePair* pair)
+{
+    return GetTypeInfoFromTypeDefinitionIndex(pair->__klassIndex);
+}
+
+Il2CppClass* il2cpp::vm::GlobalMetadata::GetTypeInfoFromTypeIndex(TypeIndex index, bool throwOnError)
+{
+    if (index == kTypeIndexInvalid)
+        return NULL;
+
+    IL2CPP_ASSERT(index < s_Il2CppMetadataRegistration->typesCount && "Invalid type index ");
+
+    if (s_TypeInfoTable[index])
+        return s_TypeInfoTable[index];
+
+    const Il2CppType* type = s_Il2CppMetadataRegistration->types[index];
+
+    Il2CppClass *klass = Class::FromIl2CppType(type, throwOnError);
+    if (klass != NULL)
+    {
+        s_TypeInfoTable[index] = ClassInlines::InitFromCodegenSlow(klass, throwOnError);
+    }
+    return s_TypeInfoTable[index];
+}
+
+const MethodInfo* il2cpp::vm::GlobalMetadata::GetMethodInfoFromMethodHandle(Il2CppMetadataMethodDefinitionHandle handle)
+{
+    const Il2CppMethodDefinition* methodDefinition = reinterpret_cast<const Il2CppMethodDefinition*>(handle);
+    const Il2CppMethodDefinition* methods = (const Il2CppMethodDefinition*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->methodsOffset);
+
+    const MethodIndex index = static_cast<MethodIndex>(methodDefinition - methods);
+
+    IL2CPP_ASSERT(index >= 0 && static_cast<uint32_t>(index) <= s_GlobalMetadataHeader->methodsSize / sizeof(Il2CppMethodDefinition));
+
+    return GetMethodInfoFromMethodDefinitionIndex(index);
+}
+
+#if IL2CPP_ENABLE_NATIVE_STACKTRACES
+void il2cpp::vm::GlobalMetadata::GetAllManagedMethods(std::vector<MethodDefinitionKey>& managedMethods)
+{
+    size_t methodDefinitionsCount = s_GlobalMetadataHeader->methodsSize / sizeof(Il2CppMethodDefinition);
+    managedMethods.reserve(methodDefinitionsCount + s_Il2CppMetadataRegistration->genericMethodTableCount);
+
+    const Il2CppTypeDefinition* typeDefinitions = (const Il2CppTypeDefinition*)((const char*)s_GlobalMetadata + s_GlobalMetadataHeader->typeDefinitionsOffset);
+    for (int32_t i = 0; i < s_MetadataImagesCount; i++)
+    {
+        const Il2CppImageGlobalMetadata* image = s_MetadataImagesTable + i;
+
+        for (size_t j = 0; j < image->image->typeCount; j++)
+        {
+            const Il2CppTypeDefinition* type = typeDefinitions + image->typeStart + j;
+
+            for (uint16_t u = 0; u < type->method_count; u++)
+            {
+                const Il2CppMethodDefinition* methodDefinition = GetMethodDefinitionFromIndex(type->methodStart + u);
+                MethodDefinitionKey currentMethodList;
+                currentMethodList.methodHandle = reinterpret_cast<Il2CppMetadataMethodDefinitionHandle>(methodDefinition);
+                currentMethodList.method = il2cpp::vm::MetadataCache::GetMethodPointer(image->image, methodDefinition->token);
+                if (currentMethodList.method)
+                    managedMethods.push_back(currentMethodList);
+            }
+        }
+    }
+
+    for (int32_t i = 0; i < s_Il2CppMetadataRegistration->genericMethodTableCount; i++)
+    {
+        const Il2CppGenericMethodFunctionsDefinitions* genericMethodIndices = s_Il2CppMetadataRegistration->genericMethodTable + i;
+
+        MethodDefinitionKey currentMethodList;
+
+        GenericMethodIndex genericMethodIndex = genericMethodIndices->genericMethodIndex;
+
+        IL2CPP_ASSERT(genericMethodIndex < s_Il2CppMetadataRegistration->methodSpecsCount);
+        const Il2CppMethodSpec* methodSpec = s_Il2CppMetadataRegistration->methodSpecs + genericMethodIndex;
+        const Il2CppMethodDefinition* methodDefinition = GetMethodDefinitionFromIndex(methodSpec->methodDefinitionIndex);
+        currentMethodList.methodHandle = reinterpret_cast<Il2CppMetadataMethodDefinitionHandle>(methodDefinition);
+
+        IL2CPP_ASSERT(genericMethodIndices->indices.methodIndex < static_cast<int32_t>(s_GlobalMetadata_CodeRegistration->genericMethodPointersCount));
+        currentMethodList.method = s_GlobalMetadata_CodeRegistration->genericMethodPointers[genericMethodIndices->indices.methodIndex];
+
+        managedMethods.push_back(currentMethodList);
+    }
+}
+
+#endif
diff --git a/O&Z_IL2CPP_Security/resource/src-res/28/GlobalMetadataFileInternals.h b/O&Z_IL2CPP_Security/resource/src-res/28/GlobalMetadataFileInternals.h
new file mode 100644
index 0000000..b11ef55
--- /dev/null
+++ b/O&Z_IL2CPP_Security/resource/src-res/28/GlobalMetadataFileInternals.h
@@ -0,0 +1,353 @@
+#pragma once
+
+#include "il2cpp-metadata.h"
+
+// This file contains the structures specifying how we store converted metadata.
+// These structures have 3 constraints:
+// 1. These structures will be stored in an external file, and as such must not contain any pointers.
+//    All references to other metadata should occur via an index into a corresponding table.
+// 2. These structures are assumed to be const. Either const structures in the binary or mapped as
+//    readonly memory from an external file. Do not add any 'calculated' fields which will be written to at runtime.
+// 3. These structures should be optimized for size. Other structures are used at runtime which can
+//    be larger to store cached information
+
+// Encoded index (1 bit)
+// MethodDef - 0
+// MethodSpec - 1
+// We use the top 3 bits to indicate what table to index into
+// Type              Binary            Hex
+// Il2CppClass       001               0x20000000
+// Il2CppType        010               0x40000000
+// MethodInfo        011               0x60000000
+// FieldInfo         100               0x80000000
+// StringLiteral     101               0xA0000000
+// MethodRef         110               0xC0000000
+
+typedef uint32_t EncodedMethodIndex;
+
+enum Il2CppMetadataUsage
+{
+    kIl2CppMetadataUsageInvalid,
+    kIl2CppMetadataUsageTypeInfo,
+    kIl2CppMetadataUsageIl2CppType,
+    kIl2CppMetadataUsageMethodDef,
+    kIl2CppMetadataUsageFieldInfo,
+    kIl2CppMetadataUsageStringLiteral,
+    kIl2CppMetadataUsageMethodRef,
+};
+
+enum Il2CppInvalidMetadataUsageToken
+{
+    kIl2CppInvalidMetadataUsageNoData = 0,
+    kIl2CppInvalidMetadataUsageAmbiguousMethod = 1,
+};
+
+#ifdef __cplusplus
+static inline Il2CppMetadataUsage GetEncodedIndexType(EncodedMethodIndex index)
+{
+    return (Il2CppMetadataUsage)((index & 0xE0000000) >> 29);
+}
+
+static inline uint32_t GetDecodedMethodIndex(EncodedMethodIndex index)
+{
+    return (index & 0x1FFFFFFEU) >> 1;
+}
+
+#endif
+
+typedef struct Il2CppInterfaceOffsetPair
+{
+    TypeIndex interfaceTypeIndex;
+    int32_t offset;
+} Il2CppInterfaceOffsetPair;
+
+typedef struct Il2CppTypeDefinition
+{
+    StringIndex nameIndex;
+    StringIndex namespaceIndex;
+    TypeIndex byvalTypeIndex;
+
+    TypeIndex declaringTypeIndex;
+    TypeIndex parentIndex;
+    TypeIndex elementTypeIndex; // we can probably remove this one. Only used for enums
+
+    GenericContainerIndex genericContainerIndex;
+
+    uint32_t flags;
+
+    FieldIndex fieldStart;
+    MethodIndex methodStart;
+    EventIndex eventStart;
+    PropertyIndex propertyStart;
+    NestedTypeIndex nestedTypesStart;
+    InterfacesIndex interfacesStart;
+    VTableIndex vtableStart;
+    InterfacesIndex interfaceOffsetsStart;
+
+    uint16_t method_count;
+    uint16_t property_count;
+    uint16_t field_count;
+    uint16_t event_count;
+    uint16_t nested_type_count;
+    uint16_t vtable_count;
+    uint16_t interfaces_count;
+    uint16_t interface_offsets_count;
+
+    // bitfield to portably encode boolean values as single bits
+    // 01 - valuetype;
+    // 02 - enumtype;
+    // 03 - has_finalize;
+    // 04 - has_cctor;
+    // 05 - is_blittable;
+    // 06 - is_import_or_windows_runtime;
+    // 07-10 - One of nine possible PackingSize values (0, 1, 2, 4, 8, 16, 32, 64, or 128)
+    // 11 - PackingSize is default
+    // 12 - ClassSize is default
+    // 13-16 - One of nine possible PackingSize values (0, 1, 2, 4, 8, 16, 32, 64, or 128) - the specified packing size (even for explicit layouts)
+    uint32_t bitfield;
+    uint32_t token;
+} Il2CppTypeDefinition;
+
+typedef struct Il2CppFieldDefinition
+{
+    StringIndex nameIndex;
+    TypeIndex typeIndex;
+    uint32_t token;
+} Il2CppFieldDefinition;
+
+typedef struct Il2CppFieldDefaultValue
+{
+    FieldIndex fieldIndex;
+    TypeIndex typeIndex;
+    DefaultValueDataIndex dataIndex;
+} Il2CppFieldDefaultValue;
+
+typedef struct Il2CppFieldMarshaledSize
+{
+    FieldIndex fieldIndex;
+    TypeIndex typeIndex;
+    int32_t size;
+} Il2CppFieldMarshaledSize;
+
+typedef struct Il2CppFieldRef
+{
+    TypeIndex typeIndex;
+    FieldIndex fieldIndex; // local offset into type fields
+} Il2CppFieldRef;
+
+typedef struct Il2CppParameterDefinition
+{
+    StringIndex nameIndex;
+    uint32_t token;
+    TypeIndex typeIndex;
+} Il2CppParameterDefinition;
+
+typedef struct Il2CppParameterDefaultValue
+{
+    ParameterIndex parameterIndex;
+    TypeIndex typeIndex;
+    DefaultValueDataIndex dataIndex;
+} Il2CppParameterDefaultValue;
+
+typedef struct Il2CppMethodDefinition
+{
+    StringIndex nameIndex;
+    TypeDefinitionIndex declaringType;
+    TypeIndex returnType;
+    ParameterIndex parameterStart;
+    GenericContainerIndex genericContainerIndex;
+    uint32_t token;
+    uint16_t flags;
+    uint16_t iflags;
+    uint16_t slot;
+    uint16_t parameterCount;
+} Il2CppMethodDefinition;
+
+typedef struct Il2CppEventDefinition
+{
+    StringIndex nameIndex;
+    TypeIndex typeIndex;
+    MethodIndex add;
+    MethodIndex remove;
+    MethodIndex raise;
+    uint32_t token;
+} Il2CppEventDefinition;
+
+typedef struct Il2CppPropertyDefinition
+{
+    StringIndex nameIndex;
+    MethodIndex get;
+    MethodIndex set;
+    uint32_t attrs;
+    uint32_t token;
+} Il2CppPropertyDefinition;
+
+typedef struct Il2CppStringLiteral
+{
+    StringLiteralIndex dataIndex;
+    uint32_t length;
+} Il2CppStringLiteral;
+
+typedef struct Il2CppAssemblyNameDefinition
+{
+    StringIndex nameIndex;
+    StringIndex cultureIndex;
+    StringIndex publicKeyIndex;
+    uint32_t hash_alg;
+    int32_t hash_len;
+    uint32_t flags;
+    int32_t major;
+    int32_t minor;
+    int32_t build;
+    int32_t revision;
+    uint8_t public_key_token[PUBLIC_KEY_BYTE_LENGTH];
+} Il2CppAssemblyNameDefinition;
+
+typedef struct Il2CppImageDefinition
+{
+    StringIndex nameIndex;
+    AssemblyIndex assemblyIndex;
+
+    TypeDefinitionIndex typeStart;
+    uint32_t typeCount;
+
+    TypeDefinitionIndex exportedTypeStart;
+    uint32_t exportedTypeCount;
+
+    MethodIndex entryPointIndex;
+    uint32_t token;
+
+    CustomAttributeIndex customAttributeStart;
+    uint32_t customAttributeCount;
+} Il2CppImageDefinition;
+
+typedef struct Il2CppAssemblyDefinition
+{
+    ImageIndex imageIndex;
+    uint32_t token;
+    int32_t referencedAssemblyStart;
+    int32_t referencedAssemblyCount;
+    Il2CppAssemblyNameDefinition aname;
+} Il2CppAssemblyDefinition;
+
+typedef struct Il2CppCustomAttributeDataRange
+{
+    uint32_t token;
+    uint32_t startOffset;
+} Il2CppCustomAttributeDataRange;
+
+typedef struct Il2CppMetadataRange
+{
+    int32_t start;
+    int32_t length;
+} Il2CppMetadataRange;
+
+typedef struct Il2CppGenericContainer
+{
+    /* index of the generic type definition or the generic method definition corresponding to this container */
+    int32_t ownerIndex; // either index into Il2CppClass metadata array or Il2CppMethodDefinition array
+    int32_t type_argc;
+    /* If true, we're a generic method, otherwise a generic type definition. */
+    int32_t is_method;
+    /* Our type parameters. */
+    GenericParameterIndex genericParameterStart;
+} Il2CppGenericContainer;
+
+typedef struct Il2CppGenericParameter
+{
+    GenericContainerIndex ownerIndex; /* Type or method this parameter was defined in. */
+    StringIndex nameIndex;
+    GenericParameterConstraintIndex constraintsStart;
+    int16_t constraintsCount;
+    uint16_t num;
+    uint16_t flags;
+} Il2CppGenericParameter;
+
+typedef struct Il2CppWindowsRuntimeTypeNamePair
+{
+    StringIndex nameIndex;
+    TypeIndex typeIndex;
+} Il2CppWindowsRuntimeTypeNamePair;
+
+#pragma pack(push, p1, 4)
+typedef struct Il2CppGlobalMetadataHeader
+{
+    int32_t sanity;
+
+    int32_t stringLiteralOffset; // string data for managed code
+    int32_t interfacesOffset;    // TypeIndex
+    int32_t stringLiteralDataOffset;
+    int32_t stringOffset;                               // string data for metadata
+    int32_t vtableMethodsOffset;                        // EncodedMethodIndex
+    int32_t eventsOffset;                               // Il2CppEventDefinition
+    int32_t interfaceOffsetsOffset;                     // Il2CppInterfaceOffsetPair
+    int32_t propertiesOffset;                           // Il2CppPropertyDefinition
+    int32_t assembliesOffset;                           // Il2CppAssemblyDefinition
+    int32_t methodsOffset;                              // Il2CppMethodDefinition
+    int32_t fieldRefsOffset;                            // Il2CppFieldRef
+    int32_t parameterDefaultValuesOffset;               // Il2CppParameterDefaultValue
+    int32_t typeDefinitionsOffset;                      // Il2CppTypeDefinition
+    int32_t fieldDefaultValuesOffset;                   // Il2CppFieldDefaultValue
+    int32_t imagesOffset;                               // Il2CppImageDefinition
+    int32_t fieldAndParameterDefaultValueDataOffset;    // uint8_t
+    int32_t referencedAssembliesOffset;                 // int32_t
+    int32_t fieldMarshaledSizesOffset;                  // Il2CppFieldMarshaledSize
+    int32_t unresolvedVirtualCallParameterTypesOffset;  // TypeIndex
+    int32_t parametersOffset;                           // Il2CppParameterDefinition
+    int32_t unresolvedVirtualCallParameterRangesOffset; // Il2CppMetadataRange
+    int32_t fieldsOffset;                               // Il2CppFieldDefinition
+    int32_t windowsRuntimeTypeNamesOffset;              // Il2CppWindowsRuntimeTypeNamePair
+    int32_t genericParametersOffset;                    // Il2CppGenericParameter
+    int32_t windowsRuntimeStringsOffset;                // const char*
+    int32_t genericParameterConstraintsOffset;          // TypeIndex
+    int32_t exportedTypeDefinitionsOffset;              // TypeDefinitionIndex
+    int32_t genericContainersOffset;                    // Il2CppGenericContainer
+    int32_t nestedTypesOffset;                          // TypeDefinitionIndex
+
+    int32_t version;
+    int32_t genericContainersSize;
+    int32_t stringLiteralSize;
+    int32_t nestedTypesSize;
+    int32_t interfacesSize;
+    int32_t stringLiteralDataSize;
+    int32_t vtableMethodsSize;
+    int32_t stringSize;
+    int32_t interfaceOffsetsSize;
+    int32_t eventsSize;
+    int32_t typeDefinitionsSize;
+    int32_t parameterDefaultValuesSize;
+    int32_t imagesSize;
+    int32_t fieldDefaultValuesSize;
+    int32_t assembliesSize;
+    int32_t propertiesSize;
+    int32_t fieldRefsSize;
+    int32_t methodsSize;
+    int32_t referencedAssembliesSize;
+    int32_t attributeDataOffset;
+    int32_t attributeDataSize;
+    int32_t attributeDataRangeOffset;
+    int32_t attributeDataRangeSize;
+    int32_t fieldAndParameterDefaultValueDataSize;
+    int32_t unresolvedVirtualCallParameterTypesSize;
+    int32_t fieldMarshaledSizesSize;
+    int32_t unresolvedVirtualCallParameterRangesSize;
+    int32_t parametersSize;
+    int32_t windowsRuntimeTypeNamesSize;
+    int32_t fieldsSize;
+    int32_t windowsRuntimeStringsSize;
+    int32_t genericParametersSize;
+    int32_t exportedTypeDefinitionsSize;
+    int32_t genericParameterConstraintsSize;
+} Il2CppGlobalMetadataHeader;
+#pragma pack(pop, p1)
+
+//FrontHeader
+#pragma pack(push, p1, 4)
+typedef struct FrontHeader
+{
+    char sign[24];
+    int64_t offset;
+    int32_t legnth;
+    unsigned char key[32];
+} FrontHeader;
+#pragma pack(pop, p1)
\ No newline at end of file
diff --git a/O&Z_IL2CPP_Security/resource/src-res/xxtea.cpp b/O&Z_IL2CPP_Security/resource/src-res/xxtea.cpp
new file mode 100644
index 0000000..0e6ab68
--- /dev/null
+++ b/O&Z_IL2CPP_Security/resource/src-res/xxtea.cpp
@@ -0,0 +1,260 @@
+/**********************************************************\
+|                                                          |
+| xxtea.c                                                  |
+|                                                          |
+| XXTEA encryption algorithm library for C.                |
+|                                                          |
+| Encryption Algorithm Authors:                            |
+|      David J. Wheeler                                    |
+|      Roger M. Needham                                    |
+|                                                          |
+| Code Authors: Chen fei <cf850118@163.com>                |
+|               Ma Bingyao <mabingyao@gmail.com>           |
+| LastModified: Feb 7, 2016                                |
+|                                                          |
+\**********************************************************/
+
+
+#include "xxtea.h"
+
+#include <string.h>
+#if defined(_MSC_VER) && _MSC_VER < 1600
+typedef unsigned __int8 uint8_t;
+typedef unsigned __int32 uint32_t;
+#else
+#if defined(__FreeBSD__) && __FreeBSD__ < 5
+/* FreeBSD 4 doesn't have stdint.h file */
+#include <inttypes.h>
+#else
+#include <stdint.h>
+#endif
+#endif
+
+#include <sys/types.h> /* This will likely define BYTE_ORDER */
+
+#ifndef BYTE_ORDER
+#if (BSD >= 199103)
+# include <machine/endian.h>
+#else
+#if defined(linux) || defined(__linux__)
+# include <endian.h>
+#else
+#define LITTLE_ENDIAN   1234    /* least-significant byte first (vax, pc) */
+#define BIG_ENDIAN  4321    /* most-significant byte first (IBM, net) */
+#define PDP_ENDIAN  3412    /* LSB first in word, MSW first in long (pdp)*/
+
+#if defined(__i386__) || defined(__x86_64__) || defined(__amd64__) || \
+   defined(vax) || defined(ns32000) || defined(sun386) || \
+   defined(MIPSEL) || defined(_MIPSEL) || defined(BIT_ZERO_ON_RIGHT) || \
+   defined(__alpha__) || defined(__alpha)
+#define BYTE_ORDER    LITTLE_ENDIAN
+#endif
+
+#if defined(sel) || defined(pyr) || defined(mc68000) || defined(sparc) || \
+    defined(is68k) || defined(tahoe) || defined(ibm032) || defined(ibm370) || \
+    defined(MIPSEB) || defined(_MIPSEB) || defined(_IBMR2) || defined(DGUX) ||\
+    defined(apollo) || defined(__convex__) || defined(_CRAY) || \
+    defined(__hppa) || defined(__hp9000) || \
+    defined(__hp9000s300) || defined(__hp9000s700) || \
+    defined (BIT_ZERO_ON_LEFT) || defined(m68k) || defined(__sparc)
+#define BYTE_ORDER  BIG_ENDIAN
+#endif
+#endif /* linux */
+#endif /* BSD */
+#endif /* BYTE_ORDER */
+
+#ifndef BYTE_ORDER
+#ifdef __BYTE_ORDER
+#if defined(__LITTLE_ENDIAN) && defined(__BIG_ENDIAN)
+#ifndef LITTLE_ENDIAN
+#define LITTLE_ENDIAN __LITTLE_ENDIAN
+#endif
+#ifndef BIG_ENDIAN
+#define BIG_ENDIAN __BIG_ENDIAN
+#endif
+#if (__BYTE_ORDER == __LITTLE_ENDIAN)
+#define BYTE_ORDER LITTLE_ENDIAN
+#else
+#define BYTE_ORDER BIG_ENDIAN
+#endif
+#endif
+#endif
+#endif
+
+#define MX (((z >> 5) ^ (y << 2)) + ((y >> 3) ^ (z << 4))) ^ ((sum ^ y) + (key[(p & 3) ^ e] ^ z))
+#define DELTA 0x9e3779b9
+
+#define FIXED_KEY \
+    size_t i;\
+    uint8_t fixed_key[16];\
+    memcpy(fixed_key, key, 16);\
+    for (i = 0; (i < 16) && (fixed_key[i] != 0); ++i);\
+    for (++i; i < 16; ++i) fixed_key[i] = 0;\
+
+
+static uint32_t * xxtea_to_uint_array(const uint8_t * data, size_t len, int inc_len, size_t * out_len) {
+    uint32_t *out;
+#if !(defined(BYTE_ORDER) && (BYTE_ORDER == LITTLE_ENDIAN))
+    size_t i;
+#endif
+    size_t n;
+
+    n = (((len & 3) == 0) ? (len >> 2) : ((len >> 2) + 1));
+
+    if (inc_len) {
+        out = (uint32_t *)calloc(n + 1, sizeof(uint32_t));
+        if (!out) return NULL;
+        out[n] = (uint32_t)len;
+        *out_len = n + 1;
+    }
+    else {
+        out = (uint32_t *)calloc(n, sizeof(uint32_t));
+        if (!out) return NULL;
+        *out_len = n;
+    }
+#if defined(BYTE_ORDER) && (BYTE_ORDER == LITTLE_ENDIAN)
+    memcpy(out, data, len);
+#else
+    for (i = 0; i < len; ++i) {
+        out[i >> 2] |= (uint32_t)data[i] << ((i & 3) << 3);
+    }
+#endif
+
+    return out;
+}
+
+static uint8_t * xxtea_to_ubyte_array(const uint32_t * data, size_t len, int inc_len, size_t * out_len) {
+    uint8_t *out;
+#if !(defined(BYTE_ORDER) && (BYTE_ORDER == LITTLE_ENDIAN))
+    size_t i;
+#endif
+    size_t m, n;
+
+    n = len << 2;
+
+    if (inc_len) {
+        m = data[len - 1];
+        n -= 4;
+        if ((m < n - 3) || (m > n)) return NULL;
+        n = m;
+    }
+
+    out = (uint8_t *)malloc(n + 1);
+
+#if defined(BYTE_ORDER) && (BYTE_ORDER == LITTLE_ENDIAN)
+    memcpy(out, data, n);
+#else
+    for (i = 0; i < n; ++i) {
+        out[i] = (uint8_t)(data[i >> 2] >> ((i & 3) << 3));
+    }
+#endif
+
+    out[n] = '\0';
+    *out_len = n;
+
+    return out;
+}
+
+static uint32_t * xxtea_uint_encrypt(uint32_t * data, size_t len, uint32_t * key) {
+    uint32_t n = (uint32_t)len - 1;
+    uint32_t z = data[n], y, p, q = 6 + 52 / (n + 1), sum = 0, e;
+
+    if (n < 1) return data;
+
+    while (0 < q--) {
+        sum += DELTA;
+        e = sum >> 2 & 3;
+
+        for (p = 0; p < n; p++) {
+            y = data[p + 1];
+            z = data[p] += MX;
+        }
+
+        y = data[0];
+        z = data[n] += MX;
+    }
+
+    return data;
+}
+
+static uint32_t * xxtea_uint_decrypt(uint32_t * data, size_t len, uint32_t * key) {
+    uint32_t n = (uint32_t)len - 1;
+    uint32_t z, y = data[0], p, q = 6 + 52 / (n + 1), sum = q * DELTA, e;
+
+    if (n < 1) return data;
+
+    while (sum != 0) {
+        e = sum >> 2 & 3;
+
+        for (p = n; p > 0; p--) {
+            z = data[p - 1];
+            y = data[p] -= MX;
+        }
+
+        z = data[n];
+        y = data[0] -= MX;
+        sum -= DELTA;
+    }
+
+    return data;
+}
+
+static uint8_t * xxtea_ubyte_encrypt(const uint8_t * data, size_t len, const uint8_t * key, size_t * out_len) {
+    uint8_t *out;
+    uint32_t *data_array, *key_array;
+    size_t data_len, key_len;
+
+    if (!len) return NULL;
+
+    data_array = xxtea_to_uint_array(data, len, 1, &data_len);
+    if (!data_array) return NULL;
+
+    key_array  = xxtea_to_uint_array(key, 16, 0, &key_len);
+    if (!key_array) {
+        free(data_array);
+        return NULL;
+    }
+
+    out = xxtea_to_ubyte_array(xxtea_uint_encrypt(data_array, data_len, key_array), data_len, 0, out_len);
+
+    free(data_array);
+    free(key_array);
+
+    return out;
+}
+
+static uint8_t * xxtea_ubyte_decrypt(const uint8_t * data, size_t len, const uint8_t * key, size_t * out_len) {
+    uint8_t *out;
+    uint32_t *data_array, *key_array;
+    size_t data_len, key_len;
+
+    if (!len) return NULL;
+
+    data_array = xxtea_to_uint_array(data, len, 0, &data_len);
+    if (!data_array) return NULL;
+
+    key_array  = xxtea_to_uint_array(key, 16, 0, &key_len);
+    if (!key_array) {
+        free(data_array);
+        return NULL;
+    }
+
+    out = xxtea_to_ubyte_array(xxtea_uint_decrypt(data_array, data_len, key_array), data_len, 1, out_len);
+
+    free(data_array);
+    free(key_array);
+
+    return out;
+}
+
+// public functions
+
+void * xxtea_encrypt(const void * data, size_t len, const void * key, size_t * out_len) {
+    FIXED_KEY
+    return xxtea_ubyte_encrypt((const uint8_t *)data, len, fixed_key, out_len);
+}
+
+void * xxtea_decrypt(const void * data, size_t len, const void * key, size_t * out_len) {
+    FIXED_KEY
+    return xxtea_ubyte_decrypt((const uint8_t *)data, len, fixed_key, out_len);
+}
diff --git a/O&Z_IL2CPP_Security/resource/src-res/xxtea.h b/O&Z_IL2CPP_Security/resource/src-res/xxtea.h
new file mode 100644
index 0000000..a54a700
--- /dev/null
+++ b/O&Z_IL2CPP_Security/resource/src-res/xxtea.h
@@ -0,0 +1,54 @@
+/**********************************************************\
+|                                                          |
+| xxtea.h                                                  |
+|                                                          |
+| XXTEA encryption algorithm library for C.                |
+|                                                          |
+| Encryption Algorithm Authors:                            |
+|      David J. Wheeler                                    |
+|      Roger M. Needham                                    |
+|                                                          |
+| Code Authors: Chen fei <cf850118@163.com>                |
+|               Ma Bingyao <mabingyao@gmail.com>           |
+| LastModified: Mar 3, 2015                                |
+|                                                          |
+\**********************************************************/
+
+#ifndef XXTEA_INCLUDED
+#define XXTEA_INCLUDED
+
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Function: xxtea_encrypt
+ * @data:    Data to be encrypted
+ * @len:     Length of the data to be encrypted
+ * @key:     Symmetric key
+ * @out_len: Pointer to output length variable
+ * Returns:  Encrypted data or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer.
+ */
+void * xxtea_encrypt(const void * data, size_t len, const void * key, size_t * out_len);
+
+/**
+ * Function: xxtea_decrypt
+ * @data:    Data to be decrypted
+ * @len:     Length of the data to be decrypted
+ * @key:     Symmetric key
+ * @out_len: Pointer to output length variable
+ * Returns:  Decrypted data or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer.
+ */
+void * xxtea_decrypt(const void * data, size_t len, const void * key, size_t * out_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/O&Z_Obfuscator/LitJson/AssemblyInfo.cs.in b/O&Z_Obfuscator/LitJson/AssemblyInfo.cs.in
new file mode 100644
index 0000000..2cd1f90
--- /dev/null
+++ b/O&Z_Obfuscator/LitJson/AssemblyInfo.cs.in
@@ -0,0 +1,18 @@
+using System;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+
+[assembly: CLSCompliant (true)]
+
+[assembly: AssemblyTitle ("LitJson")]
+[assembly: AssemblyDescription ("LitJSON library")]
+[assembly: AssemblyConfiguration ("")]
+[assembly: AssemblyCompany ("")]
+[assembly: AssemblyProduct ("LitJSON")]
+[assembly: AssemblyCopyright (
+    "The authors disclaim copyright to this source code")]
+[assembly: AssemblyTrademark ("")]
+[assembly: AssemblyCulture ("")]
+
+[assembly: AssemblyVersion ("@ASSEMBLY_VERSION@")]
diff --git a/O&Z_Obfuscator/LitJson/IJsonWrapper.cs b/O&Z_Obfuscator/LitJson/IJsonWrapper.cs
new file mode 100644
index 0000000..afa7a1f
--- /dev/null
+++ b/O&Z_Obfuscator/LitJson/IJsonWrapper.cs
@@ -0,0 +1,60 @@
+#region Header
+/**
+ * IJsonWrapper.cs
+ *   Interface that represents a type capable of handling all kinds of JSON
+ *   data. This is mainly used when mapping objects through JsonMapper, and
+ *   it's implemented by JsonData.
+ *
+ * The authors disclaim copyright to this source code. For more details, see
+ * the COPYING file included with this distribution.
+ **/
+#endregion
+
+
+using System.Collections;
+using System.Collections.Specialized;
+
+
+namespace O_Z_IL2CPP_Security.LitJson
+{
+    public enum JsonType
+    {
+        None,
+
+        Object,
+        Array,
+        String,
+        Int,
+        Long,
+        Double,
+        Boolean
+    }
+
+    public interface IJsonWrapper : IList, IOrderedDictionary
+    {
+        bool IsArray { get; }
+        bool IsBoolean { get; }
+        bool IsDouble { get; }
+        bool IsInt { get; }
+        bool IsLong { get; }
+        bool IsObject { get; }
+        bool IsString { get; }
+
+        bool GetBoolean();
+        double GetDouble();
+        int GetInt();
+        JsonType GetJsonType();
+        long GetLong();
+        string GetString();
+
+        void SetBoolean(bool val);
+        void SetDouble(double val);
+        void SetInt(int val);
+        void SetJsonType(JsonType type);
+        void SetLong(long val);
+        void SetString(string val);
+
+        string ToJson();
+        void ToJson(JsonWriter writer);
+    }
+}
diff --git a/O&Z_Obfuscator/LitJson/JsonData.cs b/O&Z_Obfuscator/LitJson/JsonData.cs
new file mode 100644
index 0000000..926ce0c
--- /dev/null
+++ b/O&Z_Obfuscator/LitJson/JsonData.cs
@@ -0,0 +1,1142 @@
+#region Header
+/**
+ * JsonData.cs
+ *   Generic type to hold JSON data (objects, arrays, and so on). This is
+ *   the default type returned by JsonMapper.ToObject().
+ *
+ * The authors disclaim copyright to this source code. For more details, see
+ * the COPYING file included with this distribution.
+ **/
+#endregion
+
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.IO;
+
+
+namespace O_Z_IL2CPP_Security.LitJson
+{
+    public class JsonData : IJsonWrapper, IEquatable<JsonData>
+    {
+        #region Fields
+        private IList<JsonData> inst_array;
+        private bool inst_boolean;
+        private double inst_double;
+        private int inst_int;
+        private long inst_long;
+        private IDictionary<string, JsonData> inst_object;
+        private string inst_string;
+        private string json;
+        private JsonType type;
+
+        // Used to implement the IOrderedDictionary interface
+        private IList<KeyValuePair<string, JsonData>> object_list;
+        #endregion
+
+
+        #region Properties
+        public int Count
+        {
+            get { return EnsureCollection().Count; }
+        }
+
+        public bool IsArray
+        {
+            get { return type == JsonType.Array; }
+        }
+
+        public bool IsBoolean
+        {
+            get { return type == JsonType.Boolean; }
+        }
+
+        public bool IsDouble
+        {
+            get { return type == JsonType.Double; }
+        }
+
+        public bool IsInt
+        {
+            get { return type == JsonType.Int; }
+        }
+
+        public bool IsLong
+        {
+            get { return type == JsonType.Long; }
+        }
+
+        public bool IsObject
+        {
+            get { return type == JsonType.Object; }
+        }
+
+        public bool IsString
+        {
+            get { return type == JsonType.String; }
+        }
+
+        public ICollection<string> Keys
+        {
+            get { EnsureDictionary(); return inst_object.Keys; }
+        }
+
+        /// <summary>
+        /// Determines whether the json contains an element that has the specified key.
+        /// </summary>
+        /// <param name="key">The key to locate in the json.</param>
+        /// <returns>true if the json contains an element that has the specified key; otherwise, false.</returns>
+        public bool ContainsKey(string key)
+        {
+            EnsureDictionary();
+            return inst_object.Keys.Contains(key);
+        }
+        #endregion
+
+
+        #region ICollection Properties
+        int ICollection.Count
+        {
+            get
+            {
+                return Count;
+            }
+        }
+
+        bool ICollection.IsSynchronized
+        {
+            get
+            {
+                return EnsureCollection().IsSynchronized;
+            }
+        }
+
+        object ICollection.SyncRoot
+        {
+            get
+            {
+                return EnsureCollection().SyncRoot;
+            }
+        }
+        #endregion
+
+
+        #region IDictionary Properties
+        bool IDictionary.IsFixedSize
+        {
+            get
+            {
+                return EnsureDictionary().IsFixedSize;
+            }
+        }
+
+        bool IDictionary.IsReadOnly
+        {
+            get
+            {
+                return EnsureDictionary().IsReadOnly;
+            }
+        }
+
+        ICollection IDictionary.Keys
+        {
+            get
+            {
+                EnsureDictionary();
+                IList<string> keys = new List<string>();
+
+                foreach (KeyValuePair<string, JsonData> entry in
+                         object_list)
+                {
+                    keys.Add(entry.Key);
+                }
+
+                return (ICollection)keys;
+            }
+        }
+
+        ICollection IDictionary.Values
+        {
+            get
+            {
+                EnsureDictionary();
+                IList<JsonData> values = new List<JsonData>();
+
+                foreach (KeyValuePair<string, JsonData> entry in
+                         object_list)
+                {
+                    values.Add(entry.Value);
+                }
+
+                return (ICollection)values;
+            }
+        }
+        #endregion
+
+
+
+        #region IJsonWrapper Properties
+        bool IJsonWrapper.IsArray
+        {
+            get { return IsArray; }
+        }
+
+        bool IJsonWrapper.IsBoolean
+        {
+            get { return IsBoolean; }
+        }
+
+        bool IJsonWrapper.IsDouble
+        {
+            get { return IsDouble; }
+        }
+
+        bool IJsonWrapper.IsInt
+        {
+            get { return IsInt; }
+        }
+
+        bool IJsonWrapper.IsLong
+        {
+            get { return IsLong; }
+        }
+
+        bool IJsonWrapper.IsObject
+        {
+            get { return IsObject; }
+        }
+
+        bool IJsonWrapper.IsString
+        {
+            get { return IsString; }
+        }
+        #endregion
+
+
+        #region IList Properties
+        bool IList.IsFixedSize
+        {
+            get
+            {
+                return EnsureList().IsFixedSize;
+            }
+        }
+
+        bool IList.IsReadOnly
+        {
+            get
+            {
+                return EnsureList().IsReadOnly;
+            }
+        }
+        #endregion
+
+
+        #region IDictionary Indexer
+        object IDictionary.this[object key]
+        {
+            get
+            {
+                return EnsureDictionary()[key];
+            }
+
+            set
+            {
+                if (!(key is string))
+                    throw new ArgumentException(
+                        "The key has to be a string");
+
+                JsonData data = ToJsonData(value);
+
+                this[(string)key] = data;
+            }
+        }
+        #endregion
+
+
+        #region IOrderedDictionary Indexer
+        object IOrderedDictionary.this[int idx]
+        {
+            get
+            {
+                EnsureDictionary();
+                return object_list[idx].Value;
+            }
+
+            set
+            {
+                EnsureDictionary();
+                JsonData data = ToJsonData(value);
+
+                KeyValuePair<string, JsonData> old_entry = object_list[idx];
+
+                inst_object[old_entry.Key] = data;
+
+                KeyValuePair<string, JsonData> entry =
+                    new KeyValuePair<string, JsonData>(old_entry.Key, data);
+
+                object_list[idx] = entry;
+            }
+        }
+        #endregion
+
+
+        #region IList Indexer
+        object IList.this[int index]
+        {
+            get
+            {
+                return EnsureList()[index];
+            }
+
+            set
+            {
+                EnsureList();
+                JsonData data = ToJsonData(value);
+
+                this[index] = data;
+            }
+        }
+        #endregion
+
+
+        #region Public Indexers
+        public JsonData this[string prop_name]
+        {
+            get
+            {
+                EnsureDictionary();
+                return inst_object[prop_name];
+            }
+
+            set
+            {
+                EnsureDictionary();
+
+                KeyValuePair<string, JsonData> entry =
+                    new KeyValuePair<string, JsonData>(prop_name, value);
+
+                if (inst_object.ContainsKey(prop_name))
+                {
+                    for (int i = 0; i < object_list.Count; i++)
+                    {
+                        if (object_list[i].Key == prop_name)
+                        {
+                            object_list[i] = entry;
+                            break;
+                        }
+                    }
+                }
+                else
+                    object_list.Add(entry);
+
+                inst_object[prop_name] = value;
+
+                json = null;
+            }
+        }
+
+        public JsonData this[int index]
+        {
+            get
+            {
+                EnsureCollection();
+
+                if (type == JsonType.Array)
+                    return inst_array[index];
+
+                return object_list[index].Value;
+            }
+
+            set
+            {
+                EnsureCollection();
+
+                if (type == JsonType.Array)
+                    inst_array[index] = value;
+                else
+                {
+                    KeyValuePair<string, JsonData> entry = object_list[index];
+                    KeyValuePair<string, JsonData> new_entry =
+                        new KeyValuePair<string, JsonData>(entry.Key, value);
+
+                    object_list[index] = new_entry;
+                    inst_object[entry.Key] = value;
+                }
+
+                json = null;
+            }
+        }
+        #endregion
+
+
+        #region Constructors
+        public JsonData()
+        {
+        }
+
+        public JsonData(bool boolean)
+        {
+            type = JsonType.Boolean;
+            inst_boolean = boolean;
+        }
+
+        public JsonData(double number)
+        {
+            type = JsonType.Double;
+            inst_double = number;
+        }
+
+        public JsonData(int number)
+        {
+            type = JsonType.Int;
+            inst_int = number;
+        }
+
+        public JsonData(long number)
+        {
+            type = JsonType.Long;
+            inst_long = number;
+        }
+
+        public JsonData(object obj)
+        {
+            if (obj is bool)
+            {
+                type = JsonType.Boolean;
+                inst_boolean = (bool)obj;
+                return;
+            }
+
+            if (obj is double)
+            {
+                type = JsonType.Double;
+                inst_double = (double)obj;
+                return;
+            }
+
+            if (obj is int)
+            {
+                type = JsonType.Int;
+                inst_int = (int)obj;
+                return;
+            }
+
+            if (obj is long)
+            {
+                type = JsonType.Long;
+                inst_long = (long)obj;
+                return;
+            }
+
+            if (obj is string)
+            {
+                type = JsonType.String;
+                inst_string = (string)obj;
+                return;
+            }
+
+            throw new ArgumentException(
+                "Unable to wrap the given object with JsonData");
+        }
+
+        public JsonData(string str)
+        {
+            type = JsonType.String;
+            inst_string = str;
+        }
+        #endregion
+
+
+        #region Implicit Conversions
+        public static implicit operator JsonData(bool data)
+        {
+            return new JsonData(data);
+        }
+
+        public static implicit operator JsonData(double data)
+        {
+            return new JsonData(data);
+        }
+
+        public static implicit operator JsonData(int data)
+        {
+            return new JsonData(data);
+        }
+
+        public static implicit operator JsonData(long data)
+        {
+            return new JsonData(data);
+        }
+
+        public static implicit operator JsonData(string data)
+        {
+            return new JsonData(data);
+        }
+        #endregion
+
+
+        #region Explicit Conversions
+        public static explicit operator bool(JsonData data)
+        {
+            if (data.type != JsonType.Boolean)
+                throw new InvalidCastException(
+                    "Instance of JsonData doesn't hold a double");
+
+            return data.inst_boolean;
+        }
+
+        public static explicit operator double(JsonData data)
+        {
+            if (data.type != JsonType.Double)
+                throw new InvalidCastException(
+                    "Instance of JsonData doesn't hold a double");
+
+            return data.inst_double;
+        }
+
+        public static explicit operator int(JsonData data)
+        {
+            if (data.type != JsonType.Int && data.type != JsonType.Long)
+            {
+                throw new InvalidCastException(
+                    "Instance of JsonData doesn't hold an int");
+            }
+
+            // cast may truncate data... but that's up to the user to consider
+            return data.type == JsonType.Int ? data.inst_int : (int)data.inst_long;
+        }
+
+        public static explicit operator long(JsonData data)
+        {
+            if (data.type != JsonType.Long && data.type != JsonType.Int)
+            {
+                throw new InvalidCastException(
+                    "Instance of JsonData doesn't hold a long");
+            }
+
+            return data.type == JsonType.Long ? data.inst_long : data.inst_int;
+        }
+
+        public static explicit operator string(JsonData data)
+        {
+            if (data.type != JsonType.String)
+                throw new InvalidCastException(
+                    "Instance of JsonData doesn't hold a string");
+
+            return data.inst_string;
+        }
+        #endregion
+
+
+        #region ICollection Methods
+        void ICollection.CopyTo(Array array, int index)
+        {
+            EnsureCollection().CopyTo(array, index);
+        }
+        #endregion
+
+
+        #region IDictionary Methods
+        void IDictionary.Add(object key, object value)
+        {
+            JsonData data = ToJsonData(value);
+
+            EnsureDictionary().Add(key, data);
+
+            KeyValuePair<string, JsonData> entry =
+                new KeyValuePair<string, JsonData>((string)key, data);
+            object_list.Add(entry);
+
+            json = null;
+        }
+
+        void IDictionary.Clear()
+        {
+            EnsureDictionary().Clear();
+            object_list.Clear();
+            json = null;
+        }
+
+        bool IDictionary.Contains(object key)
+        {
+            return EnsureDictionary().Contains(key);
+        }
+
+        IDictionaryEnumerator IDictionary.GetEnumerator()
+        {
+            return ((IOrderedDictionary)this).GetEnumerator();
+        }
+
+        void IDictionary.Remove(object key)
+        {
+            EnsureDictionary().Remove(key);
+
+            for (int i = 0; i < object_list.Count; i++)
+            {
+                if (object_list[i].Key == (string)key)
+                {
+                    object_list.RemoveAt(i);
+                    break;
+                }
+            }
+
+            json = null;
+        }
+        #endregion
+
+
+        #region IEnumerable Methods
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return EnsureCollection().GetEnumerator();
+        }
+        #endregion
+
+
+        #region IJsonWrapper Methods
+        bool IJsonWrapper.GetBoolean()
+        {
+            if (type != JsonType.Boolean)
+                throw new InvalidOperationException(
+                    "JsonData instance doesn't hold a boolean");
+
+            return inst_boolean;
+        }
+
+        double IJsonWrapper.GetDouble()
+        {
+            if (type != JsonType.Double)
+                throw new InvalidOperationException(
+                    "JsonData instance doesn't hold a double");
+
+            return inst_double;
+        }
+
+        int IJsonWrapper.GetInt()
+        {
+            if (type != JsonType.Int)
+                throw new InvalidOperationException(
+                    "JsonData instance doesn't hold an int");
+
+            return inst_int;
+        }
+
+        long IJsonWrapper.GetLong()
+        {
+            if (type != JsonType.Long)
+                throw new InvalidOperationException(
+                    "JsonData instance doesn't hold a long");
+
+            return inst_long;
+        }
+
+        string IJsonWrapper.GetString()
+        {
+            if (type != JsonType.String)
+                throw new InvalidOperationException(
+                    "JsonData instance doesn't hold a string");
+
+            return inst_string;
+        }
+
+        void IJsonWrapper.SetBoolean(bool val)
+        {
+            type = JsonType.Boolean;
+            inst_boolean = val;
+            json = null;
+        }
+
+        void IJsonWrapper.SetDouble(double val)
+        {
+            type = JsonType.Double;
+            inst_double = val;
+            json = null;
+        }
+
+        void IJsonWrapper.SetInt(int val)
+        {
+            type = JsonType.Int;
+            inst_int = val;
+            json = null;
+        }
+
+        void IJsonWrapper.SetLong(long val)
+        {
+            type = JsonType.Long;
+            inst_long = val;
+            json = null;
+        }
+
+        void IJsonWrapper.SetString(string val)
+        {
+            type = JsonType.String;
+            inst_string = val;
+            json = null;
+        }
+
+        string IJsonWrapper.ToJson()
+        {
+            return ToJson();
+        }
+
+        void IJsonWrapper.ToJson(JsonWriter writer)
+        {
+            ToJson(writer);
+        }
+        #endregion
+
+
+        #region IList Methods
+        int IList.Add(object value)
+        {
+            return Add(value);
+        }
+
+        void IList.Clear()
+        {
+            EnsureList().Clear();
+            json = null;
+        }
+
+        bool IList.Contains(object value)
+        {
+            return EnsureList().Contains(value);
+        }
+
+        int IList.IndexOf(object value)
+        {
+            return EnsureList().IndexOf(value);
+        }
+
+        void IList.Insert(int index, object value)
+        {
+            EnsureList().Insert(index, value);
+            json = null;
+        }
+
+        void IList.Remove(object value)
+        {
+            EnsureList().Remove(value);
+            json = null;
+        }
+
+        void IList.RemoveAt(int index)
+        {
+            EnsureList().RemoveAt(index);
+            json = null;
+        }
+        #endregion
+
+
+        #region IOrderedDictionary Methods
+        IDictionaryEnumerator IOrderedDictionary.GetEnumerator()
+        {
+            EnsureDictionary();
+
+            return new OrderedDictionaryEnumerator(
+                object_list.GetEnumerator());
+        }
+
+        void IOrderedDictionary.Insert(int idx, object key, object value)
+        {
+            string property = (string)key;
+            JsonData data = ToJsonData(value);
+
+            this[property] = data;
+
+            KeyValuePair<string, JsonData> entry =
+                new KeyValuePair<string, JsonData>(property, data);
+
+            object_list.Insert(idx, entry);
+        }
+
+        void IOrderedDictionary.RemoveAt(int idx)
+        {
+            EnsureDictionary();
+
+            inst_object.Remove(object_list[idx].Key);
+            object_list.RemoveAt(idx);
+        }
+        #endregion
+
+
+        #region Private Methods
+        private ICollection EnsureCollection()
+        {
+            if (type == JsonType.Array)
+                return (ICollection)inst_array;
+
+            if (type == JsonType.Object)
+                return (ICollection)inst_object;
+
+            throw new InvalidOperationException(
+                "The JsonData instance has to be initialized first");
+        }
+
+        private IDictionary EnsureDictionary()
+        {
+            if (type == JsonType.Object)
+                return (IDictionary)inst_object;
+
+            if (type != JsonType.None)
+                throw new InvalidOperationException(
+                    "Instance of JsonData is not a dictionary");
+
+            type = JsonType.Object;
+            inst_object = new Dictionary<string, JsonData>();
+            object_list = new List<KeyValuePair<string, JsonData>>();
+
+            return (IDictionary)inst_object;
+        }
+
+        private IList EnsureList()
+        {
+            if (type == JsonType.Array)
+                return (IList)inst_array;
+
+            if (type != JsonType.None)
+                throw new InvalidOperationException(
+                    "Instance of JsonData is not a list");
+
+            type = JsonType.Array;
+            inst_array = new List<JsonData>();
+
+            return (IList)inst_array;
+        }
+
+        private JsonData ToJsonData(object obj)
+        {
+            if (obj == null)
+                return null;
+
+            if (obj is JsonData)
+                return (JsonData)obj;
+
+            return new JsonData(obj);
+        }
+
+        private static void WriteJson(IJsonWrapper obj, JsonWriter writer)
+        {
+            if (obj == null)
+            {
+                writer.Write(null);
+                return;
+            }
+
+            if (obj.IsString)
+            {
+                writer.Write(obj.GetString());
+                return;
+            }
+
+            if (obj.IsBoolean)
+            {
+                writer.Write(obj.GetBoolean());
+                return;
+            }
+
+            if (obj.IsDouble)
+            {
+                writer.Write(obj.GetDouble());
+                return;
+            }
+
+            if (obj.IsInt)
+            {
+                writer.Write(obj.GetInt());
+                return;
+            }
+
+            if (obj.IsLong)
+            {
+                writer.Write(obj.GetLong());
+                return;
+            }
+
+            if (obj.IsArray)
+            {
+                writer.WriteArrayStart();
+                foreach (object elem in (IList)obj)
+                    WriteJson((JsonData)elem, writer);
+                writer.WriteArrayEnd();
+
+                return;
+            }
+
+            if (obj.IsObject)
+            {
+                writer.WriteObjectStart();
+
+                foreach (DictionaryEntry entry in (IDictionary)obj)
+                {
+                    writer.WritePropertyName((string)entry.Key);
+                    WriteJson((JsonData)entry.Value, writer);
+                }
+                writer.WriteObjectEnd();
+
+                return;
+            }
+        }
+        #endregion
+
+
+        public int Add(object value)
+        {
+            JsonData data = ToJsonData(value);
+
+            json = null;
+
+            return EnsureList().Add(data);
+        }
+
+        public bool Remove(object obj)
+        {
+            json = null;
+            if (IsObject)
+            {
+                JsonData value = null;
+                if (inst_object.TryGetValue((string)obj, out value))
+                    return inst_object.Remove((string)obj) && object_list.Remove(new KeyValuePair<string, JsonData>((string)obj, value));
+                else
+                    throw new KeyNotFoundException("The specified key was not found in the JsonData object.");
+            }
+            if (IsArray)
+            {
+                return inst_array.Remove(ToJsonData(obj));
+            }
+            throw new InvalidOperationException(
+                    "Instance of JsonData is not an object or a list.");
+        }
+
+        public void Clear()
+        {
+            if (IsObject)
+            {
+                ((IDictionary)this).Clear();
+                return;
+            }
+
+            if (IsArray)
+            {
+                ((IList)this).Clear();
+                return;
+            }
+        }
+
+        public bool Equals(JsonData x)
+        {
+            if (x == null)
+                return false;
+
+            if (x.type != type)
+            {
+                // further check to see if this is a long to int comparison
+                if (x.type != JsonType.Int && x.type != JsonType.Long
+                    || type != JsonType.Int && type != JsonType.Long)
+                {
+                    return false;
+                }
+            }
+
+            switch (type)
+            {
+                case JsonType.None:
+                    return true;
+
+                case JsonType.Object:
+                    return inst_object.Equals(x.inst_object);
+
+                case JsonType.Array:
+                    return inst_array.Equals(x.inst_array);
+
+                case JsonType.String:
+                    return inst_string.Equals(x.inst_string);
+
+                case JsonType.Int:
+                    {
+                        if (x.IsLong)
+                        {
+                            if (x.inst_long < int.MinValue || x.inst_long > int.MaxValue)
+                                return false;
+                            return inst_int.Equals((int)x.inst_long);
+                        }
+                        return inst_int.Equals(x.inst_int);
+                    }
+
+                case JsonType.Long:
+                    {
+                        if (x.IsInt)
+                        {
+                            if (inst_long < int.MinValue || inst_long > int.MaxValue)
+                                return false;
+                            return x.inst_int.Equals((int)inst_long);
+                        }
+                        return inst_long.Equals(x.inst_long);
+                    }
+
+                case JsonType.Double:
+                    return inst_double.Equals(x.inst_double);
+
+                case JsonType.Boolean:
+                    return inst_boolean.Equals(x.inst_boolean);
+            }
+
+            return false;
+        }
+
+        public JsonType GetJsonType()
+        {
+            return type;
+        }
+
+        public void SetJsonType(JsonType type)
+        {
+            if (this.type == type)
+                return;
+
+            switch (type)
+            {
+                case JsonType.None:
+                    break;
+
+                case JsonType.Object:
+                    inst_object = new Dictionary<string, JsonData>();
+                    object_list = new List<KeyValuePair<string, JsonData>>();
+                    break;
+
+                case JsonType.Array:
+                    inst_array = new List<JsonData>();
+                    break;
+
+                case JsonType.String:
+                    inst_string = default;
+                    break;
+
+                case JsonType.Int:
+                    inst_int = default;
+                    break;
+
+                case JsonType.Long:
+                    inst_long = default;
+                    break;
+
+                case JsonType.Double:
+                    inst_double = default;
+                    break;
+
+                case JsonType.Boolean:
+                    inst_boolean = default;
+                    break;
+            }
+
+            this.type = type;
+        }
+
+        public string ToJson()
+        {
+            if (json != null)
+                return json;
+
+            StringWriter sw = new StringWriter();
+            JsonWriter writer = new JsonWriter(sw);
+            writer.Validate = false;
+
+            WriteJson(this, writer);
+            json = sw.ToString();
+
+            return json;
+        }
+
+        public void ToJson(JsonWriter writer)
+        {
+            bool old_validate = writer.Validate;
+
+            writer.Validate = false;
+
+            WriteJson(this, writer);
+
+            writer.Validate = old_validate;
+        }
+
+        public override string ToString()
+        {
+            switch (type)
+            {
+                case JsonType.Array:
+                    return "JsonData array";
+
+                case JsonType.Boolean:
+                    return inst_boolean.ToString();
+
+                case JsonType.Double:
+                    return inst_double.ToString();
+
+                case JsonType.Int:
+                    return inst_int.ToString();
+
+                case JsonType.Long:
+                    return inst_long.ToString();
+
+                case JsonType.Object:
+                    return "JsonData object";
+
+                case JsonType.String:
+                    return inst_string;
+            }
+
+            return "Uninitialized JsonData";
+        }
+    }
+
+
+    internal class OrderedDictionaryEnumerator : IDictionaryEnumerator
+    {
+        IEnumerator<KeyValuePair<string, JsonData>> list_enumerator;
+
+
+        public object Current
+        {
+            get { return Entry; }
+        }
+
+        public DictionaryEntry Entry
+        {
+            get
+            {
+                KeyValuePair<string, JsonData> curr = list_enumerator.Current;
+                return new DictionaryEntry(curr.Key, curr.Value);
+            }
+        }
+
+        public object Key
+        {
+            get { return list_enumerator.Current.Key; }
+        }
+
+        public object Value
+        {
+            get { return list_enumerator.Current.Value; }
+        }
+
+
+        public OrderedDictionaryEnumerator(
+            IEnumerator<KeyValuePair<string, JsonData>> enumerator)
+        {
+            list_enumerator = enumerator;
+        }
+
+
+        public bool MoveNext()
+        {
+            return list_enumerator.MoveNext();
+        }
+
+        public void Reset()
+        {
+            list_enumerator.Reset();
+        }
+    }
+}
diff --git a/O&Z_Obfuscator/LitJson/JsonException.cs b/O&Z_Obfuscator/LitJson/JsonException.cs
new file mode 100644
index 0000000..c8d728a
--- /dev/null
+++ b/O&Z_Obfuscator/LitJson/JsonException.cs
@@ -0,0 +1,65 @@
+#region Header
+/**
+ * JsonException.cs
+ *   Base class throwed by LitJSON when a parsing error occurs.
+ *
+ * The authors disclaim copyright to this source code. For more details, see
+ * the COPYING file included with this distribution.
+ **/
+#endregion
+
+
+using System;
+
+
+namespace O_Z_IL2CPP_Security.LitJson
+{
+    public class JsonException :
+#if NETSTANDARD1_5
+        Exception
+#else
+        ApplicationException
+#endif
+    {
+        public JsonException() : base()
+        {
+        }
+
+        internal JsonException(ParserToken token) :
+            base(string.Format(
+                    "Invalid token '{0}' in input string", token))
+        {
+        }
+
+        internal JsonException(ParserToken token,
+                                Exception inner_exception) :
+            base(string.Format(
+                    "Invalid token '{0}' in input string", token),
+                inner_exception)
+        {
+        }
+
+        internal JsonException(int c) :
+            base(string.Format(
+                    "Invalid character '{0}' in input string", (char)c))
+        {
+        }
+
+        internal JsonException(int c, Exception inner_exception) :
+            base(string.Format(
+                    "Invalid character '{0}' in input string", (char)c),
+                inner_exception)
+        {
+        }
+
+
+        public JsonException(string message) : base(message)
+        {
+        }
+
+        public JsonException(string message, Exception inner_exception) :
+            base(message, inner_exception)
+        {
+        }
+    }
+}
diff --git a/O&Z_Obfuscator/LitJson/JsonMapper.cs b/O&Z_Obfuscator/LitJson/JsonMapper.cs
new file mode 100644
index 0000000..f9622e6
--- /dev/null
+++ b/O&Z_Obfuscator/LitJson/JsonMapper.cs
@@ -0,0 +1,1098 @@
+#region Header
+/**
+ * JsonMapper.cs
+ *   JSON to .Net object and object to JSON conversions.
+ *
+ * The authors disclaim copyright to this source code. For more details, see
+ * the COPYING file included with this distribution.
+ **/
+#endregion
+
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Reflection;
+
+
+namespace O_Z_IL2CPP_Security.LitJson
+{
+    internal struct PropertyMetadata
+    {
+        public MemberInfo Info;
+        public bool IsField;
+        public Type Type;
+    }
+
+
+    internal struct ArrayMetadata
+    {
+        private Type element_type;
+        private bool is_array;
+        private bool is_list;
+
+
+        public Type ElementType
+        {
+            get
+            {
+                if (element_type == null)
+                    return typeof(JsonData);
+
+                return element_type;
+            }
+
+            set { element_type = value; }
+        }
+
+        public bool IsArray
+        {
+            get { return is_array; }
+            set { is_array = value; }
+        }
+
+        public bool IsList
+        {
+            get { return is_list; }
+            set { is_list = value; }
+        }
+    }
+
+
+    internal struct ObjectMetadata
+    {
+        private Type element_type;
+        private bool is_dictionary;
+
+        private IDictionary<string, PropertyMetadata> properties;
+
+
+        public Type ElementType
+        {
+            get
+            {
+                if (element_type == null)
+                    return typeof(JsonData);
+
+                return element_type;
+            }
+
+            set { element_type = value; }
+        }
+
+        public bool IsDictionary
+        {
+            get { return is_dictionary; }
+            set { is_dictionary = value; }
+        }
+
+        public IDictionary<string, PropertyMetadata> Properties
+        {
+            get { return properties; }
+            set { properties = value; }
+        }
+    }
+
+
+    internal delegate void ExporterFunc(object obj, JsonWriter writer);
+    public delegate void ExporterFunc<T>(T obj, JsonWriter writer);
+
+    internal delegate object ImporterFunc(object input);
+    public delegate TValue ImporterFunc<TJson, TValue>(TJson input);
+
+    public delegate IJsonWrapper WrapperFactory();
+
+
+    public class JsonMapper
+    {
+        #region Fields
+        private static readonly int max_nesting_depth;
+
+        private static readonly IFormatProvider datetime_format;
+
+        private static readonly IDictionary<Type, ExporterFunc> base_exporters_table;
+        private static readonly IDictionary<Type, ExporterFunc> custom_exporters_table;
+
+        private static readonly IDictionary<Type,
+                IDictionary<Type, ImporterFunc>> base_importers_table;
+        private static readonly IDictionary<Type,
+                IDictionary<Type, ImporterFunc>> custom_importers_table;
+
+        private static readonly IDictionary<Type, ArrayMetadata> array_metadata;
+        private static readonly object array_metadata_lock = new object();
+
+        private static readonly IDictionary<Type,
+                IDictionary<Type, MethodInfo>> conv_ops;
+        private static readonly object conv_ops_lock = new object();
+
+        private static readonly IDictionary<Type, ObjectMetadata> object_metadata;
+        private static readonly object object_metadata_lock = new object();
+
+        private static readonly IDictionary<Type,
+                IList<PropertyMetadata>> type_properties;
+        private static readonly object type_properties_lock = new object();
+
+        private static readonly JsonWriter static_writer;
+        private static readonly object static_writer_lock = new object();
+        #endregion
+
+
+        #region Constructors
+        static JsonMapper()
+        {
+            max_nesting_depth = 100;
+
+            array_metadata = new Dictionary<Type, ArrayMetadata>();
+            conv_ops = new Dictionary<Type, IDictionary<Type, MethodInfo>>();
+            object_metadata = new Dictionary<Type, ObjectMetadata>();
+            type_properties = new Dictionary<Type,
+                            IList<PropertyMetadata>>();
+
+            static_writer = new JsonWriter();
+
+            datetime_format = DateTimeFormatInfo.InvariantInfo;
+
+            base_exporters_table = new Dictionary<Type, ExporterFunc>();
+            custom_exporters_table = new Dictionary<Type, ExporterFunc>();
+
+            base_importers_table = new Dictionary<Type,
+                                 IDictionary<Type, ImporterFunc>>();
+            custom_importers_table = new Dictionary<Type,
+                                   IDictionary<Type, ImporterFunc>>();
+
+            RegisterBaseExporters();
+            RegisterBaseImporters();
+        }
+        #endregion
+
+
+        #region Private Methods
+        private static void AddArrayMetadata(Type type)
+        {
+            if (array_metadata.ContainsKey(type))
+                return;
+
+            ArrayMetadata data = new ArrayMetadata();
+
+            data.IsArray = type.IsArray;
+
+            if (type.GetInterface("System.Collections.IList") != null)
+                data.IsList = true;
+
+            foreach (PropertyInfo p_info in type.GetProperties())
+            {
+                if (p_info.Name != "Item")
+                    continue;
+
+                ParameterInfo[] parameters = p_info.GetIndexParameters();
+
+                if (parameters.Length != 1)
+                    continue;
+
+                if (parameters[0].ParameterType == typeof(int))
+                    data.ElementType = p_info.PropertyType;
+            }
+
+            lock (array_metadata_lock)
+            {
+                try
+                {
+                    array_metadata.Add(type, data);
+                }
+                catch (ArgumentException)
+                {
+                    return;
+                }
+            }
+        }
+
+        private static void AddObjectMetadata(Type type)
+        {
+            if (object_metadata.ContainsKey(type))
+                return;
+
+            ObjectMetadata data = new ObjectMetadata();
+
+            if (type.GetInterface("System.Collections.IDictionary") != null)
+                data.IsDictionary = true;
+
+            data.Properties = new Dictionary<string, PropertyMetadata>();
+
+            foreach (PropertyInfo p_info in type.GetProperties())
+            {
+                if (p_info.Name == "Item")
+                {
+                    ParameterInfo[] parameters = p_info.GetIndexParameters();
+
+                    if (parameters.Length != 1)
+                        continue;
+
+                    if (parameters[0].ParameterType == typeof(string))
+                        data.ElementType = p_info.PropertyType;
+
+                    continue;
+                }
+
+                PropertyMetadata p_data = new PropertyMetadata();
+                p_data.Info = p_info;
+                p_data.Type = p_info.PropertyType;
+
+                data.Properties.Add(p_info.Name, p_data);
+            }
+
+            foreach (FieldInfo f_info in type.GetFields())
+            {
+                PropertyMetadata p_data = new PropertyMetadata();
+                p_data.Info = f_info;
+                p_data.IsField = true;
+                p_data.Type = f_info.FieldType;
+
+                data.Properties.Add(f_info.Name, p_data);
+            }
+
+            lock (object_metadata_lock)
+            {
+                try
+                {
+                    object_metadata.Add(type, data);
+                }
+                catch (ArgumentException)
+                {
+                    return;
+                }
+            }
+        }
+
+        private static void AddTypeProperties(Type type)
+        {
+            if (type_properties.ContainsKey(type))
+                return;
+
+            IList<PropertyMetadata> props = new List<PropertyMetadata>();
+
+            foreach (PropertyInfo p_info in type.GetProperties())
+            {
+                if (p_info.Name == "Item")
+                    continue;
+
+                PropertyMetadata p_data = new PropertyMetadata();
+                p_data.Info = p_info;
+                p_data.IsField = false;
+                props.Add(p_data);
+            }
+
+            foreach (FieldInfo f_info in type.GetFields())
+            {
+                PropertyMetadata p_data = new PropertyMetadata();
+                p_data.Info = f_info;
+                p_data.IsField = true;
+
+                props.Add(p_data);
+            }
+
+            lock (type_properties_lock)
+            {
+                try
+                {
+                    type_properties.Add(type, props);
+                }
+                catch (ArgumentException)
+                {
+                    return;
+                }
+            }
+        }
+
+        private static MethodInfo GetConvOp(Type t1, Type t2)
+        {
+            lock (conv_ops_lock)
+            {
+                if (!conv_ops.ContainsKey(t1))
+                    conv_ops.Add(t1, new Dictionary<Type, MethodInfo>());
+            }
+
+            if (conv_ops[t1].ContainsKey(t2))
+                return conv_ops[t1][t2];
+
+            MethodInfo op = t1.GetMethod(
+                "op_Implicit", new Type[] { t2 });
+
+            lock (conv_ops_lock)
+            {
+                try
+                {
+                    conv_ops[t1].Add(t2, op);
+                }
+                catch (ArgumentException)
+                {
+                    return conv_ops[t1][t2];
+                }
+            }
+
+            return op;
+        }
+
+        private static object ReadValue(Type inst_type, JsonReader reader)
+        {
+            reader.Read();
+
+            if (reader.Token == JsonToken.ArrayEnd)
+                return null;
+
+            Type underlying_type = Nullable.GetUnderlyingType(inst_type);
+            Type value_type = underlying_type ?? inst_type;
+
+            if (reader.Token == JsonToken.Null)
+            {
+#if NETSTANDARD1_5
+                if (inst_type.IsClass() || underlying_type != null) {
+                    return null;
+                }
+#else
+                if (inst_type.IsClass || underlying_type != null)
+                {
+                    return null;
+                }
+#endif
+
+                throw new JsonException(string.Format(
+                            "Can't assign null to an instance of type {0}",
+                            inst_type));
+            }
+
+            if (reader.Token == JsonToken.Double ||
+                reader.Token == JsonToken.Int ||
+                reader.Token == JsonToken.Long ||
+                reader.Token == JsonToken.String ||
+                reader.Token == JsonToken.Boolean)
+            {
+
+                Type json_type = reader.Value.GetType();
+
+                if (value_type.IsAssignableFrom(json_type))
+                    return reader.Value;
+
+                // If there's a custom importer that fits, use it
+                if (custom_importers_table.ContainsKey(json_type) &&
+                    custom_importers_table[json_type].ContainsKey(
+                        value_type))
+                {
+
+                    ImporterFunc importer =
+                        custom_importers_table[json_type][value_type];
+
+                    return importer(reader.Value);
+                }
+
+                // Maybe there's a base importer that works
+                if (base_importers_table.ContainsKey(json_type) &&
+                    base_importers_table[json_type].ContainsKey(
+                        value_type))
+                {
+
+                    ImporterFunc importer =
+                        base_importers_table[json_type][value_type];
+
+                    return importer(reader.Value);
+                }
+
+                // Maybe it's an enum
+#if NETSTANDARD1_5
+                if (value_type.IsEnum())
+                    return Enum.ToObject (value_type, reader.Value);
+#else
+                if (value_type.IsEnum)
+                    return Enum.ToObject(value_type, reader.Value);
+#endif
+                // Try using an implicit conversion operator
+                MethodInfo conv_op = GetConvOp(value_type, json_type);
+
+                if (conv_op != null)
+                    return conv_op.Invoke(null,
+                                           new object[] { reader.Value });
+
+                // No luck
+                throw new JsonException(string.Format(
+                        "Can't assign value '{0}' (type {1}) to type {2}",
+                        reader.Value, json_type, inst_type));
+            }
+
+            object instance = null;
+
+            if (reader.Token == JsonToken.ArrayStart)
+            {
+
+                AddArrayMetadata(inst_type);
+                ArrayMetadata t_data = array_metadata[inst_type];
+
+                if (!t_data.IsArray && !t_data.IsList)
+                    throw new JsonException(string.Format(
+                            "Type {0} can't act as an array",
+                            inst_type));
+
+                IList list;
+                Type elem_type;
+
+                if (!t_data.IsArray)
+                {
+                    list = (IList)Activator.CreateInstance(inst_type);
+                    elem_type = t_data.ElementType;
+                }
+                else
+                {
+                    list = new ArrayList();
+                    elem_type = inst_type.GetElementType();
+                }
+
+                list.Clear();
+
+                while (true)
+                {
+                    object item = ReadValue(elem_type, reader);
+                    if (item == null && reader.Token == JsonToken.ArrayEnd)
+                        break;
+
+                    list.Add(item);
+                }
+
+                if (t_data.IsArray)
+                {
+                    int n = list.Count;
+                    instance = Array.CreateInstance(elem_type, n);
+
+                    for (int i = 0; i < n; i++)
+                        ((Array)instance).SetValue(list[i], i);
+                }
+                else
+                    instance = list;
+
+            }
+            else if (reader.Token == JsonToken.ObjectStart)
+            {
+                AddObjectMetadata(value_type);
+                ObjectMetadata t_data = object_metadata[value_type];
+
+                instance = Activator.CreateInstance(value_type);
+
+                while (true)
+                {
+                    reader.Read();
+
+                    if (reader.Token == JsonToken.ObjectEnd)
+                        break;
+
+                    string property = (string)reader.Value;
+
+                    if (t_data.Properties.ContainsKey(property))
+                    {
+                        PropertyMetadata prop_data =
+                            t_data.Properties[property];
+
+                        if (prop_data.IsField)
+                        {
+                            ((FieldInfo)prop_data.Info).SetValue(
+                                instance, ReadValue(prop_data.Type, reader));
+                        }
+                        else
+                        {
+                            PropertyInfo p_info =
+                                (PropertyInfo)prop_data.Info;
+
+                            if (p_info.CanWrite)
+                                p_info.SetValue(
+                                    instance,
+                                    ReadValue(prop_data.Type, reader),
+                                    null);
+                            else
+                                ReadValue(prop_data.Type, reader);
+                        }
+
+                    }
+                    else
+                    {
+                        if (!t_data.IsDictionary)
+                        {
+
+                            if (!reader.SkipNonMembers)
+                            {
+                                throw new JsonException(string.Format(
+                                        "The type {0} doesn't have the " +
+                                        "property '{1}'",
+                                        inst_type, property));
+                            }
+                            else
+                            {
+                                ReadSkip(reader);
+                                continue;
+                            }
+                        }
+
+                        ((IDictionary)instance).Add(
+                            property, ReadValue(
+                                t_data.ElementType, reader));
+                    }
+
+                }
+
+            }
+
+            return instance;
+        }
+
+        private static IJsonWrapper ReadValue(WrapperFactory factory,
+                                               JsonReader reader)
+        {
+            reader.Read();
+
+            if (reader.Token == JsonToken.ArrayEnd ||
+                reader.Token == JsonToken.Null)
+                return null;
+
+            IJsonWrapper instance = factory();
+
+            if (reader.Token == JsonToken.String)
+            {
+                instance.SetString((string)reader.Value);
+                return instance;
+            }
+
+            if (reader.Token == JsonToken.Double)
+            {
+                instance.SetDouble((double)reader.Value);
+                return instance;
+            }
+
+            if (reader.Token == JsonToken.Int)
+            {
+                instance.SetInt((int)reader.Value);
+                return instance;
+            }
+
+            if (reader.Token == JsonToken.Long)
+            {
+                instance.SetLong((long)reader.Value);
+                return instance;
+            }
+
+            if (reader.Token == JsonToken.Boolean)
+            {
+                instance.SetBoolean((bool)reader.Value);
+                return instance;
+            }
+
+            if (reader.Token == JsonToken.ArrayStart)
+            {
+                instance.SetJsonType(JsonType.Array);
+
+                while (true)
+                {
+                    IJsonWrapper item = ReadValue(factory, reader);
+                    if (item == null && reader.Token == JsonToken.ArrayEnd)
+                        break;
+
+                    instance.Add(item);
+                }
+            }
+            else if (reader.Token == JsonToken.ObjectStart)
+            {
+                instance.SetJsonType(JsonType.Object);
+
+                while (true)
+                {
+                    reader.Read();
+
+                    if (reader.Token == JsonToken.ObjectEnd)
+                        break;
+
+                    string property = (string)reader.Value;
+
+                    ((IDictionary)instance)[property] = ReadValue(
+                        factory, reader);
+                }
+
+            }
+
+            return instance;
+        }
+
+        private static void ReadSkip(JsonReader reader)
+        {
+            ToWrapper(
+                delegate { return new JsonMockWrapper(); }, reader);
+        }
+
+        private static void RegisterBaseExporters()
+        {
+            base_exporters_table[typeof(byte)] =
+                delegate (object obj, JsonWriter writer)
+                {
+                    writer.Write(Convert.ToInt32((byte)obj));
+                };
+
+            base_exporters_table[typeof(char)] =
+                delegate (object obj, JsonWriter writer)
+                {
+                    writer.Write(Convert.ToString((char)obj));
+                };
+
+            base_exporters_table[typeof(DateTime)] =
+                delegate (object obj, JsonWriter writer)
+                {
+                    writer.Write(Convert.ToString((DateTime)obj,
+                                                    datetime_format));
+                };
+
+            base_exporters_table[typeof(decimal)] =
+                delegate (object obj, JsonWriter writer)
+                {
+                    writer.Write((decimal)obj);
+                };
+
+            base_exporters_table[typeof(sbyte)] =
+                delegate (object obj, JsonWriter writer)
+                {
+                    writer.Write(Convert.ToInt32((sbyte)obj));
+                };
+
+            base_exporters_table[typeof(short)] =
+                delegate (object obj, JsonWriter writer)
+                {
+                    writer.Write(Convert.ToInt32((short)obj));
+                };
+
+            base_exporters_table[typeof(ushort)] =
+                delegate (object obj, JsonWriter writer)
+                {
+                    writer.Write(Convert.ToInt32((ushort)obj));
+                };
+
+            base_exporters_table[typeof(uint)] =
+                delegate (object obj, JsonWriter writer)
+                {
+                    writer.Write(Convert.ToUInt64((uint)obj));
+                };
+
+            base_exporters_table[typeof(ulong)] =
+                delegate (object obj, JsonWriter writer)
+                {
+                    writer.Write((ulong)obj);
+                };
+
+            base_exporters_table[typeof(DateTimeOffset)] =
+                delegate (object obj, JsonWriter writer)
+                {
+                    writer.Write(((DateTimeOffset)obj).ToString("yyyy-MM-ddTHH:mm:ss.fffffffzzz", datetime_format));
+                };
+        }
+
+        private static void RegisterBaseImporters()
+        {
+            ImporterFunc importer;
+
+            importer = delegate (object input)
+            {
+                return Convert.ToByte((int)input);
+            };
+            RegisterImporter(base_importers_table, typeof(int),
+                              typeof(byte), importer);
+
+            importer = delegate (object input)
+            {
+                return Convert.ToUInt64((int)input);
+            };
+            RegisterImporter(base_importers_table, typeof(int),
+                              typeof(ulong), importer);
+
+            importer = delegate (object input)
+            {
+                return Convert.ToInt64((int)input);
+            };
+            RegisterImporter(base_importers_table, typeof(int),
+                              typeof(long), importer);
+
+            importer = delegate (object input)
+            {
+                return Convert.ToSByte((int)input);
+            };
+            RegisterImporter(base_importers_table, typeof(int),
+                              typeof(sbyte), importer);
+
+            importer = delegate (object input)
+            {
+                return Convert.ToInt16((int)input);
+            };
+            RegisterImporter(base_importers_table, typeof(int),
+                              typeof(short), importer);
+
+            importer = delegate (object input)
+            {
+                return Convert.ToUInt16((int)input);
+            };
+            RegisterImporter(base_importers_table, typeof(int),
+                              typeof(ushort), importer);
+
+            importer = delegate (object input)
+            {
+                return Convert.ToUInt32((int)input);
+            };
+            RegisterImporter(base_importers_table, typeof(int),
+                              typeof(uint), importer);
+
+            importer = delegate (object input)
+            {
+                return Convert.ToSingle((int)input);
+            };
+            RegisterImporter(base_importers_table, typeof(int),
+                              typeof(float), importer);
+
+            importer = delegate (object input)
+            {
+                return Convert.ToDouble((int)input);
+            };
+            RegisterImporter(base_importers_table, typeof(int),
+                              typeof(double), importer);
+
+            importer = delegate (object input)
+            {
+                return Convert.ToDecimal((double)input);
+            };
+            RegisterImporter(base_importers_table, typeof(double),
+                              typeof(decimal), importer);
+
+            importer = delegate (object input)
+            {
+                return Convert.ToSingle((double)input);
+            };
+            RegisterImporter(base_importers_table, typeof(double),
+                typeof(float), importer);
+
+            importer = delegate (object input)
+            {
+                return Convert.ToUInt32((long)input);
+            };
+            RegisterImporter(base_importers_table, typeof(long),
+                              typeof(uint), importer);
+
+            importer = delegate (object input)
+            {
+                return Convert.ToChar((string)input);
+            };
+            RegisterImporter(base_importers_table, typeof(string),
+                              typeof(char), importer);
+
+            importer = delegate (object input)
+            {
+                return Convert.ToDateTime((string)input, datetime_format);
+            };
+            RegisterImporter(base_importers_table, typeof(string),
+                              typeof(DateTime), importer);
+
+            importer = delegate (object input)
+            {
+                return DateTimeOffset.Parse((string)input, datetime_format);
+            };
+            RegisterImporter(base_importers_table, typeof(string),
+                typeof(DateTimeOffset), importer);
+        }
+
+        private static void RegisterImporter(
+            IDictionary<Type, IDictionary<Type, ImporterFunc>> table,
+            Type json_type, Type value_type, ImporterFunc importer)
+        {
+            if (!table.ContainsKey(json_type))
+                table.Add(json_type, new Dictionary<Type, ImporterFunc>());
+
+            table[json_type][value_type] = importer;
+        }
+
+        private static void WriteValue(object obj, JsonWriter writer,
+                                        bool writer_is_private,
+                                        int depth)
+        {
+            if (depth > max_nesting_depth)
+                throw new JsonException(
+                    string.Format("Max allowed object depth reached while " +
+                                   "trying to export from type {0}",
+                                   obj.GetType()));
+
+            if (obj == null)
+            {
+                writer.Write(null);
+                return;
+            }
+
+            if (obj is IJsonWrapper)
+            {
+                if (writer_is_private)
+                    writer.TextWriter.Write(((IJsonWrapper)obj).ToJson());
+                else
+                    ((IJsonWrapper)obj).ToJson(writer);
+
+                return;
+            }
+
+            if (obj is string)
+            {
+                writer.Write((string)obj);
+                return;
+            }
+
+            if (obj is double)
+            {
+                writer.Write((double)obj);
+                return;
+            }
+
+            if (obj is float)
+            {
+                writer.Write((float)obj);
+                return;
+            }
+
+            if (obj is int)
+            {
+                writer.Write((int)obj);
+                return;
+            }
+
+            if (obj is bool)
+            {
+                writer.Write((bool)obj);
+                return;
+            }
+
+            if (obj is long)
+            {
+                writer.Write((long)obj);
+                return;
+            }
+
+            if (obj is Array)
+            {
+                writer.WriteArrayStart();
+
+                foreach (object elem in (Array)obj)
+                    WriteValue(elem, writer, writer_is_private, depth + 1);
+
+                writer.WriteArrayEnd();
+
+                return;
+            }
+
+            if (obj is IList)
+            {
+                writer.WriteArrayStart();
+                foreach (object elem in (IList)obj)
+                    WriteValue(elem, writer, writer_is_private, depth + 1);
+                writer.WriteArrayEnd();
+
+                return;
+            }
+
+            if (obj is IDictionary dictionary)
+            {
+                writer.WriteObjectStart();
+                foreach (DictionaryEntry entry in dictionary)
+                {
+                    var propertyName = entry.Key is string key ?
+                        key
+                        : Convert.ToString(entry.Key, CultureInfo.InvariantCulture);
+                    writer.WritePropertyName(propertyName);
+                    WriteValue(entry.Value, writer, writer_is_private,
+                                depth + 1);
+                }
+                writer.WriteObjectEnd();
+
+                return;
+            }
+
+            Type obj_type = obj.GetType();
+
+            // See if there's a custom exporter for the object
+            if (custom_exporters_table.ContainsKey(obj_type))
+            {
+                ExporterFunc exporter = custom_exporters_table[obj_type];
+                exporter(obj, writer);
+
+                return;
+            }
+
+            // If not, maybe there's a base exporter
+            if (base_exporters_table.ContainsKey(obj_type))
+            {
+                ExporterFunc exporter = base_exporters_table[obj_type];
+                exporter(obj, writer);
+
+                return;
+            }
+
+            // Last option, let's see if it's an enum
+            if (obj is Enum)
+            {
+                Type e_type = Enum.GetUnderlyingType(obj_type);
+
+                if (e_type == typeof(long))
+                    writer.Write((long)obj);
+                else if (e_type == typeof(uint))
+                    writer.Write((uint)obj);
+                else if (e_type == typeof(ulong))
+                    writer.Write((ulong)obj);
+                else if (e_type == typeof(ushort))
+                    writer.Write((ushort)obj);
+                else if (e_type == typeof(short))
+                    writer.Write((short)obj);
+                else if (e_type == typeof(byte))
+                    writer.Write((byte)obj);
+                else if (e_type == typeof(sbyte))
+                    writer.Write((sbyte)obj);
+                else
+                    writer.Write((int)obj);
+
+                return;
+            }
+
+            // Okay, so it looks like the input should be exported as an
+            // object
+            AddTypeProperties(obj_type);
+            IList<PropertyMetadata> props = type_properties[obj_type];
+
+            writer.WriteObjectStart();
+            foreach (PropertyMetadata p_data in props)
+            {
+                if (p_data.IsField)
+                {
+                    writer.WritePropertyName(p_data.Info.Name);
+                    WriteValue(((FieldInfo)p_data.Info).GetValue(obj),
+                                writer, writer_is_private, depth + 1);
+                }
+                else
+                {
+                    PropertyInfo p_info = (PropertyInfo)p_data.Info;
+
+                    if (p_info.CanRead)
+                    {
+                        writer.WritePropertyName(p_data.Info.Name);
+                        WriteValue(p_info.GetValue(obj, null),
+                                    writer, writer_is_private, depth + 1);
+                    }
+                }
+            }
+            writer.WriteObjectEnd();
+        }
+        #endregion
+
+
+        public static string ToJson(object obj)
+        {
+            lock (static_writer_lock)
+            {
+                static_writer.Reset();
+
+                WriteValue(obj, static_writer, true, 0);
+
+                return static_writer.ToString();
+            }
+        }
+
+        public static void ToJson(object obj, JsonWriter writer)
+        {
+            WriteValue(obj, writer, false, 0);
+        }
+
+        public static JsonData ToObject(JsonReader reader)
+        {
+            return (JsonData)ToWrapper(
+                delegate { return new JsonData(); }, reader);
+        }
+
+        public static JsonData ToObject(TextReader reader)
+        {
+            JsonReader json_reader = new JsonReader(reader);
+
+            return (JsonData)ToWrapper(
+                delegate { return new JsonData(); }, json_reader);
+        }
+
+        public static JsonData ToObject(string json)
+        {
+            return (JsonData)ToWrapper(
+                delegate { return new JsonData(); }, json);
+        }
+
+        public static T ToObject<T>(JsonReader reader)
+        {
+            return (T)ReadValue(typeof(T), reader);
+        }
+
+        public static T ToObject<T>(TextReader reader)
+        {
+            JsonReader json_reader = new JsonReader(reader);
+
+            return (T)ReadValue(typeof(T), json_reader);
+        }
+
+        public static T ToObject<T>(string json)
+        {
+            JsonReader reader = new JsonReader(json);
+
+            return (T)ReadValue(typeof(T), reader);
+        }
+
+        public static object ToObject(string json, Type ConvertType)
+        {
+            JsonReader reader = new JsonReader(json);
+
+            return ReadValue(ConvertType, reader);
+        }
+
+        public static IJsonWrapper ToWrapper(WrapperFactory factory,
+                                              JsonReader reader)
+        {
+            return ReadValue(factory, reader);
+        }
+
+        public static IJsonWrapper ToWrapper(WrapperFactory factory,
+                                              string json)
+        {
+            JsonReader reader = new JsonReader(json);
+
+            return ReadValue(factory, reader);
+        }
+
+        public static void RegisterExporter<T>(ExporterFunc<T> exporter)
+        {
+            ExporterFunc exporter_wrapper =
+                delegate (object obj, JsonWriter writer)
+                {
+                    exporter((T)obj, writer);
+                };
+
+            custom_exporters_table[typeof(T)] = exporter_wrapper;
+        }
+
+        public static void RegisterImporter<TJson, TValue>(
+            ImporterFunc<TJson, TValue> importer)
+        {
+            ImporterFunc importer_wrapper =
+                delegate (object input)
+                {
+                    return importer((TJson)input);
+                };
+
+            RegisterImporter(custom_importers_table, typeof(TJson),
+                              typeof(TValue), importer_wrapper);
+        }
+
+        public static void UnregisterExporters()
+        {
+            custom_exporters_table.Clear();
+        }
+
+        public static void UnregisterImporters()
+        {
+            custom_importers_table.Clear();
+        }
+    }
+}
diff --git a/O&Z_Obfuscator/LitJson/JsonMockWrapper.cs b/O&Z_Obfuscator/LitJson/JsonMockWrapper.cs
new file mode 100644
index 0000000..1be9fd6
--- /dev/null
+++ b/O&Z_Obfuscator/LitJson/JsonMockWrapper.cs
@@ -0,0 +1,109 @@
+#region Header
+/**
+ * JsonMockWrapper.cs
+ *   Mock object implementing IJsonWrapper, to facilitate actions like
+ *   skipping data more efficiently.
+ *
+ * The authors disclaim copyright to this source code. For more details, see
+ * the COPYING file included with this distribution.
+ **/
+#endregion
+
+
+using System;
+using System.Collections;
+using System.Collections.Specialized;
+
+
+namespace O_Z_IL2CPP_Security.LitJson
+{
+    public class JsonMockWrapper : IJsonWrapper
+    {
+        public bool IsArray { get { return false; } }
+        public bool IsBoolean { get { return false; } }
+        public bool IsDouble { get { return false; } }
+        public bool IsInt { get { return false; } }
+        public bool IsLong { get { return false; } }
+        public bool IsObject { get { return false; } }
+        public bool IsString { get { return false; } }
+
+        public bool GetBoolean() { return false; }
+        public double GetDouble() { return 0.0; }
+        public int GetInt() { return 0; }
+        public JsonType GetJsonType() { return JsonType.None; }
+        public long GetLong() { return 0L; }
+        public string GetString() { return ""; }
+
+        public void SetBoolean(bool val) { }
+        public void SetDouble(double val) { }
+        public void SetInt(int val) { }
+        public void SetJsonType(JsonType type) { }
+        public void SetLong(long val) { }
+        public void SetString(string val) { }
+
+        public string ToJson() { return ""; }
+        public void ToJson(JsonWriter writer) { }
+
+
+        bool IList.IsFixedSize { get { return true; } }
+        bool IList.IsReadOnly { get { return true; } }
+
+        object IList.this[int index]
+        {
+            get { return null; }
+            set { }
+        }
+
+        int IList.Add(object value) { return 0; }
+        void IList.Clear() { }
+        bool IList.Contains(object value) { return false; }
+        int IList.IndexOf(object value) { return -1; }
+        void IList.Insert(int i, object v) { }
+        void IList.Remove(object value) { }
+        void IList.RemoveAt(int index) { }
+
+
+        int ICollection.Count { get { return 0; } }
+        bool ICollection.IsSynchronized { get { return false; } }
+        object ICollection.SyncRoot { get { return null; } }
+
+        void ICollection.CopyTo(Array array, int index) { }
+
+
+        IEnumerator IEnumerable.GetEnumerator() { return null; }
+
+
+        bool IDictionary.IsFixedSize { get { return true; } }
+        bool IDictionary.IsReadOnly { get { return true; } }
+
+        ICollection IDictionary.Keys { get { return null; } }
+        ICollection IDictionary.Values { get { return null; } }
+
+        object IDictionary.this[object key]
+        {
+            get { return null; }
+            set { }
+        }
+
+        void IDictionary.Add(object k, object v) { }
+        void IDictionary.Clear() { }
+        bool IDictionary.Contains(object key) { return false; }
+        void IDictionary.Remove(object key) { }
+
+        IDictionaryEnumerator IDictionary.GetEnumerator() { return null; }
+
+
+        object IOrderedDictionary.this[int idx]
+        {
+            get { return null; }
+            set { }
+        }
+
+        IDictionaryEnumerator IOrderedDictionary.GetEnumerator()
+        {
+            return null;
+        }
+        void IOrderedDictionary.Insert(int i, object k, object v) { }
+        void IOrderedDictionary.RemoveAt(int i) { }
+    }
+}
diff --git a/O&Z_Obfuscator/LitJson/JsonReader.cs b/O&Z_Obfuscator/LitJson/JsonReader.cs
new file mode 100644
index 0000000..7f210bf
--- /dev/null
+++ b/O&Z_Obfuscator/LitJson/JsonReader.cs
@@ -0,0 +1,523 @@
+#region Header
+/**
+ * JsonReader.cs
+ *   Stream-like access to JSON text.
+ *
+ * The authors disclaim copyright to this source code. For more details, see
+ * the COPYING file included with this distribution.
+ **/
+#endregion
+
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Text;
+
+
+namespace O_Z_IL2CPP_Security.LitJson
+{
+    public enum JsonToken
+    {
+        None,
+
+        ObjectStart,
+        PropertyName,
+        ObjectEnd,
+
+        ArrayStart,
+        ArrayEnd,
+
+        Int,
+        Long,
+        Double,
+
+        String,
+
+        Boolean,
+        Null
+    }
+
+
+    public class JsonReader
+    {
+        #region Fields
+        private static readonly IDictionary<int, IDictionary<int, int[]>> parse_table;
+
+        private Stack<int> automaton_stack;
+        private int current_input;
+        private int current_symbol;
+        private bool end_of_json;
+        private bool end_of_input;
+        private Lexer lexer;
+        private bool parser_in_string;
+        private bool parser_return;
+        private bool read_started;
+        private TextReader reader;
+        private bool reader_is_owned;
+        private bool skip_non_members;
+        private object token_value;
+        private JsonToken token;
+        #endregion
+
+
+        #region Public Properties
+        public bool AllowComments
+        {
+            get { return lexer.AllowComments; }
+            set { lexer.AllowComments = value; }
+        }
+
+        public bool AllowSingleQuotedStrings
+        {
+            get { return lexer.AllowSingleQuotedStrings; }
+            set { lexer.AllowSingleQuotedStrings = value; }
+        }
+
+        public bool SkipNonMembers
+        {
+            get { return skip_non_members; }
+            set { skip_non_members = value; }
+        }
+
+        public bool EndOfInput
+        {
+            get { return end_of_input; }
+        }
+
+        public bool EndOfJson
+        {
+            get { return end_of_json; }
+        }
+
+        public JsonToken Token
+        {
+            get { return token; }
+        }
+
+        public object Value
+        {
+            get { return token_value; }
+        }
+        #endregion
+
+
+        #region Constructors
+        static JsonReader()
+        {
+            parse_table = PopulateParseTable();
+        }
+
+        public JsonReader(string json_text) :
+            this(new StringReader(json_text), true)
+        {
+        }
+
+        public JsonReader(TextReader reader) :
+            this(reader, false)
+        {
+        }
+
+        private JsonReader(TextReader reader, bool owned)
+        {
+            if (reader == null)
+                throw new ArgumentNullException("reader");
+
+            parser_in_string = false;
+            parser_return = false;
+
+            read_started = false;
+            automaton_stack = new Stack<int>();
+            automaton_stack.Push((int)ParserToken.End);
+            automaton_stack.Push((int)ParserToken.Text);
+
+            lexer = new Lexer(reader);
+
+            end_of_input = false;
+            end_of_json = false;
+
+            skip_non_members = true;
+
+            this.reader = reader;
+            reader_is_owned = owned;
+        }
+        #endregion
+
+
+        #region Static Methods
+        private static IDictionary<int, IDictionary<int, int[]>> PopulateParseTable()
+        {
+            // See section A.2. of the manual for details
+            IDictionary<int, IDictionary<int, int[]>> parse_table = new Dictionary<int, IDictionary<int, int[]>>();
+
+            TableAddRow(parse_table, ParserToken.Array);
+            TableAddCol(parse_table, ParserToken.Array, '[',
+                            '[',
+                            (int)ParserToken.ArrayPrime);
+
+            TableAddRow(parse_table, ParserToken.ArrayPrime);
+            TableAddCol(parse_table, ParserToken.ArrayPrime, '"',
+                            (int)ParserToken.Value,
+
+                            (int)ParserToken.ValueRest,
+                            ']');
+            TableAddCol(parse_table, ParserToken.ArrayPrime, '[',
+                            (int)ParserToken.Value,
+                            (int)ParserToken.ValueRest,
+                            ']');
+            TableAddCol(parse_table, ParserToken.ArrayPrime, ']',
+                            ']');
+            TableAddCol(parse_table, ParserToken.ArrayPrime, '{',
+                            (int)ParserToken.Value,
+                            (int)ParserToken.ValueRest,
+                            ']');
+            TableAddCol(parse_table, ParserToken.ArrayPrime, (int)ParserToken.Number,
+                            (int)ParserToken.Value,
+                            (int)ParserToken.ValueRest,
+                            ']');
+            TableAddCol(parse_table, ParserToken.ArrayPrime, (int)ParserToken.True,
+                            (int)ParserToken.Value,
+                            (int)ParserToken.ValueRest,
+                            ']');
+            TableAddCol(parse_table, ParserToken.ArrayPrime, (int)ParserToken.False,
+                            (int)ParserToken.Value,
+                            (int)ParserToken.ValueRest,
+                            ']');
+            TableAddCol(parse_table, ParserToken.ArrayPrime, (int)ParserToken.Null,
+                            (int)ParserToken.Value,
+                            (int)ParserToken.ValueRest,
+                            ']');
+
+            TableAddRow(parse_table, ParserToken.Object);
+            TableAddCol(parse_table, ParserToken.Object, '{',
+                            '{',
+                            (int)ParserToken.ObjectPrime);
+
+            TableAddRow(parse_table, ParserToken.ObjectPrime);
+            TableAddCol(parse_table, ParserToken.ObjectPrime, '"',
+                            (int)ParserToken.Pair,
+                            (int)ParserToken.PairRest,
+                            '}');
+            TableAddCol(parse_table, ParserToken.ObjectPrime, '}',
+                            '}');
+
+            TableAddRow(parse_table, ParserToken.Pair);
+            TableAddCol(parse_table, ParserToken.Pair, '"',
+                            (int)ParserToken.String,
+                            ':',
+                            (int)ParserToken.Value);
+
+            TableAddRow(parse_table, ParserToken.PairRest);
+            TableAddCol(parse_table, ParserToken.PairRest, ',',
+                            ',',
+                            (int)ParserToken.Pair,
+                            (int)ParserToken.PairRest);
+            TableAddCol(parse_table, ParserToken.PairRest, '}',
+                            (int)ParserToken.Epsilon);
+
+            TableAddRow(parse_table, ParserToken.String);
+            TableAddCol(parse_table, ParserToken.String, '"',
+                            '"',
+                            (int)ParserToken.CharSeq,
+                            '"');
+
+            TableAddRow(parse_table, ParserToken.Text);
+            TableAddCol(parse_table, ParserToken.Text, '[',
+                            (int)ParserToken.Array);
+            TableAddCol(parse_table, ParserToken.Text, '{',
+                            (int)ParserToken.Object);
+
+            TableAddRow(parse_table, ParserToken.Value);
+            TableAddCol(parse_table, ParserToken.Value, '"',
+                            (int)ParserToken.String);
+            TableAddCol(parse_table, ParserToken.Value, '[',
+                            (int)ParserToken.Array);
+            TableAddCol(parse_table, ParserToken.Value, '{',
+                            (int)ParserToken.Object);
+            TableAddCol(parse_table, ParserToken.Value, (int)ParserToken.Number,
+                            (int)ParserToken.Number);
+            TableAddCol(parse_table, ParserToken.Value, (int)ParserToken.True,
+                            (int)ParserToken.True);
+            TableAddCol(parse_table, ParserToken.Value, (int)ParserToken.False,
+                            (int)ParserToken.False);
+            TableAddCol(parse_table, ParserToken.Value, (int)ParserToken.Null,
+                            (int)ParserToken.Null);
+
+            TableAddRow(parse_table, ParserToken.ValueRest);
+            TableAddCol(parse_table, ParserToken.ValueRest, ',',
+                            ',',
+                            (int)ParserToken.Value,
+                            (int)ParserToken.ValueRest);
+            TableAddCol(parse_table, ParserToken.ValueRest, ']',
+                            (int)ParserToken.Epsilon);
+
+            return parse_table;
+        }
+
+        private static void TableAddCol(IDictionary<int, IDictionary<int, int[]>> parse_table, ParserToken row, int col,
+                                         params int[] symbols)
+        {
+            parse_table[(int)row].Add(col, symbols);
+        }
+
+        private static void TableAddRow(IDictionary<int, IDictionary<int, int[]>> parse_table, ParserToken rule)
+        {
+            parse_table.Add((int)rule, new Dictionary<int, int[]>());
+        }
+        #endregion
+
+
+        #region Private Methods
+        private void ProcessNumber(string number)
+        {
+            if (number.IndexOf('.') != -1 ||
+                number.IndexOf('e') != -1 ||
+                number.IndexOf('E') != -1)
+            {
+
+                double n_double;
+                if (double.TryParse(number, NumberStyles.Any, CultureInfo.InvariantCulture, out n_double))
+                {
+                    token = JsonToken.Double;
+                    token_value = n_double;
+
+                    return;
+                }
+            }
+
+            int n_int32;
+            if (int.TryParse(number, NumberStyles.Integer, CultureInfo.InvariantCulture, out n_int32))
+            {
+                token = JsonToken.Int;
+                token_value = n_int32;
+
+                return;
+            }
+
+            long n_int64;
+            if (long.TryParse(number, NumberStyles.Integer, CultureInfo.InvariantCulture, out n_int64))
+            {
+                token = JsonToken.Long;
+                token_value = n_int64;
+
+                return;
+            }
+
+            ulong n_uint64;
+            if (ulong.TryParse(number, NumberStyles.Integer, CultureInfo.InvariantCulture, out n_uint64))
+            {
+                token = JsonToken.Long;
+                token_value = n_uint64;
+
+                return;
+            }
+
+            // Shouldn't happen, but just in case, return something
+            token = JsonToken.Int;
+            token_value = 0;
+        }
+
+        private void ProcessSymbol()
+        {
+            if (current_symbol == '[')
+            {
+                token = JsonToken.ArrayStart;
+                parser_return = true;
+
+            }
+            else if (current_symbol == ']')
+            {
+                token = JsonToken.ArrayEnd;
+                parser_return = true;
+
+            }
+            else if (current_symbol == '{')
+            {
+                token = JsonToken.ObjectStart;
+                parser_return = true;
+
+            }
+            else if (current_symbol == '}')
+            {
+                token = JsonToken.ObjectEnd;
+                parser_return = true;
+
+            }
+            else if (current_symbol == '"')
+            {
+                if (parser_in_string)
+                {
+                    parser_in_string = false;
+
+                    parser_return = true;
+
+                }
+                else
+                {
+                    if (token == JsonToken.None)
+                        token = JsonToken.String;
+
+                    parser_in_string = true;
+                }
+
+            }
+            else if (current_symbol == (int)ParserToken.CharSeq)
+            {
+                token_value = lexer.StringValue;
+
+            }
+            else if (current_symbol == (int)ParserToken.False)
+            {
+                token = JsonToken.Boolean;
+                token_value = false;
+                parser_return = true;
+
+            }
+            else if (current_symbol == (int)ParserToken.Null)
+            {
+                token = JsonToken.Null;
+                parser_return = true;
+
+            }
+            else if (current_symbol == (int)ParserToken.Number)
+            {
+                ProcessNumber(lexer.StringValue);
+
+                parser_return = true;
+
+            }
+            else if (current_symbol == (int)ParserToken.Pair)
+            {
+                token = JsonToken.PropertyName;
+
+            }
+            else if (current_symbol == (int)ParserToken.True)
+            {
+                token = JsonToken.Boolean;
+                token_value = true;
+                parser_return = true;
+
+            }
+        }
+
+        private bool ReadToken()
+        {
+            if (end_of_input)
+                return false;
+
+            lexer.NextToken();
+
+            if (lexer.EndOfInput)
+            {
+                Close();
+
+                return false;
+            }
+
+            current_input = lexer.Token;
+
+            return true;
+        }
+        #endregion
+
+
+        public void Close()
+        {
+            if (end_of_input)
+                return;
+
+            end_of_input = true;
+            end_of_json = true;
+
+            if (reader_is_owned)
+            {
+                using (reader) { }
+            }
+
+            reader = null;
+        }
+
+        public bool Read()
+        {
+            if (end_of_input)
+                return false;
+
+            if (end_of_json)
+            {
+                end_of_json = false;
+                automaton_stack.Clear();
+                automaton_stack.Push((int)ParserToken.End);
+                automaton_stack.Push((int)ParserToken.Text);
+            }
+
+            parser_in_string = false;
+            parser_return = false;
+
+            token = JsonToken.None;
+            token_value = null;
+
+            if (!read_started)
+            {
+                read_started = true;
+
+                if (!ReadToken())
+                    return false;
+            }
+
+
+            int[] entry_symbols;
+
+            while (true)
+            {
+                if (parser_return)
+                {
+                    if (automaton_stack.Peek() == (int)ParserToken.End)
+                        end_of_json = true;
+
+                    return true;
+                }
+
+                current_symbol = automaton_stack.Pop();
+
+                ProcessSymbol();
+
+                if (current_symbol == current_input)
+                {
+                    if (!ReadToken())
+                    {
+                        if (automaton_stack.Peek() != (int)ParserToken.End)
+                            throw new JsonException(
+                                "Input doesn't evaluate to proper JSON text");
+
+                        if (parser_return)
+                            return true;
+
+                        return false;
+                    }
+
+                    continue;
+                }
+
+                try
+                {
+
+                    entry_symbols =
+                        parse_table[current_symbol][current_input];
+
+                }
+                catch (KeyNotFoundException e)
+                {
+                    throw new JsonException((ParserToken)current_input, e);
+                }
+
+                if (entry_symbols[0] == (int)ParserToken.Epsilon)
+                    continue;
+
+                for (int i = entry_symbols.Length - 1; i >= 0; i--)
+                    automaton_stack.Push(entry_symbols[i]);
+            }
+        }
+
+    }
+}
diff --git a/O&Z_Obfuscator/LitJson/JsonWriter.cs b/O&Z_Obfuscator/LitJson/JsonWriter.cs
new file mode 100644
index 0000000..8e27db0
--- /dev/null
+++ b/O&Z_Obfuscator/LitJson/JsonWriter.cs
@@ -0,0 +1,499 @@
+#region Header
+/**
+ * JsonWriter.cs
+ *   Stream-like facility to output JSON text.
+ *
+ * The authors disclaim copyright to this source code. For more details, see
+ * the COPYING file included with this distribution.
+ **/
+#endregion
+
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Text;
+
+
+namespace O_Z_IL2CPP_Security.LitJson
+{
+    internal enum Condition
+    {
+        InArray,
+        InObject,
+        NotAProperty,
+        Property,
+        Value
+    }
+
+    internal class WriterContext
+    {
+        public int Count;
+        public bool InArray;
+        public bool InObject;
+        public bool ExpectingValue;
+        public int Padding;
+    }
+
+    public class JsonWriter
+    {
+        #region Fields
+        private static readonly NumberFormatInfo number_format;
+
+        private WriterContext context;
+        private Stack<WriterContext> ctx_stack;
+        private bool has_reached_end;
+        private char[] hex_seq;
+        private int indentation;
+        private int indent_value;
+        private StringBuilder inst_string_builder;
+        private bool pretty_print;
+        private bool validate;
+        private bool lower_case_properties;
+        private TextWriter writer;
+        #endregion
+
+
+        #region Properties
+        public int IndentValue
+        {
+            get { return indent_value; }
+            set
+            {
+                indentation = indentation / indent_value * value;
+                indent_value = value;
+            }
+        }
+
+        public bool PrettyPrint
+        {
+            get { return pretty_print; }
+            set { pretty_print = value; }
+        }
+
+        public TextWriter TextWriter
+        {
+            get { return writer; }
+        }
+
+        public bool Validate
+        {
+            get { return validate; }
+            set { validate = value; }
+        }
+
+        public bool LowerCaseProperties
+        {
+            get { return lower_case_properties; }
+            set { lower_case_properties = value; }
+        }
+        #endregion
+
+
+        #region Constructors
+        static JsonWriter()
+        {
+            number_format = NumberFormatInfo.InvariantInfo;
+        }
+
+        public JsonWriter()
+        {
+            inst_string_builder = new StringBuilder();
+            writer = new StringWriter(inst_string_builder);
+
+            Init();
+        }
+
+        public JsonWriter(StringBuilder sb) :
+            this(new StringWriter(sb))
+        {
+        }
+
+        public JsonWriter(TextWriter writer)
+        {
+            if (writer == null)
+                throw new ArgumentNullException("writer");
+
+            this.writer = writer;
+
+            Init();
+        }
+        #endregion
+
+
+        #region Private Methods
+        private void DoValidation(Condition cond)
+        {
+            if (!context.ExpectingValue)
+                context.Count++;
+
+            if (!validate)
+                return;
+
+            if (has_reached_end)
+                throw new JsonException(
+                    "A complete JSON symbol has already been written");
+
+            switch (cond)
+            {
+                case Condition.InArray:
+                    if (!context.InArray)
+                        throw new JsonException(
+                            "Can't close an array here");
+                    break;
+
+                case Condition.InObject:
+                    if (!context.InObject || context.ExpectingValue)
+                        throw new JsonException(
+                            "Can't close an object here");
+                    break;
+
+                case Condition.NotAProperty:
+                    if (context.InObject && !context.ExpectingValue)
+                        throw new JsonException(
+                            "Expected a property");
+                    break;
+
+                case Condition.Property:
+                    if (!context.InObject || context.ExpectingValue)
+                        throw new JsonException(
+                            "Can't add a property here");
+                    break;
+
+                case Condition.Value:
+                    if (!context.InArray &&
+                        (!context.InObject || !context.ExpectingValue))
+                        throw new JsonException(
+                            "Can't add a value here");
+
+                    break;
+            }
+        }
+
+        private void Init()
+        {
+            has_reached_end = false;
+            hex_seq = new char[4];
+            indentation = 0;
+            indent_value = 4;
+            pretty_print = false;
+            validate = true;
+            lower_case_properties = false;
+
+            ctx_stack = new Stack<WriterContext>();
+            context = new WriterContext();
+            ctx_stack.Push(context);
+        }
+
+        private static void IntToHex(int n, char[] hex)
+        {
+            int num;
+
+            for (int i = 0; i < 4; i++)
+            {
+                num = n % 16;
+
+                if (num < 10)
+                    hex[3 - i] = (char)('0' + num);
+                else
+                    hex[3 - i] = (char)('A' + (num - 10));
+
+                n >>= 4;
+            }
+        }
+
+        private void Indent()
+        {
+            if (pretty_print)
+                indentation += indent_value;
+        }
+
+
+        private void Put(string str)
+        {
+            if (pretty_print && !context.ExpectingValue)
+                for (int i = 0; i < indentation; i++)
+                    writer.Write(' ');
+
+            writer.Write(str);
+        }
+
+        private void PutNewline()
+        {
+            PutNewline(true);
+        }
+
+        private void PutNewline(bool add_comma)
+        {
+            if (add_comma && !context.ExpectingValue &&
+                context.Count > 1)
+                writer.Write(',');
+
+            if (pretty_print && !context.ExpectingValue)
+                writer.Write(Environment.NewLine);
+        }
+
+        private void PutString(string str)
+        {
+            Put(string.Empty);
+
+            writer.Write('"');
+
+            int n = str.Length;
+            for (int i = 0; i < n; i++)
+            {
+                switch (str[i])
+                {
+                    case '\n':
+                        writer.Write("\\n");
+                        continue;
+
+                    case '\r':
+                        writer.Write("\\r");
+                        continue;
+
+                    case '\t':
+                        writer.Write("\\t");
+                        continue;
+
+                    case '"':
+                    case '\\':
+                        writer.Write('\\');
+                        writer.Write(str[i]);
+                        continue;
+
+                    case '\f':
+                        writer.Write("\\f");
+                        continue;
+
+                    case '\b':
+                        writer.Write("\\b");
+                        continue;
+                }
+
+                if (str[i] >= 32 && str[i] <= 126)
+                {
+                    writer.Write(str[i]);
+                    continue;
+                }
+
+                // Default, turn into a \uXXXX sequence
+                IntToHex(str[i], hex_seq);
+                writer.Write("\\u");
+                writer.Write(hex_seq);
+            }
+
+            writer.Write('"');
+        }
+
+        private void Unindent()
+        {
+            if (pretty_print)
+                indentation -= indent_value;
+        }
+        #endregion
+
+
+        public override string ToString()
+        {
+            if (inst_string_builder == null)
+                return string.Empty;
+
+            return inst_string_builder.ToString();
+        }
+
+        public void Reset()
+        {
+            has_reached_end = false;
+
+            ctx_stack.Clear();
+            context = new WriterContext();
+            ctx_stack.Push(context);
+
+            if (inst_string_builder != null)
+                inst_string_builder.Remove(0, inst_string_builder.Length);
+        }
+
+        public void Write(bool boolean)
+        {
+            DoValidation(Condition.Value);
+            PutNewline();
+
+            Put(boolean ? "true" : "false");
+
+            context.ExpectingValue = false;
+        }
+
+        public void Write(decimal number)
+        {
+            DoValidation(Condition.Value);
+            PutNewline();
+
+            Put(Convert.ToString(number, number_format));
+
+            context.ExpectingValue = false;
+        }
+
+        public void Write(double number)
+        {
+            DoValidation(Condition.Value);
+            PutNewline();
+
+            string str = Convert.ToString(number, number_format);
+            Put(str);
+
+            if (str.IndexOf('.') == -1 &&
+                str.IndexOf('E') == -1)
+                writer.Write(".0");
+
+            context.ExpectingValue = false;
+        }
+
+        public void Write(float number)
+        {
+            DoValidation(Condition.Value);
+            PutNewline();
+
+            string str = Convert.ToString(number, number_format);
+            Put(str);
+
+            context.ExpectingValue = false;
+        }
+
+        public void Write(int number)
+        {
+            DoValidation(Condition.Value);
+            PutNewline();
+
+            Put(Convert.ToString(number, number_format));
+
+            context.ExpectingValue = false;
+        }
+
+        public void Write(long number)
+        {
+            DoValidation(Condition.Value);
+            PutNewline();
+
+            Put(Convert.ToString(number, number_format));
+
+            context.ExpectingValue = false;
+        }
+
+        public void Write(string str)
+        {
+            DoValidation(Condition.Value);
+            PutNewline();
+
+            if (str == null)
+                Put("null");
+            else
+                PutString(str);
+
+            context.ExpectingValue = false;
+        }
+
+        [CLSCompliant(false)]
+        public void Write(ulong number)
+        {
+            DoValidation(Condition.Value);
+            PutNewline();
+
+            Put(Convert.ToString(number, number_format));
+
+            context.ExpectingValue = false;
+        }
+
+        public void WriteArrayEnd()
+        {
+            DoValidation(Condition.InArray);
+            PutNewline(false);
+
+            ctx_stack.Pop();
+            if (ctx_stack.Count == 1)
+                has_reached_end = true;
+            else
+            {
+                context = ctx_stack.Peek();
+                context.ExpectingValue = false;
+            }
+
+            Unindent();
+            Put("]");
+        }
+
+        public void WriteArrayStart()
+        {
+            DoValidation(Condition.NotAProperty);
+            PutNewline();
+
+            Put("[");
+
+            context = new WriterContext();
+            context.InArray = true;
+            ctx_stack.Push(context);
+
+            Indent();
+        }
+
+        public void WriteObjectEnd()
+        {
+            DoValidation(Condition.InObject);
+            PutNewline(false);
+
+            ctx_stack.Pop();
+            if (ctx_stack.Count == 1)
+                has_reached_end = true;
+            else
+            {
+                context = ctx_stack.Peek();
+                context.ExpectingValue = false;
+            }
+
+            Unindent();
+            Put("}");
+        }
+
+        public void WriteObjectStart()
+        {
+            DoValidation(Condition.NotAProperty);
+            PutNewline();
+
+            Put("{");
+
+            context = new WriterContext();
+            context.InObject = true;
+            ctx_stack.Push(context);
+
+            Indent();
+        }
+
+        public void WritePropertyName(string property_name)
+        {
+            DoValidation(Condition.Property);
+            PutNewline();
+            string propertyName = property_name == null || !lower_case_properties
+                ? property_name
+                : property_name.ToLowerInvariant();
+
+            PutString(propertyName);
+
+            if (pretty_print)
+            {
+                if (propertyName.Length > context.Padding)
+                    context.Padding = propertyName.Length;
+
+                for (int i = context.Padding - propertyName.Length;
+                     i >= 0; i--)
+                    writer.Write(' ');
+
+                writer.Write(": ");
+            }
+            else
+                writer.Write(':');
+
+            context.ExpectingValue = true;
+        }
+    }
+}
diff --git a/O&Z_Obfuscator/LitJson/Lexer.cs b/O&Z_Obfuscator/LitJson/Lexer.cs
new file mode 100644
index 0000000..f476ede
--- /dev/null
+++ b/O&Z_Obfuscator/LitJson/Lexer.cs
@@ -0,0 +1,971 @@
+#region Header
+/**
+ * Lexer.cs
+ *   JSON lexer implementation based on a finite state machine.
+ *
+ * The authors disclaim copyright to this source code. For more details, see
+ * the COPYING file included with this distribution.
+ **/
+#endregion
+
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+
+namespace O_Z_IL2CPP_Security.LitJson
+{
+    internal class FsmContext
+    {
+        public bool Return;
+        public int NextState;
+        public Lexer L;
+        public int StateStack;
+    }
+
+
+    internal class Lexer
+    {
+        #region Fields
+        private delegate bool StateHandler(FsmContext ctx);
+
+        private static readonly int[] fsm_return_table;
+        private static readonly StateHandler[] fsm_handler_table;
+
+        private bool allow_comments;
+        private bool allow_single_quoted_strings;
+        private bool end_of_input;
+        private FsmContext fsm_context;
+        private int input_buffer;
+        private int input_char;
+        private TextReader reader;
+        private int state;
+        private StringBuilder string_buffer;
+        private string string_value;
+        private int token;
+        private int unichar;
+        #endregion
+
+
+        #region Properties
+        public bool AllowComments
+        {
+            get { return allow_comments; }
+            set { allow_comments = value; }
+        }
+
+        public bool AllowSingleQuotedStrings
+        {
+            get { return allow_single_quoted_strings; }
+            set { allow_single_quoted_strings = value; }
+        }
+
+        public bool EndOfInput
+        {
+            get { return end_of_input; }
+        }
+
+        public int Token
+        {
+            get { return token; }
+        }
+
+        public string StringValue
+        {
+            get { return string_value; }
+        }
+        #endregion
+
+
+        #region Constructors
+        static Lexer()
+        {
+            PopulateFsmTables(out fsm_handler_table, out fsm_return_table);
+        }
+
+        public Lexer(TextReader reader)
+        {
+            allow_comments = true;
+            allow_single_quoted_strings = true;
+
+            input_buffer = 0;
+            string_buffer = new StringBuilder(128);
+            state = 1;
+            end_of_input = false;
+            this.reader = reader;
+
+            fsm_context = new FsmContext();
+            fsm_context.L = this;
+        }
+        #endregion
+
+
+        #region Static Methods
+        private static int HexValue(int digit)
+        {
+            switch (digit)
+            {
+                case 'a':
+                case 'A':
+                    return 10;
+
+                case 'b':
+                case 'B':
+                    return 11;
+
+                case 'c':
+                case 'C':
+                    return 12;
+
+                case 'd':
+                case 'D':
+                    return 13;
+
+                case 'e':
+                case 'E':
+                    return 14;
+
+                case 'f':
+                case 'F':
+                    return 15;
+
+                default:
+                    return digit - '0';
+            }
+        }
+
+        private static void PopulateFsmTables(out StateHandler[] fsm_handler_table, out int[] fsm_return_table)
+        {
+            // See section A.1. of the manual for details of the finite
+            // state machine.
+            fsm_handler_table = new StateHandler[28] {
+                State1,
+                State2,
+                State3,
+                State4,
+                State5,
+                State6,
+                State7,
+                State8,
+                State9,
+                State10,
+                State11,
+                State12,
+                State13,
+                State14,
+                State15,
+                State16,
+                State17,
+                State18,
+                State19,
+                State20,
+                State21,
+                State22,
+                State23,
+                State24,
+                State25,
+                State26,
+                State27,
+                State28
+            };
+
+            fsm_return_table = new int[28] {
+                (int) ParserToken.Char,
+                0,
+                (int) ParserToken.Number,
+                (int) ParserToken.Number,
+                0,
+                (int) ParserToken.Number,
+                0,
+                (int) ParserToken.Number,
+                0,
+                0,
+                (int) ParserToken.True,
+                0,
+                0,
+                0,
+                (int) ParserToken.False,
+                0,
+                0,
+                (int) ParserToken.Null,
+                (int) ParserToken.CharSeq,
+                (int) ParserToken.Char,
+                0,
+                0,
+                (int) ParserToken.CharSeq,
+                (int) ParserToken.Char,
+                0,
+                0,
+                0,
+                0
+            };
+        }
+
+        private static char ProcessEscChar(int esc_char)
+        {
+            switch (esc_char)
+            {
+                case '"':
+                case '\'':
+                case '\\':
+                case '/':
+                    return Convert.ToChar(esc_char);
+
+                case 'n':
+                    return '\n';
+
+                case 't':
+                    return '\t';
+
+                case 'r':
+                    return '\r';
+
+                case 'b':
+                    return '\b';
+
+                case 'f':
+                    return '\f';
+
+                default:
+                    // Unreachable
+                    return '?';
+            }
+        }
+
+        private static bool State1(FsmContext ctx)
+        {
+            while (ctx.L.GetChar())
+            {
+                if (ctx.L.input_char == ' ' ||
+                    ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r')
+                    continue;
+
+                if (ctx.L.input_char >= '1' && ctx.L.input_char <= '9')
+                {
+                    ctx.L.string_buffer.Append((char)ctx.L.input_char);
+                    ctx.NextState = 3;
+                    return true;
+                }
+
+                switch (ctx.L.input_char)
+                {
+                    case '"':
+                        ctx.NextState = 19;
+                        ctx.Return = true;
+                        return true;
+
+                    case ',':
+                    case ':':
+                    case '[':
+                    case ']':
+                    case '{':
+                    case '}':
+                        ctx.NextState = 1;
+                        ctx.Return = true;
+                        return true;
+
+                    case '-':
+                        ctx.L.string_buffer.Append((char)ctx.L.input_char);
+                        ctx.NextState = 2;
+                        return true;
+
+                    case '0':
+                        ctx.L.string_buffer.Append((char)ctx.L.input_char);
+                        ctx.NextState = 4;
+                        return true;
+
+                    case 'f':
+                        ctx.NextState = 12;
+                        return true;
+
+                    case 'n':
+                        ctx.NextState = 16;
+                        return true;
+
+                    case 't':
+                        ctx.NextState = 9;
+                        return true;
+
+                    case '\'':
+                        if (!ctx.L.allow_single_quoted_strings)
+                            return false;
+
+                        ctx.L.input_char = '"';
+                        ctx.NextState = 23;
+                        ctx.Return = true;
+                        return true;
+
+                    case '/':
+                        if (!ctx.L.allow_comments)
+                            return false;
+
+                        ctx.NextState = 25;
+                        return true;
+
+                    default:
+                        return false;
+                }
+            }
+
+            return true;
+        }
+
+        private static bool State2(FsmContext ctx)
+        {
+            ctx.L.GetChar();
+
+            if (ctx.L.input_char >= '1' && ctx.L.input_char <= '9')
+            {
+                ctx.L.string_buffer.Append((char)ctx.L.input_char);
+                ctx.NextState = 3;
+                return true;
+            }
+
+            switch (ctx.L.input_char)
+            {
+                case '0':
+                    ctx.L.string_buffer.Append((char)ctx.L.input_char);
+                    ctx.NextState = 4;
+                    return true;
+
+                default:
+                    return false;
+            }
+        }
+
+        private static bool State3(FsmContext ctx)
+        {
+            while (ctx.L.GetChar())
+            {
+                if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9')
+                {
+                    ctx.L.string_buffer.Append((char)ctx.L.input_char);
+                    continue;
+                }
+
+                if (ctx.L.input_char == ' ' ||
+                    ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r')
+                {
+                    ctx.Return = true;
+                    ctx.NextState = 1;
+                    return true;
+                }
+
+                switch (ctx.L.input_char)
+                {
+                    case ',':
+                    case ']':
+                    case '}':
+                        ctx.L.UngetChar();
+                        ctx.Return = true;
+                        ctx.NextState = 1;
+                        return true;
+
+                    case '.':
+                        ctx.L.string_buffer.Append((char)ctx.L.input_char);
+                        ctx.NextState = 5;
+                        return true;
+
+                    case 'e':
+                    case 'E':
+                        ctx.L.string_buffer.Append((char)ctx.L.input_char);
+                        ctx.NextState = 7;
+                        return true;
+
+                    default:
+                        return false;
+                }
+            }
+            return true;
+        }
+
+        private static bool State4(FsmContext ctx)
+        {
+            ctx.L.GetChar();
+
+            if (ctx.L.input_char == ' ' ||
+                ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r')
+            {
+                ctx.Return = true;
+                ctx.NextState = 1;
+                return true;
+            }
+
+            switch (ctx.L.input_char)
+            {
+                case ',':
+                case ']':
+                case '}':
+                    ctx.L.UngetChar();
+                    ctx.Return = true;
+                    ctx.NextState = 1;
+                    return true;
+
+                case '.':
+                    ctx.L.string_buffer.Append((char)ctx.L.input_char);
+                    ctx.NextState = 5;
+                    return true;
+
+                case 'e':
+                case 'E':
+                    ctx.L.string_buffer.Append((char)ctx.L.input_char);
+                    ctx.NextState = 7;
+                    return true;
+
+                default:
+                    return false;
+            }
+        }
+
+        private static bool State5(FsmContext ctx)
+        {
+            ctx.L.GetChar();
+
+            if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9')
+            {
+                ctx.L.string_buffer.Append((char)ctx.L.input_char);
+                ctx.NextState = 6;
+                return true;
+            }
+
+            return false;
+        }
+
+        private static bool State6(FsmContext ctx)
+        {
+            while (ctx.L.GetChar())
+            {
+                if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9')
+                {
+                    ctx.L.string_buffer.Append((char)ctx.L.input_char);
+                    continue;
+                }
+
+                if (ctx.L.input_char == ' ' ||
+                    ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r')
+                {
+                    ctx.Return = true;
+                    ctx.NextState = 1;
+                    return true;
+                }
+
+                switch (ctx.L.input_char)
+                {
+                    case ',':
+                    case ']':
+                    case '}':
+                        ctx.L.UngetChar();
+                        ctx.Return = true;
+                        ctx.NextState = 1;
+                        return true;
+
+                    case 'e':
+                    case 'E':
+                        ctx.L.string_buffer.Append((char)ctx.L.input_char);
+                        ctx.NextState = 7;
+                        return true;
+
+                    default:
+                        return false;
+                }
+            }
+
+            return true;
+        }
+
+        private static bool State7(FsmContext ctx)
+        {
+            ctx.L.GetChar();
+
+            if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9')
+            {
+                ctx.L.string_buffer.Append((char)ctx.L.input_char);
+                ctx.NextState = 8;
+                return true;
+            }
+
+            switch (ctx.L.input_char)
+            {
+                case '+':
+                case '-':
+                    ctx.L.string_buffer.Append((char)ctx.L.input_char);
+                    ctx.NextState = 8;
+                    return true;
+
+                default:
+                    return false;
+            }
+        }
+
+        private static bool State8(FsmContext ctx)
+        {
+            while (ctx.L.GetChar())
+            {
+                if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9')
+                {
+                    ctx.L.string_buffer.Append((char)ctx.L.input_char);
+                    continue;
+                }
+
+                if (ctx.L.input_char == ' ' ||
+                    ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r')
+                {
+                    ctx.Return = true;
+                    ctx.NextState = 1;
+                    return true;
+                }
+
+                switch (ctx.L.input_char)
+                {
+                    case ',':
+                    case ']':
+                    case '}':
+                        ctx.L.UngetChar();
+                        ctx.Return = true;
+                        ctx.NextState = 1;
+                        return true;
+
+                    default:
+                        return false;
+                }
+            }
+
+            return true;
+        }
+
+        private static bool State9(FsmContext ctx)
+        {
+            ctx.L.GetChar();
+
+            switch (ctx.L.input_char)
+            {
+                case 'r':
+                    ctx.NextState = 10;
+                    return true;
+
+                default:
+                    return false;
+            }
+        }
+
+        private static bool State10(FsmContext ctx)
+        {
+            ctx.L.GetChar();
+
+            switch (ctx.L.input_char)
+            {
+                case 'u':
+                    ctx.NextState = 11;
+                    return true;
+
+                default:
+                    return false;
+            }
+        }
+
+        private static bool State11(FsmContext ctx)
+        {
+            ctx.L.GetChar();
+
+            switch (ctx.L.input_char)
+            {
+                case 'e':
+                    ctx.Return = true;
+                    ctx.NextState = 1;
+                    return true;
+
+                default:
+                    return false;
+            }
+        }
+
+        private static bool State12(FsmContext ctx)
+        {
+            ctx.L.GetChar();
+
+            switch (ctx.L.input_char)
+            {
+                case 'a':
+                    ctx.NextState = 13;
+                    return true;
+
+                default:
+                    return false;
+            }
+        }
+
+        private static bool State13(FsmContext ctx)
+        {
+            ctx.L.GetChar();
+
+            switch (ctx.L.input_char)
+            {
+                case 'l':
+                    ctx.NextState = 14;
+                    return true;
+
+                default:
+                    return false;
+            }
+        }
+
+        private static bool State14(FsmContext ctx)
+        {
+            ctx.L.GetChar();
+
+            switch (ctx.L.input_char)
+            {
+                case 's':
+                    ctx.NextState = 15;
+                    return true;
+
+                default:
+                    return false;
+            }
+        }
+
+        private static bool State15(FsmContext ctx)
+        {
+            ctx.L.GetChar();
+
+            switch (ctx.L.input_char)
+            {
+                case 'e':
+                    ctx.Return = true;
+                    ctx.NextState = 1;
+                    return true;
+
+                default:
+                    return false;
+            }
+        }
+
+        private static bool State16(FsmContext ctx)
+        {
+            ctx.L.GetChar();
+
+            switch (ctx.L.input_char)
+            {
+                case 'u':
+                    ctx.NextState = 17;
+                    return true;
+
+                default:
+                    return false;
+            }
+        }
+
+        private static bool State17(FsmContext ctx)
+        {
+            ctx.L.GetChar();
+
+            switch (ctx.L.input_char)
+            {
+                case 'l':
+                    ctx.NextState = 18;
+                    return true;
+
+                default:
+                    return false;
+            }
+        }
+
+        private static bool State18(FsmContext ctx)
+        {
+            ctx.L.GetChar();
+
+            switch (ctx.L.input_char)
+            {
+                case 'l':
+                    ctx.Return = true;
+                    ctx.NextState = 1;
+                    return true;
+
+                default:
+                    return false;
+            }
+        }
+
+        private static bool State19(FsmContext ctx)
+        {
+            while (ctx.L.GetChar())
+            {
+                switch (ctx.L.input_char)
+                {
+                    case '"':
+                        ctx.L.UngetChar();
+                        ctx.Return = true;
+                        ctx.NextState = 20;
+                        return true;
+
+                    case '\\':
+                        ctx.StateStack = 19;
+                        ctx.NextState = 21;
+                        return true;
+
+                    default:
+                        ctx.L.string_buffer.Append((char)ctx.L.input_char);
+                        continue;
+                }
+            }
+
+            return true;
+        }
+
+        private static bool State20(FsmContext ctx)
+        {
+            ctx.L.GetChar();
+
+            switch (ctx.L.input_char)
+            {
+                case '"':
+                    ctx.Return = true;
+                    ctx.NextState = 1;
+                    return true;
+
+                default:
+                    return false;
+            }
+        }
+
+        private static bool State21(FsmContext ctx)
+        {
+            ctx.L.GetChar();
+
+            switch (ctx.L.input_char)
+            {
+                case 'u':
+                    ctx.NextState = 22;
+                    return true;
+
+                case '"':
+                case '\'':
+                case '/':
+                case '\\':
+                case 'b':
+                case 'f':
+                case 'n':
+                case 'r':
+                case 't':
+                    ctx.L.string_buffer.Append(
+                        ProcessEscChar(ctx.L.input_char));
+                    ctx.NextState = ctx.StateStack;
+                    return true;
+
+                default:
+                    return false;
+            }
+        }
+
+        private static bool State22(FsmContext ctx)
+        {
+            int counter = 0;
+            int mult = 4096;
+
+            ctx.L.unichar = 0;
+
+            while (ctx.L.GetChar())
+            {
+
+                if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9' ||
+                    ctx.L.input_char >= 'A' && ctx.L.input_char <= 'F' ||
+                    ctx.L.input_char >= 'a' && ctx.L.input_char <= 'f')
+                {
+
+                    ctx.L.unichar += HexValue(ctx.L.input_char) * mult;
+
+                    counter++;
+                    mult /= 16;
+
+                    if (counter == 4)
+                    {
+                        ctx.L.string_buffer.Append(
+                            Convert.ToChar(ctx.L.unichar));
+                        ctx.NextState = ctx.StateStack;
+                        return true;
+                    }
+
+                    continue;
+                }
+
+                return false;
+            }
+
+            return true;
+        }
+
+        private static bool State23(FsmContext ctx)
+        {
+            while (ctx.L.GetChar())
+            {
+                switch (ctx.L.input_char)
+                {
+                    case '\'':
+                        ctx.L.UngetChar();
+                        ctx.Return = true;
+                        ctx.NextState = 24;
+                        return true;
+
+                    case '\\':
+                        ctx.StateStack = 23;
+                        ctx.NextState = 21;
+                        return true;
+
+                    default:
+                        ctx.L.string_buffer.Append((char)ctx.L.input_char);
+                        continue;
+                }
+            }
+
+            return true;
+        }
+
+        private static bool State24(FsmContext ctx)
+        {
+            ctx.L.GetChar();
+
+            switch (ctx.L.input_char)
+            {
+                case '\'':
+                    ctx.L.input_char = '"';
+                    ctx.Return = true;
+                    ctx.NextState = 1;
+                    return true;
+
+                default:
+                    return false;
+            }
+        }
+
+        private static bool State25(FsmContext ctx)
+        {
+            ctx.L.GetChar();
+
+            switch (ctx.L.input_char)
+            {
+                case '*':
+                    ctx.NextState = 27;
+                    return true;
+
+                case '/':
+                    ctx.NextState = 26;
+                    return true;
+
+                default:
+                    return false;
+            }
+        }
+
+        private static bool State26(FsmContext ctx)
+        {
+            while (ctx.L.GetChar())
+            {
+                if (ctx.L.input_char == '\n')
+                {
+                    ctx.NextState = 1;
+                    return true;
+                }
+            }
+
+            return true;
+        }
+
+        private static bool State27(FsmContext ctx)
+        {
+            while (ctx.L.GetChar())
+            {
+                if (ctx.L.input_char == '*')
+                {
+                    ctx.NextState = 28;
+                    return true;
+                }
+            }
+
+            return true;
+        }
+
+        private static bool State28(FsmContext ctx)
+        {
+            while (ctx.L.GetChar())
+            {
+                if (ctx.L.input_char == '*')
+                    continue;
+
+                if (ctx.L.input_char == '/')
+                {
+                    ctx.NextState = 1;
+                    return true;
+                }
+
+                ctx.NextState = 27;
+                return true;
+            }
+
+            return true;
+        }
+        #endregion
+
+
+        private bool GetChar()
+        {
+            if ((input_char = NextChar()) != -1)
+                return true;
+
+            end_of_input = true;
+            return false;
+        }
+
+        private int NextChar()
+        {
+            if (input_buffer != 0)
+            {
+                int tmp = input_buffer;
+                input_buffer = 0;
+
+                return tmp;
+            }
+
+            return reader.Read();
+        }
+
+        public bool NextToken()
+        {
+            StateHandler handler;
+            fsm_context.Return = false;
+
+            while (true)
+            {
+                handler = fsm_handler_table[state - 1];
+
+                if (!handler(fsm_context))
+                    throw new JsonException(input_char);
+
+                if (end_of_input)
+                    return false;
+
+                if (fsm_context.Return)
+                {
+                    string_value = string_buffer.ToString();
+                    string_buffer.Remove(0, string_buffer.Length);
+                    token = fsm_return_table[state - 1];
+
+                    if (token == (int)ParserToken.Char)
+                        token = input_char;
+
+                    state = fsm_context.NextState;
+
+                    return true;
+                }
+
+                state = fsm_context.NextState;
+            }
+        }
+
+        private void UngetChar()
+        {
+            input_buffer = input_char;
+        }
+    }
+}
diff --git a/O&Z_Obfuscator/LitJson/LitJSON.csproj b/O&Z_Obfuscator/LitJson/LitJSON.csproj
new file mode 100644
index 0000000..73a77ff
--- /dev/null
+++ b/O&Z_Obfuscator/LitJson/LitJSON.csproj
@@ -0,0 +1,61 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFrameworks>netstandard2.1;netstandard2.0;net45;netstandard1.5;net40;net35;net20;net6.0</TargetFrameworks>
+  </PropertyGroup>
+
+  <PropertyGroup>
+    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
+    <DebugType>embedded</DebugType>
+    <EmbedUntrackedSources>true</EmbedUntrackedSources>
+    <PublishRepositoryUrl>true</PublishRepositoryUrl>
+    <SourceLinkCreate Condition="'$(OS)' == 'Windows_NT'">true</SourceLinkCreate>
+  </PropertyGroup>
+
+  <ItemGroup Condition="'$(OS)' == 'Windows_NT'">
+    <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
+    <DotNetCliToolReference Include="dotnet-sourcelink-git" Version="2.8.3" />
+    <DotNetCliToolReference Include="dotnet-sourcelink" Version="2.8.3" />
+  </ItemGroup>
+
+  <PropertyGroup>
+    <PackageId>LitJson</PackageId>
+    <Description>A .Net library to handle conversions from and to JSON (JavaScript Object Notation) strings. Written in C#, and it’s intended to be small, fast and easy to use.
+It's quick and lean, without external dependencies.</Description>
+    <Copyright>The authors disclaim copyright to this source code.</Copyright>
+    <Authors>Leonardo Boshell, Mattias Karlsson and contributors</Authors>
+    <Company>Leonardo Boshell, Mattias Karlsson and contributors</Company>
+    <PackageLicenseExpression>Unlicense</PackageLicenseExpression>
+    <PackageIcon>litjson.png</PackageIcon>
+    <RepositoryUrl>https://github.com/LitJSON/litjson</RepositoryUrl>
+    <RepositoryType>git</RepositoryType>
+    <PackageTags>JSON;Serializer</PackageTags>
+    <IncludeSource>true</IncludeSource>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <None Include="litjson.png" Pack="true" PackagePath="" />
+  </ItemGroup>
+
+  <PropertyGroup Condition="'$(TargetFramework)' == 'net20' ">
+    <DefineConstants>$(DefineConstants);LEGACY</DefineConstants>
+    <FrameworkPathOverride Condition="'$(TargetFramework)' == 'net20' and '$(OS)' == 'Windows_NT'">C:\Windows\Microsoft.NET\Framework\v2.0.50727</FrameworkPathOverride>
+  </PropertyGroup>
+
+  <PropertyGroup Condition="'$(TargetFramework)' == 'net35' ">
+    <DefineConstants>$(DefineConstants);LEGACY</DefineConstants>
+    <FrameworkPathOverride Condition="'$(TargetFramework)' == 'net35' and '$(OS)' == 'Windows_NT'">C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v3.5\Profile\Client</FrameworkPathOverride>
+  </PropertyGroup>
+
+  <PropertyGroup Condition="'$(TargetFramework)' == 'net40' ">
+    <DefineConstants>$(DefineConstants);LEGACY</DefineConstants>
+  </PropertyGroup>
+
+  <ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.5' ">
+    <PackageReference Include="System.Collections.NonGeneric" Version="4.0.1" />
+    <PackageReference Include="System.Collections.Specialized" Version="4.0.1" />
+    <PackageReference Include="System.Reflection" Version="4.3.0" />
+    <PackageReference Include="System.Reflection.TypeExtensions" Version="4.1.0" />
+  </ItemGroup>
+
+</Project>
diff --git a/O&Z_Obfuscator/LitJson/Netstandard15Polyfill.cs b/O&Z_Obfuscator/LitJson/Netstandard15Polyfill.cs
new file mode 100644
index 0000000..55b02a2
--- /dev/null
+++ b/O&Z_Obfuscator/LitJson/Netstandard15Polyfill.cs
@@ -0,0 +1,24 @@
+#if NETSTANDARD1_5
+using System;
+using System.Reflection;
+namespace LitJson
+{
+    internal static class Netstandard15Polyfill
+    {
+        internal static Type GetInterface(this Type type, string name)
+        {
+            return type.GetTypeInfo().GetInterface(name); 
+        }
+
+        internal static bool IsClass(this Type type)
+        {
+            return type.GetTypeInfo().IsClass;
+        }
+
+        internal static bool IsEnum(this Type type)
+        {
+            return type.GetTypeInfo().IsEnum;
+        }
+    }
+}
+#endif
\ No newline at end of file
diff --git a/O&Z_Obfuscator/LitJson/ParserToken.cs b/O&Z_Obfuscator/LitJson/ParserToken.cs
new file mode 100644
index 0000000..0dabea2
--- /dev/null
+++ b/O&Z_Obfuscator/LitJson/ParserToken.cs
@@ -0,0 +1,45 @@
+#region Header
+
+#endregion
+
+
+/**
+* ParserToken.cs
+*   Internal representation of the tokens used by the lexer and the parser.
+*
+* The authors disclaim copyright to this source code. For more details, see
+* the COPYING file included with this distribution.
+**/
+namespace O_Z_IL2CPP_Security.LitJson
+{
+    internal enum ParserToken
+    {
+        // Lexer tokens (see section A.1.1. of the manual)
+        None = char.MaxValue + 1,
+        Number,
+        True,
+        False,
+        Null,
+        CharSeq,
+        // Single char
+        Char,
+
+        // Parser Rules (see section A.2.1 of the manual)
+        Text,
+        Object,
+        ObjectPrime,
+        Pair,
+        PairRest,
+        Array,
+        ArrayPrime,
+        Value,
+        ValueRest,
+        String,
+
+        // End of input
+        End,
+
+        // The empty rule
+        Epsilon
+    }
+}
diff --git a/O&Z_Obfuscator/LitJson/litjson.png b/O&Z_Obfuscator/LitJson/litjson.png
new file mode 100644
index 0000000..a4c15e5
Binary files /dev/null and b/O&Z_Obfuscator/LitJson/litjson.png differ
diff --git a/O&Z_Obfuscator/OZ_Obfuscator.csproj b/O&Z_Obfuscator/OZ_Obfuscator.csproj
index 8e73c3b..ecc4aa6 100644
--- a/O&Z_Obfuscator/OZ_Obfuscator.csproj
+++ b/O&Z_Obfuscator/OZ_Obfuscator.csproj
@@ -71,9 +71,20 @@
   </ItemGroup>
   <ItemGroup>
     <Compile Include="AssemblyLoader.cs" />
+    <Compile Include="LitJson\IJsonWrapper.cs" />
+    <Compile Include="LitJson\JsonData.cs" />
+    <Compile Include="LitJson\JsonException.cs" />
+    <Compile Include="LitJson\JsonMapper.cs" />
+    <Compile Include="LitJson\JsonMockWrapper.cs" />
+    <Compile Include="LitJson\JsonReader.cs" />
+    <Compile Include="LitJson\JsonWriter.cs" />
+    <Compile Include="LitJson\Lexer.cs" />
+    <Compile Include="LitJson\Netstandard15Polyfill.cs" />
+    <Compile Include="LitJson\ParserToken.cs" />
     <Compile Include="Ofbuscators\ControlFlow.cs" />
     <Compile Include="Ofbuscators\Antide4dot.cs" />
     <Compile Include="Ofbuscators\LocalVariables2Field.cs" />
+    <Compile Include="Ofbuscators\ObfusFunc.cs" />
     <Compile Include="Runtime\Num2Modle.cs" />
     <Compile Include="Ofbuscators\NumObfus.cs" />
     <Compile Include="Program.cs" />
@@ -89,5 +100,12 @@
       <Install>false</Install>
     </BootstrapperPackage>
   </ItemGroup>
+  <ItemGroup>
+    <None Include="LitJson\AssemblyInfo.cs.in" />
+    <None Include="LitJson\LitJSON.csproj" />
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="LitJson\litjson.png" />
+  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
 </Project>
\ No newline at end of file
diff --git a/O&Z_Obfuscator/Ofbuscators/ObfusFunc.cs b/O&Z_Obfuscator/Ofbuscators/ObfusFunc.cs
new file mode 100644
index 0000000..0442df3
--- /dev/null
+++ b/O&Z_Obfuscator/Ofbuscators/ObfusFunc.cs
@@ -0,0 +1,90 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using dnlib.DotNet;
+using dnlib.DotNet.Emit;
+using O_Z_IL2CPP_Security.LitJson;
+using OZ_Obfus;
+
+namespace OZ_Obfuscator.Ofbuscators
+{
+    public class ObfusFunc
+    {
+        ModuleDefMD module;
+        List<string> ignoreMethod = new List<string>();
+        List<string> ignoreField = new List<string>();
+        List<string> obfusClass = new List<string>();
+        public ObfusFunc(ModuleDefMD module)
+        {
+            this.module = module;
+            if(!File.Exists("keyfunc.json"))
+            {
+                Console.ForegroundColor = ConsoleColor.Red;
+                Console.WriteLine("keyfunc.json not found!");
+                Console.ForegroundColor = ConsoleColor.Yellow;
+                Console.WriteLine("正在重新生成默认keyfunc.json...");
+                Console.WriteLine("如果您不想使用默认keyfunc.json,请重新配置keyfunc.json");
+                Console.ForegroundColor = ConsoleColor.White;
+                File.WriteAllBytes("keyfunc.json", Convert.FromBase64String(ignore.origin));
+            }
+            ignore ig = JsonMapper.ToObject<ignore>(File.ReadAllText("keyfunc.json"));
+            foreach (var item in ig.ignoreMethod)
+                ignoreMethod.Add(item.ToLower());
+            foreach (var item in ig.ignoreField)
+                ignoreField.Add(item.ToLower());
+            foreach(var item in ig.customignoreMethod)
+                ignoreMethod.Add(item.ToLower());
+            foreach (var item in ig.customignoreField)
+                ignoreField.Add(item.ToLower());
+            foreach (var item in ig.customignoreClass)
+                obfusClass.Add(item.ToLower());
+        }
+        public void Excute()
+        {
+            foreach (var type in module.Types.Where(x => !(x.Name.StartsWith("<"))))
+            {
+                foreach (var field in type.Fields.Where(x => !x.IsRuntimeSpecialName && !x.IsSpecialName
+                && !(x.Name.StartsWith("<"))))
+                {
+                    if (ignoreField.FirstOrDefault(x => field.FullName.ToLower().Contains(x)) == null)
+                        NameGenerator.SetObfusName(field, NameGenerator.Mode.FuncName, 3);
+                }
+                foreach (var method in type.Methods.Where(x => !x.IsConstructor && !x.IsVirtual
+                && !x.IsRuntime && !x.IsRuntimeSpecialName && !x.IsAbstract
+                && !((x.GenericParameters != null) && x.GenericParameters.Count > 0) && !(x.Overrides.Count > 0)
+                && !(x.Name.StartsWith("<") || x.Name.ToLower().StartsWith("do"))))
+                {
+                    if (ignoreMethod.FirstOrDefault(x => method.FullName.ToLower().Contains(x)) == null)
+                        NameGenerator.SetObfusName(method, NameGenerator.Mode.FuncName, 5);
+                    if (method.HasParams())
+                    {
+                        foreach (var p in method.Parameters)
+                        {
+                            p.Name = NameGenerator.GetName(NameGenerator.Mode.FuncName, 4);
+                        }
+                    }
+                }
+                foreach (var p in type.Properties.Where(x => !x.IsRuntimeSpecialName && !x.IsSpecialName))
+                    NameGenerator.SetObfusName(p, NameGenerator.Mode.Base64, 5);
+                //NameGenerator.SetObfusName(type, NameGenerator.Mode.FuncName, 6);
+
+                if (obfusClass.FirstOrDefault(x => type.FullName.ToLower().Contains(x)) != null)
+                {
+                    NameGenerator.SetObfusName(type, NameGenerator.Mode.FuncName, 6);
+                }
+            }
+        }
+    }
+    public class ignore
+    {
+        public string[] ignoreMethod;
+        public string[] ignoreField;
+        public string[] customignoreMethod;
+        public string[] customignoreField;
+        public string[] customignoreClass;
+        public static string origin = "ewogICAgImlnbm9yZU1ldGhvZCI6IFsKICAgICAgICAiQXdha2UiLAogICAgICAgICJPbkVuYWJsZSIsCiAgICAgICAgIlN0YXJ0IiwKICAgICAgICAiRml4ZWRVcGRhdGUiLAogICAgICAgICJVcGRhdGUiLAogICAgICAgICJPbkRpc2FibGUiLAogICAgICAgICJMYXRlVXBkYXRlIiwKICAgICAgICAiUmVzZXQiLAogICAgICAgICJPblZhbGlkYXRlIiwKICAgICAgICAiRml4ZWRVcGRhdGUiLAogICAgICAgICJPblRyaWdnZXJFbnRlciIsCiAgICAgICAgIk9uVHJpZ2dlckVudGVyMkQiLAogICAgICAgICJPblRyaWdnZXJFeGl0IiwKICAgICAgICAiT25UcmlnZ2VyRXhpdDJEIiwKICAgICAgICAiT25UcmlnZ2VyU3RheTJEIiwKICAgICAgICAiT25Db2xsaXNpb25FbnRlciIsCiAgICAgICAgIk9uQ29sbGlzaW9uRW50ZXIyRCIsCiAgICAgICAgIk9uQ29sbGlzaW9uRXhpdCIsCiAgICAgICAgIk9uQ29sbGlzaW9uRXhpdDJEIiwKICAgICAgICAiT25Db2xsaXNpb25TdGF5IiwKICAgICAgICAiT25Db2xsaXNpb25TdGF5MkQiLAogICAgICAgICJPbk1vdXNlRG93biIsCiAgICAgICAgIk9uTW91c2VEcmFnIiwKICAgICAgICAiT25Nb3VzZUVudGVyIiwKICAgICAgICAiT25Nb3VzZUV4aXQiLAogICAgICAgICJPbk1vdXNlT3ZlciIsCiAgICAgICAgIk9uTW91c2VVcCIsCiAgICAgICAgIk9uTW91c2VVcEFzQnV0dG9uIiwKICAgICAgICAiT25QcmVDdWxsIiwKICAgICAgICAiT25CZWNhbWVWaXNpYmxlIiwKICAgICAgICAiT25CZWNhbWVJbnZpc2libGUiLAogICAgICAgICJPbldpbGxSZW5kZXJPYmplY3QiLAogICAgICAgICJPblByZVJlbmRlciIsCiAgICAgICAgIk9uUmVuZGVyT2JqZWN0IiwKICAgICAgICAiT25Qb3N0UmVuZGVyIiwKICAgICAgICAiT25SZW5kZXJJbWFnZSIsCiAgICAgICAgIk9uR1VJIiwKICAgICAgICAiT25EcmF3R2l6bW9zIiwKICAgICAgICAiT25EcmF3R2l6bW9zU2VsZWN0ZWQiLAogICAgICAgICJPbkFwcGxpY2F0aW9uRm9jdXMiLAogICAgICAgICJPbkFwcGxpY2F0aW9uUGF1c2UiLAogICAgICAgICJPbkFwcGxpY2F0aW9uUXVpdCIsCiAgICAgICAgIk9uRGlzYWJsZSIsCiAgICAgICAgIk9uRGVzdG9yeSIsCiAgICAgICAgIk9uTGV2ZWxXYXNMb2FkZWQiLAogICAgICAgICJPbkFuaW1hdG9ySUsiLAogICAgICAgICJPbkFuaW1hdG9yTW92ZSIsCiAgICAgICAgIk9uQXBwbGljYXRpb25Gb2N1cyIsCiAgICAgICAgIk9uQXBwbGljYXRpb25QYXVzZSIsCiAgICAgICAgIk9uQXBwbGljYXRpb25RdWl0IiwKICAgICAgICAiT25BdWRpb0ZpbHRlclJlYWQiLAogICAgICAgICJPbkJlY2FtZUludmlzaWJsZSIsCiAgICAgICAgIk9uQmVjYW1lVmlzaWJsZSIsCiAgICAgICAgIk9uQ29ubmVjdGVkVG9TZXJ2ZXIiLAogICAgICAgICJPbkNvbnRyb2xsZXJDb2xsaWRlckhpdCIsCiAgICAgICAgIk9uRW5hYmxlIiwKICAgICAgICAiT25GYWlsZWRUb0Nvbm5lY3QiLAogICAgICAgICJPbkRpc2Nvbm5lY3RlZEZyb21TZXJ2ZXIiLAogICAgICAgICJPbkRyYXdHaXptb3MiLAogICAgICAgICJPbkRyYXdHaXptb3NTZWxlY3RlZCIsCiAgICAgICAgIk9uRW5hYmxlIiwKICAgICAgICAiT25GYWlsZWRUb0Nvbm5lY3QiLAogICAgICAgICJPbkZhaWxlZFRvQ29ubmVjdFRvTWFzdGVyU2VydmVyIiwKICAgICAgICAiT25Kb2ludEJyZWFrIiwKICAgICAgICAiT25Kb2ludEJyZWFrMkQiLAogICAgICAgICJPbk1hc3RlclNlcnZlckV2ZW50IiwKICAgICAgICAiT25OZXR3b3JrSW5zdGFudGlhdGUiLAogICAgICAgICJPblBhcnRpY2xlQ29sbGlzaW9uIiwKICAgICAgICAiT25QYXJ0aWNsZVN5c3RlbVN0b3BwZWQiLAogICAgICAgICJPblBhcnRpY2xlVHJpZ2dlciIsCiAgICAgICAgIk9uUGFydGljbGVVcGRhdGVKb2JTY2hlZHVsZWQiLAogICAgICAgICJPblBsYXllckNvbm5lY3RlZCIsCiAgICAgICAgIk9uUGxheWVyRGlzY29ubmVjdGVkIiwKICAgICAgICAiT25Qb3N0UmVuZGVyIiwKICAgICAgICAiT25QcmVDdWxsIiwKICAgICAgICAiT25QcmVSZW5kZXIiLAogICAgICAgICJPblJlbmRlckltYWdlIiwKICAgICAgICAiT25SZW5kZXJPYmplY3QiLAogICAgICAgICJPblNlcmlhbGl6ZU5ldHdvcmtWaWV3IiwKICAgICAgICAiT25TZXJ2ZXJJbml0aWFsaXplZCIsCiAgICAgICAgIk9uVHJhbnNmb3JtQ2hpbGRyZW5DaGFuZ2VkIiwKICAgICAgICAiT25UcmFuc2Zvcm1QYXJlbnRDaGFuZ2VkIiwKICAgICAgICAiT25WYWxpZGF0ZSIsCiAgICAgICAgIk9uV2lsbFJlbmRlck9iamVjdCIsCiAgICAgICAgIlJlc2V0IiwKICAgICAgICAiX18iLAogICAgICAgICJpbmNvbnRyb2wiLAogICAgICAgICJzdG9wIiwKICAgICAgICAib3B0aW9uIiwKICAgICAgICAicGF1c2VtYW5hZ2VyIiwKICAgICAgICAiZmFsbGluZ3JvY2siLAogICAgICAgICJwb3N0Zml4IiwKICAgICAgICAicHJlZml4IiwKICAgICAgICAidHJhbnNwaWxlciIKICAgIF0sCiAgICAiaWdub3JlRmllbGQiOlsKICAgICAgICAiaW5jb250cm9sIiwKICAgICAgICAiZW51bSIsCiAgICAgICAgIm9wdGlvbmFsIiwKICAgICAgICAiX18iCiAgICBdLAogICAgIi8vIjoi5Lul5LiK5Li66buY6K6k5b+955Wl5YiX6KGo77yM6buY6K6k5YyF5ZCr5YWo6YOo55qEVW5pdHnlhbPplK7mlrnms5XvvIzlu7rorq7kuI3opoHkv67mlLnvvIzku6XkuIvkuLroh6rlrprkuYnlv73nlaXliJfooajvvIzlj6/ku6XmoLnmja7pnIDopoHoh6rooYzmt7vliqAo5aaC5p6c6ZyA6KaB55So5Yiw5Y+N5bCE5oiW6ICF5Yqo5oCB6LCD55So55qE5pa55rOV77yM5bu66K6u5re75Yqg5Yiw6L+Z6YeMKSkiLAoKICAgICIvLyI6IuWFs+S6juWmguS9leaYr+S9v+eUqOiHquWumuS5ieW/veeVpeWIl+ihqO+8jOi/memHjOacieWHoOeCueW7uuiuriIsCiAgICAiLy8iOiIxLuWcqFVuaXR55Lit77yMR2FtZU9iamVjdOaIluiAhXByZWZhYnPliJ3lp4vnu5HlrprkuobohJrmnKzvvIzliJnor6XohJrmnKznmoTnsbvlkI3kuI3lj6/mt7fmt4bvvIzmlrnms5XlkI3lkozlrZfmrrXlkI3lj6/ku6Xmt7fmt4YiLAogICAgIi8vIjoiMi7lnKhVbml0eeS4re+8jEdhbWVPYmplY3TmiJbogIVwcmVmYWJz5Yid5aeL5rKh5pyJ57uR5a6a6ISa5pys77yM5L2G5piv5Zyo5Luj56CB5Lit5Yqo5oCB5re75Yqg5LqG6ISa5pys77yM5YiZ6K+l6ISa5pys55qE57G75ZCN44CB5pa55rOV5ZCN5ZKM5a2X5q615ZCN6YO95Y+v5Lul5re35reGIiwKICAgICIvLyI6IjMu5aaC5p6c6K+l6ISa5pys5Lit5raJ5Y+K5Yiw5LqGVUnnmoTkuovku7blk43lupQo5aaCQnV0dG9uLk9uQ2xpY2spLOWImeivpeiEmuacrOeahOexu+WQjeWSjOivpeaWueazleWQjemDveS4jeWPr+a3t+a3hizlrZfmrrXlkI3lj6/ku6Xmt7fmt4YiLAogICAgIi8vIjoiNC5Vbml0eeeahOeUn+WRveWRqOacn+aWueazleWSjOWbnuiwg+aWueazleS4jeiDvea3t+a3hizkuIrmlrnnmoTlv73nlaXliJfooajljIXlkKvkuoblpKflpJrmlbDluLjnlKjnmoTnlJ/lkb3lkajmnJ/lkozlm57osIPmlrnms5XvvIzlpoLmnpzmnInpgZfmvI/vvIzlj6/ku6Xoh6rooYzmt7vliqAiLAogICAgIi8vIjoiNS5Vbml0eeS4reeahEludm9rZeetieeJueauiuaWueazleaJgOiwg+eUqOeahOWHveaVsOaWueazleS4jeWPr+a3t+a3hizlkIznkIbljY/nqIvnsbvnmoTmlrnms5XkuZ/kuI3lj6/mt7fmt4Ys6K+36Ieq6KGM5re75Yqg5Yiw6Ieq5a6a5LmJ5b+955Wl5YiX6KGoIiwKICAgICIvLyI6IjYu6YOo5YiG5raJ5Y+K5Y+N5bCE57G755qE5Luj56CB5LiN6IO95re35reGLOWmglN5c3RlbS5SZWZsZWN0aW9uKEdldEZpZWxkLEdldE1ldGhvZCxJbnZva2XnrYkpLOivt+iHquihjOa3u+WKoOWIsOiHquWumuS5ieW/veeVpeWIl+ihqCIsCiAgICAiLy8iOiI3Lk5hdGl2ZeWxgumHjOebtOaOpeiwg+eUqEMj5oiW6YCa6L+HVW5pdHnlhoXnva5BUEnlj5HpgIHkuovku7bliLBDI+eahOexu+WSjOaWueazleS4jeWPr+a3t+a3hijlpKflpJrmlbDlnKjnp7vliqjlubPlj7DkuK0pIiwKICAgICIvLyI6Ijgu5LiA5Lqb54m55q6K5o+S5Lu25a+55bqU55qE6ISa5pys5LiN5Y+v5re35reG77yM5L6L5aaCeEx1YeWSjOS4juS5i+e7keWumueahEMj6ISa5pysIiwKCiAgICAKICAgICIvLyI6IuWvueS6juaWueazleWQjeeahOa3t+a3humHh+eUqOeahOaYr+eZveWQjeWNleaooeW8j++8jOWNs+m7mOiupOa3t+a3hu+8jOWmguaenOS4jemcgOimgea3t+a3hu+8jOWPr+S7pea3u+WKoOWIsOi/memHjCIsCiAgICAiY3VzdG9taWdub3JlTWV0aG9kIjpbCiAgICBdLAogICAgIi8vIjoi5a+55LqO5a2X5q615ZCN55qE5re35reG6YeH55So55qE5piv55m95ZCN5Y2V5qih5byP77yM5Y2z6buY6K6k5re35reG77yM5aaC5p6c5LiN6ZyA6KaB5re35reG77yM5Y+v5Lul5re75Yqg5Yiw6L+Z6YeMIiwKICAgICJjdXN0b21pZ25vcmVGaWVsZCI6WwogICAgXSwKICAgICIvLyI6IuWvueS6juexu+WQjeeahOa3t+a3humHh+eUqOeahOaYr+m7keWQjeWNleaooeW8j++8jOWNs+m7mOiupOS4jea3t+a3hu+8jOWmguaenOmcgOimgea3t+a3hu+8jOWPr+S7pea3u+WKoOWIsOi/memHjCIsCiAgICAiY3VzdG9taWdub3JlQ2xhc3MiOlsKICAgIF0KfQ==";
+    }
+}
diff --git a/O&Z_Obfuscator/Program.cs b/O&Z_Obfuscator/Program.cs
index 36c7140..1de5e04 100644
--- a/O&Z_Obfuscator/Program.cs
+++ b/O&Z_Obfuscator/Program.cs
@@ -15,6 +15,12 @@ class Program
     {
         static void Main(string[] args)
         {
+            AssemblyLoader loader = new AssemblyLoader("C:\\Users\\22864\\Desktop\\END_AUTO V2\\END_Data\\Managed\\Assembly-CSharp.dll.bak");
+            ObfusFunc obfusFunc = new ObfusFunc(loader.Module);
+            obfusFunc.Excute();
+            loader.Save();
+            Console.ReadKey();
+            /*
             AssemblyLoader loader;
             if (args.Length > 0)
             {
@@ -61,6 +67,7 @@ static void Main(string[] args)
                 Console.WriteLine("Press any key to exit...");
                 Console.ReadKey();
             }
+            */
         }
         void printfinstr(ModuleDefMD Module)
         {
diff --git a/O&Z_Obfuscator/README.md b/O&Z_Obfuscator/README.md
index 414e884..8aebdd5 100644
--- a/O&Z_Obfuscator/README.md
+++ b/O&Z_Obfuscator/README.md
@@ -10,11 +10,7 @@
    O&Z_IL2CPP_Security.exe input MonoObfus
    ~~~
 3. Enjoy Safe! xD
-4. ~~您也可以直接使用命令行来操作加密你的NET程序集(*不仅是Unity Script,而是任何NET程序集!*)~~
-
-   (此功能已删除,目前已经将主程序合并到O&Z_IL2CPP_Security.exe中)
-   
-   ![Usage](img/usage.png)
+4. 如果你想使用ObfusFunc参数来获取更加强大的混淆,请仔细阅 **读加密参数说明-ObfusFunc** 中的条例
 
 ## 加密参数说明
  - ControlFlow(控制流程加密)
@@ -37,4 +33,27 @@
    使用本方法加密您游戏内的字符串常量,每一个字符串都单独对应一个单独和密码和单独的解密函数,使破解难度上升
    ![Stringobfus](img/strobfus.png)
 
-   
+ - ObfusFunc(类&方法&字段混淆)
+
+   使用本方法加密您项目中所有的函数,类,甚至是参数,使程序的不可读性达到最高(我们采用了Unity函数名堆积作为字典,使得这种方法混淆的函数难以被反混淆器识别为Obfuscated或JunkFunc)
+
+   ![ObfusFunc](img/funcobfus.png)
+   ### 使用方法以及注意事项
+   1. 您需要配置 **keyfunc.json**,来完成本程序对于您项目的适配
+   ![KeyFunc](img/keyfunc.png)
+   2. 在配置keyfunc.json中,我们已经预先配置好了Unity中的大部分生命周期函数以及关键回调,这些都将会作为skip的部分跳过混淆
+   3. 我们为您提供了三种可以自定义的部分,用于适配您的程序
+       - 忽略的方法(customignoreMethod): **此项采用白名单的模式**,如果您不需要混淆某个方法或者某个方法不能被混淆(例如使用了反射),可以将方法名称添加到这里
+       - 忽略的字段(customignoreField): **此项采用白名单的模式**,如果您不需要混淆某个字段或者某个字段不能被混淆(例如使用了反射),可以将字段名称添加到这里
+       - 需要混淆的类(customignoreClass): **此项采用白名单的模式**,因为涉及到Unity预制体的影响,类名一般来说不能够轻易混淆(*详细原因见下方*),如果你需要混淆某个类名,可以将类名添加到这里
+   4. **需要注意的事项**
+       - 在Unity中,GameObject或者prefabs初始绑定了脚本,则该脚本的类名不可混淆,方法名和字段名可以混淆
+       - 在Unity中,GameObject或者prefabs初始没有绑定脚本,但是在代码中动态添加了脚本,则该脚本的类名、方法名和字段名都可以混淆 
+       - 如果该脚本中涉及到了UI的事件响应(如Button.OnClick),则该脚本的类名和该方法名都不可混淆,字段名可以混淆
+       - Unity的生命周期方法和回调方法不能混淆,上方的忽略列表包含了大多数常用的生命周期和回调方法,如果有遗漏,可以自行添加
+       - Unity中的Invoke等特殊方法所调用的函数方法不可混淆,同理协程类的方法也不可混淆,请自行添加到自定义忽略列表
+       - 部分涉及反射类的代码不能混淆,如System.Reflection(GetField,GetMethod,Invoke等),请自行添加到自定义忽略列表
+       - Native层里直接调用C#或通过Unity内置API发送事件到C#的类和方法不可混淆(大多数在移动平台中)
+       - 一些特殊插件对应的脚本不可混淆,例如xLua和与之绑定的C#脚本
+       - 你可以将一些关键的方法(例如涉及到*游戏内购,广告的接入,游戏全局管理控制,游戏资源的管理,游戏本地化保存,与服务器云交互*等等)写到一个不涉及Unity预制体或者UI事件等情况的专用的脚本中,并对该脚本的类进行混淆
+    5. 正确的配置好keyfunc,可以最大程度为您的游戏带来安全,谢谢您的使用!如果有任何问题,欢迎联系作者QQ,添加讨论群或者在issue提出
diff --git a/O&Z_Obfuscator/img/config.png b/O&Z_Obfuscator/img/config.png
index 8d272cf..2b8486d 100644
Binary files a/O&Z_Obfuscator/img/config.png and b/O&Z_Obfuscator/img/config.png differ
diff --git a/O&Z_Obfuscator/img/funcobfus.png b/O&Z_Obfuscator/img/funcobfus.png
new file mode 100644
index 0000000..b66e39e
Binary files /dev/null and b/O&Z_Obfuscator/img/funcobfus.png differ
diff --git a/O&Z_Obfuscator/img/keyfunc.png b/O&Z_Obfuscator/img/keyfunc.png
new file mode 100644
index 0000000..1a8f3f4
Binary files /dev/null and b/O&Z_Obfuscator/img/keyfunc.png differ
diff --git a/O&Z_Obfuscator/utils.cs b/O&Z_Obfuscator/utils.cs
index 9a0b886..a8d7ada 100644
--- a/O&Z_Obfuscator/utils.cs
+++ b/O&Z_Obfuscator/utils.cs
@@ -8,7 +8,7 @@
 using System.Security.Cryptography;
 using System.Text;
 using System.Threading.Tasks;
-
+using O_Z_IL2CPP_Security.LitJson;
 namespace OZ_Obfus
 {
     public static class Extensions
@@ -211,7 +211,6 @@ public static string GenertateRandomFuncName()
 {
             return FuncNames[RandomGenerator.Generate(FuncNames.Length)];
         }
-
         public static string[] FuncNames =
         {
             "Awake","Start","Updata","FixedUpdata",
@@ -225,9 +224,11 @@ public static string GenertateRandomFuncName()
             "OnGUI","OnJointBreak","OnLevelWasLoaded","OnMouseDown","OnMouseDrag","OnMouseEnter",
             "OnMouseExit","OnMouseOver","OnMouseUp","OnPostRender","OnPreCull","OnPreRender",
             "OnRenderImage","OnRenderObject","OnSerializeNetworkView","OnServerInitialized",
-            "OnTriggerEnter","OnTriggerExit","OnTriggerStay"
+            "OnTriggerEnter","OnTriggerExit","OnTriggerStay","Reset","OnTransformParentChanged",
+            "OnPreCull","OnJointBreak","OnApplicationQuit","OnDestory","OnDisable","OnAnimatorIK",
+            "OnAnimatorMove","OnApplicationQuit","OnEnable","OnParticleTrigger","OnParticleUpdateJobScheduled",
+            "OnPlayerConnected","OnPostRender","__"
         };
-        
         public const string ERROR = ";̥͓̠̙̠̺̫̱̹̮͈͈͓͍̟̻͆ͧ͒ͩͨ̉ͯ̂̈̉̽̉͑̔̊́͟͜;̢̧͔͓͉̝̆̒ͣͣ̄ͣ̊̈́̎̓͛̇͆ͯͪ̿͟;ͫͭ͒̉̐͑̀҉̭̭͕̟͇̰̺͖͎̗̰̩͉;̸̛̘̬̫̫͔̜͙̣̯̠̯̻͍̰͍̥͓ͦ̎ͯͯ͂ͤ̉̃̊͐̐̽͜;̵̧̂͐̉̆́̚̚҉̜̦̳͇͍;̙͈̞̪̖͚̬͍͙̹ͭ̿͒ͧͧͨ̀;͐̇̋̍̿̎̀͌ͣ͌҉ ̞̙̘̱͟͠_̍̽̋̑͒ͧ̌͐̿͞͡҉̯̣̥̹̗̫̥̩͈̘͟ͅͅ_̈͛̈͊̈́ͥͬ̌ͪ̃̽͑̓͋͛̆̈͋̽҉̸̛̠̝̜͈̮͢_͒͂̋̈́͋̉͒ͦ̊ͯ̐̾̂̐҉҉̧̯̜̣̮̦̱̦̖̗͡_̧̨̹̳̘̯̱͖͙̘̍ͥ͊͌̌ͧͥ̍ͨ̐͡_̵̺̮̞̖̰͔̮̺̳͖̳̳̥͖͖͊͐͛ͥͪ͛͑͠ͅ_ͧ̓ ̴̡̪͎̣̘̳̤̬͔̟̺̳̻̥͇ͧͫ̽͐̄ͤ̎̔_̸̠̪̺͕̩̮̹̦͇̫͙͖̦̻̏̈́̅ͦ͐_̴̸̢͚̤͙͓̱̬̫̝̞̣̥̽͛͊ͥͬ̍͆ͨ͑͋̍͊ͭ͗́ͅ^̵͖̖̹̦͎̦̜͋̉͋͐̈́ͪ̋̊̄́͘͟ ̨͚͙͖̫͚̙̊̏̍̐ͥ̅̏̎͆͗ͧ́̚͞!̧͕͈͕͙̱̟̆ͭ͋ͫ̕͢͞;̛̣̭̖̹̜̘̮̜̭͓̰̫͙͋̏ͯͤ̂ͬ͗ͥ̌ͥ̓ͮͪ͗́͞ͅ;̪̳̼̱̽ͨ͋͛̔ͪͬ̃͌̂̌͐̀ͧͬ̾ͨ̚̚;̛͍̘̗̣͉͓̘͖͙̪͙̦͇̩͈ͩ͋̄̓ͣ́̃ͦͫ͒̑͋̃ͣͥ̋̀;̢͚̰͈͍ͮͤͣ͂̆͋ͨ̀̐̕͞͞ͅ;̨̢̬̹̯̯̤͕͍̺̩̫͈͉̙̪̪̜̻͚̂͋̏̓͛ͣ͟;̥̖̭͕͔̝͇̞̠̰͐̿̆ͣ̈͟͡;̵̸̻̫͔̼͚̤͇̝̞̬̞͚͇̓̐͆̾ͭ̈́ͫ̈́́͜͞;̌ͨ͌̐̉̂̃̅̃̋ͤͤͣͯ҉̧̹̗̺̹͈̙͇̦̣ͅ;̸̫̙͈̫̮̻͎̱͓̗̍&a_̈͛̈͊̈́ͥͬ̌ͪ̃̽͑̓͋͛̆̈͋̽҉̸̛̠̝̜͈̮͢_͒&‮‮‮‮‮‮‮‮‮‮‮";
 
 
diff --git a/README.md b/README.md
index 26cc689..ed4da60 100644
--- a/README.md
+++ b/README.md
@@ -5,25 +5,21 @@ O&Z Protector 是由 **Z1029[QQ:3408708525]** **和[oRangeSumMer](https://space.
 
 ***本程序基于[Net6.0](https://dotnet.microsoft.com/zh-cn/download/dotnet/6.0) & [NETFramework4.8](https://dotnet.microsoft.com/zh-cn/download/dotnet-framework/net48)开发,运行需要[Net6.0](https://dotnet.microsoft.com/zh-cn/download/dotnet/6.0) & [NETFramework4.8](https://dotnet.microsoft.com/zh-cn/download/dotnet-framework/net48)环境,请确保您的PC正确安装了NET Runtime或者NET SDK***
 
-## >>>[O&Z-IL2CPP(Click me!)](/O%26Z_IL2CPP_Security/README.md)<<<
+## >>>[O&Z-IL2CPP(Click me!)](O%26Z_IL2CPP_Security/README.md)<<<
 
-## >>>[O&Z-MonoObfuscator(Click me!)](/O%26Z_Obfuscator/README.md)<<<
+## >>>[O&Z-MonoObfuscator(Click me!)](O%26Z_Obfuscator/README.md)<<<
 
 ## What's New
-1. 我们正式完成了O&Z MonoObfuscator的编写并且在此次更新中release!
-2. **修复了MonoObfuscate 功能使用过程中无法对路径中含有空格的程序集使用**
-
-   目前实现的功能:
-- 字符串加密
-- 常量预设值加密
-- 流程混淆(ControlFlow)
-- 局部变量转为Feild
-- . . . . ([更多](/O%26Z_IL2CPP_Security/README.md))
+1. **修复了MonoObfuscate 功能使用过程中无法对路径中含有空格的程序集使用**
+2. 在MonoObfuscate功能中,我们添加了对类,方法,字段名的混淆是的代码的不可读性和破解难度上升到了最高,而且此方法可以兼容Unity(需要自定义配置keyfunc.json文件)!
+   ![obfusfunc](O%26Z_Obfuscator/img/funcobfus.png)
 
 ## 预告
 1. UI窗口界面即将完成!
 2. 正在测试对于所有unity版本il2cpp的支持,自动生成libil2cpp
-3. 我们正在编写O&ZMonoObfus的函数与方法名称的混淆
+3. ~~我们正在编写O&ZMonoObfus的函数与方法名称的混淆~~
+4. 我们准备重写Mono虚拟机,在底层对Unity Mono的JIT,AOT等进行加密
+5. 我们正在尝试对于IL2CPP生成方式中,在生成IL代码时,插入MonoObfuscate的功能,使得IL2CPP获得最佳保险
 
 ## 未来的规划
 1. 对AssetBundle资源进行加密