using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Text.RegularExpressions; using Microsoft.CodeAnalysis; using StableNameDotNet.Providers; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")] [assembly: AssemblyCompany("Samboy063")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright © Samboy063 2022-2023")] [assembly: AssemblyDescription("Library for generating somewhat stable names for obfuscated types, based on their content.")] [assembly: AssemblyFileVersion("0.1.0.0")] [assembly: AssemblyInformationalVersion("0.1.0-development.866+f87ccd1")] [assembly: AssemblyProduct("StableNameDotNet")] [assembly: AssemblyTitle("StableNameDotNet")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/SamboyCoding/Cpp2IL.git")] [assembly: AssemblyVersion("0.1.0.0")] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace StableNameDotNet { public static class Extensions { public static bool ContainsAnyInvalidSourceCodeChars(this string s, bool allowCompilerGenerated = false) { foreach (char c in s) { if (c >= 'A') { if (c >= 'a') { if (c <= 'z') { continue; } } else if (c <= 'Z' || c == '_' || c == '`') { continue; } } else if (c >= '0') { if (c <= '9') { continue; } if (c == '<' || c == '>') { goto IL_004b; } } else if (c == '.') { goto IL_004b; } goto IL_004e; IL_004b: if (allowCompilerGenerated) { continue; } goto IL_004e; IL_004e: return true; } return false; } public static TValue GetOrCreate(this Dictionary dict, TKey key, Func defaultGetter) { if (dict.TryGetValue(key, out TValue value)) { return value; } value = defaultGetter(); dict.Add(key, value); return value; } public static string Join(this IEnumerable strings, string separator = "") { return string.Join(separator, strings); } public static ulong StableHash(this string str) { return str.Aggregate(0uL, (ulong current, char c) => current * 37 + c); } } public static class StableNameGenerator { public static Regex? ObfuscatedNameRegex; public static readonly ConcurrentDictionary RenamedTypes = new ConcurrentDictionary(); private static readonly string[] ClassAccessNames = new string[8] { "Private", "Public", "NPublic", "NPrivate", "NProtected", "NInternal", "NFamAndAssem", "NFamOrAssem" }; private static readonly string[] MemberAccessTypeLabels = new string[7] { "CompilerControlled", "Private", "FamAndAssem", "Internal", "Protected", "FamOrAssem", "Public" }; private static readonly (MethodSemantics, string)[] SemanticsToCheck = new(MethodSemantics, string)[6] { (MethodSemantics.Setter, "_set"), (MethodSemantics.Getter, "_get"), (MethodSemantics.Other, "_oth"), (MethodSemantics.AddOn, "_add"), (MethodSemantics.RemoveOn, "_rem"), (MethodSemantics.Fire, "_fire") }; public static string? GetStableNameForTypeIfNeeded(ITypeInfoProvider type, bool includeMethodsForNonInterfaces) { if (!IsObfuscated(type.OriginalTypeName)) { return null; } return GetStableNameForType(type, includeMethodsForNonInterfaces); } public static string GetStableNameForType(ITypeInfoProvider type, bool includeMethodsForNonInterfaces) { int num = -1; ITypeInfoProvider typeInfoProvider = null; foreach (ITypeInfoProvider item in type.GetBaseTypeHierarchy()) { typeInfoProvider = item; num++; if (!RenamedTypes.ContainsKey(item) && !IsObfuscated(item.OriginalTypeName)) { break; } } string text = (type.TypeAttributes.HasFlag(TypeAttributes.ClassSemanticsMask) ? "Interface" : (type.IsValueType ? "Struct" : "Class")); List list = type.Interfaces.Where((ITypeInfoProvider i) => !IsObfuscated(i.OriginalTypeName)).ToList(); string value = ClassAccessNames[(int)(type.TypeAttributes & TypeAttributes.VisibilityMask)]; StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(((typeInfoProvider != null) ? typeInfoProvider.FormatTypeNameForType().Join() : null) ?? text); if (num > 0) { stringBuilder.Append(num); } if (type.OriginalTypeName.StartsWith("<")) { stringBuilder.Append("CompilerGenerated"); } stringBuilder.Append(value); if (type.TypeAttributes.HasFlag(TypeAttributes.Abstract)) { stringBuilder.Append("Abstract"); } if (type.TypeAttributes.HasFlag(TypeAttributes.Sealed)) { stringBuilder.Append("Sealed"); } if (type.TypeAttributes.HasFlag(TypeAttributes.SpecialName)) { stringBuilder.Append("SpecialName"); } foreach (ITypeInfoProvider item2 in list) { stringBuilder.Append(item2.FormatTypeNameForType().Join()); } UniqueIdentifierGenerator uniqueIdentifierGenerator = new UniqueIdentifierGenerator(); bool isEnumType = type.IsEnumType; IFieldInfoProvider[] array = type.FieldInfoProviders.ToArray(); IFieldInfoProvider[] array2 = array; foreach (IFieldInfoProvider fieldInfoProvider in array2) { if ((!isEnumType && !uniqueIdentifierGenerator.PushInputs(fieldInfoProvider.FieldTypeInfoProvider.FormatTypeNameForType())) || !uniqueIdentifierGenerator.PushInput(fieldInfoProvider.FieldName) || uniqueIdentifierGenerator.IsFull) { break; } } if (isEnumType) { uniqueIdentifierGenerator.PushInput(array.Length + "v"); } foreach (IPropertyInfoProvider propertyInfoProvider in type.PropertyInfoProviders) { if (!uniqueIdentifierGenerator.PushInputs(propertyInfoProvider.PropertyTypeInfoProvider.FormatTypeNameForType()) || !uniqueIdentifierGenerator.PushInput(propertyInfoProvider.PropertyName) || uniqueIdentifierGenerator.IsFull) { break; } } if (typeInfoProvider?.OriginalTypeName == "MulticastDelegate") { IMethodInfoProvider methodInfoProvider = type.MethodInfoProviders.FirstOrDefault((IMethodInfoProvider m) => m.MethodName == "Invoke"); if (methodInfoProvider != null) { uniqueIdentifierGenerator.PushInputs(methodInfoProvider.ReturnType.FormatTypeNameForType()); foreach (IParameterInfoProvider parameterInfoProvider in methodInfoProvider.ParameterInfoProviders) { uniqueIdentifierGenerator.PushInputs(parameterInfoProvider.ParameterTypeInfoProvider.FormatTypeNameForType()); if (uniqueIdentifierGenerator.IsFull) { break; } } } } if (includeMethodsForNonInterfaces || type.TypeAttributes.HasFlag(TypeAttributes.ClassSemanticsMask)) { foreach (IMethodInfoProvider methodInfoProvider2 in type.MethodInfoProviders) { uniqueIdentifierGenerator.PushInput(methodInfoProvider2.MethodName); uniqueIdentifierGenerator.PushInputs(methodInfoProvider2.ReturnType.FormatTypeNameForType()); foreach (IParameterInfoProvider parameterInfoProvider2 in methodInfoProvider2.ParameterInfoProviders) { uniqueIdentifierGenerator.PushInput(parameterInfoProvider2.ParameterName); uniqueIdentifierGenerator.PushInputs(parameterInfoProvider2.ParameterTypeInfoProvider.FormatTypeNameForType()); if (uniqueIdentifierGenerator.IsFull) { break; } } if (uniqueIdentifierGenerator.IsFull) { break; } } } stringBuilder.Append(uniqueIdentifierGenerator.GenerateUniqueName()); if (type.GenericParameterCount > 0 && (Enumerable.Contains(type.OriginalTypeName, '`') || type.DeclaringTypeInfoProvider == null || type.DeclaringTypeInfoProvider?.GenericParameterCount != type.GenericParameterCount)) { stringBuilder.Append('`').Append(type.GenericParameterCount); } return stringBuilder.ToString(); } public static string? GetStableNameForMethodIfNeeded(IMethodInfoProvider method) { if (!IsObfuscated(method.MethodName)) { return null; } return GetStableNameForMethod(method); } public static string GetStableNameForMethod(IMethodInfoProvider method) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("Method_"); MethodAttributes methodAttributes = method.MethodAttributes; stringBuilder.Append(MemberAccessTypeLabels[(int)(methodAttributes & MethodAttributes.MemberAccessMask)]); if (methodAttributes.HasFlag(MethodAttributes.Abstract)) { stringBuilder.Append("_Abstract"); } if (methodAttributes.HasFlag(MethodAttributes.Virtual)) { stringBuilder.Append("_Virtual"); } if (methodAttributes.HasFlag(MethodAttributes.Static)) { stringBuilder.Append("_Static"); } if (methodAttributes.HasFlag(MethodAttributes.Final)) { stringBuilder.Append("_Final"); } if (methodAttributes.HasFlag(MethodAttributes.VtableLayoutMask)) { stringBuilder.Append("_New"); } MethodSemantics methodSemantics = method.MethodSemantics; (MethodSemantics, string)[] semanticsToCheck = SemanticsToCheck; for (int i = 0; i < semanticsToCheck.Length; i++) { var (methodSemantics2, value) = semanticsToCheck[i]; if (methodSemantics.HasFlag(methodSemantics2)) { stringBuilder.Append(value); } } stringBuilder.Append('_'); stringBuilder.Append(method.ReturnType.FormatTypeNameForMember()); foreach (IParameterInfoProvider parameterInfoProvider in method.ParameterInfoProviders) { stringBuilder.Append('_'); stringBuilder.Append(parameterInfoProvider.ParameterTypeInfoProvider.FormatTypeNameForMember()); } return stringBuilder.ToString(); } public static string? GetStableNameForFieldIfNeeded(IFieldInfoProvider field) { if (!IsObfuscated(field.FieldName)) { return null; } return GetStableNameForField(field); } public static string GetStableNameForField(IFieldInfoProvider field) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("field_"); FieldAttributes fieldAttributes = field.FieldAttributes; stringBuilder.Append(MemberAccessTypeLabels[(int)(fieldAttributes & FieldAttributes.FieldAccessMask)]); if (fieldAttributes.HasFlag(FieldAttributes.Static)) { stringBuilder.Append("_Static"); } stringBuilder.Append('_'); stringBuilder.Append(field.FieldTypeInfoProvider.FormatTypeNameForMember()); return stringBuilder.ToString(); } public static string? GetStableNameForPropertyIfNeeded(IPropertyInfoProvider property) { if (!IsObfuscated(property.PropertyName)) { return null; } return GetStableNameForProperty(property); } public static string GetStableNameForProperty(IPropertyInfoProvider property) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("prop_"); stringBuilder.Append(property.PropertyTypeInfoProvider.FormatTypeNameForMember()); return stringBuilder.ToString(); } public static string? GetStableNameForEventIfNeeded(IEventInfoProvider evt) { if (!IsObfuscated(evt.EventName)) { return null; } return GetStableNameForEvent(evt); } public static string GetStableNameForEvent(IEventInfoProvider evt) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("event_"); stringBuilder.Append(evt.EventTypeInfoProvider.FormatTypeNameForMember()); return stringBuilder.ToString(); } public static bool IsObfuscated(string s) { if (ObfuscatedNameRegex != null) { return ObfuscatedNameRegex.IsMatch(s); } return s.ContainsAnyInvalidSourceCodeChars(allowCompilerGenerated: true); } private static List FormatTypeNameForType(this ITypeInfoProvider type) { if (type.IsGenericInstance) { string text = type.NameOrRename(); int num = text.IndexOf('`'); if (num > 0) { text = text.Substring(0, num); } List list = type.GenericArgumentInfoProviders.ToList(); List list2 = new List(); list2.Add(text); list2.Add(list.Count.ToString()); list2.AddRange(list.SelectMany(FormatTypeNameForType)); return list2; } if (IsObfuscated(type.NameOrRename())) { return new List { "Obf" }; } return new List { type.NameOrRename() }; } private static string FormatTypeNameForMember(this ITypeInfoProvider type) { StringBuilder stringBuilder = new StringBuilder(); if (!(type is GenericInstanceTypeInfoProviderWrapper genericInstanceTypeInfoProviderWrapper)) { if (!(type is ByRefTypeInfoProviderWrapper byRefTypeInfoProviderWrapper)) { if (type is PointerTypeInfoProviderWrapper pointerTypeInfoProviderWrapper) { stringBuilder.Append("ptr_"); stringBuilder.Append(pointerTypeInfoProviderWrapper.ElementTypeProvider.FormatTypeNameForMember()); } else if (type.TypeNamespace.StartsWith("System") && type.OriginalTypeName.Contains("Array")) { stringBuilder.Append("ArrayOf"); } else { stringBuilder.Append(type.RewrittenTypeName.Replace('`', '_')); } } else { stringBuilder.Append("byref_"); stringBuilder.Append(byRefTypeInfoProviderWrapper.ElementTypeProvider.FormatTypeNameForMember()); } } else { stringBuilder.Append(genericInstanceTypeInfoProviderWrapper.ElementTypeProvider.FormatTypeNameForMember()); foreach (ITypeInfoProvider genericArgumentInfoProvider in genericInstanceTypeInfoProviderWrapper.GenericArgumentInfoProviders) { stringBuilder.Append('_'); stringBuilder.Append(genericArgumentInfoProvider.FormatTypeNameForMember()); } } return stringBuilder.ToString(); } private static string NameOrRename(this ITypeInfoProvider typeName) { if (RenamedTypes.TryGetValue(typeName, out string value)) { return (value.StableHash() % (ulong)Math.Pow(10.0, UniqueIdentifierGenerator.NumCharsToTakeFromEachInput)).ToString(); } return typeName.OriginalTypeName; } } public class UniqueIdentifierGenerator { private struct Input : IComparable { public string Value; public float Weight; public Input(string value, float weight) { Value = value; Weight = weight; } public int CompareTo(Input other) { return Weight.CompareTo(other.Weight); } public override string ToString() { return $"{{{Value}, {Weight}}}"; } } public static int NumCharsToTakeFromEachInput = 2; public static int MaxInputs = 10; private readonly object _lock = new object(); private readonly Dictionary _inputOccurrenceCounts = new Dictionary(); private readonly SortedSet _resultSet = new SortedSet(); public bool IsFull => _inputOccurrenceCounts.Count >= MaxInputs; public bool PushInput(string input) { lock (_lock) { if (input.ContainsAnyInvalidSourceCodeChars()) { return true; } string text = input.Substring(0, Math.Min(input.Length, NumCharsToTakeFromEachInput)); int num2 = (_inputOccurrenceCounts[text] = _inputOccurrenceCounts.GetOrCreate(text, () => 0) + 1); int num3 = num2; int count = _inputOccurrenceCounts.Count; float num4 = (float)_resultSet.Count / 100f; float weight = (float)(count + num3 * 2) + num4; _resultSet.Add(new Input(text, weight)); return true; } } public bool PushInputs(List inputs) { return inputs.All(PushInput); } public string GenerateUniqueName() { return string.Join("", from x in _resultSet.Take(MaxInputs) select x.Value); } } } namespace StableNameDotNet.Providers { public class ByRefTypeInfoProviderWrapper : ITypeInfoProvider { public ITypeInfoProvider ElementTypeProvider { get; } public ITypeInfoProvider? DeclaringTypeInfoProvider => ElementTypeProvider.DeclaringTypeInfoProvider; public IEnumerable Interfaces => ElementTypeProvider.Interfaces; public TypeAttributes TypeAttributes => ElementTypeProvider.TypeAttributes; public string OriginalTypeName => ElementTypeProvider.OriginalTypeName; public string RewrittenTypeName => ElementTypeProvider.RewrittenTypeName; public string TypeNamespace => ElementTypeProvider.TypeNamespace; public bool IsGenericInstance => false; public bool IsValueType => ElementTypeProvider.IsValueType; public bool IsEnumType => false; public int GenericParameterCount => 0; public IEnumerable GenericArgumentInfoProviders => Array.Empty(); public IEnumerable FieldInfoProviders => ElementTypeProvider.FieldInfoProviders; public IEnumerable MethodInfoProviders => ElementTypeProvider.MethodInfoProviders; public IEnumerable PropertyInfoProviders => ElementTypeProvider.PropertyInfoProviders; public ByRefTypeInfoProviderWrapper(ITypeInfoProvider elementTypeProvider) { ElementTypeProvider = elementTypeProvider; } public IEnumerable GetBaseTypeHierarchy() { return ElementTypeProvider.GetBaseTypeHierarchy(); } } public class GenericInstanceTypeInfoProviderWrapper : ITypeInfoProvider { public ITypeInfoProvider ElementTypeProvider { get; } public ITypeInfoProvider[] GenericTypeProviders { get; } public ITypeInfoProvider? DeclaringTypeInfoProvider => ElementTypeProvider.DeclaringTypeInfoProvider; public IEnumerable Interfaces => ElementTypeProvider.Interfaces; public TypeAttributes TypeAttributes => ElementTypeProvider.TypeAttributes; public string OriginalTypeName => ElementTypeProvider.OriginalTypeName; public string TypeNamespace => ElementTypeProvider.TypeNamespace; public string RewrittenTypeName => ElementTypeProvider.RewrittenTypeName; public bool IsGenericInstance => true; public bool IsValueType => ElementTypeProvider.IsValueType; public bool IsEnumType => false; public int GenericParameterCount => ElementTypeProvider.GenericParameterCount; public IEnumerable GenericArgumentInfoProviders => GenericTypeProviders; public IEnumerable FieldInfoProviders => ElementTypeProvider.FieldInfoProviders; public IEnumerable MethodInfoProviders => ElementTypeProvider.MethodInfoProviders; public IEnumerable PropertyInfoProviders => ElementTypeProvider.PropertyInfoProviders; public GenericInstanceTypeInfoProviderWrapper(ITypeInfoProvider elementTypeProvider, ITypeInfoProvider[] genericTypeProviders) { ElementTypeProvider = elementTypeProvider; GenericTypeProviders = genericTypeProviders; } public IEnumerable GetBaseTypeHierarchy() { return ElementTypeProvider.GetBaseTypeHierarchy(); } } public class GenericParameterTypeInfoProviderWrapper : ITypeInfoProvider { public readonly string GenericParameterName; public ITypeInfoProvider? DeclaringTypeInfoProvider => null; public IEnumerable Interfaces => Array.Empty(); public TypeAttributes TypeAttributes => TypeAttributes.NotPublic; public string OriginalTypeName => GenericParameterName; public string TypeNamespace => string.Empty; public string RewrittenTypeName => GenericParameterName; public bool IsGenericInstance => false; public bool IsValueType => false; public bool IsEnumType => false; public int GenericParameterCount => 0; public IEnumerable GenericArgumentInfoProviders => Array.Empty(); public IEnumerable FieldInfoProviders => Array.Empty(); public IEnumerable MethodInfoProviders => Array.Empty(); public IEnumerable PropertyInfoProviders => Array.Empty(); public GenericParameterTypeInfoProviderWrapper(string genericParameterName) { GenericParameterName = genericParameterName; } public IEnumerable GetBaseTypeHierarchy() { return Array.Empty(); } } public interface IEventInfoProvider { ITypeInfoProvider EventTypeInfoProvider { get; } string EventName { get; } } public interface IFieldInfoProvider { ITypeInfoProvider FieldTypeInfoProvider { get; } FieldAttributes FieldAttributes { get; } string FieldName { get; } } public interface IMethodInfoProvider { ITypeInfoProvider ReturnType { get; } IEnumerable ParameterInfoProviders { get; } string MethodName { get; } MethodAttributes MethodAttributes { get; } MethodSemantics MethodSemantics { get; } } public interface IParameterInfoProvider { ITypeInfoProvider ParameterTypeInfoProvider { get; } string ParameterName { get; } } public interface IPropertyInfoProvider { ITypeInfoProvider PropertyTypeInfoProvider { get; } string PropertyName { get; } } public interface ITypeInfoProvider { ITypeInfoProvider? DeclaringTypeInfoProvider { get; } IEnumerable Interfaces { get; } TypeAttributes TypeAttributes { get; } string OriginalTypeName { get; } string RewrittenTypeName { get; } string TypeNamespace { get; } bool IsGenericInstance { get; } bool IsValueType { get; } bool IsEnumType { get; } int GenericParameterCount { get; } IEnumerable GenericArgumentInfoProviders { get; } IEnumerable FieldInfoProviders { get; } IEnumerable MethodInfoProviders { get; } IEnumerable PropertyInfoProviders { get; } IEnumerable GetBaseTypeHierarchy(); } [Flags] public enum MethodSemantics { Setter = 1, Getter = 2, Other = 4, AddOn = 8, RemoveOn = 0x10, Fire = 0x20 } public class PointerTypeInfoProviderWrapper : ITypeInfoProvider { public ITypeInfoProvider ElementTypeProvider { get; } public ITypeInfoProvider? DeclaringTypeInfoProvider => ElementTypeProvider.DeclaringTypeInfoProvider; public IEnumerable Interfaces => ElementTypeProvider.Interfaces; public TypeAttributes TypeAttributes => ElementTypeProvider.TypeAttributes; public string OriginalTypeName => ElementTypeProvider.OriginalTypeName; public bool IsGenericInstance => false; public bool IsValueType => ElementTypeProvider.IsValueType; public string TypeNamespace => ElementTypeProvider.TypeNamespace; public string RewrittenTypeName => ElementTypeProvider.RewrittenTypeName; public bool IsEnumType => false; public int GenericParameterCount => 0; public IEnumerable GenericArgumentInfoProviders => Array.Empty(); public IEnumerable FieldInfoProviders => ElementTypeProvider.FieldInfoProviders; public IEnumerable MethodInfoProviders => ElementTypeProvider.MethodInfoProviders; public IEnumerable PropertyInfoProviders => ElementTypeProvider.PropertyInfoProviders; public PointerTypeInfoProviderWrapper(ITypeInfoProvider elementTypeProvider) { ElementTypeProvider = elementTypeProvider; } public IEnumerable GetBaseTypeHierarchy() { return ElementTypeProvider.GetBaseTypeHierarchy(); } } }