0
0
mirror of https://github.com/sp-tarkov/assembly-tool.git synced 2025-02-13 09:50:44 -05:00
Archangel 77a24319b1 Update de4dot to use dnlib 4.4.0 and x64
Adds the source code used for this modification, this de4dot source code has been cleaned of any things not needed for deobfuscating the tarkov assembly

Co-authored-by: 静穏靄 <170472707+seionmoya@users.noreply.github.com>
2024-12-30 16:01:39 +01:00

474 lines
14 KiB
C#

/*
Copyright (C) 2011-2015 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using dnlib.DotNet;
namespace de4dot.code.renamer.asmmodules {
public class Modules : IResolver {
bool initializeCalled = false;
IDeobfuscatorContext deobfuscatorContext;
List<Module> modules = new List<Module>();
Dictionary<ModuleDef, Module> modulesDict = new Dictionary<ModuleDef, Module>();
AssemblyHash assemblyHash = new AssemblyHash();
List<MTypeDef> allTypes = new List<MTypeDef>();
List<MTypeDef> baseTypes = new List<MTypeDef>();
List<MTypeDef> nonNestedTypes;
public IList<Module> TheModules => modules;
public IEnumerable<MTypeDef> AllTypes => allTypes;
public IEnumerable<MTypeDef> BaseTypes => baseTypes;
public List<MTypeDef> NonNestedTypes => nonNestedTypes;
class AssemblyHash {
IDictionary<string, ModuleHash> assemblyHash = new Dictionary<string, ModuleHash>(StringComparer.Ordinal);
public void Add(Module module) {
var key = GetModuleKey(module);
if (!assemblyHash.TryGetValue(key, out var moduleHash))
assemblyHash[key] = moduleHash = new ModuleHash();
moduleHash.Add(module);
}
static string GetModuleKey(Module module) {
if (module.ModuleDefMD.Assembly != null)
return GetAssemblyName(module.ModuleDefMD.Assembly);
return Utils.GetBaseName(module.ModuleDefMD.Location);
}
public ModuleHash Lookup(IAssembly asm) {
if (assemblyHash.TryGetValue(GetAssemblyName(asm), out var moduleHash))
return moduleHash;
return null;
}
static string GetAssemblyName(IAssembly asm) {
if (asm == null)
return string.Empty;
if (PublicKeyBase.IsNullOrEmpty2(asm.PublicKeyOrToken))
return asm.Name;
return asm.FullName;
}
}
class ModuleHash {
ModulesDict modulesDict = new ModulesDict();
Module mainModule = null;
public void Add(Module module) {
var asm = module.ModuleDefMD.Assembly;
if (asm != null && ReferenceEquals(asm.ManifestModule, module.ModuleDefMD)) {
if (mainModule != null) {
throw new UserException(
"Two modules in the same assembly are main modules.\n" +
"Is one 32-bit and the other 64-bit?\n" +
$" Module1: \"{module.ModuleDefMD.Location}\"" +
$" Module2: \"{mainModule.ModuleDefMD.Location}\"");
}
mainModule = module;
}
modulesDict.Add(module);
}
public Module Lookup(string moduleName) => modulesDict.Lookup(moduleName);
public IEnumerable<Module> Modules => modulesDict.Modules;
}
class ModulesDict {
IDictionary<string, Module> modulesDict = new Dictionary<string, Module>(StringComparer.Ordinal);
public void Add(Module module) {
var moduleName = module.ModuleDefMD.Name.String;
if (Lookup(moduleName) != null)
throw new ApplicationException($"Module \"{moduleName}\" was found twice");
modulesDict[moduleName] = module;
}
public Module Lookup(string moduleName) {
if (modulesDict.TryGetValue(moduleName, out var module))
return module;
return null;
}
public IEnumerable<Module> Modules => modulesDict.Values;
}
public bool Empty => modules.Count == 0;
public Modules(IDeobfuscatorContext deobfuscatorContext) => this.deobfuscatorContext = deobfuscatorContext;
public void Add(Module module) {
if (initializeCalled)
throw new ApplicationException("initialize() has been called");
if (modulesDict.TryGetValue(module.ModuleDefMD, out var otherModule))
return;
modulesDict[module.ModuleDefMD] = module;
modules.Add(module);
assemblyHash.Add(module);
}
public void Initialize() {
initializeCalled = true;
FindAllMemberRefs();
InitAllTypes();
ResolveAllRefs();
}
void FindAllMemberRefs() {
Logger.v("Finding all MemberRefs");
int index = 0;
foreach (var module in modules) {
if (modules.Count > 1)
Logger.v("Finding all MemberRefs ({0})", module.Filename);
Logger.Instance.Indent();
module.FindAllMemberRefs(ref index);
Logger.Instance.DeIndent();
}
}
void ResolveAllRefs() {
Logger.v("Resolving references");
foreach (var module in modules) {
if (modules.Count > 1)
Logger.v("Resolving references ({0})", module.Filename);
Logger.Instance.Indent();
module.ResolveAllRefs(this);
Logger.Instance.DeIndent();
}
}
void InitAllTypes() {
foreach (var module in modules)
allTypes.AddRange(module.GetAllTypes());
var typeToTypeDef = new Dictionary<TypeDef, MTypeDef>(allTypes.Count);
foreach (var typeDef in allTypes)
typeToTypeDef[typeDef.TypeDef] = typeDef;
// Initialize Owner
foreach (var typeDef in allTypes) {
if (typeDef.TypeDef.DeclaringType != null)
typeDef.Owner = typeToTypeDef[typeDef.TypeDef.DeclaringType];
}
// Initialize baseType and derivedTypes
foreach (var typeDef in allTypes) {
var baseType = typeDef.TypeDef.BaseType;
if (baseType == null)
continue;
var baseTypeDef = ResolveType(baseType) ?? ResolveOther(baseType);
if (baseTypeDef != null) {
typeDef.AddBaseType(baseTypeDef, baseType);
baseTypeDef.derivedTypes.Add(typeDef);
}
}
// Initialize interfaces
foreach (var typeDef in allTypes) {
foreach (var iface in typeDef.TypeDef.Interfaces) {
var ifaceTypeDef = ResolveType(iface.Interface) ?? ResolveOther(iface.Interface);
if (ifaceTypeDef != null)
typeDef.AddInterface(ifaceTypeDef, iface.Interface);
}
}
// Find all non-nested types
var allTypesDict = new Dictionary<MTypeDef, bool>();
foreach (var t in allTypes)
allTypesDict[t] = true;
foreach (var t in allTypes) {
foreach (var t2 in t.NestedTypes)
allTypesDict.Remove(t2);
}
nonNestedTypes = new List<MTypeDef>(allTypesDict.Keys);
foreach (var typeDef in allTypes) {
if (typeDef.baseType == null || !typeDef.baseType.typeDef.HasModule)
baseTypes.Add(typeDef);
}
}
class AssemblyKeyDictionary<T> where T : class {
Dictionary<ITypeDefOrRef, T> dict = new Dictionary<ITypeDefOrRef, T>(new TypeEqualityComparer(SigComparerOptions.CompareAssemblyVersion));
Dictionary<ITypeDefOrRef, List<ITypeDefOrRef>> refs = new Dictionary<ITypeDefOrRef, List<ITypeDefOrRef>>(TypeEqualityComparer.Instance);
public T this[ITypeDefOrRef type] {
get {
if (TryGetValue(type, out var value))
return value;
throw new KeyNotFoundException();
}
set {
dict[type] = value;
if (value != null) {
if (!refs.TryGetValue(type, out var list))
refs[type] = list = new List<ITypeDefOrRef>();
list.Add(type);
}
}
}
public bool TryGetValue(ITypeDefOrRef type, out T value) => dict.TryGetValue(type, out value);
public bool TryGetSimilarValue(ITypeDefOrRef type, out T value) {
if (!refs.TryGetValue(type, out var list)) {
value = default;
return false;
}
// Find a type whose version is >= type's version and closest to it.
ITypeDefOrRef foundType = null;
var typeAsmName = type.DefinitionAssembly;
IAssembly foundAsmName = null;
foreach (var otherRef in list) {
if (!dict.TryGetValue(otherRef, out value))
continue;
if (typeAsmName == null) {
foundType = otherRef;
break;
}
var otherAsmName = otherRef.DefinitionAssembly;
if (otherAsmName == null)
continue;
// Check pkt or we could return a type in eg. a SL assembly when it's not a SL app.
if (!PublicKeyBase.TokenEquals(typeAsmName.PublicKeyOrToken, otherAsmName.PublicKeyOrToken))
continue;
if (typeAsmName.Version > otherAsmName.Version)
continue; // old version
if (foundType == null) {
foundAsmName = otherAsmName;
foundType = otherRef;
continue;
}
if (foundAsmName.Version <= otherAsmName.Version)
continue;
foundAsmName = otherAsmName;
foundType = otherRef;
}
if (foundType != null) {
value = dict[foundType];
return true;
}
value = default;
return false;
}
}
AssemblyKeyDictionary<MTypeDef> typeToTypeDefDict = new AssemblyKeyDictionary<MTypeDef>();
public MTypeDef ResolveOther(ITypeDefOrRef type) {
if (type == null)
return null;
type = type.ScopeType;
if (type == null)
return null;
if (typeToTypeDefDict.TryGetValue(type, out var typeDef))
return typeDef;
var typeDef2 = deobfuscatorContext.ResolveType(type);
if (typeDef2 == null) {
typeToTypeDefDict.TryGetSimilarValue(type, out typeDef);
typeToTypeDefDict[type] = typeDef;
return typeDef;
}
if (typeToTypeDefDict.TryGetValue(typeDef2, out typeDef)) {
typeToTypeDefDict[type] = typeDef;
return typeDef;
}
typeToTypeDefDict[type] = null; // In case of a circular reference
typeToTypeDefDict[typeDef2] = null;
typeDef = new MTypeDef(typeDef2, null, 0);
typeDef.AddMembers();
foreach (var iface in typeDef.TypeDef.Interfaces) {
var ifaceDef = ResolveOther(iface.Interface);
if (ifaceDef == null)
continue;
typeDef.AddInterface(ifaceDef, iface.Interface);
}
var baseDef = ResolveOther(typeDef.TypeDef.BaseType);
if (baseDef != null)
typeDef.AddBaseType(baseDef, typeDef.TypeDef.BaseType);
typeToTypeDefDict[type] = typeDef;
if (type != typeDef2)
typeToTypeDefDict[typeDef2] = typeDef;
return typeDef;
}
public MethodNameGroups InitializeVirtualMembers() {
var groups = new MethodNameGroups();
foreach (var typeDef in allTypes)
typeDef.InitializeVirtualMembers(groups, this);
return groups;
}
public void OnTypesRenamed() {
foreach (var module in modules)
module.OnTypesRenamed();
}
public void CleanUp() {
#if PORT
foreach (var module in DotNetUtils.typeCaches.invalidateAll())
AssemblyResolver.Instance.removeModule(module);
#endif
}
// Returns null if it's a non-loaded module/assembly
IEnumerable<Module> FindModules(ITypeDefOrRef type) {
if (type == null)
return null;
var scope = type.Scope;
if (scope == null)
return null;
var scopeType = scope.ScopeType;
if (scopeType == ScopeType.AssemblyRef)
return FindModules((AssemblyRef)scope);
if (scopeType == ScopeType.ModuleDef) {
var modules = FindModules((ModuleDef)scope);
if (modules != null)
return modules;
}
if (scopeType == ScopeType.ModuleRef) {
var moduleRef = (ModuleRef)scope;
if (moduleRef.Name == type.Module.Name) {
var modules = FindModules(type.Module);
if (modules != null)
return modules;
}
}
if (scopeType == ScopeType.ModuleRef || scopeType == ScopeType.ModuleDef) {
var asm = type.Module.Assembly;
if (asm == null)
return null;
var moduleHash = assemblyHash.Lookup(asm);
if (moduleHash == null)
return null;
var module = moduleHash.Lookup(scope.ScopeName);
if (module == null)
return null;
return new List<Module> { module };
}
throw new ApplicationException($"scope is an unsupported type: {scope.GetType()}");
}
IEnumerable<Module> FindModules(AssemblyRef assemblyRef) {
var moduleHash = assemblyHash.Lookup(assemblyRef);
if (moduleHash != null)
return moduleHash.Modules;
return null;
}
IEnumerable<Module> FindModules(ModuleDef moduleDef) {
if (modulesDict.TryGetValue(moduleDef, out var module))
return new List<Module> { module };
return null;
}
bool IsAutoCreatedType(ITypeDefOrRef typeRef) {
var ts = typeRef as TypeSpec;
if (ts == null)
return false;
var sig = ts.TypeSig;
if (sig == null)
return false;
return sig.IsSZArray || sig.IsArray || sig.IsPointer;
}
public MTypeDef ResolveType(ITypeDefOrRef typeRef) {
var modules = FindModules(typeRef);
if (modules == null)
return null;
foreach (var module in modules) {
var rv = module.ResolveType(typeRef);
if (rv != null)
return rv;
}
if (IsAutoCreatedType(typeRef))
return null;
Logger.e("Could not resolve TypeRef {0} ({1:X8}) (from {2} -> {3})",
Utils.RemoveNewlines(typeRef),
typeRef.MDToken.ToInt32(),
typeRef.Module,
typeRef.Scope);
return null;
}
public MMethodDef ResolveMethod(IMethodDefOrRef methodRef) {
if (methodRef.DeclaringType == null)
return null;
var modules = FindModules(methodRef.DeclaringType);
if (modules == null)
return null;
foreach (var module in modules) {
var rv = module.ResolveMethod(methodRef);
if (rv != null)
return rv;
}
if (IsAutoCreatedType(methodRef.DeclaringType))
return null;
Logger.e("Could not resolve MethodRef {0} ({1:X8}) (from {2} -> {3})",
Utils.RemoveNewlines(methodRef),
methodRef.MDToken.ToInt32(),
methodRef.DeclaringType.Module,
methodRef.DeclaringType.Scope);
return null;
}
public MFieldDef ResolveField(MemberRef fieldRef) {
if (fieldRef.DeclaringType == null)
return null;
var modules = FindModules(fieldRef.DeclaringType);
if (modules == null)
return null;
foreach (var module in modules) {
var rv = module.ResolveField(fieldRef);
if (rv != null)
return rv;
}
if (IsAutoCreatedType(fieldRef.DeclaringType))
return null;
Logger.e("Could not resolve FieldRef {0} ({1:X8}) (from {2} -> {3})",
Utils.RemoveNewlines(fieldRef),
fieldRef.MDToken.ToInt32(),
fieldRef.DeclaringType.Module,
fieldRef.DeclaringType.Scope);
return null;
}
}
}