public static void DoPass(RewriteGlobalContext context) { var typesUnstripped = 0; foreach (var unityAssembly in context.UnityAssemblies.Assemblies) { var processedAssembly = context.TryGetAssemblyByName(unityAssembly.Name.Name); if (processedAssembly == null) { var newAssembly = new AssemblyRewriteContext(context, unityAssembly, AssemblyDefinition.CreateAssembly(unityAssembly.Name, unityAssembly.MainModule.Name, ModuleKind.Dll)); context.AddAssemblyContext(unityAssembly.Name.Name, newAssembly); processedAssembly = newAssembly; } var imports = processedAssembly.Imports; foreach (var unityType in unityAssembly.MainModule.Types) { ProcessType(processedAssembly, unityType, null, imports, ref typesUnstripped); } } LogSupport.Trace(""); // end the progress message LogSupport.Trace($"{typesUnstripped} types restored"); }
private static void ProcessType(AssemblyRewriteContext processedAssembly, TypeDefinition unityType, TypeDefinition?enclosingNewType, AssemblyKnownImports imports, ref int typesUnstripped) { var processedType = enclosingNewType == null?processedAssembly.TryGetTypeByName(unityType.FullName)?.NewType : enclosingNewType.NestedTypes.SingleOrDefault(it => it.Name == unityType.Name); if (unityType.IsEnum) { if (processedType != null) { return; } typesUnstripped++; var clonedType = CloneEnum(unityType, imports); if (enclosingNewType == null) { processedAssembly.NewAssembly.MainModule.Types.Add(clonedType); } else { enclosingNewType.NestedTypes.Add(clonedType); clonedType.DeclaringType = enclosingNewType; } processedAssembly.RegisterTypeRewrite(new TypeRewriteContext(processedAssembly, null, clonedType)); return; } foreach (var nestedUnityType in unityType.NestedTypes) { ProcessType(processedAssembly, nestedUnityType, processedType, imports, ref typesUnstripped); } }
public static void DoPass(RewriteGlobalContext context) { var unityAssemblyFiles = Directory.EnumerateFiles(context.Options.UnityBaseLibsDir, "*.dll"); var loadedAssemblies = unityAssemblyFiles.Select(it => AssemblyDefinition.ReadAssembly(it, new ReaderParameters(ReadingMode.Deferred))).ToList(); var typesUnstripped = 0; foreach (var unityAssembly in loadedAssemblies) { var processedAssembly = context.TryGetAssemblyByName(unityAssembly.Name.Name); if (processedAssembly == null) { var newAssembly = new AssemblyRewriteContext(context, unityAssembly, AssemblyDefinition.CreateAssembly(unityAssembly.Name, unityAssembly.MainModule.Name, ModuleKind.Dll)); context.AddAssemblyContext(unityAssembly.Name.Name, newAssembly); processedAssembly = newAssembly; } var imports = processedAssembly.Imports; foreach (var unityType in unityAssembly.MainModule.Types) { ProcessType(processedAssembly, unityType, null, imports, ref typesUnstripped); } } LogSupport.Trace(""); // end the progress message LogSupport.Trace($"{typesUnstripped} types restored"); }
private static void ProcessType(TypeDefinition type, AssemblyRewriteContext assemblyContext, TypeDefinition?parentType) { var convertedTypeName = GetConvertedTypeName(assemblyContext.GlobalContext, type, parentType); var newType = new TypeDefinition(convertedTypeName.Namespace ?? type.Namespace.UnSystemify(), convertedTypeName.Name, AdjustAttributes(type.Attributes)); if (type.IsSealed && type.IsAbstract) // is static { newType.IsSealed = newType.IsAbstract = true; } if (parentType == null) { assemblyContext.NewAssembly.MainModule.Types.Add(newType); } else { parentType.NestedTypes.Add(newType); newType.DeclaringType = parentType; } foreach (var typeNestedType in type.NestedTypes) { ProcessType(typeNestedType, assemblyContext, newType); } assemblyContext.RegisterTypeRewrite(new TypeRewriteContext(assemblyContext, type, newType)); }
private static string UnmanglePropertyName(AssemblyRewriteContext assemblyContext, PropertyDefinition prop) { if (!prop.Name.IsObfuscated()) { return(prop.Name); } return("prop_" + assemblyContext.RewriteTypeRef(prop.PropertyType).Name + "_" + prop.DeclaringType.Properties .Where(it => it.PropertyType.FullName == prop.PropertyType.FullName).ToList().IndexOf(prop)); }
private static string UnmanglePropertyName(AssemblyRewriteContext assemblyContext, PropertyDefinition prop) { if (!prop.Name.IsInvalidInSource()) { return(prop.Name); } return("prop_" + assemblyContext.RewriteTypeRef(prop.PropertyType).GetUnmangledName() + "_" + prop.DeclaringType.Properties .Where(it => it.PropertyType.UnmangledNamesMatch(prop.PropertyType)).ToList().IndexOf(prop)); }
private static void ProcessType(AssemblyRewriteContext processedAssembly, TypeDefinition unityType, TypeDefinition?enclosingNewType, AssemblyKnownImports imports, ref int typesUnstripped) { var processedType = enclosingNewType == null?processedAssembly.TryGetTypeByName(unityType.FullName)?.NewType : enclosingNewType.NestedTypes.SingleOrDefault(it => it.Name == unityType.Name); if (unityType.IsEnum) { if (processedType != null) { return; } typesUnstripped++; var clonedType = CloneEnum(unityType, imports); if (enclosingNewType == null) { processedAssembly.NewAssembly.MainModule.Types.Add(clonedType); } else { enclosingNewType.NestedTypes.Add(clonedType); clonedType.DeclaringType = enclosingNewType; } processedAssembly.RegisterTypeRewrite(new TypeRewriteContext(processedAssembly, null, clonedType)); return; } if (processedType == null && !unityType.IsEnum && !HasNonBlittableFields(unityType) && !unityType.HasGenericParameters) // restore all types even if it would be not entirely correct { typesUnstripped++; var clonedType = CloneStatic(unityType, imports); if (enclosingNewType == null) { processedAssembly.NewAssembly.MainModule.Types.Add(clonedType); } else { enclosingNewType.NestedTypes.Add(clonedType); clonedType.DeclaringType = enclosingNewType; } processedAssembly.RegisterTypeRewrite(new TypeRewriteContext(processedAssembly, null, clonedType)); } foreach (var nestedUnityType in unityType.NestedTypes) { ProcessType(processedAssembly, nestedUnityType, processedType, imports, ref typesUnstripped); } }
private static string UnmanglePropertyName(AssemblyRewriteContext assemblyContext, PropertyDefinition prop, TypeReference declaringType, Dictionary <string, int> countsByBaseName) { if (assemblyContext.GlobalContext.Options.PassthroughNames || !prop.Name.IsObfuscated(assemblyContext.GlobalContext.Options)) { return(prop.Name); } var baseName = "prop_" + assemblyContext.RewriteTypeRef(prop.PropertyType).GetUnmangledName(); countsByBaseName.TryGetValue(baseName, out var index); countsByBaseName[baseName] = index + 1; var unmanglePropertyName = baseName + "_" + index; if (assemblyContext.GlobalContext.Options.RenameMap.TryGetValue(declaringType.GetNamespacePrefix() + "::" + unmanglePropertyName, out var newName)) { unmanglePropertyName = newName; } return(unmanglePropertyName); }
private static void ProcessType(TypeDefinition type, AssemblyRewriteContext assemblyContext, TypeDefinition?parentType) { var newType = new TypeDefinition(type.Namespace.UnSystemify(), GetConvertedTypeName(type), AdjustAttributes(type.Attributes)); if (parentType == null) { assemblyContext.NewAssembly.MainModule.Types.Add(newType); } else { parentType.NestedTypes.Add(newType); newType.DeclaringType = parentType; } foreach (var typeNestedType in type.NestedTypes) { ProcessType(typeNestedType, assemblyContext, newType); } assemblyContext.RegisterTypeRewrite(new TypeRewriteContext(assemblyContext, type, newType)); }
private static void GenerateStaticProxy(AssemblyRewriteContext assemblyContext, TypeRewriteContext typeContext) { var oldType = typeContext.OriginalType; var newType = typeContext.NewType; if (oldType.IsEnum) { return; } var staticCtorMethod = new MethodDefinition(".cctor", MethodAttributes.Static | MethodAttributes.Private | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.RTSpecialName, assemblyContext.Imports.Void); newType.Methods.Add(staticCtorMethod); var ctorBuilder = staticCtorMethod.Body.GetILProcessor(); if (newType.IsNested) { ctorBuilder.Emit(OpCodes.Ldsfld, assemblyContext.GlobalContext.GetNewTypeForOriginal(oldType.DeclaringType).ClassPointerFieldRef); ctorBuilder.Emit(OpCodes.Ldstr, oldType.Name); ctorBuilder.Emit(OpCodes.Call, assemblyContext.Imports.GetIl2CppNestedClass); } else { ctorBuilder.Emit(OpCodes.Ldstr, oldType.Module.Name); ctorBuilder.Emit(OpCodes.Ldstr, oldType.Namespace); ctorBuilder.Emit(OpCodes.Ldstr, oldType.Name); ctorBuilder.Emit(OpCodes.Call, assemblyContext.Imports.GetIl2CppGlobalClass); } if (oldType.HasGenericParameters) { var il2CppTypeTypeRewriteContext = assemblyContext.GlobalContext.GetAssemblyByName("mscorlib").GetTypeByName("System.Type"); var il2CppSystemTypeRef = newType.Module.ImportReference(il2CppTypeTypeRewriteContext.NewType); var il2CppTypeHandleTypeRewriteContext = assemblyContext.GlobalContext.GetAssemblyByName("mscorlib").GetTypeByName("System.RuntimeTypeHandle"); var il2CppSystemTypeHandleRef = newType.Module.ImportReference(il2CppTypeHandleTypeRewriteContext.NewType); ctorBuilder.Emit(OpCodes.Call, assemblyContext.Imports.GetIl2CppTypeFromClass); ctorBuilder.Emit(OpCodes.Call, new MethodReference("internal_from_handle", il2CppSystemTypeRef, il2CppSystemTypeRef) { Parameters = { new ParameterDefinition(assemblyContext.Imports.IntPtr) } }); ctorBuilder.EmitLdcI4(oldType.GenericParameters.Count); ctorBuilder.Emit(OpCodes.Newarr, il2CppSystemTypeRef); for (var i = 0; i < oldType.GenericParameters.Count; i++) { ctorBuilder.Emit(OpCodes.Dup); ctorBuilder.EmitLdcI4(i); var param = oldType.GenericParameters[i]; var storeRef = new GenericInstanceType(assemblyContext.Imports.Il2CppClassPointerStore) { GenericArguments = { param } }; var fieldRef = new FieldReference(nameof(Il2CppClassPointerStore <object> .NativeClassPtr), assemblyContext.Imports.IntPtr, storeRef); ctorBuilder.Emit(OpCodes.Ldsfld, fieldRef); ctorBuilder.Emit(OpCodes.Call, assemblyContext.Imports.GetIl2CppTypeFromClass); ctorBuilder.Emit(OpCodes.Call, new MethodReference("internal_from_handle", il2CppSystemTypeRef, il2CppSystemTypeRef) { Parameters = { new ParameterDefinition(assemblyContext.Imports.IntPtr) } }); ctorBuilder.Emit(OpCodes.Stelem_Ref); } var il2CppTypeArray = new GenericInstanceType(assemblyContext.Imports.Il2CppReferenceArray) { GenericArguments = { il2CppSystemTypeRef } }; ctorBuilder.Emit(OpCodes.Newobj, new MethodReference(".ctor", assemblyContext.Imports.Void, il2CppTypeArray) { HasThis = true, Parameters = { new ParameterDefinition(new ArrayType(assemblyContext.Imports.Il2CppReferenceArray.GenericParameters[0])) } }); ctorBuilder.Emit(OpCodes.Call, new MethodReference(nameof(Type.MakeGenericType), il2CppSystemTypeRef, il2CppSystemTypeRef) { HasThis = true, Parameters = { new ParameterDefinition(il2CppTypeArray) } }); ctorBuilder.Emit(OpCodes.Call, new MethodReference(typeof(Type).GetProperty(nameof(Type.TypeHandle)) !.GetMethod !.Name, il2CppSystemTypeHandleRef, il2CppSystemTypeRef) { HasThis = true });
private static (TypeRewriteContext?, int) FindBestMatchType(TypeRewriteContext obfType, AssemblyRewriteContext cleanAssembly, TypeRewriteContext?enclosingCleanType) { var inheritanceDepthOfOriginal = 0; var currentBase = obfType.OriginalType.BaseType; while (true) { if (currentBase == null) { break; } var currentBaseContext = obfType.AssemblyContext.GlobalContext.TryGetNewTypeForOriginal(currentBase.Resolve()); if (currentBaseContext == null || !currentBaseContext.OriginalNameWasObfuscated) { break; } inheritanceDepthOfOriginal++; currentBase = currentBaseContext.OriginalType.BaseType; } var bestPenalty = int.MinValue; TypeRewriteContext?bestMatch = null; var source = enclosingCleanType?.OriginalType.NestedTypes.Select(it => cleanAssembly.GlobalContext.GetNewTypeForOriginal(it)) ?? cleanAssembly.Types.Where(it => it.NewType.DeclaringType == null); foreach (var candidateCleanType in source) { if (obfType.OriginalType.HasMethods != candidateCleanType.OriginalType.HasMethods) { continue; } if (obfType.OriginalType.HasFields != candidateCleanType.OriginalType.HasFields) { continue; } if (obfType.OriginalType.IsEnum) { if (obfType.OriginalType.Fields.Count != candidateCleanType.OriginalType.Fields.Count) { continue; } } int currentPenalty = 0; var tryBase = candidateCleanType.OriginalType.BaseType; var actualBaseDepth = 0; while (tryBase != null) { if (tryBase?.Name == currentBase?.Name && tryBase?.Namespace == currentBase?.Namespace) { break; } tryBase = tryBase?.Resolve().BaseType; actualBaseDepth++; } if (tryBase == null && currentBase != null) { continue; } var baseDepthDifference = Math.Abs(actualBaseDepth - inheritanceDepthOfOriginal); if (baseDepthDifference > 1) { continue; // heuristic optimization } currentPenalty -= baseDepthDifference * 50; currentPenalty -= Math.Abs(candidateCleanType.OriginalType.Fields.Count - obfType.OriginalType.Fields.Count) * 5; currentPenalty -= Math.Abs(obfType.OriginalType.NestedTypes.Count - candidateCleanType.OriginalType.NestedTypes.Count) * 10; currentPenalty -= Math.Abs(obfType.OriginalType.Properties.Count - candidateCleanType.OriginalType.Properties.Count) * 5; currentPenalty -= Math.Abs(obfType.OriginalType.Interfaces.Count - candidateCleanType.OriginalType.Interfaces.Count) * 35; var options = obfType.AssemblyContext.GlobalContext.Options; foreach (var obfuscatedField in obfType.OriginalType.Fields) { if (obfuscatedField.Name.IsObfuscated(options)) { var bestFieldScore = candidateCleanType.OriginalType.Fields.Max(it => TypeMatchWeight(obfuscatedField.FieldType, it.FieldType, options)); currentPenalty += bestFieldScore * (bestFieldScore < 0 ? 10 : 2); continue; } if (candidateCleanType.OriginalType.Fields.Any(it => it.Name == obfuscatedField.Name)) { currentPenalty += 10; } } foreach (var obfuscatedMethod in obfType.OriginalType.Methods) { if (obfuscatedMethod.Name.Contains(".ctor")) { continue; } if (obfuscatedMethod.Name.IsObfuscated(options)) { var bestMethodScore = candidateCleanType.OriginalType.Methods.Max(it => MethodSignatureMatchWeight(obfuscatedMethod, it, options)); currentPenalty += bestMethodScore * (bestMethodScore < 0 ? 10 : 1); continue; } if (candidateCleanType.OriginalType.Methods.Any(it => it.Name == obfuscatedMethod.Name)) { currentPenalty += obfuscatedMethod.Name.Length / 10 * 5 + 1; } } if (currentPenalty == bestPenalty) { bestMatch = null; } else if (currentPenalty > bestPenalty) { bestPenalty = currentPenalty; bestMatch = candidateCleanType; } } // if (bestPenalty < -100) // bestMatch = null; return(bestMatch, bestPenalty); }