private static Compilation GetCompilation(Type type) { lock (decompiledTypes) { if (!decompiledTypes.TryGetValue(type, out Compilation compilation)) { EntityHandle handle = MetadataTokenHelpers.TryAsEntityHandle(type.MetadataToken) ?? throw new InvalidOperationException(); string assemblyPath = type.Assembly.Location; if (!decompilers.TryGetValue(assemblyPath, out CSharpDecompiler decompiler)) { decompiler = CreateDecompiler(assemblyPath); decompilers.Add(assemblyPath, decompiler); } string sourceCode = decompiler.DecompileAsString(handle); sourceCode = ClosureTypeDeclarationRegex.Replace(sourceCode, ShaderGenerator.DelegateTypeName); sourceCode = LambdaMethodDeclarationRegex.Replace(sourceCode, $"internal void {ShaderGenerator.DelegateEntryPointName}"); SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(sourceCode, CSharpParseOptions.Default.WithLanguageVersion(Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp8)); compilation = globalCompilation.AddSyntaxTrees(syntaxTree); decompiledTypes.Add(type, compilation); } return(compilation); } }
bool ScanMethodBody(ITypeDefinition analyzedEntity, IMethod method, MethodBodyBlock methodBody) { bool found = false; var blob = methodBody.GetILReader(); var module = (MetadataModule)method.ParentModule; var genericContext = new Decompiler.TypeSystem.GenericContext(); // type parameters don't matter for this analyzer while (!found && blob.RemainingBytes > 0) { var opCode = blob.DecodeOpCode(); if (!CanBeReference(opCode)) { blob.SkipOperand(opCode); continue; } EntityHandle methodHandle = MetadataTokenHelpers.EntityHandleOrNil(blob.ReadInt32()); if (!methodHandle.Kind.IsMemberKind()) { continue; } var ctor = module.ResolveMethod(methodHandle, genericContext); if (ctor == null || !ctor.IsConstructor) { continue; } if (ctor.DeclaringTypeDefinition?.MetadataToken == analyzedEntity.MetadataToken && ctor.ParentModule.PEFile == analyzedEntity.ParentModule.PEFile) { return(true); } } return(false); }
private static Compilation GetCompilation(Type type) { lock (decompiledTypes) { if (!decompiledTypes.TryGetValue(type, out Compilation compilation)) { EntityHandle handle = MetadataTokenHelpers.TryAsEntityHandle(type.MetadataToken) ?? throw new InvalidOperationException(); string assemblyPath = type.Assembly.Location; if (!decompilers.TryGetValue(assemblyPath, out CSharpDecompiler decompiler)) { decompiler = CreateDecompiler(assemblyPath); decompilers.Add(assemblyPath, decompiler); } string sourceCode = decompiler.DecompileAsString(handle); sourceCode = AnonymousMethodDeclaringTypeDeclarationRegex.Replace(sourceCode, ShaderGenerator.AnonymousMethodDeclaringTypeName); sourceCode = AnonymousMethodDeclarationRegex.Replace(sourceCode, $"internal void {ShaderGenerator.AnonymousMethodEntryPointName}"); SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(sourceCode); IList <MetadataReference> metadataReferences = GetMetadataReferences(type.Assembly, type.Assembly.GetName(), typeof(object).Assembly.GetName()); compilation = CSharpCompilation.Create("ShaderAssembly", new[] { syntaxTree }, metadataReferences); decompiledTypes.Add(type, compilation); } return(compilation); } }
public MetadataTokenSearchStrategy(Language language, ApiVisibility apiVisibility, IProducerConsumerCollection <SearchResult> resultQueue, params string[] terms) : base(language, apiVisibility, resultQueue, terms) { if (terms.Length == 1) { int.TryParse(terms[0], NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var token); searchTermToken = MetadataTokenHelpers.EntityHandleOrNil(token); } }
public MetadataTokenSearchStrategy(Language language, Action <SearchResult> addResult, params string[] terms) : base(language, addResult, terms) { if (terms.Length == 1) { int.TryParse(terms[0], NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var token); searchTermToken = MetadataTokenHelpers.EntityHandleOrNil(token); } }
bool ScanMethodBody(IField analyzedField, IMethod method, MethodBodyBlock methodBody) { if (methodBody == null) { return(false); } var mainModule = (MetadataModule)method.ParentModule; var blob = methodBody.GetILReader(); var genericContext = new Decompiler.TypeSystem.GenericContext(); // type parameters don't matter for this analyzer while (blob.RemainingBytes > 0) { ILOpCode opCode; try { opCode = blob.DecodeOpCode(); if (!CanBeReference(opCode)) { blob.SkipOperand(opCode); continue; } } catch (BadImageFormatException) { return(false); } EntityHandle fieldHandle = MetadataTokenHelpers.EntityHandleOrNil(blob.ReadInt32()); if (!fieldHandle.Kind.IsMemberKind()) { continue; } IField field; try { field = mainModule.ResolveEntity(fieldHandle, genericContext) as IField; } catch (BadImageFormatException) { continue; } if (field == null) { continue; } if (field.MetadataToken == analyzedField.MetadataToken && field.ParentModule.PEFile == analyzedField.ParentModule.PEFile) { return(true); } } return(false); }
/// <summary> /// Decompiles a target method and returns its <see cref="SyntaxTree"/> and <see cref="SemanticModel"/> info /// </summary> /// <param name="methodInfo">The input <see cref="MethodInfo"/> to inspect</param> /// <param name="rootNode">The root node for the syntax tree of the input method</param> /// <param name="semanticModel">The semantic model for the input method</param> public void GetSyntaxTree(MethodInfo methodInfo, out MethodDeclarationSyntax rootNode, out SemanticModel semanticModel) { lock (Lock) { // Get the handle of the containing type method string assemblyPath = methodInfo.DeclaringType?.Assembly.Location ?? throw new InvalidOperationException(); EntityHandle typeHandle = MetadataTokenHelpers.TryAsEntityHandle(methodInfo.DeclaringType.MetadataToken) ?? throw new InvalidOperationException(); // Get or create a decompiler for the target assembly, and decompile the type if (!Decompilers.TryGetValue(assemblyPath, out CSharpDecompiler decompiler)) { decompiler = CreateDecompiler(assemblyPath); Decompilers.Add(assemblyPath, decompiler); } // Decompile the method source and fix the method declaration for local methods converted to lambdas string sourceCode = decompiler.DecompileAsString(typeHandle), typeFixedCode = ClosureTypeDeclarationRegex.Replace(sourceCode, "Shader"), methodFixedCode = LambdaMethodDeclarationRegex.Replace(typeFixedCode, m => $"// {m.Value}{Environment.NewLine} internal void Main"); // Workaround for some local methods not being decompiled correctly if (!methodFixedCode.Contains("internal void Main")) { EntityHandle methodHandle = MetadataTokenHelpers.TryAsEntityHandle(methodInfo.MetadataToken) ?? throw new InvalidOperationException(); string methodOnlySourceCode = decompiler.DecompileAsString(methodHandle), methodOnlyFixedSourceCode = LambdaMethodDeclarationRegex.Replace(methodOnlySourceCode, m => $"// {m.Value}{Environment.NewLine} internal void Main"), methodOnlyIndentedSourceCode = $" {methodOnlyFixedSourceCode.Replace(Environment.NewLine, $"{Environment.NewLine} ")}"; int lastClosedBracketsIndex = methodFixedCode.LastIndexOf('}'); methodFixedCode = methodFixedCode.Insert(lastClosedBracketsIndex, methodOnlyIndentedSourceCode); } // Unwrap the nested fields string unwrappedSourceCode = UnwrapSyntaxTree(methodFixedCode); // Remove the in keyword from the source string inFixedSourceCode = Regex.Replace(unwrappedSourceCode, @"(?<!\w)in ", string.Empty); // Tweak the out declarations string outFixedSourceCode = RefactorInlineOutDeclarations(inFixedSourceCode, methodInfo.Name); // Load the type syntax tree SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(outFixedSourceCode); // Get the root node to return rootNode = syntaxTree.GetRoot().DescendantNodes().OfType <MethodDeclarationSyntax>().First(node => node.GetLeadingTrivia().ToFullString().Contains(methodInfo.Name)); // Update the incremental compilation and retrieve the syntax tree for the method _Compilation = _Compilation.AddSyntaxTrees(syntaxTree); semanticModel = _Compilation.GetSemanticModel(syntaxTree); } }
public MetadataTokenSearchStrategy(ILanguage language, ApiVisibility apiVisibility, SearchRequest request, IProducerConsumerCollection <SearchResult> resultQueue) : base(language, apiVisibility, request, resultQueue) { var terms = request.Keywords; if (terms.Length == 1) { int.TryParse(terms[0], NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var token); searchTermToken = MetadataTokenHelpers.EntityHandleOrNil(token); } }
public DecompilationResult Decompile <TRes>(Func <ICursor, RedisValue[], RedisKey[], TRes> action) where TRes : RedResult { var token = action.Method.MetadataToken; var method = MetadataTokenHelpers.TryAsEntityHandle(token); var ast = _decompiler.Decompile(new List <EntityHandle>() { method.Value }); return(ExtractTreeAndMetadata(ast)); }
private string DecompileMethodOrDeclaringType(MethodInfo methodInfo, bool methodOnly = false) { // Get the handle of the containing type method string assemblyPath = methodInfo.DeclaringType?.Assembly.Location ?? throw new InvalidOperationException(); int metadataToken = methodInfo.IsStatic || methodOnly ? methodInfo.MetadataToken : methodInfo.DeclaringType.MetadataToken; EntityHandle typeHandle = MetadataTokenHelpers.TryAsEntityHandle(metadataToken) ?? throw new InvalidOperationException(); // Get or create a decompiler for the target assembly, and decompile the type if (!Decompilers.TryGetValue(assemblyPath, out CSharpDecompiler decompiler)) { decompiler = CreateDecompiler(assemblyPath); Decompilers.Add(assemblyPath, decompiler); } return(decompiler.DecompileAsString(typeHandle)); }
public SyntaxTree Read(Delegate @delegate) { Contract.Assert(@delegate?.Method?.DeclaringType != null); var asm = @delegate.Method.DeclaringType.Assembly; _assemblyProvider.Prepare(asm); var decompiler = new CSharpDecompiler(asm.Location, _assemblyProvider, new DecompilerSettings() { ExtensionMethods = false, NamedArguments = false }); var token = @delegate.Method.MetadataToken; var method = MetadataTokenHelpers.TryAsEntityHandle(token); var ast = decompiler.Decompile(new List <EntityHandle>() { method.Value }); return(ast); }
public override ProjectId DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options) { var module = assembly.GetPEFileOrNull(); if (module == null) { return(null); } if (options.FullDecompilation && options.SaveAsProjectDirectory != null) { if (!WholeProjectDecompiler.CanUseSdkStyleProjectFormat(module)) { options.DecompilerSettings.UseSdkStyleProjectFormat = false; } var decompiler = new ILSpyWholeProjectDecompiler(assembly, options); return(decompiler.DecompileProject(module, options.SaveAsProjectDirectory, new TextOutputWriter(output), options.CancellationToken)); } else { AddReferenceAssemblyWarningMessage(module, output); AddReferenceWarningMessage(module, output); output.WriteLine(); base.DecompileAssembly(assembly, output, options); // don't automatically load additional assemblies when an assembly node is selected in the tree view IAssemblyResolver assemblyResolver = assembly.GetAssemblyResolver(loadOnDemand: options.FullDecompilation); var typeSystem = new DecompilerTypeSystem(module, assemblyResolver, options.DecompilerSettings); var globalType = typeSystem.MainModule.TypeDefinitions.FirstOrDefault(); if (globalType != null) { output.Write("// Global type: "); output.WriteReference(globalType, globalType.FullName); output.WriteLine(); } var metadata = module.Metadata; var corHeader = module.Reader.PEHeaders.CorHeader; var entrypointHandle = MetadataTokenHelpers.EntityHandleOrNil(corHeader.EntryPointTokenOrRelativeVirtualAddress); if (!entrypointHandle.IsNil && entrypointHandle.Kind == HandleKind.MethodDefinition) { var entrypoint = typeSystem.MainModule.ResolveMethod(entrypointHandle, new Decompiler.TypeSystem.GenericContext()); if (entrypoint != null) { output.Write("// Entry point: "); output.WriteReference(entrypoint, entrypoint.DeclaringType.FullName + "." + entrypoint.Name); output.WriteLine(); } } output.WriteLine("// Architecture: " + GetPlatformDisplayName(module)); if ((corHeader.Flags & System.Reflection.PortableExecutable.CorFlags.ILOnly) == 0) { output.WriteLine("// This assembly contains unmanaged code."); } string runtimeName = GetRuntimeDisplayName(module); if (runtimeName != null) { output.WriteLine("// Runtime: " + runtimeName); } if ((corHeader.Flags & System.Reflection.PortableExecutable.CorFlags.StrongNameSigned) != 0) { output.WriteLine("// This assembly is signed with a strong name key."); } if (module.Reader.ReadDebugDirectory().Any(d => d.Type == DebugDirectoryEntryType.Reproducible)) { output.WriteLine("// This assembly was compiled using the /deterministic option."); } if (metadata.IsAssembly) { var asm = metadata.GetAssemblyDefinition(); if (asm.HashAlgorithm != AssemblyHashAlgorithm.None) { output.WriteLine("// Hash algorithm: " + asm.HashAlgorithm.ToString().ToUpper()); } if (!asm.PublicKey.IsNil) { output.Write("// Public key: "); var reader = metadata.GetBlobReader(asm.PublicKey); while (reader.RemainingBytes > 0) { output.Write(reader.ReadByte().ToString("x2")); } output.WriteLine(); } } var debugInfo = assembly.GetDebugInfoOrNull(); if (debugInfo != null) { output.WriteLine("// Debug info: " + debugInfo.Description); } output.WriteLine(); CSharpDecompiler decompiler = new CSharpDecompiler(typeSystem, options.DecompilerSettings); decompiler.CancellationToken = options.CancellationToken; if (options.EscapeInvalidIdentifiers) { decompiler.AstTransforms.Add(new EscapeInvalidIdentifiers()); } SyntaxTree st; if (options.FullDecompilation) { st = decompiler.DecompileWholeModuleAsSingleFile(); } else { st = decompiler.DecompileModuleAndAssemblyAttributes(); } WriteCode(output, options.DecompilerSettings, st, decompiler.TypeSystem); return(null); } }
void ScanMethodBody(TypeDefinitionUsedVisitor visitor, IMethod method, MethodBodyBlock methodBody, AnalyzerContext context) { if (methodBody == null) { return; } var module = (MetadataModule)method.ParentModule; var genericContext = new Decompiler.TypeSystem.GenericContext(); // type parameters don't matter for this analyzer if (!methodBody.LocalSignature.IsNil) { ImmutableArray <IType> localSignature; try { localSignature = module.DecodeLocalSignature(methodBody.LocalSignature, genericContext); } catch (BadImageFormatException) { // Issue #2197: ignore invalid local signatures localSignature = ImmutableArray <IType> .Empty; } foreach (var type in localSignature) { type.AcceptVisitor(visitor); if (visitor.Found) { return; } } } var blob = methodBody.GetILReader(); while (!visitor.Found && blob.RemainingBytes > 0) { var opCode = blob.DecodeOpCode(); switch (opCode.GetOperandType()) { case OperandType.Field: case OperandType.Method: case OperandType.Sig: case OperandType.Tok: case OperandType.Type: var member = MetadataTokenHelpers.EntityHandleOrNil(blob.ReadInt32()); if (member.IsNil) { continue; } switch (member.Kind) { case HandleKind.TypeReference: case HandleKind.TypeSpecification: case HandleKind.TypeDefinition: module.ResolveType(member, genericContext).AcceptVisitor(visitor); if (visitor.Found) { return; } break; case HandleKind.FieldDefinition: case HandleKind.MethodDefinition: case HandleKind.MemberReference: case HandleKind.MethodSpecification: VisitMember(visitor, module.ResolveEntity(member, genericContext) as IMember, context); if (visitor.Found) { return; } break; case HandleKind.StandaloneSignature: var(_, fpt) = module.DecodeMethodSignature((StandaloneSignatureHandle)member, genericContext); fpt.AcceptVisitor(visitor); if (visitor.Found) { return; } break; default: break; } break; default: blob.SkipOperand(opCode); break; } } }
void CollectNamespacesFromMethodBody(MethodBodyBlock method, MetadataModule module) { var metadata = module.metadata; var instructions = method.GetILReader(); if (!method.LocalSignature.IsNil) { ImmutableArray <IType> localSignature; try { localSignature = module.DecodeLocalSignature(method.LocalSignature, genericContext); } catch (BadImageFormatException) { // Issue #1211: ignore invalid local signatures localSignature = ImmutableArray <IType> .Empty; } foreach (var type in localSignature) { CollectNamespacesForTypeReference(type); } } foreach (var region in method.ExceptionRegions) { if (region.CatchType.IsNil) { continue; } IType ty; try { ty = module.ResolveType(region.CatchType, genericContext); } catch (BadImageFormatException) { continue; } CollectNamespacesForTypeReference(ty); } while (instructions.RemainingBytes > 0) { ILOpCode opCode; try { opCode = instructions.DecodeOpCode(); } catch (BadImageFormatException) { return; } switch (opCode.GetOperandType()) { case OperandType.Field: case OperandType.Method: case OperandType.Sig: case OperandType.Tok: case OperandType.Type: var handle = MetadataTokenHelpers.EntityHandleOrNil(instructions.ReadInt32()); if (handle.IsNil) { break; } switch (handle.Kind) { case HandleKind.TypeDefinition: case HandleKind.TypeReference: case HandleKind.TypeSpecification: IType type; try { type = module.ResolveType(handle, genericContext); } catch (BadImageFormatException) { break; } CollectNamespacesForTypeReference(type); break; case HandleKind.FieldDefinition: case HandleKind.MethodDefinition: case HandleKind.MethodSpecification: case HandleKind.MemberReference: IMember member; try { member = module.ResolveEntity(handle, genericContext) as IMember; } catch (BadImageFormatException) { break; } CollectNamespacesForMemberReference(member); break; case HandleKind.StandaloneSignature: StandaloneSignature sig; try { sig = metadata.GetStandaloneSignature((StandaloneSignatureHandle)handle); } catch (BadImageFormatException) { break; } if (sig.GetKind() == StandaloneSignatureKind.Method) { MethodSignature <IType> methodSig; try { methodSig = module.DecodeMethodSignature((StandaloneSignatureHandle)handle, genericContext); } catch (BadImageFormatException) { break; } CollectNamespacesForTypeReference(methodSig.ReturnType); foreach (var paramType in methodSig.ParameterTypes) { CollectNamespacesForTypeReference(paramType); } } break; } break; default: try { instructions.SkipOperand(opCode); } catch (BadImageFormatException) { return; } break; } } }
protected virtual void WriteInstruction(ITextOutput output, MetadataReader metadata, MethodDefinitionHandle methodDefinition, ref BlobReader blob) { int offset = blob.Offset; if (ShowSequencePoints && nextSequencePointIndex < sequencePoints?.Count) { var sp = sequencePoints[nextSequencePointIndex]; if (sp.Offset <= offset) { output.Write("// sequence point: "); if (sp.Offset != offset) { output.Write("!! at " + DisassemblerHelpers.OffsetToString(sp.Offset) + " !!"); } if (sp.IsHidden) { output.WriteLine("hidden"); } else { output.WriteLine($"(line {sp.StartLine}, col {sp.StartColumn}) to (line {sp.EndLine}, col {sp.EndColumn}) in {sp.DocumentUrl}"); } nextSequencePointIndex++; } } ILOpCode opCode = ILParser.DecodeOpCode(ref blob); output.WriteLocalReference(DisassemblerHelpers.OffsetToString(offset), offset, isDefinition: true); output.Write(": "); if (opCode.IsDefined()) { output.WriteReference(new OpCodeInfo(opCode, opCode.GetDisplayName())); switch (opCode.GetOperandType()) { case OperandType.BrTarget: case OperandType.ShortBrTarget: output.Write(' '); int targetOffset = ILParser.DecodeBranchTarget(ref blob, opCode); output.WriteLocalReference($"IL_{targetOffset:x4}", targetOffset); break; case OperandType.Field: case OperandType.Method: case OperandType.Sig: case OperandType.Type: output.Write(' '); int metadataToken = blob.ReadInt32(); EntityHandle?handle = MetadataTokenHelpers.TryAsEntityHandle(metadataToken); try { handle?.WriteTo(module, output, genericContext); } catch (BadImageFormatException) { handle = null; } WriteMetadataToken(handle, metadataToken, spaceBefore: true); break; case OperandType.Tok: output.Write(' '); metadataToken = blob.ReadInt32(); handle = MetadataTokenHelpers.TryAsEntityHandle(metadataToken); switch (handle?.Kind) { case HandleKind.MemberReference: switch (metadata.GetMemberReference((MemberReferenceHandle)handle).GetKind()) { case MemberReferenceKind.Method: output.Write("method "); break; case MemberReferenceKind.Field: output.Write("field "); break; } break; case HandleKind.FieldDefinition: output.Write("field "); break; case HandleKind.MethodDefinition: output.Write("method "); break; } try { handle?.WriteTo(module, output, genericContext); } catch (BadImageFormatException) { handle = null; } WriteMetadataToken(handle, metadataToken, spaceBefore: true); break; case OperandType.ShortI: output.Write(' '); DisassemblerHelpers.WriteOperand(output, blob.ReadSByte()); break; case OperandType.I: output.Write(' '); DisassemblerHelpers.WriteOperand(output, blob.ReadInt32()); break; case OperandType.I8: output.Write(' '); DisassemblerHelpers.WriteOperand(output, blob.ReadInt64()); break; case OperandType.ShortR: output.Write(' '); DisassemblerHelpers.WriteOperand(output, blob.ReadSingle()); break; case OperandType.R: output.Write(' '); DisassemblerHelpers.WriteOperand(output, blob.ReadDouble()); break; case OperandType.String: metadataToken = blob.ReadInt32(); output.Write(' '); UserStringHandle?userString; string text; try { userString = MetadataTokens.UserStringHandle(metadataToken); text = metadata.GetUserString(userString.Value); } catch (BadImageFormatException) { userString = null; text = null; } if (userString != null) { DisassemblerHelpers.WriteOperand(output, text); } WriteMetadataToken(userString, metadataToken, spaceBefore: true); break; case OperandType.Switch: int[] targets = ILParser.DecodeSwitchTargets(ref blob); output.Write(" ("); for (int i = 0; i < targets.Length; i++) { if (i > 0) { output.Write(", "); } output.WriteLocalReference($"IL_{targets[i]:x4}", targets[i]); } output.Write(")"); break; case OperandType.Variable: output.Write(' '); int index = blob.ReadUInt16(); if (opCode == ILOpCode.Ldloc || opCode == ILOpCode.Ldloca || opCode == ILOpCode.Stloc) { DisassemblerHelpers.WriteVariableReference(output, metadata, methodDefinition, index); } else { DisassemblerHelpers.WriteParameterReference(output, metadata, methodDefinition, index); } break; case OperandType.ShortVariable: output.Write(' '); index = blob.ReadByte(); if (opCode == ILOpCode.Ldloc_s || opCode == ILOpCode.Ldloca_s || opCode == ILOpCode.Stloc_s) { DisassemblerHelpers.WriteVariableReference(output, metadata, methodDefinition, index); } else { DisassemblerHelpers.WriteParameterReference(output, metadata, methodDefinition, index); } break; } } else { ushort opCodeValue = (ushort)opCode; if (opCodeValue > 0xFF) { // split 16-bit value into two emitbyte directives output.WriteLine($".emitbyte 0x{(byte)(opCodeValue >> 8):x}"); // add label output.WriteLocalReference(DisassemblerHelpers.OffsetToString(offset + 1), offset + 1, isDefinition: true); output.Write(": "); output.Write($".emitbyte 0x{(byte)(opCodeValue & 0xFF):x}"); } else { output.Write($".emitbyte 0x{(byte)opCodeValue:x}"); } } output.WriteLine(); }
public override void DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options) { var module = assembly.GetPEFileOrNull(); if (options.FullDecompilation && options.SaveAsProjectDirectory != null) { var decompiler = new ILSpyWholeProjectDecompiler(assembly, options); decompiler.DecompileProject(module, options.SaveAsProjectDirectory, new TextOutputWriter(output), options.CancellationToken); } else { AddReferenceAssemblyWarningMessage(module, output); AddReferenceWarningMessage(module, output); output.WriteLine(); base.DecompileAssembly(assembly, output, options); // don't automatically load additional assemblies when an assembly node is selected in the tree view using (options.FullDecompilation ? null : LoadedAssembly.DisableAssemblyLoad()) { IAssemblyResolver assemblyResolver = assembly.GetAssemblyResolver(); var typeSystem = new DecompilerTypeSystem(module, assemblyResolver, options.DecompilerSettings); var globalType = typeSystem.MainModule.TypeDefinitions.FirstOrDefault(); if (globalType != null) { output.Write("// Global type: "); output.WriteReference(globalType, globalType.FullName); output.WriteLine(); } var metadata = module.Metadata; var corHeader = module.Reader.PEHeaders.CorHeader; var entrypointHandle = MetadataTokenHelpers.EntityHandleOrNil(corHeader.EntryPointTokenOrRelativeVirtualAddress); if (!entrypointHandle.IsNil && entrypointHandle.Kind == HandleKind.MethodDefinition) { var entrypoint = typeSystem.MainModule.ResolveMethod(entrypointHandle, new Decompiler.TypeSystem.GenericContext()); if (entrypoint != null) { output.Write("// Entry point: "); output.WriteReference(entrypoint, entrypoint.DeclaringType.FullName + "." + entrypoint.Name); output.WriteLine(); } } output.WriteLine("// Architecture: " + GetPlatformDisplayName(module)); if ((corHeader.Flags & System.Reflection.PortableExecutable.CorFlags.ILOnly) == 0) { output.WriteLine("// This assembly contains unmanaged code."); } string runtimeName = GetRuntimeDisplayName(module); if (runtimeName != null) { output.WriteLine("// Runtime: " + runtimeName); } var debugInfo = assembly.GetDebugInfoOrNull(); if (debugInfo != null) { output.WriteLine("// Debug info: " + debugInfo.Description); } output.WriteLine(); CSharpDecompiler decompiler = new CSharpDecompiler(typeSystem, options.DecompilerSettings); decompiler.CancellationToken = options.CancellationToken; SyntaxTree st; if (options.FullDecompilation) { st = decompiler.DecompileWholeModuleAsSingleFile(); } else { st = decompiler.DecompileModuleAndAssemblyAttributes(); } WriteCode(output, options.DecompilerSettings, st, decompiler.TypeSystem); } } }
private string GetAssemblyCode(string assemblyPath, CSharpDecompiler decompiler) { using (var output = new StringWriter()) { WriteCommentLine(output, assemblyPath); var module = decompiler.TypeSystem.MainModule.PEFile; var metadata = module.Metadata; if (metadata.IsAssembly) { var name = metadata.GetAssemblyDefinition(); if ((name.Flags & System.Reflection.AssemblyFlags.WindowsRuntime) != 0) { WriteCommentLine(output, metadata.GetString(name.Name) + " [WinRT]"); } else { WriteCommentLine(output, metadata.GetFullAssemblyName()); } } else { WriteCommentLine(output, module.Name); } var mainModule = decompiler.TypeSystem.MainModule; var globalType = mainModule.TypeDefinitions.FirstOrDefault(); if (globalType != null) { output.Write("// Global type: "); output.Write(globalType.FullName); output.WriteLine(); } var corHeader = module.Reader.PEHeaders.CorHeader; var entrypointHandle = MetadataTokenHelpers.EntityHandleOrNil(corHeader.EntryPointTokenOrRelativeVirtualAddress); if (!entrypointHandle.IsNil && entrypointHandle.Kind == HandleKind.MethodDefinition) { var entrypoint = mainModule.ResolveMethod(entrypointHandle, new ICSharpCode.Decompiler.TypeSystem.GenericContext()); if (entrypoint != null) { output.Write("// Entry point: "); output.Write(entrypoint.DeclaringType.FullName + "." + entrypoint.Name); output.WriteLine(); } } output.WriteLine("// Architecture: " + module.GetPlatformDisplayName()); if ((corHeader.Flags & System.Reflection.PortableExecutable.CorFlags.ILOnly) == 0) { output.WriteLine("// This assembly contains unmanaged code."); } string runtimeName = module.GetRuntimeDisplayName(); if (runtimeName != null) { output.WriteLine("// Runtime: " + runtimeName); } output.WriteLine(); output.Write(decompiler.DecompileModuleAndAssemblyAttributesToString()); output.WriteLine(); return(output.ToString()); } }
/// <summary> /// Saves this object as an Inno Setup formatted script /// </summary> /// <param name="textWriter"><see cref="TextWriter"/> with which script is written</param> public virtual void Save(TextWriter textWriter) { var thisType = typeof(Installation); var derivedType = GetType(); var entriesBuilder = new ParameterizedEntriesBuilder(textWriter); // list of methods referenced by constants var constReferencedMethods = new HashSet <InstallationMethod>(); _constantReferencedMethod = methodInfo => constReferencedMethods.Add(new InstallationMethod(methodInfo)); try { using (new Section(textWriter, "Setup")) { var setupProperties = thisType.GetProperties(BindingFlags.Public | BindingFlags.Instance) .Where(p => p.GetCustomAttribute <SetupDirectiveAttribute>() != null) .Select(p => new { Alias = p.GetCustomAttribute <AliasAttribute>()?.Name, Property = derivedType.GetProperty(p.Name), TypeConverter = p.GetCustomAttribute <TypeConverterAttribute>() }) .Where(p => p.Property.DeclaringType != thisType) .Select(p => new { p.Property, Name = p.Alias ?? p.Property.Name, p.TypeConverter }) .OrderBy(p => p.Name) .ToList(); WriteDirectives(textWriter, setupProperties.Select(p => (p.Name, p.Property, p.TypeConverter))); } var langOptionsProperties = thisType.GetProperties(BindingFlags.Public | BindingFlags.Instance) .Where(p => p.GetCustomAttribute <LanguageDirectiveAttribute>() != null) .Select(p => new { Alias = p.GetCustomAttribute <AliasAttribute>()?.Name, Property = derivedType.GetProperty(p.Name), TypeConverter = p.GetCustomAttribute <TypeConverterAttribute>() }) .Where(p => derivedType.GetProperty(p.Property.Name).DeclaringType != thisType) .Select(p => new { p.Property, Name = p.Alias ?? p.Property.Name, p.TypeConverter }) .OrderBy(p => p.Name) .ToList(); if (langOptionsProperties.Count > 0) { using (new Section(textWriter, "LanguageOptions")) { WriteDirectives(textWriter, langOptionsProperties.Select(p => (p.Name, p.Property, p.TypeConverter))); } } ParameterizedEntriesBuilderHandler?.Invoke(entriesBuilder); } finally { _constantReferencedMethod = null; } using (new Section(textWriter, "Code")) { textWriter.WriteLine("const"); textWriter.WriteLine(" MB_ICONWARNING = $30;"); textWriter.WriteLine(" MB_ICONINFORMATION = $40;"); textWriter.WriteLine(" MB_ICONQUESTION = $20;"); textWriter.WriteLine(" MB_ICONERROR = $10;"); textWriter.WriteBlankLine(); var decompilers = new Dictionary <string, CSharpDecompiler>(); SyntaxTree GetSyntaxTree(string assemblyLocation, int metadataToken) { var settings = new DecompilerSettings { UseDebugSymbols = true, NamedArguments = false, SwitchExpressions = false, OutVariables = false, SeparateLocalVariableDeclarations = true, LoadInMemory = true, ShowXmlDocumentation = false, Discards = false }; var assemblyName = assemblyLocation; var peFile = new PEFile( assemblyName, new FileStream(assemblyName, FileMode.Open, FileAccess.Read), streamOptions: settings.LoadInMemory ? PEStreamOptions.PrefetchEntireImage : PEStreamOptions.Default, metadataOptions: settings.ApplyWindowsRuntimeProjections ? MetadataReaderOptions.ApplyWindowsRuntimeProjections : MetadataReaderOptions.None ); var resolver = new UniversalAssemblyResolver(assemblyName, settings.ThrowOnAssemblyResolveErrors, peFile.DetectTargetFrameworkId(), settings.LoadInMemory ? PEStreamOptions.PrefetchMetadata : PEStreamOptions.Default, settings.ApplyWindowsRuntimeProjections ? MetadataReaderOptions.ApplyWindowsRuntimeProjections : MetadataReaderOptions.None); var typeSystem = new DecompilerTypeSystem(peFile, resolver); var decompiler = decompilers.Set( assemblyName, new CSharpDecompiler(typeSystem, settings) { DebugInfoProvider = new MetadataDebugInfoProvider(assemblyName) } ); var method = MetadataTokenHelpers.TryAsEntityHandle(metadataToken); return(decompiler.Decompile(new List <EntityHandle>() { method.Value })); } var eventHandlers = thisType.GetMethods(BindingFlags.Instance | BindingFlags.Public).Where(m => m.GetCustomAttribute <EventHandlerAttribute>() != null) .Select(m => new { DerivedMethod = derivedType.GetMethod(m.Name, BindingFlags.Public | BindingFlags.Instance), InterfaceMethod = m }) .Select(m => { if (m.DerivedMethod.DeclaringType != typeof(Installation)) { return(new InstallationMethod(m.DerivedMethod, m.InterfaceMethod)); } return(null); }) .Where(m => m != null) .ToList(); var allMethods = entriesBuilder.Methods .Concat(eventHandlers) .Concat(constReferencedMethods) .ToList(); var aliasFactory = new Func <string, string>(name => { var method = allMethods.Single(m => m.Name == name); return(method.GetAttribute <AliasAttribute>()?.Name); }); bool encounteredInitializeSetup = false; bool encounteredInitializeUninstall = false; var referencedGlobalVariables = new Dictionary <FieldInfo, string>(); var definedMethods = new HashSet <string>(); var declaredMembers = new HashSet <MemberInfo>(); var namespaces = new HashSet <string>(); using var typeDefinitions = new Snippet(); var type = derivedType; while (type != null && type != typeof(Installation)) { namespaces.Add(type.Namespace); type = type.BaseType; } using (var snippet = new Snippet()) { foreach (var installationMethod in allMethods) { switch (installationMethod.Name) { case nameof(Installation.InitializeSetup): encounteredInitializeSetup = true; break; case nameof(Installation.InitializeUninstall): encounteredInitializeUninstall = true; break; } if (!definedMethods.Add(installationMethod.UniqueId)) { // already defined, probably via recursion when one method called another continue; } var ast = GetSyntaxTree(installationMethod.AssemblyLocation, installationMethod.MetadataToken); //ast.VisitChildren(new DiagnosticVisitor(Console.Out)); var methodDecl = ast.Children.OfType <MethodDeclaration>().Single(); using (var masterWriter = new TextCodeWriter(snippet, null, true)) { var codeWriterFactory = new NestedCodeWriterFactory(masterWriter); using (var methodWriter = codeWriterFactory.New()) { var context = new PascalScriptVisitorContext( this, methodWriter, null, namespaces, mi => GetSyntaxTree(mi.DeclaringType.Assembly.Location, mi.MetadataToken), referencedGlobalVariables, aliasFactory, new TextCodeWriter(typeDefinitions, null, false), declaredMembers, () => codeWriterFactory.New(), derivedType.BaseType, definedMethods); ast.VisitChildren(new PascalScriptVisitor(context)); methodWriter.WriteBlankLine(); } } } using (var codeWriter = new TextCodeWriter(textWriter, null, true)) { typeDefinitions.CopyTo(codeWriter); var usedSwitches = new HashSet <string>(); var variableInitialization = new List <(string name, string rhs)>(); // write global variables if (referencedGlobalVariables.Count > 0) { codeWriter.WriteLine("var"); using (codeWriter.Indent()) { foreach (var globalVariable in referencedGlobalVariables) { codeWriter.WriteLine($"{globalVariable.Value}: {globalVariable.Key.FieldType.ToPascal()};"); var defaultValue = globalVariable.Key.GetValue(this); var formattedDefaultValue = defaultValue == null || globalVariable.Key.FieldType.IsStruct() ? null : PascalScriptVisitor.FormatPrimitive(defaultValue); var cmdLineAttr = (globalVariable.Key.GetCustomAttribute <CommandLineParameterAttribute>()); if (cmdLineAttr != null) { var name = cmdLineAttr.SwitchName ?? globalVariable.Key.Name; var initialization = $"ExpandConstant('{{param:{name.ToLower()}"; if (defaultValue != null) { defaultValue = defaultValue.GetType() == typeof(bool) ? ((bool)defaultValue ? "1" : "0") : formattedDefaultValue; initialization += $"|{defaultValue}"; } initialization += "}')"; if (globalVariable.Key.FieldType == typeof(bool)) { initialization = $"({initialization} = '1')"; } if (!usedSwitches.Add(name)) { throw new NotSupportedException($"The command line parameter name {name} can be used only once"); } variableInitialization.Add((globalVariable.Key.Name, initialization)); } else if (formattedDefaultValue != null) { // FormatPrimitive() won't single quote the string if (defaultValue is string) { formattedDefaultValue = $"'{formattedDefaultValue}'"; } variableInitialization.Add((globalVariable.Key.Name, formattedDefaultValue)); } } } } codeWriter.WriteBlankLine(); // write body of code snippet.CopyTo(codeWriter); using (var globalVariableSnippet = new Snippet()) { using (var globalVariableWriter = new TextCodeWriter(globalVariableSnippet, null, true)) { variableInitialization.ForEach(init => globalVariableWriter.WriteLine($"{init.name} := {init.rhs};")); } if (encounteredInitializeSetup || variableInitialization.Count > 0) { // write InitializeSetup codeWriter.WriteLine($"function {nameof(Installation.InitializeSetup)}: Boolean;"); codeWriter.WriteBegin(); using (codeWriter.Indent()) { // write variable initialization globalVariableSnippet.CopyTo(codeWriter); codeWriter.WriteBlankLine(); codeWriter.WriteLine(encounteredInitializeSetup ? "Result := this_InitializeSetup();" : "Result := True;"); } codeWriter.WriteEnd(); } if (encounteredInitializeUninstall || variableInitialization.Count > 0) { // write InitializeSetup codeWriter.WriteLine($"function {nameof(Installation.InitializeUninstall)}: Boolean;"); codeWriter.WriteBegin(); using (codeWriter.Indent()) { // write variable initialization globalVariableSnippet.CopyTo(codeWriter); codeWriter.WriteBlankLine(); codeWriter.WriteLine(encounteredInitializeUninstall ? "Result := this_InitializeUninstall();" : "Result := True;"); } codeWriter.WriteEnd(); } } } } } }
private string UnwrapSyntaxTree(string source) { List <FieldDeclarationSyntax> parsedFields = new List <FieldDeclarationSyntax>(); // Local function to recursively extract all the nested fields void ParseNestedFields(string typeSource) { // Find the field declarations Match match = NestedClosureFieldRegex.Match(typeSource); if (!match.Success) { return; } // Load the nested closure type string fullname = match.Groups[1].Value.Replace(".<>", "+<>"); // Fullname of a nested type Type type = AppDomain.CurrentDomain.GetAssemblies().Select(a => a.GetType(fullname)).First(t => t != null); // Decompile the type and get a readable source code EntityHandle typeHandle = MetadataTokenHelpers.TryAsEntityHandle(type.MetadataToken) ?? throw new InvalidOperationException(); CSharpDecompiler decompiler = Decompilers[type.Assembly.Location]; string sourceCode = decompiler.DecompileAsString(typeHandle), typeFixedCode = ClosureTypeDeclarationRegex.Replace(sourceCode, "Scope"); // Load the syntax tree and retrieve the list of fields SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(typeFixedCode); FieldDeclarationSyntax[] fields = syntaxTree.GetRoot().DescendantNodes().OfType <ClassDeclarationSyntax>().First().ChildNodes().OfType <FieldDeclarationSyntax>().ToArray(); // Add the captured fields foreach (FieldDeclarationSyntax field in fields) { if (!field.Declaration.Variables.ToFullString().StartsWith("CS$<>")) { parsedFields.Add(field); } } // Explore the new decompiled type ParseNestedFields(typeFixedCode); } ParseNestedFields(source); if (parsedFields.Count > 0) { // Build the aggregated string with all the captured fields StringBuilder builder = new StringBuilder(); foreach (FieldDeclarationSyntax field in parsedFields) { builder.AppendLine(field.ToFullString()); } string fields = builder.ToString().TrimEnd(' ', '\r', '\n'); // Replace the field declarations Match match = NestedClosureFieldRegex.Match(source); source = source.Remove(match.Index - 11, match.Length + 12); // leading " public " and trailing ";" source = source.Insert(match.Index - 11, fields); // Adjust the method body to remove references to compiler generated fields source = CompilerGeneratedFieldRegex.Replace(source, string.Empty); } return(source); }