private SourceFile(ApkFile apk, JarFile jar, ISpySettings settings, MapFile mapFile, string singleFilePath = null) { this.apk = apk; this.jar = jar; this.settings = settings; this.mapFile = mapFile; this.singleFilePath = singleFilePath; #if DEBUG classLoader = new AssemblyClassLoader(module.OnClassLoaded); var modParams = new ModuleParameters { AssemblyResolver = new AssemblyResolver(new[] { Frameworks.Instance.FirstOrDefault().Folder }, classLoader, module.OnAssemblyLoaded), Kind = ModuleKind.Dll }; assembly = AssemblyDefinition.CreateAssembly(new AssemblyNameDefinition("spy", Version.Parse("1.0.0.0")), "main", modParams); classLoader.LoadAssembly(assembly); var dot42Assembly = modParams.AssemblyResolver.Resolve("dot42"); // Force loading of classes if (jar != null) { foreach (var fileName in jar.ClassFileNames) { OpenClass(fileName); } } #endif }
private SourceFile(IApkFile apk, JarFile jar, ISpySettings settings, MapFileLookup mapFile, string singleFilePath = null) { this.apk = apk; this.jar = jar; this.settings = settings; this.mapFile = mapFile; this.singleFilePath = singleFilePath; #if DEBUG || ENABLE_SHOW_AST classLoader = new AssemblyClassLoader(module.OnClassLoaded); var modParams = new ModuleParameters { AssemblyResolver = new AssemblyResolver(new[] { Frameworks.Instance.FirstOrDefault().Folder }, classLoader, module.OnAssemblyLoaded), Kind = ModuleKind.Dll }; assembly = AssemblyDefinition.CreateAssembly(new AssemblyNameDefinition("spy", Version.Parse("1.0.0.0")), "main", modParams); classLoader.LoadAssembly(assembly); var dot42Assembly = modParams.AssemblyResolver.Resolve("dot42"); // Force loading of classes if (jar != null) { foreach (var fileName in jar.ClassFileNames) { OpenClass(fileName); } } #endif }
private static AssemblyDefinition AssemblyDefinitionFor(Assembly assembly) { var name = assembly.GetName(); var moduleParams = new ModuleParameters { Kind = ModuleKind.Dll, AssemblyResolver = new AppDomainAssemblyResolver() }; var assembly_definition = AssemblyDefinition.CreateAssembly( new AssemblyNameDefinition(name.Name, name.Version), assembly.ManifestModule.Name, moduleParams); assembly_definition.MainModule.Runtime = TargetRuntime.Net_4_0; return(assembly_definition); }
public AssemblyEmitter(CompilerArguments compilerArgs, Version version = null) { if (version == null) { version = new Version(0, 0, 0, 0); } var assemblyName = new AssemblyNameDefinition(Path.GetFileNameWithoutExtension(compilerArgs.OutputPath), version); var moduleParameters = new ModuleParameters() { Kind = compilerArgs.ModuleKind, Runtime = TargetRuntime.Net_4_0 }; assemblyDefinition = AssemblyDefinition.CreateAssembly(assemblyName, Path.GetFileName(compilerArgs.OutputPath), moduleParameters); AssemblyRegistry.RegisterAssembly(assemblyDefinition); outputPath = compilerArgs.OutputPath; DebugBuild = compilerArgs.DebugBuild; functorUsageMap = new Dictionary <TypeReference, bool>(); }
static void CreateModule() { var parameters = new ModuleParameters() { Kind = ModuleKind.Dll, ReflectionImporterProvider = MMReflectionImporter.Provider }; using var module = ModuleDefinition.CreateModule(name, parameters); var attr = Mono.Cecil.TypeAttributes.Public | Mono.Cecil.TypeAttributes.Abstract | Mono.Cecil.TypeAttributes.Sealed | Mono.Cecil.TypeAttributes.Class; var typedef = new TypeDefinition("", name, attr) { BaseType = module.TypeSystem.Object }; module.Types.Add(typedef); typedef.Fields.Add(new FieldDefinition( "state", Mono.Cecil.FieldAttributes.Public | Mono.Cecil.FieldAttributes.Static, module.ImportReference(typeof(Dictionary <MethodBase, byte[]>)) )); var versionFieldDef = new FieldDefinition( "version", Mono.Cecil.FieldAttributes.Public | Mono.Cecil.FieldAttributes.Static, module.ImportReference(typeof(int)) ) { Constant = internalVersion }; typedef.Fields.Add(versionFieldDef); _ = ReflectionHelper.Load(module); }
public DiscordRichPresenceModule([Import("ModuleParameters")] ModuleParameters moduleParameters) : base(moduleParameters) { ModuleInstance = this; }
public Gerald([Import("ModuleParameters")] ModuleParameters moduleParameters) : base(moduleParameters) { }
public UniversalSearchModule([Import("ModuleParameters")] ModuleParameters moduleParameters) : base(moduleParameters) { ModuleInstance = this; }
public ExtendedBuildStorage([Import("ModuleParameters")] ModuleParameters moduleParameters) : base(moduleParameters) { ModuleInstance = this; }
public static int Main(string[] args) { Console.WriteLine("===Cpp2IL by Samboy063==="); Console.WriteLine("A Tool to Reverse Unity's \"il2cpp\" Build Process."); Console.WriteLine("Running on " + Environment.OSVersion.Platform); #region Command Line Parsing CommandLineOptions = null; Parser.Default.ParseArguments <Options>(args).WithParsed(options => { CommandLineOptions = options; }); if (CommandLineOptions == null) { Console.WriteLine("Invalid command line. Exiting."); return(1); } if (!CheckForceOptionsAreValid()) { Console.WriteLine("Read the help."); return(1); } int[] unityVerUseful; string assemblyPath; string metadataPath; if (CommandLineOptions.ForcedBinaryPath == null) { var baseGamePath = CommandLineOptions.GamePath; Console.WriteLine("Using path: " + baseGamePath); if (!Directory.Exists(baseGamePath)) { Console.WriteLine("Specified game-path does not exist: " + baseGamePath); return(2); } assemblyPath = Path.Combine(baseGamePath, "GameAssembly.dll"); var exeName = Path.GetFileNameWithoutExtension(Directory.GetFiles(baseGamePath) .First(f => f.EndsWith(".exe") && !BlacklistedExecutableFilenames.Any(bl => f.EndsWith(bl)))); if (CommandLineOptions.ExeName != null) { exeName = CommandLineOptions.ExeName; Console.WriteLine($"Using OVERRIDDEN game name: {exeName}"); } else { Console.WriteLine($"Auto-detected game name: {exeName}"); } var unityPlayerPath = Path.Combine(baseGamePath, $"{exeName}.exe"); metadataPath = Path.Combine(baseGamePath, $"{exeName}_Data", "il2cpp_data", "Metadata", "global-metadata.dat"); if (!File.Exists(assemblyPath) || !File.Exists(unityPlayerPath) || !File.Exists(metadataPath)) { Console.WriteLine("Invalid game-path or exe-name specified. Failed to find one of the following:\n" + $"\t{assemblyPath}\n" + $"\t{unityPlayerPath}\n" + $"\t{metadataPath}\n"); return(2); } #endregion Console.WriteLine($"Located game EXE: {unityPlayerPath}"); Console.WriteLine($"Located global-metadata: {metadataPath}"); #region Unity Version Determination Console.WriteLine("\nAttempting to determine Unity version..."); if (Environment.OSVersion.Platform == PlatformID.Win32NT) { var unityVer = FileVersionInfo.GetVersionInfo(unityPlayerPath); unityVerUseful = new[] { unityVer.FileMajorPart, unityVer.FileMinorPart, unityVer.FileBuildPart }; } else { //Globalgamemanagers var globalgamemanagersPath = Path.Combine(baseGamePath, $"{exeName}_Data", "globalgamemanagers"); var ggmBytes = File.ReadAllBytes(globalgamemanagersPath); var verString = new StringBuilder(); var idx = 0x14; while (ggmBytes[idx] != 0) { verString.Append(Convert.ToChar(ggmBytes[idx])); idx++; } var unityVer = verString.ToString(); unityVer = unityVer.Substring(0, unityVer.IndexOf("f", StringComparison.Ordinal)); Console.WriteLine("Read version string from globalgamemanagers: " + unityVer); unityVerUseful = unityVer.Split(".").Select(int.Parse).ToArray(); } Console.WriteLine("This game is built with Unity version " + string.Join(".", unityVerUseful)); if (unityVerUseful[0] <= 4) { Console.WriteLine("Unable to determine a valid unity version. Aborting."); return(1); } #endregion } else { Console.WriteLine("Warning: Using force options, I sure hope you know what you're doing!"); assemblyPath = CommandLineOptions.ForcedBinaryPath !; metadataPath = CommandLineOptions.ForcedMetadataPath !; unityVerUseful = CommandLineOptions.ForcedUnityVersion !.Split('.').Select(int.Parse).ToArray(); } //Set this flag from command line options LibCpp2IlMain.Settings.AllowManualMetadataAndCodeRegInput = !CommandLineOptions.DisableRegistrationPrompts; //Disable Method Ptr Mapping and Global Resolving if skipping analysis LibCpp2IlMain.Settings.DisableMethodPointerMapping = LibCpp2IlMain.Settings.DisableGlobalResolving = CommandLineOptions.SkipAnalysis; if (!LibCpp2IlMain.LoadFromFile(assemblyPath, metadataPath, unityVerUseful)) { Console.WriteLine("Initialization with LibCpp2IL failed."); return(1); } //Dump DLLs #region Assembly Generation var resolver = new RegistryAssemblyResolver(); var moduleParams = new ModuleParameters { Kind = ModuleKind.Dll, AssemblyResolver = resolver, MetadataResolver = new MetadataResolver(resolver) }; Console.WriteLine("Building assemblies..."); Console.WriteLine("\tPass 1: Creating empty types..."); Assemblies = AssemblyBuilder.CreateAssemblies(LibCpp2IlMain.TheMetadata !, resolver, moduleParams); Utils.BuildPrimitiveMappings(); Console.WriteLine("\tPass 2: Setting parents and handling inheritance..."); //Stateful method, no return value AssemblyBuilder.ConfigureHierarchy(LibCpp2IlMain.TheMetadata, LibCpp2IlMain.ThePe !); Console.WriteLine("\tPass 3: Populating types..."); var methods = new List <(TypeDefinition type, List <CppMethodData> methods)>(); //Create out dirs if needed var outputPath = Path.GetFullPath("cpp2il_out"); if (!Directory.Exists(outputPath)) { Directory.CreateDirectory(outputPath); } var methodOutputDir = Path.Combine(outputPath, "types"); if (!(CommandLineOptions.SkipAnalysis && CommandLineOptions.SkipMetadataTextFiles) && !Directory.Exists(methodOutputDir)) { Directory.CreateDirectory(methodOutputDir); } for (var imageIndex = 0; imageIndex < LibCpp2IlMain.TheMetadata.imageDefinitions.Length; imageIndex++) { var imageDef = LibCpp2IlMain.TheMetadata.imageDefinitions[imageIndex]; Console.WriteLine($"\t\tPopulating {imageDef.typeCount} types in assembly {imageIndex + 1} of {LibCpp2IlMain.TheMetadata.imageDefinitions.Length}: {imageDef.Name}..."); var assemblySpecificPath = Path.Combine(methodOutputDir, imageDef.Name.Replace(".dll", "")); if (!(CommandLineOptions.SkipMetadataTextFiles && CommandLineOptions.SkipAnalysis) && !Directory.Exists(assemblySpecificPath)) { Directory.CreateDirectory(assemblySpecificPath); } methods.AddRange(AssemblyBuilder.ProcessAssemblyTypes(LibCpp2IlMain.TheMetadata, LibCpp2IlMain.ThePe, imageDef)); } //Invert dict for CppToMono SharedState.UnmanagedToManagedTypes = SharedState.MonoToCppTypeDefs.ToDictionary(i => i.Value, i => i.Key); Console.WriteLine("\tPass 4: Applying type, method, and field attributes..."); #region Attributes var unityEngineAssembly = Assemblies.Find(x => x.MainModule.Types.Any(t => t.Namespace == "UnityEngine" && t.Name == "SerializeField")); if (unityEngineAssembly != null) { foreach (var imageDef in LibCpp2IlMain.TheMetadata.imageDefinitions) { //Cache these per-module. var attributeCtorsByClassIndex = new Dictionary <long, MethodReference>(); var lastTypeIndex = imageDef.firstTypeIndex + imageDef.typeCount; for (var typeIndex = imageDef.firstTypeIndex; typeIndex < lastTypeIndex; typeIndex++) { var typeDef = LibCpp2IlMain.TheMetadata.typeDefs[typeIndex]; var typeDefinition = SharedState.UnmanagedToManagedTypes[typeDef !];
public DummyAssemblyGenerator(Il2CppExecutor il2CppExecutor, bool addToken) { executor = il2CppExecutor; metadata = il2CppExecutor.metadata; il2Cpp = il2CppExecutor.il2Cpp; //Il2CppDummyDll var il2CppDummyDll = Il2CppDummyDll.Create(); Assemblies.Add(il2CppDummyDll); var addressAttribute = il2CppDummyDll.MainModule.Types.First(x => x.Name == "AddressAttribute").Methods[0]; var fieldOffsetAttribute = il2CppDummyDll.MainModule.Types.First(x => x.Name == "FieldOffsetAttribute").Methods[0]; attributeAttribute = il2CppDummyDll.MainModule.Types.First(x => x.Name == "AttributeAttribute").Methods[0]; var metadataOffsetAttribute = il2CppDummyDll.MainModule.Types.First(x => x.Name == "MetadataOffsetAttribute").Methods[0]; var tokenAttribute = il2CppDummyDll.MainModule.Types.First(x => x.Name == "TokenAttribute").Methods[0]; stringType = il2CppDummyDll.MainModule.TypeSystem.String; var resolver = new MyAssemblyResolver(); var moduleParameters = new ModuleParameters { Kind = ModuleKind.Dll, AssemblyResolver = resolver }; resolver.Register(il2CppDummyDll); var parameterDefinitionDic = new Dictionary <int, ParameterDefinition>(); var eventDefinitionDic = new Dictionary <int, EventDefinition>(); //创建程序集,同时创建所有类 foreach (var imageDef in metadata.imageDefs) { var imageName = metadata.GetStringFromIndex(imageDef.nameIndex); var aname = metadata.assemblyDefs[imageDef.assemblyIndex].aname; var assemblyName = metadata.GetStringFromIndex(aname.nameIndex); Version vers; if (aname.build >= 0) { vers = new Version(aname.major, aname.minor, aname.build, aname.revision); } else { //__Generated vers = new Version(3, 7, 1, 6); } var assemblyNameDef = new AssemblyNameDefinition(assemblyName, vers); /*assemblyNameDef.Culture = metadata.GetStringFromIndex(aname.cultureIndex); * assemblyNameDef.PublicKey = Encoding.UTF8.GetBytes(metadata.GetStringFromIndex(aname.publicKeyIndex)); * assemblyNameDef.HashAlgorithm = (AssemblyHashAlgorithm)aname.hash_alg; * assemblyNameDef.Attributes = (AssemblyAttributes)aname.flags; * assemblyNameDef.PublicKeyToken = aname.public_key_token;*/ var assemblyDefinition = AssemblyDefinition.CreateAssembly(assemblyNameDef, imageName, moduleParameters); resolver.Register(assemblyDefinition); Assemblies.Add(assemblyDefinition); var moduleDefinition = assemblyDefinition.MainModule; moduleDefinition.Types.Clear();//清除自动创建的<Module>类 var typeEnd = imageDef.typeStart + imageDef.typeCount; for (var index = imageDef.typeStart; index < typeEnd; ++index) { var typeDef = metadata.typeDefs[index]; var namespaceName = metadata.GetStringFromIndex(typeDef.namespaceIndex); var typeName = metadata.GetStringFromIndex(typeDef.nameIndex); var typeDefinition = new TypeDefinition(namespaceName, typeName, (TypeAttributes)typeDef.flags); typeDefinitionDic.Add(typeDef, typeDefinition); if (typeDef.declaringTypeIndex == -1) { moduleDefinition.Types.Add(typeDefinition); } } } foreach (var imageDef in metadata.imageDefs) { var typeEnd = imageDef.typeStart + imageDef.typeCount; for (var index = imageDef.typeStart; index < typeEnd; ++index) { var typeDef = metadata.typeDefs[index]; var typeDefinition = typeDefinitionDic[typeDef]; //nestedtype for (int i = 0; i < typeDef.nested_type_count; i++) { var nestedIndex = metadata.nestedTypeIndices[typeDef.nestedTypesStart + i]; var nestedTypeDef = metadata.typeDefs[nestedIndex]; var nestedTypeDefinition = typeDefinitionDic[nestedTypeDef]; typeDefinition.NestedTypes.Add(nestedTypeDefinition); } } } //提前处理 foreach (var imageDef in metadata.imageDefs) { var typeEnd = imageDef.typeStart + imageDef.typeCount; for (var index = imageDef.typeStart; index < typeEnd; ++index) { var typeDef = metadata.typeDefs[index]; var typeDefinition = typeDefinitionDic[typeDef]; if (addToken) { var customTokenAttribute = new CustomAttribute(typeDefinition.Module.ImportReference(tokenAttribute)); customTokenAttribute.Fields.Add(new CustomAttributeNamedArgument("Token", new CustomAttributeArgument(stringType, $"0x{typeDef.token:X}"))); typeDefinition.CustomAttributes.Add(customTokenAttribute); } //genericParameter if (typeDef.genericContainerIndex >= 0) { var genericContainer = metadata.genericContainers[typeDef.genericContainerIndex]; for (int i = 0; i < genericContainer.type_argc; i++) { var genericParameterIndex = genericContainer.genericParameterStart + i; var param = metadata.genericParameters[genericParameterIndex]; var genericParameter = CreateGenericParameter(param, typeDefinition); typeDefinition.GenericParameters.Add(genericParameter); } } //parent if (typeDef.parentIndex >= 0) { var parentType = il2Cpp.types[typeDef.parentIndex]; var parentTypeRef = GetTypeReference(typeDefinition, parentType); typeDefinition.BaseType = parentTypeRef; } //interfaces for (int i = 0; i < typeDef.interfaces_count; i++) { var interfaceType = il2Cpp.types[metadata.interfaceIndices[typeDef.interfacesStart + i]]; var interfaceTypeRef = GetTypeReference(typeDefinition, interfaceType); typeDefinition.Interfaces.Add(new InterfaceImplementation(interfaceTypeRef)); } } } //处理field, method, property等等 foreach (var imageDef in metadata.imageDefs) { var imageName = metadata.GetStringFromIndex(imageDef.nameIndex); var typeEnd = imageDef.typeStart + imageDef.typeCount; for (int index = imageDef.typeStart; index < typeEnd; index++) { var typeDef = metadata.typeDefs[index]; var typeDefinition = typeDefinitionDic[typeDef]; //field var fieldEnd = typeDef.fieldStart + typeDef.field_count; for (var i = typeDef.fieldStart; i < fieldEnd; ++i) { var fieldDef = metadata.fieldDefs[i]; var fieldType = il2Cpp.types[fieldDef.typeIndex]; var fieldName = metadata.GetStringFromIndex(fieldDef.nameIndex); var fieldTypeRef = GetTypeReference(typeDefinition, fieldType); var fieldDefinition = new FieldDefinition(fieldName, (FieldAttributes)fieldType.attrs, fieldTypeRef); typeDefinition.Fields.Add(fieldDefinition); fieldDefinitionDic.Add(i, fieldDefinition); if (addToken) { var customTokenAttribute = new CustomAttribute(typeDefinition.Module.ImportReference(tokenAttribute)); customTokenAttribute.Fields.Add(new CustomAttributeNamedArgument("Token", new CustomAttributeArgument(stringType, $"0x{fieldDef.token:X}"))); fieldDefinition.CustomAttributes.Add(customTokenAttribute); } //fieldDefault if (metadata.GetFieldDefaultValueFromIndex(i, out var fieldDefault) && fieldDefault.dataIndex != -1) { if (executor.TryGetDefaultValue(fieldDefault.typeIndex, fieldDefault.dataIndex, out var value)) { fieldDefinition.Constant = value; } else { var customAttribute = new CustomAttribute(typeDefinition.Module.ImportReference(metadataOffsetAttribute)); var offset = new CustomAttributeNamedArgument("Offset", new CustomAttributeArgument(stringType, $"0x{value:X}")); customAttribute.Fields.Add(offset); fieldDefinition.CustomAttributes.Add(customAttribute); } } //fieldOffset if (!fieldDefinition.IsLiteral) { var fieldOffset = il2Cpp.GetFieldOffsetFromIndex(index, i - typeDef.fieldStart, i, typeDefinition.IsValueType, fieldDefinition.IsStatic); if (fieldOffset >= 0) { var customAttribute = new CustomAttribute(typeDefinition.Module.ImportReference(fieldOffsetAttribute)); var offset = new CustomAttributeNamedArgument("Offset", new CustomAttributeArgument(stringType, $"0x{fieldOffset:X}")); customAttribute.Fields.Add(offset); fieldDefinition.CustomAttributes.Add(customAttribute); } } } //method var methodEnd = typeDef.methodStart + typeDef.method_count; for (var i = typeDef.methodStart; i < methodEnd; ++i) { var methodDef = metadata.methodDefs[i]; var methodName = metadata.GetStringFromIndex(methodDef.nameIndex); var methodDefinition = new MethodDefinition(methodName, (MethodAttributes)methodDef.flags, typeDefinition.Module.ImportReference(typeof(void))); methodDefinition.ImplAttributes = (MethodImplAttributes)methodDef.iflags; typeDefinition.Methods.Add(methodDefinition); //genericParameter if (methodDef.genericContainerIndex >= 0) { var genericContainer = metadata.genericContainers[methodDef.genericContainerIndex]; for (int j = 0; j < genericContainer.type_argc; j++) { var genericParameterIndex = genericContainer.genericParameterStart + j; var param = metadata.genericParameters[genericParameterIndex]; var genericParameter = CreateGenericParameter(param, methodDefinition); methodDefinition.GenericParameters.Add(genericParameter); } } var methodReturnType = il2Cpp.types[methodDef.returnType]; var returnType = GetTypeReferenceWithByRef(methodDefinition, methodReturnType); methodDefinition.ReturnType = returnType; if (addToken) { var customTokenAttribute = new CustomAttribute(typeDefinition.Module.ImportReference(tokenAttribute)); customTokenAttribute.Fields.Add(new CustomAttributeNamedArgument("Token", new CustomAttributeArgument(stringType, $"0x{methodDef.token:X}"))); methodDefinition.CustomAttributes.Add(customTokenAttribute); } if (methodDefinition.HasBody && typeDefinition.BaseType?.FullName != "System.MulticastDelegate") { var ilprocessor = methodDefinition.Body.GetILProcessor(); if (returnType.FullName == "System.Void") { ilprocessor.Append(ilprocessor.Create(OpCodes.Ret)); } else if (returnType.IsValueType) { var variable = new VariableDefinition(returnType); methodDefinition.Body.Variables.Add(variable); ilprocessor.Append(ilprocessor.Create(OpCodes.Ldloca_S, variable)); ilprocessor.Append(ilprocessor.Create(OpCodes.Initobj, returnType)); ilprocessor.Append(ilprocessor.Create(OpCodes.Ldloc_0)); ilprocessor.Append(ilprocessor.Create(OpCodes.Ret)); } else { ilprocessor.Append(ilprocessor.Create(OpCodes.Ldnull)); ilprocessor.Append(ilprocessor.Create(OpCodes.Ret)); } } methodDefinitionDic.Add(i, methodDefinition); //method parameter for (var j = 0; j < methodDef.parameterCount; ++j) { var parameterDef = metadata.parameterDefs[methodDef.parameterStart + j]; var parameterName = metadata.GetStringFromIndex(parameterDef.nameIndex); var parameterType = il2Cpp.types[parameterDef.typeIndex]; var parameterTypeRef = GetTypeReferenceWithByRef(methodDefinition, parameterType); var parameterDefinition = new ParameterDefinition(parameterName, (ParameterAttributes)parameterType.attrs, parameterTypeRef); methodDefinition.Parameters.Add(parameterDefinition); parameterDefinitionDic.Add(methodDef.parameterStart + j, parameterDefinition); //ParameterDefault if (metadata.GetParameterDefaultValueFromIndex(methodDef.parameterStart + j, out var parameterDefault) && parameterDefault.dataIndex != -1) { if (executor.TryGetDefaultValue(parameterDefault.typeIndex, parameterDefault.dataIndex, out var value)) { parameterDefinition.Constant = value; } else { var customAttribute = new CustomAttribute(typeDefinition.Module.ImportReference(metadataOffsetAttribute)); var offset = new CustomAttributeNamedArgument("Offset", new CustomAttributeArgument(stringType, $"0x{value:X}")); customAttribute.Fields.Add(offset); parameterDefinition.CustomAttributes.Add(customAttribute); } } } //methodAddress if (!methodDefinition.IsAbstract) { var methodPointer = il2Cpp.GetMethodPointer(imageName, methodDef); if (methodPointer > 0) { var customAttribute = new CustomAttribute(typeDefinition.Module.ImportReference(addressAttribute)); var fixedMethodPointer = il2Cpp.GetRVA(methodPointer); var rva = new CustomAttributeNamedArgument("RVA", new CustomAttributeArgument(stringType, $"0x{fixedMethodPointer:X}")); var offset = new CustomAttributeNamedArgument("Offset", new CustomAttributeArgument(stringType, $"0x{il2Cpp.MapVATR(methodPointer):X}")); var va = new CustomAttributeNamedArgument("VA", new CustomAttributeArgument(stringType, $"0x{methodPointer:X}")); customAttribute.Fields.Add(rva); customAttribute.Fields.Add(offset); customAttribute.Fields.Add(va); if (methodDef.slot != ushort.MaxValue) { var slot = new CustomAttributeNamedArgument("Slot", new CustomAttributeArgument(stringType, methodDef.slot.ToString())); customAttribute.Fields.Add(slot); } methodDefinition.CustomAttributes.Add(customAttribute); } } } //property var propertyEnd = typeDef.propertyStart + typeDef.property_count; for (var i = typeDef.propertyStart; i < propertyEnd; ++i) { var propertyDef = metadata.propertyDefs[i]; var propertyName = metadata.GetStringFromIndex(propertyDef.nameIndex); TypeReference propertyType = null; MethodDefinition GetMethod = null; MethodDefinition SetMethod = null; if (propertyDef.get >= 0) { GetMethod = methodDefinitionDic[typeDef.methodStart + propertyDef.get]; propertyType = GetMethod.ReturnType; } if (propertyDef.set >= 0) { SetMethod = methodDefinitionDic[typeDef.methodStart + propertyDef.set]; if (propertyType == null) { propertyType = SetMethod.Parameters[0].ParameterType; } } var propertyDefinition = new PropertyDefinition(propertyName, (PropertyAttributes)propertyDef.attrs, propertyType) { GetMethod = GetMethod, SetMethod = SetMethod }; typeDefinition.Properties.Add(propertyDefinition); propertyDefinitionDic.Add(i, propertyDefinition); if (addToken) { var customTokenAttribute = new CustomAttribute(typeDefinition.Module.ImportReference(tokenAttribute)); customTokenAttribute.Fields.Add(new CustomAttributeNamedArgument("Token", new CustomAttributeArgument(stringType, $"0x{propertyDef.token:X}"))); propertyDefinition.CustomAttributes.Add(customTokenAttribute); } } //event var eventEnd = typeDef.eventStart + typeDef.event_count; for (var i = typeDef.eventStart; i < eventEnd; ++i) { var eventDef = metadata.eventDefs[i]; var eventName = metadata.GetStringFromIndex(eventDef.nameIndex); var eventType = il2Cpp.types[eventDef.typeIndex]; var eventTypeRef = GetTypeReference(typeDefinition, eventType); var eventDefinition = new EventDefinition(eventName, (EventAttributes)eventType.attrs, eventTypeRef); if (eventDef.add >= 0) { eventDefinition.AddMethod = methodDefinitionDic[typeDef.methodStart + eventDef.add]; } if (eventDef.remove >= 0) { eventDefinition.RemoveMethod = methodDefinitionDic[typeDef.methodStart + eventDef.remove]; } if (eventDef.raise >= 0) { eventDefinition.InvokeMethod = methodDefinitionDic[typeDef.methodStart + eventDef.raise]; } typeDefinition.Events.Add(eventDefinition); eventDefinitionDic.Add(i, eventDefinition); if (addToken) { var customTokenAttribute = new CustomAttribute(typeDefinition.Module.ImportReference(tokenAttribute)); customTokenAttribute.Fields.Add(new CustomAttributeNamedArgument("Token", new CustomAttributeArgument(stringType, $"0x{eventDef.token:X}"))); eventDefinition.CustomAttributes.Add(customTokenAttribute); } } } } //第三遍,添加CustomAttribute if (il2Cpp.Version > 20) { foreach (var imageDef in metadata.imageDefs) { var typeEnd = imageDef.typeStart + imageDef.typeCount; for (int index = imageDef.typeStart; index < typeEnd; index++) { var typeDef = metadata.typeDefs[index]; var typeDefinition = typeDefinitionDic[typeDef]; //typeAttribute CreateCustomAttribute(imageDef, typeDef.customAttributeIndex, typeDef.token, typeDefinition.Module, typeDefinition.CustomAttributes); //field var fieldEnd = typeDef.fieldStart + typeDef.field_count; for (var i = typeDef.fieldStart; i < fieldEnd; ++i) { var fieldDef = metadata.fieldDefs[i]; var fieldDefinition = fieldDefinitionDic[i]; //fieldAttribute CreateCustomAttribute(imageDef, fieldDef.customAttributeIndex, fieldDef.token, typeDefinition.Module, fieldDefinition.CustomAttributes); } //method var methodEnd = typeDef.methodStart + typeDef.method_count; for (var i = typeDef.methodStart; i < methodEnd; ++i) { var methodDef = metadata.methodDefs[i]; var methodDefinition = methodDefinitionDic[i]; //methodAttribute CreateCustomAttribute(imageDef, methodDef.customAttributeIndex, methodDef.token, typeDefinition.Module, methodDefinition.CustomAttributes); //method parameter for (var j = 0; j < methodDef.parameterCount; ++j) { var parameterDef = metadata.parameterDefs[methodDef.parameterStart + j]; var parameterDefinition = parameterDefinitionDic[methodDef.parameterStart + j]; //parameterAttribute CreateCustomAttribute(imageDef, parameterDef.customAttributeIndex, parameterDef.token, typeDefinition.Module, parameterDefinition.CustomAttributes); } } //property var propertyEnd = typeDef.propertyStart + typeDef.property_count; for (var i = typeDef.propertyStart; i < propertyEnd; ++i) { var propertyDef = metadata.propertyDefs[i]; var propertyDefinition = propertyDefinitionDic[i]; //propertyAttribute CreateCustomAttribute(imageDef, propertyDef.customAttributeIndex, propertyDef.token, typeDefinition.Module, propertyDefinition.CustomAttributes); } //event var eventEnd = typeDef.eventStart + typeDef.event_count; for (var i = typeDef.eventStart; i < eventEnd; ++i) { var eventDef = metadata.eventDefs[i]; var eventDefinition = eventDefinitionDic[i]; //eventAttribute CreateCustomAttribute(imageDef, eventDef.customAttributeIndex, eventDef.token, typeDefinition.Module, eventDefinition.CustomAttributes); } } } } }
public Module([Import("ModuleParameters")] ModuleParameters moduleParameters) : base(moduleParameters) { }
/// <summary> /// Get all of the default properties from the model /// </summary> /// <param name="modelType">The model that we want all of the properties from</param> /// <returns>A set of parameters with their default values</returns> public static IModuleParameters GetParameters(Type modelType) { if (modelType == null) return null; ModuleParameters parameters = new ModuleParameters(); foreach (var property in modelType.GetProperties()) { AddProperties(parameters, property.GetCustomAttributes(true), property.Name, false, property.PropertyType); } foreach (var field in modelType.GetFields()) { AddProperties(parameters, field.GetCustomAttributes(true), field.Name, true, field.FieldType); } return parameters; }
/// <summary> /// Build up the model parameters /// </summary> /// <param name="parameters">The parameter structure we are building</param> /// <param name="attributes">The attributes that we have found</param> private static void AddProperties(ModuleParameters parameters, object[] attributes, string fieldName, bool field, Type t) { foreach (var attribute in attributes) { if (attribute is ParameterAttribute) { var temp = attribute as ParameterAttribute; temp.AttachedToField = field; temp.VariableName = fieldName; parameters.Add(temp, t); } } }
public InteropAssemblyBuilder(AssemblyNameDefinition assemblyName, ModuleParameters moduleParams = null, string targetFramework = null) { Name = assemblyName; Namespace = assemblyName.Name; Statistics = new ReadOnlyDictionary <string, long>(_statistics); if (moduleParams == null) { moduleParams = DefaultModuleParameters; } // ReSharper disable once UnusedVariable var forceUnsafeToLoad = Unsafe.AreSame(ref assemblyName, ref assemblyName); //var loadedAsms = AppDomain.CurrentDomain.GetAssemblies(); //var loadedAsms = AssemblyResolver.KnownAssemblies; var asmResolver = new AssemblyResolver(); //var mdResolver = new MetadataResolver(asmResolver); var shadowAsmFilePath = Path.Combine(Directory.GetCurrentDirectory(), $"{BaseInteropAsmName}.dll"); File.Copy(BaseInteropAsmPath, shadowAsmFilePath); Assembly = AssemblyDefinition.ReadAssembly(shadowAsmFilePath, new ReaderParameters { InMemory = true, ReadWrite = true, ReadingMode = ReadingMode.Immediate, AssemblyResolver = asmResolver, //MetadataResolver = mdResolver, ReadSymbols = false, ApplyWindowsRuntimeProjections = false, //SymbolReaderProvider = null, //MetadataImporterProvider = null, //ReflectionImporterProvider = null, }); Assembly.Name = assemblyName; Module = Assembly.MainModule; ModuleName = $"{Name.Name}.dll"; Module.Name = ModuleName; if (EmitBoundsChecks) { ArgumentOutOfRangeCtor = ArgumentOutOfRangeCtorInfo.Import(Module); } if (EmitNullChecks) { ArgumentNullCtor = ArgumentNullCtorInfo.Import(Module); } NonVersionableAttribute = NonVersionableAttributeInfo? .GetCecilCustomAttribute(Module); FlagsAttribute = FlagsAttributeInfo .GetCecilCustomAttribute(Module); VoidPointerType = Module.TypeSystem.Void.MakePointerType(); MulticastDelegateType = typeof(MulticastDelegate).Import(Module); //var interopAsm = typeof(IHandle<>).Assembly; //var interopAsmName = interopAsm.GetName(); //var interopMod = interopAsm.ManifestModule; //Module.AssemblyReferences.Add(new AssemblyNameReference(interopAsmName.Name, interopAsmName.Version)); //Module.ModuleReferences.Add(new ModuleReference(interopAsmName.Name)); ITypedHandleType = typeof(ITypedHandle).Import(Module); IHandleGtd = typeof(IHandle <>).Import(Module); ITypedHandleGtd = typeof(ITypedHandle <>).Import(Module); HandleInt32Gtd = typeof(HandleInt32 <>).Import(Module); HandleUInt32Gtd = typeof(HandleUInt32 <>).Import(Module); HandleInt64Gtd = typeof(HandleInt64 <>).Import(Module); HandleUInt64Gtd = typeof(HandleUInt64 <>).Import(Module); HandleIntPtrGtd = typeof(HandleIntPtr <>).Import(Module); HandleUIntPtrGtd = typeof(HandleUIntPtr <>).Import(Module); SplitPointerGtd = typeof(SplitPointer <, ,>).Import(Module); BinderGeneratedAttributeType = typeof(BinderGeneratedAttribute).Import(Module); IUnmanagedFunctionPointerGtd = typeof(IUnmanagedFunctionPointer <>).Import(Module); TypeArrayOfSingularVoidPointer = new[] { VoidPointerType }; TypeArrayOfSingularUInt = new[] { Module.TypeSystem.UInt32 }; TypeArrayOfSingularULong = new[] { Module.TypeSystem.UInt64 }; IntegrateInteropTypes(Module.Types); if (targetFramework == null) { targetFramework = DefaultTargetFramework; } var asmCustAttrs = new[] { AttributeInfo.Create (() => new CompilationRelaxationsAttribute(8)), AttributeInfo.Create (() => new RuntimeCompatibilityAttribute { WrapNonExceptionThrows = true }), AttributeInfo.Create (() => new DebuggableAttribute(DebuggableAttribute.DebuggingModes.None)), AttributeInfo.Create (() => new TargetFrameworkAttribute(targetFramework) { FrameworkDisplayName = "" }), AttributeInfo.Create (() => new AssemblyCompanyAttribute("")), AttributeInfo.Create (() => new AssemblyConfigurationAttribute("Release")), AttributeInfo.Create (() => new AssemblyDescriptionAttribute($"Generated {Name.Name} Library")), AttributeInfo.Create (() => new AssemblyFileVersionAttribute(Name.Version.ToString())), AttributeInfo.Create (() => new AssemblyInformationalVersionAttribute(Name.Version.ToString())), AttributeInfo.Create (() => new AssemblyProductAttribute(Name.Name)), AttributeInfo.Create (() => new AssemblyTitleAttribute(Name.Name)), }.Select(ca => ca.GetCecilCustomAttribute(Module)); /* where the hell did this go... * var unverifiableCodeAttributeTypeRef = new TypeReference("System.Security", "UnverifiableCodeAttribute", * Module.TypeSystem.IntPtr.Resolve().Module, * Module.TypeSystem.CoreLibrary, false); * var unverifiableCodeAttributeTypeDef = unverifiableCodeAttributeTypeRef.Resolve(); * var unverifiableCodeAttributeCtor = unverifiableCodeAttributeTypeDef.GetConstructors().Single(); * * var unverifiableCodeAttribute = new CustomAttribute(unverifiableCodeAttributeCtor); */ while (Assembly.HasCustomAttributes) { Assembly.CustomAttributes.RemoveAt(0); } Assembly.CustomAttributes.Clear(); while (Module.HasCustomAttributes) { Module.CustomAttributes.RemoveAt(0); } Module.CustomAttributes.Clear(); foreach (var custAttr in asmCustAttrs) { Assembly.CustomAttributes.Add(custAttr); } //Module.CustomAttributes.Add(unverifiableCodeAttribute); /* * Assembly.SecurityDeclarations.Add(new SecurityDeclaration(SecurityAction.RequestMinimum) { * SecurityAttributes = { * // ... * } * }); * Module.CustomAttributes.Add( * AttributeInfo.Create(() => new UnverifiableCodeAttribute()) * .GetCecilCustomAttribute(Module)); */ MarshalTypeRef = typeof(Marshal).Import(Module); GetDelegateForFpMethodGtd = MarshalTypeRef.Resolve().GetMethods() .First(md => md.Name == "GetDelegateForFunctionPointer" && md.HasGenericParameters) .Import(Module); GetFpForDelegateMethodGtd = MarshalTypeRef.Resolve().GetMethods() .First(md => md.Name == "GetFunctionPointerForDelegate" && md.HasGenericParameters) .Import(Module); }
/// <summary> /// Creates all the Assemblies defined in the provided metadata, along with (stub) definitions of all the types contained therein, and registers them with the resolver. /// </summary> /// <param name="metadata">The Il2Cpp metadata to extract assemblies from</param> /// <param name="resolver">The Assembly Resolver that assemblies are registered with, used to ensure assemblies can cross reference.</param> /// <param name="moduleParams">Configuration for the module creation.</param> /// <returns>A list of Mono.Cecil Assemblies, containing empty type definitions for each defined type.</returns> internal static List <AssemblyDefinition> CreateAssemblies(Il2CppMetadata metadata, RegistryAssemblyResolver resolver, ModuleParameters moduleParams) { var assemblies = new List <AssemblyDefinition>(); foreach (var assemblyDefinition in metadata.imageDefinitions) { //Get the name of the assembly (= the name of the DLL without the file extension) var assemblyNameString = metadata.GetStringFromIndex(assemblyDefinition.nameIndex).Replace(".dll", ""); //Build a Mono.Cecil assembly name from this name var asmName = new AssemblyNameDefinition(assemblyNameString, new Version("0.0.0.0")); Console.Write($"\t\t{assemblyNameString}..."); //Create an empty assembly and register it var assembly = AssemblyDefinition.CreateAssembly(asmName, metadata.GetStringFromIndex(assemblyDefinition.nameIndex), moduleParams); resolver.Register(assembly); assemblies.Add(assembly); //Ensure it really _is_ empty var mainModule = assembly.MainModule; mainModule.Types.Clear(); //Find the end index of the types belonging to this assembly (as they're all in one huge list in the metadata) var end = assemblyDefinition.firstTypeIndex + assemblyDefinition.typeCount; for (var defNumber = assemblyDefinition.firstTypeIndex; defNumber < end; defNumber++) { //Get the metadata type info, its namespace, and name. var type = metadata.typeDefs[defNumber]; var ns = metadata.GetStringFromIndex(type.namespaceIndex); var name = metadata.GetStringFromIndex(type.nameIndex); TypeDefinition?definition = null; if (type.declaringTypeIndex != -1) { //This is a type declared within another (inner class/type) //Have we already declared this type due to handling its parent? SharedState.TypeDefsByIndex.TryGetValue(defNumber, out definition); } if (definition == null) { //This is a new type (including nested type with parent not defined yet) so ensure it's registered definition = new TypeDefinition(ns, name, (TypeAttributes)type.flags); if (ns == "System" && name == "String") { typeof(TypeReference).GetField("etype", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(definition, (byte)0x0e); //mark as string } mainModule.Types.Add(definition); SharedState.AllTypeDefinitions.Add(definition); SharedState.TypeDefsByIndex.Add(defNumber, definition); } //Ensure we include all inner types within this type. for (var nestedNumber = 0; nestedNumber < type.nested_type_count; nestedNumber++) { //These are stored in a separate field in the metadata. var nestedIndex = metadata.nestedTypeIndices[type.nestedTypesStart + nestedNumber]; var nested = metadata.typeDefs[nestedIndex]; if (SharedState.TypeDefsByIndex.TryGetValue(nestedIndex, out var alreadyMadeNestedType)) { //Type has already been defined (can be out-of-order in v27+) so we just add it. definition.NestedTypes.Add(alreadyMadeNestedType); } else { //Create it and register. var nestedDef = new TypeDefinition(metadata.GetStringFromIndex(nested.namespaceIndex), metadata.GetStringFromIndex(nested.nameIndex), (TypeAttributes)nested.flags); definition.NestedTypes.Add(nestedDef); SharedState.AllTypeDefinitions.Add(nestedDef); SharedState.TypeDefsByIndex.Add(nestedIndex, nestedDef); } } } Console.WriteLine("OK"); } return(assemblies); }
public static IEnumerable <EcsFile> Run(MethodReference entryPoint) { var usedTypes = GetUsedTypesOrdered(entryPoint).ToList(); var moduleParameter = new ModuleParameters { Kind = ModuleKind.Dll, AssemblyResolver = entryPoint.Module.AssemblyResolver }; var mod = ModuleDefinition.CreateModule("test", moduleParameter); // copy search path from old assembly // todo move to new transform, discovery transform? foreach (var t in usedTypes) { t.IsNestedPrivate = false; } foreach (var t in usedTypes) { mod.Types.Add(t); } (new NewobjTransform()).TransformIL(usedTypes); //(new ArrayTransform()).TransformIL(usedTypes); (new FinalizerOptimization()).TransformIL(usedTypes); (new VirtualCallOptimization()).TransformIL(usedTypes); (new MainNoReturnCodeTransform()).TransformIL(usedTypes); RenameTransform.Rename(usedTypes); (new ThisParameterTransform()).TransformIL(usedTypes); (new DelegateTransform()).TransformIL(usedTypes); (new StringLiteralOptimization()).GlobalOptimization(usedTypes); (new ValueTypeOptimization()).TransformIL(usedTypes); (new IsInstanceOptimization()).TransformIL(usedTypes); // has to be before Interface Optimization (IsInterface is set to false there) (new InterfaceOptimization()).TransformIL(usedTypes); (new FinalizerImplementationOptimization()).TransformIL(usedTypes); (new ExceptionTransform()).TransformIL(usedTypes); (new StripExternalAnnotations()).TransformIL(usedTypes); //(new StripTryCatch()).TransformIL(usedTypes); // do this after ExceptionTransform as it will create default values. (new PrimitiveDefaultValues()).TransformIL(usedTypes); ILAstDebugPrinter.ClearLogs(); ReferenceImportHelper.ImportReferences(mod); mod.Write(@"logs\compacted.dll"); File.Copy("ESharpCore.dll", @"logs\ESharpCore.dll"); // todo, just disabled temporarly because of poiter types resolving to null?? Should this happen? ReferenceChecker.CheckReferences(mod); var files = (new DecompilerService()).Generate(usedTypes, @"logs\compacted.dll").ToList(); // file optimization var fileOptimizationContext = new FileOptimizationContext { UsedTypes = usedTypes }; TypeEnumGenerator.FileOptimization(files, fileOptimizationContext); IncludeCFiles.Run(files); var mergedFiles = CMerger.MergeIntoSingleFile(files); return(mergedFiles); }
public Module([Import("ModuleParameters")] ModuleParameters moduleParameters) : base(moduleParameters) { ModuleInstance = this; }
public DummyAssemblyGenerator(Metadata metadata, Il2Cpp il2Cpp) { this.metadata = metadata; this.il2Cpp = il2Cpp; //Il2CppDummyDll var il2CppDummyDll = Il2CppDummyDll.Create(); Assemblies.Add(il2CppDummyDll); var addressAttribute = il2CppDummyDll.MainModule.Types.First(x => x.Name == "AddressAttribute").Methods[0]; var fieldOffsetAttribute = il2CppDummyDll.MainModule.Types.First(x => x.Name == "FieldOffsetAttribute").Methods[0]; attributeAttribute = il2CppDummyDll.MainModule.Types.First(x => x.Name == "AttributeAttribute").Methods[0]; var metadataOffsetAttribute = il2CppDummyDll.MainModule.Types.First(x => x.Name == "MetadataOffsetAttribute").Methods[0]; stringType = il2CppDummyDll.MainModule.TypeSystem.String; var resolver = new MyAssemblyResolver(); var moduleParameters = new ModuleParameters { Kind = ModuleKind.Dll, AssemblyResolver = resolver }; resolver.Register(il2CppDummyDll); var fieldDefinitionDic = new Dictionary <int, FieldDefinition>(); var methodDefinitionDic = new Dictionary <int, MethodDefinition>(); var parameterDefinitionDic = new Dictionary <int, ParameterDefinition>(); var propertyDefinitionDic = new Dictionary <int, PropertyDefinition>(); var eventDefinitionDic = new Dictionary <int, EventDefinition>(); //创建程序集,同时创建所有类 foreach (var imageDef in metadata.imageDefs) { var imageName = metadata.GetStringFromIndex(imageDef.nameIndex); var assemblyName = new AssemblyNameDefinition(imageName.Replace(".dll", ""), new Version("3.7.1.6")); var assemblyDefinition = AssemblyDefinition.CreateAssembly(assemblyName, imageName, moduleParameters); resolver.Register(assemblyDefinition); Assemblies.Add(assemblyDefinition); var moduleDefinition = assemblyDefinition.MainModule; moduleDefinition.Types.Clear();//清除自动创建的<Module>类 var typeEnd = imageDef.typeStart + imageDef.typeCount; for (var index = imageDef.typeStart; index < typeEnd; ++index) { var typeDef = metadata.typeDefs[index]; var namespaceName = metadata.GetStringFromIndex(typeDef.namespaceIndex); var typeName = metadata.GetStringFromIndex(typeDef.nameIndex); TypeDefinition typeDefinition; if (typeDef.declaringTypeIndex != -1)//nested types { typeDefinition = typeDefinitionDic[index]; } else { typeDefinition = new TypeDefinition(namespaceName, typeName, (TypeAttributes)typeDef.flags); moduleDefinition.Types.Add(typeDefinition); typeDefinitionDic.Add(index, typeDefinition); } //nestedtype for (int i = 0; i < typeDef.nested_type_count; i++) { var nestedIndex = metadata.nestedTypeIndices[typeDef.nestedTypesStart + i]; var nestedTypeDef = metadata.typeDefs[nestedIndex]; var nestedTypeDefinition = new TypeDefinition(metadata.GetStringFromIndex(nestedTypeDef.namespaceIndex), metadata.GetStringFromIndex(nestedTypeDef.nameIndex), (TypeAttributes)nestedTypeDef.flags); typeDefinition.NestedTypes.Add(nestedTypeDefinition); typeDefinitionDic.Add(nestedIndex, nestedTypeDefinition); } } } //先单独处理,因为不知道会不会有问题 for (var index = 0; index < metadata.typeDefs.Length; ++index) { var typeDef = metadata.typeDefs[index]; var typeDefinition = typeDefinitionDic[index]; //parent if (typeDef.parentIndex >= 0) { var parentType = il2Cpp.types[typeDef.parentIndex]; var parentTypeRef = GetTypeReference(typeDefinition, parentType); typeDefinition.BaseType = parentTypeRef; } //interfaces for (int i = 0; i < typeDef.interfaces_count; i++) { var interfaceType = il2Cpp.types[metadata.interfaceIndices[typeDef.interfacesStart + i]]; var interfaceTypeRef = GetTypeReference(typeDefinition, interfaceType); typeDefinition.Interfaces.Add(new InterfaceImplementation(interfaceTypeRef)); } } //处理field, method, property等等 for (var imageIndex = 0; imageIndex < metadata.imageDefs.Length; imageIndex++) { var imageDef = metadata.imageDefs[imageIndex]; var typeEnd = imageDef.typeStart + imageDef.typeCount; for (int index = imageDef.typeStart; index < typeEnd; index++) { var typeDef = metadata.typeDefs[index]; var typeDefinition = typeDefinitionDic[index]; //field var fieldEnd = typeDef.fieldStart + typeDef.field_count; for (var i = typeDef.fieldStart; i < fieldEnd; ++i) { var fieldDef = metadata.fieldDefs[i]; var fieldType = il2Cpp.types[fieldDef.typeIndex]; var fieldName = metadata.GetStringFromIndex(fieldDef.nameIndex); var fieldTypeRef = GetTypeReference(typeDefinition, fieldType); var fieldDefinition = new FieldDefinition(fieldName, (FieldAttributes)fieldType.attrs, fieldTypeRef); typeDefinition.Fields.Add(fieldDefinition); fieldDefinitionDic.Add(i, fieldDefinition); //fieldDefault if (metadata.GetFieldDefaultValueFromIndex(i, out var fieldDefault) && fieldDefault.dataIndex != -1) { if (TryGetDefaultValue(fieldDefault.typeIndex, fieldDefault.dataIndex, out var value)) { fieldDefinition.Constant = value; } else { var customAttribute = new CustomAttribute(typeDefinition.Module.ImportReference(metadataOffsetAttribute)); var offset = new CustomAttributeNamedArgument("Offset", new CustomAttributeArgument(stringType, $"0x{value:X}")); customAttribute.Fields.Add(offset); fieldDefinition.CustomAttributes.Add(customAttribute); } } //fieldOffset if (!fieldDefinition.IsLiteral) { var fieldOffset = il2Cpp.GetFieldOffsetFromIndex(index, i - typeDef.fieldStart, i, typeDefinition.IsValueType, fieldDefinition.IsStatic); if (fieldOffset >= 0) { var customAttribute = new CustomAttribute(typeDefinition.Module.ImportReference(fieldOffsetAttribute)); var offset = new CustomAttributeNamedArgument("Offset", new CustomAttributeArgument(stringType, $"0x{fieldOffset:X}")); customAttribute.Fields.Add(offset); fieldDefinition.CustomAttributes.Add(customAttribute); } } } //method var methodEnd = typeDef.methodStart + typeDef.method_count; for (var i = typeDef.methodStart; i < methodEnd; ++i) { var methodDef = metadata.methodDefs[i]; var methodName = metadata.GetStringFromIndex(methodDef.nameIndex); var methodDefinition = new MethodDefinition(methodName, (MethodAttributes)methodDef.flags, typeDefinition.Module.ImportReference(typeof(void))); methodDefinition.ImplAttributes = (MethodImplAttributes)methodDef.iflags; typeDefinition.Methods.Add(methodDefinition); var methodReturnType = il2Cpp.types[methodDef.returnType]; var returnType = GetTypeReferenceWithByRef(methodDefinition, methodReturnType); methodDefinition.ReturnType = returnType; if (methodDefinition.HasBody && typeDefinition.BaseType?.FullName != "System.MulticastDelegate") { var ilprocessor = methodDefinition.Body.GetILProcessor(); if (returnType.FullName == "System.Void") { ilprocessor.Append(ilprocessor.Create(OpCodes.Ret)); } else if (returnType.IsValueType) { var variable = new VariableDefinition(returnType); methodDefinition.Body.Variables.Add(variable); ilprocessor.Append(ilprocessor.Create(OpCodes.Ldloca_S, variable)); ilprocessor.Append(ilprocessor.Create(OpCodes.Initobj, returnType)); ilprocessor.Append(ilprocessor.Create(OpCodes.Ldloc_0)); ilprocessor.Append(ilprocessor.Create(OpCodes.Ret)); } else { ilprocessor.Append(ilprocessor.Create(OpCodes.Ldnull)); ilprocessor.Append(ilprocessor.Create(OpCodes.Ret)); } } methodDefinitionDic.Add(i, methodDefinition); //method parameter for (var j = 0; j < methodDef.parameterCount; ++j) { var parameterDef = metadata.parameterDefs[methodDef.parameterStart + j]; var parameterName = metadata.GetStringFromIndex(parameterDef.nameIndex); var parameterType = il2Cpp.types[parameterDef.typeIndex]; var parameterTypeRef = GetTypeReferenceWithByRef(methodDefinition, parameterType); var parameterDefinition = new ParameterDefinition(parameterName, (ParameterAttributes)parameterType.attrs, parameterTypeRef); methodDefinition.Parameters.Add(parameterDefinition); parameterDefinitionDic.Add(methodDef.parameterStart + j, parameterDefinition); //ParameterDefault if (metadata.GetParameterDefaultValueFromIndex(methodDef.parameterStart + j, out var parameterDefault) && parameterDefault.dataIndex != -1) { if (TryGetDefaultValue(parameterDefault.typeIndex, parameterDefault.dataIndex, out var value)) { parameterDefinition.Constant = value; } else { var customAttribute = new CustomAttribute(typeDefinition.Module.ImportReference(metadataOffsetAttribute)); var offset = new CustomAttributeNamedArgument("Offset", new CustomAttributeArgument(stringType, $"0x{value:X}")); customAttribute.Fields.Add(offset); parameterDefinition.CustomAttributes.Add(customAttribute); } } } //补充泛型参数 if (methodDef.genericContainerIndex >= 0) { var genericContainer = metadata.genericContainers[methodDef.genericContainerIndex]; if (genericContainer.type_argc > methodDefinition.GenericParameters.Count) { for (int j = 0; j < genericContainer.type_argc; j++) { var genericParameterIndex = genericContainer.genericParameterStart + j; if (!genericParameterDic.TryGetValue(genericParameterIndex, out var genericParameter)) { CreateGenericParameter(genericParameterIndex, methodDefinition); } else { if (!methodDefinition.GenericParameters.Contains(genericParameter)) { methodDefinition.GenericParameters.Add(genericParameter); } } } } } //methodAddress var methodPointer = il2Cpp.GetMethodPointer(methodDef, imageIndex); if (methodPointer > 0) { var customAttribute = new CustomAttribute(typeDefinition.Module.ImportReference(addressAttribute)); var fixedMethodPointer = il2Cpp.GetRVA(methodPointer); var rva = new CustomAttributeNamedArgument("RVA", new CustomAttributeArgument(stringType, $"0x{fixedMethodPointer:X}")); var offset = new CustomAttributeNamedArgument("Offset", new CustomAttributeArgument(stringType, $"0x{il2Cpp.MapVATR(methodPointer):X}")); var va = new CustomAttributeNamedArgument("VA", new CustomAttributeArgument(stringType, $"0x{methodPointer:X}")); customAttribute.Fields.Add(rva); customAttribute.Fields.Add(offset); customAttribute.Fields.Add(va); if (methodDef.slot != ushort.MaxValue) { var slot = new CustomAttributeNamedArgument("Slot", new CustomAttributeArgument(stringType, methodDef.slot.ToString())); customAttribute.Fields.Add(slot); } methodDefinition.CustomAttributes.Add(customAttribute); } } //property var propertyEnd = typeDef.propertyStart + typeDef.property_count; for (var i = typeDef.propertyStart; i < propertyEnd; ++i) { var propertyDef = metadata.propertyDefs[i]; var propertyName = metadata.GetStringFromIndex(propertyDef.nameIndex); TypeReference propertyType = null; MethodDefinition GetMethod = null; MethodDefinition SetMethod = null; if (propertyDef.get >= 0) { GetMethod = methodDefinitionDic[typeDef.methodStart + propertyDef.get]; propertyType = GetMethod.ReturnType; } if (propertyDef.set >= 0) { SetMethod = methodDefinitionDic[typeDef.methodStart + propertyDef.set]; if (propertyType == null) { propertyType = SetMethod.Parameters[0].ParameterType; } } var propertyDefinition = new PropertyDefinition(propertyName, (PropertyAttributes)propertyDef.attrs, propertyType) { GetMethod = GetMethod, SetMethod = SetMethod }; typeDefinition.Properties.Add(propertyDefinition); propertyDefinitionDic.Add(i, propertyDefinition); } //event var eventEnd = typeDef.eventStart + typeDef.event_count; for (var i = typeDef.eventStart; i < eventEnd; ++i) { var eventDef = metadata.eventDefs[i]; var eventName = metadata.GetStringFromIndex(eventDef.nameIndex); var eventType = il2Cpp.types[eventDef.typeIndex]; var eventTypeRef = GetTypeReference(typeDefinition, eventType); var eventDefinition = new EventDefinition(eventName, (EventAttributes)eventType.attrs, eventTypeRef); if (eventDef.add >= 0) { eventDefinition.AddMethod = methodDefinitionDic[typeDef.methodStart + eventDef.add]; } if (eventDef.remove >= 0) { eventDefinition.RemoveMethod = methodDefinitionDic[typeDef.methodStart + eventDef.remove]; } if (eventDef.raise >= 0) { eventDefinition.InvokeMethod = methodDefinitionDic[typeDef.methodStart + eventDef.raise]; } typeDefinition.Events.Add(eventDefinition); eventDefinitionDic.Add(i, eventDefinition); } //补充泛型参数 if (typeDef.genericContainerIndex >= 0) { var genericContainer = metadata.genericContainers[typeDef.genericContainerIndex]; if (genericContainer.type_argc > typeDefinition.GenericParameters.Count) { for (int i = 0; i < genericContainer.type_argc; i++) { var genericParameterIndex = genericContainer.genericParameterStart + i; if (!genericParameterDic.TryGetValue(genericParameterIndex, out var genericParameter)) { CreateGenericParameter(genericParameterIndex, typeDefinition); } else { if (!typeDefinition.GenericParameters.Contains(genericParameter)) { typeDefinition.GenericParameters.Add(genericParameter); } } } } } } } //第三遍,添加CustomAttribute if (il2Cpp.Version > 20) { PrepareCustomAttribute(); foreach (var imageDef in metadata.imageDefs) { var typeEnd = imageDef.typeStart + imageDef.typeCount; for (int index = imageDef.typeStart; index < typeEnd; index++) { var typeDef = metadata.typeDefs[index]; var typeDefinition = typeDefinitionDic[index]; //typeAttribute CreateCustomAttribute(imageDef, typeDef.customAttributeIndex, typeDef.token, typeDefinition.Module, typeDefinition.CustomAttributes); //field var fieldEnd = typeDef.fieldStart + typeDef.field_count; for (var i = typeDef.fieldStart; i < fieldEnd; ++i) { var fieldDef = metadata.fieldDefs[i]; var fieldDefinition = fieldDefinitionDic[i]; //fieldAttribute CreateCustomAttribute(imageDef, fieldDef.customAttributeIndex, fieldDef.token, typeDefinition.Module, fieldDefinition.CustomAttributes); } //method var methodEnd = typeDef.methodStart + typeDef.method_count; for (var i = typeDef.methodStart; i < methodEnd; ++i) { var methodDef = metadata.methodDefs[i]; var methodDefinition = methodDefinitionDic[i]; //methodAttribute CreateCustomAttribute(imageDef, methodDef.customAttributeIndex, methodDef.token, typeDefinition.Module, methodDefinition.CustomAttributes); //method parameter for (var j = 0; j < methodDef.parameterCount; ++j) { var parameterDef = metadata.parameterDefs[methodDef.parameterStart + j]; var parameterDefinition = parameterDefinitionDic[methodDef.parameterStart + j]; //parameterAttribute CreateCustomAttribute(imageDef, parameterDef.customAttributeIndex, parameterDef.token, typeDefinition.Module, parameterDefinition.CustomAttributes); } } //property var propertyEnd = typeDef.propertyStart + typeDef.property_count; for (var i = typeDef.propertyStart; i < propertyEnd; ++i) { var propertyDef = metadata.propertyDefs[i]; var propertyDefinition = propertyDefinitionDic[i]; //propertyAttribute CreateCustomAttribute(imageDef, propertyDef.customAttributeIndex, propertyDef.token, typeDefinition.Module, propertyDefinition.CustomAttributes); } //event var eventEnd = typeDef.eventStart + typeDef.event_count; for (var i = typeDef.eventStart; i < eventEnd; ++i) { var eventDef = metadata.eventDefs[i]; var eventDefinition = eventDefinitionDic[i]; //eventAttribute CreateCustomAttribute(imageDef, eventDef.customAttributeIndex, eventDef.token, typeDefinition.Module, eventDefinition.CustomAttributes); } } } } }
public static void Main(string[] args) { Console.WriteLine("===Cpp2IL by Samboy063==="); Console.WriteLine("A Tool to Reverse Unity's \"il2cpp\" Build Process."); Console.WriteLine("Running on " + Environment.OSVersion.Platform); #region Command Line Parsing CommandLineOptions = null; Parser.Default.ParseArguments <Options>(args).WithParsed(options => { CommandLineOptions = options; }); if (CommandLineOptions == null) { Console.WriteLine("Invalid command line. Exiting."); return; } var baseGamePath = CommandLineOptions.GamePath; Console.WriteLine("Using path: " + baseGamePath); if (!Directory.Exists(baseGamePath)) { Console.WriteLine("Specified game-path does not exist: " + baseGamePath); return; } var assemblyPath = Path.Combine(baseGamePath, "GameAssembly.dll"); var exeName = Path.GetFileNameWithoutExtension(Directory.GetFiles(baseGamePath) .First(f => f.EndsWith(".exe") && !BlacklistedExecutableFilenames.Any(bl => f.EndsWith(bl)))); if (CommandLineOptions.ExeName != null) { exeName = CommandLineOptions.ExeName; Console.WriteLine($"Using OVERRIDDEN game name: {exeName}"); } else { Console.WriteLine($"Auto-detected game name: {exeName}"); } var unityPlayerPath = Path.Combine(baseGamePath, $"{exeName}.exe"); var metadataPath = Path.Combine(baseGamePath, $"{exeName}_Data", "il2cpp_data", "Metadata", "global-metadata.dat"); if (!File.Exists(assemblyPath) || !File.Exists(unityPlayerPath) || !File.Exists(metadataPath)) { Console.WriteLine("Invalid game-path or exe-name specified. Failed to find one of the following:\n" + $"\t{assemblyPath}\n" + $"\t{unityPlayerPath}\n" + $"\t{metadataPath}\n"); return; } #endregion Console.WriteLine($"Located game EXE: {unityPlayerPath}"); Console.WriteLine($"Located global-metadata: {metadataPath}"); #region Unity Version Determination Console.WriteLine("\nAttempting to determine Unity version..."); int[] unityVerUseful; if (Environment.OSVersion.Platform == PlatformID.Win32NT) { var unityVer = FileVersionInfo.GetVersionInfo(unityPlayerPath); unityVerUseful = new[] { unityVer.FileMajorPart, unityVer.FileMinorPart, unityVer.FileBuildPart }; } else { //Globalgamemanagers var globalgamemanagersPath = Path.Combine(baseGamePath, $"{exeName}_Data", "globalgamemanagers"); var ggmBytes = File.ReadAllBytes(globalgamemanagersPath); var verString = new StringBuilder(); var idx = 0x14; while (ggmBytes[idx] != 0) { verString.Append(Convert.ToChar(ggmBytes[idx])); idx++; } var unityVer = verString.ToString(); unityVer = unityVer.Substring(0, unityVer.IndexOf("f", StringComparison.Ordinal)); Console.WriteLine("Read version string from globalgamemanagers: " + unityVer); unityVerUseful = unityVer.Split(".").Select(int.Parse).ToArray(); } Console.WriteLine("This game is built with Unity version " + string.Join(".", unityVerUseful)); if (unityVerUseful[0] <= 4) { Console.WriteLine("Unable to determine a valid unity version. Aborting."); return; } #endregion LibCpp2IlMain.Settings.AllowManualMetadataAndCodeRegInput = true; if (!LibCpp2IlMain.LoadFromFile(assemblyPath, metadataPath, unityVerUseful)) { Console.WriteLine("Initialization with LibCpp2IL failed."); return; } Console.WriteLine(LibCpp2IlReflection.GetType("String", "System").DeclaringAssembly.Name); //Dump DLLs #region Assembly Generation var resolver = new RegistryAssemblyResolver(); var moduleParams = new ModuleParameters { Kind = ModuleKind.Dll, AssemblyResolver = resolver, MetadataResolver = new MetadataResolver(resolver) }; Console.WriteLine("Building assemblies..."); Console.WriteLine("\tPass 1: Creating empty types..."); Assemblies = AssemblyBuilder.CreateAssemblies(LibCpp2IlMain.TheMetadata !, resolver, moduleParams); Utils.BuildPrimitiveMappings(); Console.WriteLine("\tPass 2: Setting parents and handling inheritance..."); //Stateful method, no return value AssemblyBuilder.ConfigureHierarchy(LibCpp2IlMain.TheMetadata, LibCpp2IlMain.ThePe !); Console.WriteLine("\tPass 3: Populating types..."); var methods = new List <(TypeDefinition type, List <CppMethodData> methods)>(); //Create out dirs if needed var outputPath = Path.GetFullPath("cpp2il_out"); if (!Directory.Exists(outputPath)) { Directory.CreateDirectory(outputPath); } var methodOutputDir = Path.Combine(outputPath, "types"); if (!(CommandLineOptions.SkipAnalysis && CommandLineOptions.SkipMetadataTextFiles) && !Directory.Exists(methodOutputDir)) { Directory.CreateDirectory(methodOutputDir); } for (var imageIndex = 0; imageIndex < LibCpp2IlMain.TheMetadata.assemblyDefinitions.Length; imageIndex++) { var imageDef = LibCpp2IlMain.TheMetadata.assemblyDefinitions[imageIndex]; Console.WriteLine($"\t\tPopulating {imageDef.typeCount} types in assembly {imageIndex + 1} of {LibCpp2IlMain.TheMetadata.assemblyDefinitions.Length}: {imageDef.Name}..."); var assemblySpecificPath = Path.Combine(methodOutputDir, imageDef.Name.Replace(".dll", "")); if (!(CommandLineOptions.SkipMetadataTextFiles && CommandLineOptions.SkipAnalysis) && !Directory.Exists(assemblySpecificPath)) { Directory.CreateDirectory(assemblySpecificPath); } methods.AddRange(AssemblyBuilder.ProcessAssemblyTypes(LibCpp2IlMain.TheMetadata, LibCpp2IlMain.ThePe, imageDef)); } //Invert dict for CppToMono SharedState.CppToMonoTypeDefs = SharedState.MonoToCppTypeDefs.ToDictionary(i => i.Value, i => i.Key); Console.WriteLine("\tPass 4: Handling SerializeFields..."); //Add serializefield to monobehaviors #region SerializeFields var unityEngineAssembly = Assemblies.Find(x => x.MainModule.Types.Any(t => t.Namespace == "UnityEngine" && t.Name == "SerializeField")); if (unityEngineAssembly != null) { var serializeFieldMethod = unityEngineAssembly.MainModule.Types.First(x => x.Name == "SerializeField").Methods.First(); foreach (var imageDef in LibCpp2IlMain.TheMetadata.assemblyDefinitions) { var lastTypeIndex = imageDef.firstTypeIndex + imageDef.typeCount; for (var typeIndex = imageDef.firstTypeIndex; typeIndex < lastTypeIndex; typeIndex++) { var typeDef = LibCpp2IlMain.TheMetadata.typeDefs[typeIndex]; var typeDefinition = SharedState.TypeDefsByIndex[typeIndex]; //Fields var lastFieldIdx = typeDef.firstFieldIdx + typeDef.field_count; for (var fieldIdx = typeDef.firstFieldIdx; fieldIdx < lastFieldIdx; ++fieldIdx) { var fieldDef = LibCpp2IlMain.TheMetadata.fieldDefs[fieldIdx]; var fieldName = LibCpp2IlMain.TheMetadata.GetStringFromIndex(fieldDef.nameIndex); var fieldDefinition = typeDefinition.Fields.First(x => x.Name == fieldName); //Get attributes and look for the serialize field attribute. var attributeIndex = LibCpp2IlMain.TheMetadata.GetCustomAttributeIndex(imageDef, fieldDef.customAttributeIndex, fieldDef.token); if (attributeIndex < 0) { continue; } var attributeTypeRange = LibCpp2IlMain.TheMetadata.attributeTypeRanges[attributeIndex]; for (var attributeIdxIdx = 0; attributeIdxIdx < attributeTypeRange.count; attributeIdxIdx++) { var attributeTypeIndex = LibCpp2IlMain.TheMetadata.attributeTypes[attributeTypeRange.start + attributeIdxIdx]; var attributeType = LibCpp2IlMain.ThePe.types[attributeTypeIndex]; if (attributeType.type != Il2CppTypeEnum.IL2CPP_TYPE_CLASS) { continue; } var cppAttribType = LibCpp2IlMain.TheMetadata.typeDefs[attributeType.data.classIndex]; var attributeName = LibCpp2IlMain.TheMetadata.GetStringFromIndex(cppAttribType.nameIndex); if (attributeName != "SerializeField") { continue; } var customAttribute = new CustomAttribute(typeDefinition.Module.ImportReference(serializeFieldMethod)); fieldDefinition.CustomAttributes.Add(customAttribute); } } } } } #endregion KeyFunctionAddresses keyFunctionAddresses = null; if (!CommandLineOptions.SkipAnalysis) { Console.WriteLine("\tPass 5: Locating Globals..."); Console.WriteLine($"\t\tFound {LibCpp2IlGlobalMapper.TypeRefs.Count} type globals"); Console.WriteLine($"\t\tFound {LibCpp2IlGlobalMapper.MethodRefs.Count} method globals"); Console.WriteLine($"\t\tFound {LibCpp2IlGlobalMapper.FieldRefs.Count} field globals"); Console.WriteLine($"\t\tFound {LibCpp2IlGlobalMapper.Literals.Count} string literals"); //TODO: Don't do this. Rework everything to use the API surface. SharedState.Globals.AddRange(LibCpp2IlGlobalMapper.TypeRefs); SharedState.Globals.AddRange(LibCpp2IlGlobalMapper.MethodRefs); SharedState.Globals.AddRange(LibCpp2IlGlobalMapper.FieldRefs); SharedState.Globals.AddRange(LibCpp2IlGlobalMapper.Literals); foreach (var globalIdentifier in SharedState.Globals) { SharedState.GlobalsByOffset[globalIdentifier.Offset] = globalIdentifier; } Console.WriteLine("\tPass 6: Looking for key functions..."); //This part involves decompiling known functions to search for other function calls Disassembler.Translator.IncludeAddress = true; Disassembler.Translator.IncludeBinary = true; keyFunctionAddresses = KeyFunctionAddresses.Find(methods, LibCpp2IlMain.ThePe); } #endregion Console.WriteLine("Saving Header DLLs to " + outputPath + "..."); GCSettings.LatencyMode = GCLatencyMode.SustainedLowLatency; foreach (var assembly in Assemblies) { var dllPath = Path.Combine(outputPath, assembly.MainModule.Name); var reference = assembly.MainModule.AssemblyReferences.FirstOrDefault(a => a.Name == "System.Private.CoreLib"); if (reference != null) { assembly.MainModule.AssemblyReferences.Remove(reference); } assembly.Write(dllPath); if (assembly.Name.Name != "Assembly-CSharp" || CommandLineOptions.SkipAnalysis) { continue; } Console.WriteLine("Dumping method bytes to " + methodOutputDir); Directory.CreateDirectory(Path.Combine(methodOutputDir, assembly.Name.Name)); //Write methods var allUsedMnemonics = new List <ud_mnemonic_code>(); var counter = 0; var toProcess = methods.Where(tuple => tuple.type.Module.Assembly == assembly).ToList(); //Sort alphabetically by type. toProcess.Sort((a, b) => String.Compare(a.type.FullName, b.type.FullName, StringComparison.Ordinal)); var thresholds = new[] { 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 }.ToList(); var nextThreshold = thresholds.First(); var successfullyProcessed = 0; var failedProcess = 0; var startTime = DateTime.Now; var methodTaintDict = new ConcurrentDictionary <string, AsmDumper.TaintReason>(); thresholds.RemoveAt(0); Action <(TypeDefinition type, List <CppMethodData> methods)> action = tuple => { var(type, methodData) = tuple; counter++; var pct = 100 * ((decimal)counter / toProcess.Count); if (pct > nextThreshold) { lock (thresholds) { //Check again to prevent races if (pct > nextThreshold) { var elapsedSoFar = DateTime.Now - startTime; var rate = counter / elapsedSoFar.TotalSeconds; var remaining = toProcess.Count - counter; Console.WriteLine($"{nextThreshold}% ({counter} classes in {Math.Round(elapsedSoFar.TotalSeconds)} sec, ~{Math.Round(rate)} classes / sec, {remaining} classes remaining, approx {Math.Round(remaining / rate + 5)} sec remaining)"); nextThreshold = thresholds.First(); thresholds.RemoveAt(0); } } } // Console.WriteLine($"\t-Dumping methods in type {counter}/{methodBytes.Count}: {type.Key}"); try { var filename = Path.Combine(methodOutputDir, assembly.Name.Name, type.Name.Replace("<", "_").Replace(">", "_").Replace("|", "_") + "_methods.txt"); var typeDump = new StringBuilder("Type: " + type.Name + "\n\n"); foreach (var method in methodData) { var methodStart = method.MethodOffsetRam; if (methodStart == 0) { continue; } var methodDefinition = SharedState.MethodsByIndex[method.MethodId]; var taintResult = new AsmDumper(methodDefinition, method, methodStart, keyFunctionAddresses !, LibCpp2IlMain.ThePe) .AnalyzeMethod(typeDump, ref allUsedMnemonics); var key = new StringBuilder(); key.Append(methodDefinition.DeclaringType.FullName).Append("::").Append(methodDefinition.Name); methodDefinition.MethodSignatureFullName(key); methodTaintDict[key.ToString()] = taintResult; if (taintResult != AsmDumper.TaintReason.UNTAINTED) { Interlocked.Increment(ref failedProcess); } else { Interlocked.Increment(ref successfullyProcessed); } } lock (type) File.WriteAllText(filename, typeDump.ToString()); } catch (Exception e) { Console.WriteLine("Failed to dump methods for type " + type.Name + " " + e); } }; var parallel = false; if (parallel) { toProcess.AsParallel().ForAll(action); } else { toProcess.ForEach(action); } var total = successfullyProcessed + failedProcess; var elapsed = DateTime.Now - startTime; Console.WriteLine($"Finished method processing in {elapsed.Ticks} ticks (about {Math.Round(elapsed.TotalSeconds, 1)} seconds), at an overall rate of about {Math.Round(toProcess.Count / elapsed.TotalSeconds)} methods/sec"); Console.WriteLine($"Processed {total} methods, {successfullyProcessed} ({Math.Round(successfullyProcessed * 100.0 / total, 2)}%) successfully, {failedProcess} ({Math.Round(failedProcess * 100.0 / total, 2)}%) with errors."); Console.WriteLine("Breakdown By Taint Reason:"); foreach (var reason in Enum.GetValues(typeof(AsmDumper.TaintReason))) { var count = (decimal)methodTaintDict.Values.Count(v => v == (AsmDumper.TaintReason)reason); Console.WriteLine($"{reason}: {count} (about {Math.Round(count * 100 / total, 1)}%)"); } var summary = new StringBuilder(); foreach (var keyValuePair in methodTaintDict) { summary.Append("\t") .Append(keyValuePair.Key) .Append(Utils.Repeat(" ", 250 - keyValuePair.Key.Length)) .Append(keyValuePair.Value) .Append(" (") .Append((int)keyValuePair.Value) .Append(")") .Append("\n"); } #if DUMP_PACKAGE_SUCCESS_DATA Console.WriteLine("By Package:"); var keys = methodTaintDict .Select(kvp => kvp.Key) .GroupBy( GetPackageName, className => className, (packageName, classEnumerable) => new { package = packageName, classes = classEnumerable.ToList() }) .ToList(); foreach (var key in keys) { var resultLine = new StringBuilder(); var totalClassCount = key.classes.Count; resultLine.Append($"\tIn package {key.package} ({totalClassCount} classes): "); foreach (var reason in Enum.GetValues(typeof(AsmDumper.TaintReason))) { var count = (decimal)methodTaintDict.Where(kvp => key.classes.Contains(kvp.Key)).Count(v => v.Value == (AsmDumper.TaintReason)reason); resultLine.Append(reason).Append(":").Append(count).Append($" ({Math.Round(count * 100 / totalClassCount, 1)}%) "); } Console.WriteLine(resultLine.ToString()); } #endif File.WriteAllText(Path.Combine(outputPath, "method_statuses.txt"), summary.ToString()); Console.WriteLine($"Wrote file: {Path.Combine(outputPath, "method_statuses.txt")}"); // Console.WriteLine("Assembly uses " + allUsedMnemonics.Count + " mnemonics"); } // Console.WriteLine("[Finished. Press enter to exit]"); // Console.ReadLine(); }
public static void Main(string[] args) { Console.WriteLine("===Cpp2IL by Samboy063==="); Console.WriteLine("A Tool to Reverse Unity's \"il2cpp\" Build Process."); Console.WriteLine("Running on " + Environment.OSVersion.Platform); Options commandLineOptions = null; Parser.Default.ParseArguments <Options>(args).WithParsed(options => { commandLineOptions = options; }); if (commandLineOptions == null) { return; } string loc; //TODO: No longer needed // if (Environment.OSVersion.Platform == PlatformID.Win32Windows || Environment.OSVersion.Platform == PlatformID.Win32NT) // { // loc = Registry.GetValue( // "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Steam App 1020340", // "InstallLocation", null) as string; // } // else if (Environment.OSVersion.Platform == PlatformID.Unix) // { // // $HOME/.local/share/Steam/steamapps/common/Audica // loc = Environment.GetEnvironmentVariable("HOME") + "/.local/share/Steam/steamapps/common/Audica"; // } // else // { // loc = null; // } // // if (args.Length != 1 && loc == null) // { // Console.WriteLine( // "Couldn't auto-detect Audica installation folder (via steam), and you didn't tell me where it is."); // PrintUsage(); // return; // } var baseGamePath = commandLineOptions.GamePath; Console.WriteLine("Using path: " + baseGamePath); if (!Directory.Exists(baseGamePath)) { Console.WriteLine("Specified path does not exist: " + baseGamePath); PrintUsage(); return; } var assemblyPath = Path.Combine(baseGamePath, "GameAssembly.dll"); var exeName = Path.GetFileNameWithoutExtension(Directory.GetFiles(baseGamePath).First(f => f.EndsWith(".exe") && !blacklistedExecutableFilenames.Contains(f))); if (commandLineOptions.ExeName != null) { exeName = commandLineOptions.ExeName; Console.WriteLine($"Using OVERRIDDEN game name: {exeName}"); } else { Console.WriteLine($"Auto-detected game name: {exeName}"); } var unityPlayerPath = Path.Combine(baseGamePath, $"{exeName}.exe"); var metadataPath = Path.Combine(baseGamePath, $"{exeName}_Data", "il2cpp_data", "Metadata", "global-metadata.dat"); if (!File.Exists(assemblyPath) || !File.Exists(unityPlayerPath) || !File.Exists(metadataPath)) { Console.WriteLine("Invalid path specified. Failed to find one of the following:\n" + $"\t{assemblyPath}\n" + $"\t{unityPlayerPath}\n" + $"\t{metadataPath}\n"); PrintUsage(); return; } Console.WriteLine($"Located game EXE: {unityPlayerPath}"); Console.WriteLine($"Located global-metadata: {metadataPath}"); Console.WriteLine("\nAttempting to determine Unity version..."); var unityVer = FileVersionInfo.GetVersionInfo(unityPlayerPath); var unityVerUseful = new[] { unityVer.FileMajorPart, unityVer.FileMinorPart, unityVer.FileBuildPart }; Console.WriteLine("This game is built with Unity version " + string.Join(".", unityVerUseful)); if (unityVerUseful[0] <= 4) { Console.WriteLine("Unable to determine a valid unity version. Aborting."); return; } Console.WriteLine("Reading metadata..."); Metadata = Il2CppMetadata.ReadFrom(metadataPath, unityVerUseful); Console.WriteLine("Reading binary / game assembly..."); var PEBytes = File.ReadAllBytes(assemblyPath); Console.WriteLine($"\t-Initializing MemoryStream of {PEBytes.Length} bytes, parsing sections, and initializing with auto+ mode."); ThePE = new PE.PE(new MemoryStream(PEBytes, 0, PEBytes.Length, false, true), Metadata.maxMetadataUsages); if (!ThePE.PlusSearch(Metadata.methodDefs.Count(x => x.methodIndex >= 0), Metadata.typeDefs.Length)) { Console.WriteLine("Initialize failed. Aborting."); return; } //Dump DLLs #region Assembly Generation var resolver = new RegistryAssemblyResolver(); var moduleParams = new ModuleParameters { Kind = ModuleKind.Dll, AssemblyResolver = resolver, MetadataResolver = new MetadataResolver(resolver) }; Console.WriteLine("Building assemblies..."); Console.WriteLine("\tPass 1: Creating types..."); Assemblies = AssemblyBuilder.CreateAssemblies(Metadata, resolver, moduleParams); Console.WriteLine("\tPass 2: Setting parents and handling inheritance..."); //Stateful method, no return value AssemblyBuilder.ConfigureHierarchy(Metadata, ThePE); Console.WriteLine("\tPass 3: Handling Fields, methods, and properties (THIS MAY TAKE A WHILE)..."); var methods = new List <(TypeDefinition type, List <CppMethodData> methods)>(); for (var imageIndex = 0; imageIndex < Metadata.assemblyDefinitions.Length; imageIndex++) { Console.WriteLine($"\t\tProcessing DLL {imageIndex + 1} of {Metadata.assemblyDefinitions.Length}..."); methods.AddRange(AssemblyBuilder.ProcessAssemblyTypes(Metadata, ThePE, Metadata.assemblyDefinitions[imageIndex])); } //Invert dict for CppToMono SharedState.CppToMonoTypeDefs = SharedState.MonoToCppTypeDefs.ToDictionary(i => i.Value, i => i.Key); Console.WriteLine("\tPass 4: Handling SerializeFields..."); //Add serializefield to monobehaviors #region SerializeFields var unityEngineAssembly = Assemblies.Find(x => x.MainModule.Types.Any(t => t.Namespace == "UnityEngine" && t.Name == "SerializeField")); if (unityEngineAssembly != null) { var serializeFieldMethod = unityEngineAssembly.MainModule.Types.First(x => x.Name == "SerializeField").Methods.First(); foreach (var imageDef in Metadata.assemblyDefinitions) { var lastTypeIndex = imageDef.firstTypeIndex + imageDef.typeCount; for (var typeIndex = imageDef.firstTypeIndex; typeIndex < lastTypeIndex; typeIndex++) { var typeDef = Metadata.typeDefs[typeIndex]; var typeDefinition = SharedState.TypeDefsByIndex[typeIndex]; //Fields var lastFieldIdx = typeDef.firstFieldIdx + typeDef.field_count; for (var fieldIdx = typeDef.firstFieldIdx; fieldIdx < lastFieldIdx; ++fieldIdx) { var fieldDef = Metadata.fieldDefs[fieldIdx]; var fieldName = Metadata.GetStringFromIndex(fieldDef.nameIndex); var fieldDefinition = typeDefinition.Fields.First(x => x.Name == fieldName); //Get attributes and look for the serialize field attribute. var attributeIndex = Metadata.GetCustomAttributeIndex(imageDef, fieldDef.customAttributeIndex, fieldDef.token); if (attributeIndex < 0) { continue; } var attributeTypeRange = Metadata.attributeTypeRanges[attributeIndex]; for (var attributeIdxIdx = 0; attributeIdxIdx < attributeTypeRange.count; attributeIdxIdx++) { var attributeTypeIndex = Metadata.attributeTypes[attributeTypeRange.start + attributeIdxIdx]; var attributeType = ThePE.types[attributeTypeIndex]; if (attributeType.type != Il2CppTypeEnum.IL2CPP_TYPE_CLASS) { continue; } var cppAttribType = Metadata.typeDefs[attributeType.data.classIndex]; var attributeName = Metadata.GetStringFromIndex(cppAttribType.nameIndex); if (attributeName != "SerializeField") { continue; } var customAttribute = new CustomAttribute(typeDefinition.Module.ImportReference(serializeFieldMethod)); fieldDefinition.CustomAttributes.Add(customAttribute); } } } } } #endregion KeyFunctionAddresses keyFunctionAddresses = null; if (!commandLineOptions.SkipAnalysis) { Console.WriteLine("\tPass 5: Locating Globals..."); var globals = AssemblyBuilder.MapGlobalIdentifiers(Metadata, ThePE); Console.WriteLine($"\t\tFound {globals.Count(g => g.IdentifierType == GlobalIdentifier.Type.TYPE)} type globals"); Console.WriteLine($"\t\tFound {globals.Count(g => g.IdentifierType == GlobalIdentifier.Type.METHOD)} method globals"); Console.WriteLine($"\t\tFound {globals.Count(g => g.IdentifierType == GlobalIdentifier.Type.FIELD)} field globals"); Console.WriteLine($"\t\tFound {globals.Count(g => g.IdentifierType == GlobalIdentifier.Type.LITERAL)} string literals"); SharedState.Globals.AddRange(globals); foreach (var globalIdentifier in globals) { SharedState.GlobalsDict[globalIdentifier.Offset] = globalIdentifier; } Console.WriteLine("\tPass 6: Looking for key functions..."); //This part involves decompiling known functions to search for other function calls Disassembler.Translator.IncludeAddress = true; Disassembler.Translator.IncludeBinary = true; keyFunctionAddresses = KeyFunctionAddresses.Find(methods, ThePE); } #endregion Utils.BuildPrimitiveMappings(); var outputPath = Path.GetFullPath("cpp2il_out"); if (!Directory.Exists(outputPath)) { Directory.CreateDirectory(outputPath); } var methodOutputDir = Path.Combine(outputPath, "types"); if (!Directory.Exists(methodOutputDir)) { Directory.CreateDirectory(methodOutputDir); } Console.WriteLine("Saving Header DLLs to " + outputPath + "..."); GCSettings.LatencyMode = GCLatencyMode.SustainedLowLatency; foreach (var assembly in Assemblies) { var dllPath = Path.Combine(outputPath, assembly.MainModule.Name); assembly.Write(dllPath); if (assembly.Name.Name != "Assembly-CSharp" || commandLineOptions.SkipAnalysis) { continue; } Console.WriteLine("Dumping method bytes to " + methodOutputDir); Directory.CreateDirectory(Path.Combine(methodOutputDir, assembly.Name.Name)); //Write methods var imageIndex = Assemblies.IndexOf(assembly); var allUsedMnemonics = new List <ud_mnemonic_code>(); var counter = 0; var toProcess = methods.Where(tuple => tuple.type.Module.Assembly == assembly).ToList(); //Sort alphabetically by type. toProcess.Sort((a, b) => String.Compare(a.type.FullName, b.type.FullName, StringComparison.Ordinal)); var thresholds = new[] { 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 }.ToList(); var nextThreshold = thresholds.First(); var successfullyProcessed = 0; var failedProcess = 0; var startTime = DateTime.Now; var methodTaintDict = new ConcurrentDictionary <string, AsmDumper.TaintReason>(); thresholds.RemoveAt(0); toProcess .AsParallel() .ForAll(tuple => { var(type, methodData) = tuple; counter++; var pct = 100 * ((decimal)counter / toProcess.Count); if (pct > nextThreshold) { lock (thresholds) { //Check again to prevent races if (pct > nextThreshold) { var elapsedSoFar = DateTime.Now - startTime; var rate = counter / elapsedSoFar.TotalSeconds; var remaining = toProcess.Count - counter; Console.WriteLine($"{nextThreshold}% ({counter} classes in {Math.Round(elapsedSoFar.TotalSeconds)} sec, ~{Math.Round(rate)} classes / sec, {remaining} classes remaining, approx {Math.Round(remaining / rate + 5)} sec remaining)"); nextThreshold = thresholds.First(); thresholds.RemoveAt(0); } } } // Console.WriteLine($"\t-Dumping methods in type {counter}/{methodBytes.Count}: {type.Key}"); try { var filename = Path.Combine(methodOutputDir, assembly.Name.Name, type.Name.Replace("<", "_").Replace(">", "_") + "_methods.txt"); var typeDump = new StringBuilder("Type: " + type.Name + "\n\n"); foreach (var method in methodData) { var methodDef = Metadata.methodDefs[method.MethodId]; var methodStart = method.MethodOffsetRam; var methodDefinition = SharedState.MethodsByIndex[method.MethodId]; var taintResult = new AsmDumper(methodDefinition, method, methodStart, keyFunctionAddresses, ThePE) .AnalyzeMethod(typeDump, ref allUsedMnemonics); var key = new StringBuilder(); key.Append(methodDefinition.DeclaringType.FullName).Append("::").Append(methodDefinition.Name); methodDefinition.MethodSignatureFullName(key); methodTaintDict[key.ToString()] = taintResult; if (taintResult != AsmDumper.TaintReason.UNTAINTED) { Interlocked.Increment(ref failedProcess); } else { Interlocked.Increment(ref successfullyProcessed); } } lock (type) File.WriteAllText(filename, typeDump.ToString()); } catch (Exception e) { Console.WriteLine("Failed to dump methods for type " + type.Name + " " + e); } }); var total = successfullyProcessed + failedProcess; var elapsed = DateTime.Now - startTime; Console.WriteLine($"Finished method processing in {elapsed.Ticks} ticks (about {Math.Round(elapsed.TotalSeconds, 1)} seconds), at an overall rate of about {Math.Round(toProcess.Count / elapsed.TotalSeconds)} methods/sec"); Console.WriteLine($"Processed {total} methods, {successfullyProcessed} ({Math.Round(successfullyProcessed * 100.0 / total, 2)}%) successfully, {failedProcess} ({Math.Round(failedProcess * 100.0 / total, 2)}%) with errors."); Console.WriteLine("Breakdown By Taint Reason:"); foreach (var reason in Enum.GetValues(typeof(AsmDumper.TaintReason))) { var count = (decimal)methodTaintDict.Values.Count(v => v == (AsmDumper.TaintReason)reason); Console.WriteLine($"{reason}: {count} (about {Math.Round(count * 100 / total, 1)}%)"); } var summary = new StringBuilder(); foreach (var keyValuePair in methodTaintDict) { summary.Append("\t") .Append(keyValuePair.Key) .Append(Utils.Repeat(" ", 250 - keyValuePair.Key.Length)) .Append(keyValuePair.Value) .Append(" (") .Append((int)keyValuePair.Value) .Append(")") .Append("\n"); } if (false) { Console.WriteLine("By Package:"); var keys = methodTaintDict .Select(kvp => kvp.Key) .GroupBy( GetPackageName, className => className, (packageName, keys) => new { package = packageName, classes = keys.ToList() }) .ToList(); foreach (var key in keys) { var resultLine = new StringBuilder(); var totalClassCount = key.classes.Count; resultLine.Append($"\tIn package {key.package} ({totalClassCount} classes): "); foreach (var reason in Enum.GetValues(typeof(AsmDumper.TaintReason))) { var count = (decimal)methodTaintDict.Where(kvp => key.classes.Contains(kvp.Key)).Count(v => v.Value == (AsmDumper.TaintReason)reason); resultLine.Append(reason).Append(":").Append(count).Append($" ({Math.Round(count * 100 / totalClassCount, 1)}%) "); } Console.WriteLine(resultLine.ToString()); } } File.WriteAllText(Path.Combine(outputPath, "method_statuses.txt"), summary.ToString()); Console.WriteLine($"Wrote file: {Path.Combine(outputPath, "method_statuses.txt")}"); // Console.WriteLine("Assembly uses " + allUsedMnemonics.Count + " mnemonics"); } // Console.WriteLine("[Finished. Press enter to exit]"); // Console.ReadLine(); }
public void CreateClientDll(Stream stream) { var transformedTypes = this.typeMapper.TransformedTypes.ToList(); // Use Pomona.Client lib as starting point! AssemblyDefinition assembly; this.assemblyName = this.typeMapper.Filter.GetClientAssemblyName(); var assemblyResolver = GetAssemblyResolver(); var version = new Version(string.Join(".", this.typeMapper.Filter.ApiVersion.Split('.').Pad(4, "0").Take(4))); if (PomonaClientEmbeddingEnabled) { var readerParameters = new ReaderParameters { AssemblyResolver = assemblyResolver }; assembly = AssemblyDefinition.ReadAssembly(typeof(ResourceBase).Assembly.Location, readerParameters); assembly.CustomAttributes.Clear(); } else { var moduleParameters = new ModuleParameters { Kind = ModuleKind.Dll, AssemblyResolver = assemblyResolver }; assembly = AssemblyDefinition.CreateAssembly( new AssemblyNameDefinition(this.assemblyName, version), this.assemblyName, moduleParameters); } assembly.Name = new AssemblyNameDefinition(this.assemblyName, version); //var assembly = // AssemblyDefinition.CreateAssembly( // new AssemblyNameDefinition("Critter", new Version(1, 0, 0, 134)), "Critter", ModuleKind.Dll); this.module = assembly.MainModule; this.module.Name = this.assemblyName + ".dll"; this.module.Mvid = Guid.NewGuid(); this.clientTypeInfoDict = new Dictionary<TypeSpec, TypeCodeGenInfo>(); this.enumClientTypeDict = new Dictionary<EnumTypeSpec, TypeReference>(); BuildEnumTypes(); BuildInterfacesAndPocoTypes(transformedTypes); CreateProxies( new WrappedPropertyProxyBuilder( this.module, GetProxyType("LazyProxyBase"), Import(typeof(PropertyWrapper<,>)).Resolve()), (info, def) => { info.LazyProxyType = def; }); CreateProxies( new PatchFormProxyBuilder(this, MakeProxyTypesPublic), (info, def) => { info.PatchFormType = def; }, typeIsGeneratedPredicate : x => x.TransformedType.PatchAllowed); CreateProxies( new PostFormProxyBuilder(this), (info, def) => { info.PostFormType = def; }, typeIsGeneratedPredicate : x => x.TransformedType.PostAllowed); CreateClientInterface("IClient"); CreateClientType("Client"); foreach (var typeInfo in this.clientTypeInfoDict.Values) AddResourceInfoAttribute(typeInfo); foreach (var typeInfo in this.clientTypeInfoDict.Values.Where(x => x.CustomRepositoryInterface != null)) CreateRepositoryInterfaceAndImplementation(typeInfo); //AddRepositoryPostExtensionMethods(); // Copy types from running assembly if (PomonaClientEmbeddingEnabled) { foreach ( var clientHelperType in this.module.Types.Where( methodDefinition => !methodDefinition.Namespace.StartsWith(this.assemblyName) && !string.IsNullOrEmpty(methodDefinition.Namespace))) clientHelperType.Namespace = this.assemblyName + "." + clientHelperType.Namespace; } AddAssemblyAttributes(); var memstream = new MemoryStream(); assembly.Write(memstream); var array = memstream.ToArray(); stream.Write(array, 0, array.Length); //assembly.Write(stream); }
public DummyAssemblyCreator(Metadata metadata, Il2Cpp il2cpp) { this.metadata = metadata; this.il2cpp = il2cpp; //Il2CppDummyDll var il2CppDummyDll = AssemblyDefinition.ReadAssembly(new MemoryStream(Resource1.Il2CppDummyDll)); var addressAttribute = il2CppDummyDll.MainModule.Types.First(x => x.Name == "AddressAttribute").Methods.First(); var fieldOffsetAttribute = il2CppDummyDll.MainModule.Types.First(x => x.Name == "FieldOffsetAttribute").Methods.First(); var stringType = il2CppDummyDll.MainModule.TypeSystem.String; var resolver = new MyAssemblyResolver(); var moduleParameters = new ModuleParameters { Kind = ModuleKind.Dll, AssemblyResolver = resolver }; //创建程序集,同时创建所有类 foreach (var imageDef in metadata.imageDefs) { var assemblyName = new AssemblyNameDefinition(metadata.GetStringFromIndex(imageDef.nameIndex).Replace(".dll", ""), new Version("3.7.1.6")); var assemblyDefinition = AssemblyDefinition.CreateAssembly(assemblyName, metadata.GetStringFromIndex(imageDef.nameIndex), moduleParameters); resolver.Register(assemblyDefinition); Assemblies.Add(assemblyDefinition); var moduleDefinition = assemblyDefinition.MainModule; moduleDefinition.Types.Clear();//清除自动创建的<Module>类 var typeEnd = imageDef.typeStart + imageDef.typeCount; for (var index = imageDef.typeStart; index < typeEnd; ++index) { var typeDef = metadata.typeDefs[index]; var namespaceName = metadata.GetStringFromIndex(typeDef.namespaceIndex); var typeName = metadata.GetStringFromIndex(typeDef.nameIndex); TypeDefinition typeDefinition; if (typeDef.declaringTypeIndex != -1)//nested types { typeDefinition = typeDefinitionDic[index]; } else { typeDefinition = new TypeDefinition(namespaceName, typeName, (TypeAttributes)typeDef.flags); moduleDefinition.Types.Add(typeDefinition); typeDefinitionDic.Add(index, typeDefinition); } //nestedtype for (int i = 0; i < typeDef.nested_type_count; i++) { var nestedIndex = metadata.nestedTypeIndices[typeDef.nestedTypesStart + i]; var nestedTypeDef = metadata.typeDefs[nestedIndex]; var nestedTypeDefinition = new TypeDefinition(metadata.GetStringFromIndex(nestedTypeDef.namespaceIndex), metadata.GetStringFromIndex(nestedTypeDef.nameIndex), (TypeAttributes)nestedTypeDef.flags); typeDefinition.NestedTypes.Add(nestedTypeDefinition); typeDefinitionDic.Add(nestedIndex, nestedTypeDefinition); } } } //先单独处理,因为不知道会不会有问题 for (var index = 0; index < metadata.uiNumTypes; ++index) { var typeDef = metadata.typeDefs[index]; var typeDefinition = typeDefinitionDic[index]; //parent if (typeDef.parentIndex >= 0) { var parentType = il2cpp.types[typeDef.parentIndex]; var parentTypeRef = GetTypeReference(typeDefinition, parentType); typeDefinition.BaseType = parentTypeRef; } //interfaces for (int i = 0; i < typeDef.interfaces_count; i++) { var interfaceType = il2cpp.types[metadata.interfaceIndices[typeDef.interfacesStart + i]]; var interfaceTypeRef = GetTypeReference(typeDefinition, interfaceType); typeDefinition.Interfaces.Add(interfaceTypeRef); } } //处理field, method, property等等 for (var index = 0; index < metadata.uiNumTypes; ++index) { var typeDef = metadata.typeDefs[index]; var typeDefinition = typeDefinitionDic[index]; //field var fieldEnd = typeDef.fieldStart + typeDef.field_count; for (var i = typeDef.fieldStart; i < fieldEnd; ++i) { var fieldDef = metadata.fieldDefs[i]; var fieldType = il2cpp.types[fieldDef.typeIndex]; var fieldName = metadata.GetStringFromIndex(fieldDef.nameIndex); var fieldTypeRef = GetTypeReference(typeDefinition, fieldType); var fieldDefinition = new FieldDefinition(fieldName, (FieldAttributes)fieldType.attrs, fieldTypeRef); typeDefinition.Fields.Add(fieldDefinition); //fieldDefault if (fieldDefinition.HasDefault) { var fieldDefault = metadata.GetFieldDefaultValueFromIndex(i); if (fieldDefault != null && fieldDefault.dataIndex != -1) { fieldDefinition.Constant = GetDefaultValue(fieldDefault.dataIndex, fieldDefault.typeIndex); } } //fieldOffset var fieldOffset = il2cpp.GetFieldOffsetFromIndex(index, i - typeDef.fieldStart, i); if (fieldOffset > 0) { var customAttribute = new CustomAttribute(typeDefinition.Module.Import(fieldOffsetAttribute)); var offset = new CustomAttributeNamedArgument("Offset", new CustomAttributeArgument(stringType, $"0x{fieldOffset:X}")); customAttribute.Fields.Add(offset); fieldDefinition.CustomAttributes.Add(customAttribute); } } //method var methodEnd = typeDef.methodStart + typeDef.method_count; for (var i = typeDef.methodStart; i < methodEnd; ++i) { var methodDef = metadata.methodDefs[i]; var methodReturnType = il2cpp.types[methodDef.returnType]; var methodName = metadata.GetStringFromIndex(methodDef.nameIndex); var methodDefinition = new MethodDefinition(methodName, (MethodAttributes)methodDef.flags, typeDefinition.Module.Import(typeof(void))); typeDefinition.Methods.Add(methodDefinition); methodDefinition.ReturnType = GetTypeReference(methodDefinition, methodReturnType); if (methodDefinition.HasBody && typeDefinition.BaseType?.FullName != "System.MulticastDelegate") { var ilprocessor = methodDefinition.Body.GetILProcessor(); ilprocessor.Append(ilprocessor.Create(OpCodes.Nop)); } methodDefinitionDic.Add(i, methodDefinition); //method parameter for (var j = 0; j < methodDef.parameterCount; ++j) { var parameterDef = metadata.parameterDefs[methodDef.parameterStart + j]; var parameterName = metadata.GetStringFromIndex(parameterDef.nameIndex); var parameterType = il2cpp.types[parameterDef.typeIndex]; var parameterTypeRef = GetTypeReference(methodDefinition, parameterType); var parameterDefinition = new ParameterDefinition(parameterName, (ParameterAttributes)parameterType.attrs, parameterTypeRef); methodDefinition.Parameters.Add(parameterDefinition); //ParameterDefault if (parameterDefinition.HasDefault) { var parameterDefault = metadata.GetParameterDefaultValueFromIndex(methodDef.parameterStart + j); if (parameterDefault != null && parameterDefault.dataIndex != -1) { parameterDefinition.Constant = GetDefaultValue(parameterDefault.dataIndex, parameterDefault.typeIndex); } } } //补充泛型参数 if (methodDef.genericContainerIndex >= 0) { var genericContainer = metadata.genericContainers[methodDef.genericContainerIndex]; if (genericContainer.type_argc > methodDefinition.GenericParameters.Count) { for (int j = methodDefinition.GenericParameters.Count + 1; j <= genericContainer.type_argc; j++) { var genericParameter = new GenericParameter("T" + j, methodDefinition); methodDefinition.GenericParameters.Add(genericParameter); } } } //address ulong methodPointer; if (methodDef.methodIndex >= 0) { methodPointer = il2cpp.methodPointers[methodDef.methodIndex]; } else { il2cpp.genericMethoddDictionary.TryGetValue(i, out methodPointer); } if (methodPointer > 0) { var customAttribute = new CustomAttribute(typeDefinition.Module.Import(addressAttribute)); var rva = new CustomAttributeNamedArgument("RVA", new CustomAttributeArgument(stringType, $"0x{methodPointer:X}")); var offset = new CustomAttributeNamedArgument("Offset", new CustomAttributeArgument(stringType, $"0x{il2cpp.MapVATR(methodPointer):X}")); customAttribute.Fields.Add(rva); customAttribute.Fields.Add(offset); methodDefinition.CustomAttributes.Add(customAttribute); } } //property var propertyEnd = typeDef.propertyStart + typeDef.property_count; for (var i = typeDef.propertyStart; i < propertyEnd; ++i) { var propertyDef = metadata.propertyDefs[i]; var propertyName = metadata.GetStringFromIndex(propertyDef.nameIndex); TypeReference propertyType = null; MethodDefinition GetMethod = null; MethodDefinition SetMethod = null; if (propertyDef.get >= 0) { GetMethod = methodDefinitionDic[typeDef.methodStart + propertyDef.get]; propertyType = GetMethod.ReturnType; } if (propertyDef.set >= 0) { SetMethod = methodDefinitionDic[typeDef.methodStart + propertyDef.set]; if (propertyType == null) { propertyType = SetMethod.Parameters[0].ParameterType; } } var propertyDefinition = new PropertyDefinition(propertyName, (PropertyAttributes)propertyDef.attrs, propertyType) { GetMethod = GetMethod, SetMethod = SetMethod }; typeDefinition.Properties.Add(propertyDefinition); } //event var eventEnd = typeDef.eventStart + typeDef.event_count; for (var i = typeDef.eventStart; i < eventEnd; ++i) { var eventDef = metadata.eventDefs[i]; var eventName = metadata.GetStringFromIndex(eventDef.nameIndex); var eventType = il2cpp.types[eventDef.typeIndex]; var eventTypeRef = GetTypeReference(typeDefinition, eventType); var eventDefinition = new EventDefinition(eventName, (EventAttributes)eventType.attrs, eventTypeRef); if (eventDef.add >= 0) { eventDefinition.AddMethod = methodDefinitionDic[typeDef.methodStart + eventDef.add]; } if (eventDef.remove >= 0) { eventDefinition.RemoveMethod = methodDefinitionDic[typeDef.methodStart + eventDef.remove]; } if (eventDef.raise >= 0) { eventDefinition.InvokeMethod = methodDefinitionDic[typeDef.methodStart + eventDef.raise]; } typeDefinition.Events.Add(eventDefinition); } //补充泛型参数 if (typeDef.genericContainerIndex >= 0) { var genericContainer = metadata.genericContainers[typeDef.genericContainerIndex]; if (genericContainer.type_argc > typeDefinition.GenericParameters.Count) { for (int j = typeDefinition.GenericParameters.Count + 1; j <= genericContainer.type_argc; j++) { var genericParameter = new GenericParameter("T" + j, typeDefinition); typeDefinition.GenericParameters.Add(genericParameter); } } } } //第三遍,添加CustomAttribute。只添加SerializeField用于MonoBehaviour的反序列化 if (il2cpp.version > 20) { var engine = Assemblies.Find(x => x.MainModule.Types.Any(t => t.Namespace == "UnityEngine" && t.Name == "SerializeField")); var serializeField = engine.MainModule.Types.First(x => x.Name == "SerializeField").Methods.First(); foreach (var imageDef in metadata.imageDefs) { var typeEnd = imageDef.typeStart + imageDef.typeCount; for (int index = imageDef.typeStart; index < typeEnd; index++) { var typeDef = metadata.typeDefs[index]; var typeDefinition = typeDefinitionDic[index]; //field var fieldEnd = typeDef.fieldStart + typeDef.field_count; for (var i = typeDef.fieldStart; i < fieldEnd; ++i) { var fieldDef = metadata.fieldDefs[i]; var fieldName = metadata.GetStringFromIndex(fieldDef.nameIndex); var fieldDefinition = typeDefinition.Fields.First(x => x.Name == fieldName); //fieldAttribute var attributeIndex = metadata.GetCustomAttributeIndex(imageDef, fieldDef.customAttributeIndex, fieldDef.token); if (attributeIndex >= 0) { var attributeTypeRange = metadata.attributeTypeRanges[attributeIndex]; for (int j = 0; j < attributeTypeRange.count; j++) { var attributeTypeIndex = metadata.attributeTypes[attributeTypeRange.start + j]; var attributeType = il2cpp.types[attributeTypeIndex]; if (attributeType.type == Il2CppTypeEnum.IL2CPP_TYPE_CLASS) { var klass = metadata.typeDefs[attributeType.data.klassIndex]; var attributeName = metadata.GetStringFromIndex(klass.nameIndex); if (attributeName == "SerializeField") { var customAttribute = new CustomAttribute(typeDefinition.Module.Import(serializeField)); fieldDefinition.CustomAttributes.Add(customAttribute); } } } } } } } } }
public LoadingScreenHintsModule([Import("ModuleParameters")] ModuleParameters moduleParameters) : base(moduleParameters) { ModuleInstance = this; }
public ScreenshotManagerModule([Import("ModuleParameters")] ModuleParameters moduleParameters) : base( moduleParameters) { ModuleInstance = this; _invalidFileNameCharacters = Path.GetInvalidFileNameChars().Union(Path.GetInvalidPathChars()); }
public static AssemblyDefinition CreateAssembly(AssemblyNameDefinition assemblyName, string moduleName, ModuleParameters parameters) { if (assemblyName == null) throw new ArgumentNullException("assemblyName"); if (moduleName == null) throw new ArgumentNullException("moduleName"); Mixin.CheckParameters(parameters); if (parameters.Kind == ModuleKind.NetModule) throw new ArgumentException("kind"); var assembly = ModuleDefinition.CreateModule(moduleName, parameters).Assembly; assembly.Name = assemblyName; return assembly; }
/// <summary> /// Creates all the Assemblies defined in the provided metadata, along with (stub) definitions of all the types contained therein, and registers them with the resolver. /// </summary> /// <param name="metadata">The Il2Cpp metadata to extract assemblies from</param> /// <param name="resolver">The Assembly Resolver that assemblies are registered with, used to ensure assemblies can cross reference.</param> /// <param name="moduleParams">Configuration for the module creation.</param> /// <returns>A list of Mono.Cecil Assemblies, containing empty type definitions for each defined type.</returns> internal static List <AssemblyDefinition> CreateAssemblies(Il2CppMetadata metadata, RegistryAssemblyResolver resolver, ModuleParameters moduleParams) { var assemblies = new List <AssemblyDefinition>(); foreach (var assemblyDefinition in metadata.assemblyDefinitions) { //Get the name of the assembly (= the name of the DLL without the file extension) var assemblyNameString = metadata.GetStringFromIndex(assemblyDefinition.nameIndex).Replace(".dll", ""); //Build a Mono.Cecil assembly name from this name var asmName = new AssemblyNameDefinition(assemblyNameString, new Version("0.0.0.0")); Console.Write($"\t\t{assemblyNameString}..."); //Create an empty assembly and register it var assembly = AssemblyDefinition.CreateAssembly(asmName, metadata.GetStringFromIndex(assemblyDefinition.nameIndex), moduleParams); resolver.Register(assembly); assemblies.Add(assembly); //Ensure it really _is_ empty var mainModule = assembly.MainModule; mainModule.Types.Clear(); //Find the end index of the types belonging to this assembly (as they're all in one huge list in the metadata) var end = assemblyDefinition.firstTypeIndex + assemblyDefinition.typeCount; for (var defNumber = assemblyDefinition.firstTypeIndex; defNumber < end; defNumber++) { //Get the metadata type info, its namespace, and name. var type = metadata.typeDefs[defNumber]; var ns = metadata.GetStringFromIndex(type.namespaceIndex); var name = metadata.GetStringFromIndex(type.nameIndex); TypeDefinition definition; if (type.declaringTypeIndex != -1) { //This is a type declared within another (inner class/type) definition = SharedState.TypeDefsByIndex[defNumber]; } else { //This is a new type so ensure it's registered definition = new TypeDefinition(ns, name, (TypeAttributes)type.flags); mainModule.Types.Add(definition); SharedState.TypeDefsByIndex.Add(defNumber, definition); } //Ensure we include all inner types within this type. for (var nestedNumber = 0; nestedNumber < type.nested_type_count; nestedNumber++) { //These are stored in a separate field in the metadata. var nestedIndex = metadata.nestedTypeIndices[type.nestedTypesStart + nestedNumber]; var nested = metadata.typeDefs[nestedIndex]; //Create it and register. var nestedDef = new TypeDefinition(metadata.GetStringFromIndex(nested.namespaceIndex), metadata.GetStringFromIndex(nested.nameIndex), (TypeAttributes)nested.flags); definition.NestedTypes.Add(nestedDef); SharedState.TypeDefsByIndex.Add(nestedIndex, nestedDef); } } Console.WriteLine("OK"); } return(assemblies); }