### Static CFG Construction using Extension Method (AsmResolver) Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/cfg-construction.md An example of constructing a static control flow graph (CFG) using a platform-specific extension method provided by Echo.Platforms.AsmResolver. This simplifies graph construction for CilMethodBody objects. ```csharp CilMethodBody methodBody = ...; var cfg = methodBody.ConstructStaticFlowGraph(); ``` -------------------------------- ### Get Ordered Dependencies - C# Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/dfg-basics.md Provides an example of using the GetOrderedDependencies extension method to recursively traverse the DFG and obtain all instructions an instruction depends on. By default, it includes all dependency types. ```csharp DataFlowGraph node = ... var dependencies = node.GetOrderedDependencies(); ``` -------------------------------- ### Get All Outgoing Edges (C#) Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/cfg-basics.md Demonstrates using GetOutgoingEdges() to retrieve all edges that start from a given node, allowing for comprehensive graph traversal. ```csharp foreach (var edge in node.GetOutgoingEdges()) Console.WriteLine(edge.Target); ``` -------------------------------- ### Create a New Control Flow Graph (C#) Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/cfg-basics.md Demonstrates how to instantiate a new, empty control flow graph using the ControlFlowGraph class. This is the starting point for building or analyzing CFGs. ```csharp var cfg = new ControlFlowGraph(); ``` -------------------------------- ### Create Empty Data Flow Graph - C# Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/dfg-basics.md Demonstrates how to instantiate a new, empty DataFlowGraph. This is the starting point for building or analyzing data flow. ```csharp var dfg = new DataFlowGraph(); ``` -------------------------------- ### Get Successor Nodes (C#) Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/cfg-basics.md Shows how to efficiently obtain only the successor nodes (targets of outgoing edges) from a given node using GetSuccessors(). ```csharp foreach (var successor in node.GetSuccessors()) Console.WriteLine(successor); ``` -------------------------------- ### Get Incoming Edges and Predecessors (C#) Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/cfg-basics.md Illustrates how to retrieve incoming edges and predecessor nodes for a given node using GetIncomingEdges() and GetPredecessors(), facilitating backward traversal of the control flow graph. ```csharp foreach (var edge in node.GetIncomingEdges()) Console.WriteLine(edge.Source); foreach (var predecessor in node.GetPredecessors()) Console.WriteLine(predecessor); ``` -------------------------------- ### Symbolic CFG Construction using Extension Method (AsmResolver) Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/cfg-construction.md An example of constructing a control flow graph (CFG) and a data flow graph (DFG) using a platform-specific extension method provided by Echo.Platforms.AsmResolver. This simplifies symbolic graph construction for CilMethodBody objects. ```csharp CilMethodBody methodBody = ...; var cfg = methodBody.ConstructSymbolicFlowGraph(out var dfg); ``` -------------------------------- ### Serialize Control Flow Graphs to DOT Format Source: https://context7.com/washi1337/echo/llms.txt Provides methods to export control flow graphs (CFGs), data flow graphs (DFGs), and ASTs into the GraphViz DOT format. This facilitates visualization and debugging. The code includes examples for simple serialization and advanced customization of node, edge, and subgraph appearances. ```csharp using Echo.ControlFlow.Serialization.Dot; using Echo.Graphing.Serialization.Dot; using System.IO; // Build graphs var cfg = body.ConstructSymbolicFlowGraph(out var dfg); // Simple serialization using (var writer = File.CreateText("cfg.dot")) cfg.ToDotGraph(writer); using (var writer = File.CreateText("dfg.dot")) dfg.ToDotGraph(writer); // Advanced serialization with customization using (var writer = File.CreateText("cfg_custom.dot")) { var dotWriter = new DotWriter(writer) { // Customize node appearance NodeAdorner = new ControlFlowNodeAdorner( new CustomInstructionFormatter() ), // Customize edge appearance EdgeAdorner = new ControlFlowEdgeAdorner(), // Customize exception handler regions SubGraphAdorner = new ExceptionHandlerAdorner() }; dotWriter.Write(cfg); } // Custom instruction formatter public class CustomInstructionFormatter : IInstructionFormatter { public string Format(in CilInstruction instruction) { return $"{instruction.Offset:X4}: {instruction.OpCode.Mnemonic}"; } } // Generate visualization (requires Graphviz installed) // Run: dot -Tpng cfg.dot -o cfg.png ``` -------------------------------- ### Get Ordered Stack Dependencies - C# Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/dfg-basics.md Shows how to use GetOrderedDependencies with flags to specifically traverse only stack dependencies, useful for analyzing expression components. ```csharp DataFlowGraph node = ... var dependencies = add.GetOrderedDependencies(DependencyCollectionFlags.IncludeStackDependencies); ``` -------------------------------- ### Iterate Control Flow Graph Nodes (C#) Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/cfg-basics.md Shows how to iterate through all the nodes within a ControlFlowGraph. Each node represents a basic block of code. The example prints the offset of each node. ```csharp ControlFlowGraph cfg = ...; // Iterate over all nodes in a control flow graph: foreach (var node in cfg.Nodes) Console.WriteLine($"{node.Offset:X8}"); ``` -------------------------------- ### Traversing a Block Tree with BlockWalker in C# Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/blocks.md Demonstrates how to use the BlockWalker class in conjunction with a custom listener (like MyListener) to traverse a block tree. The Walk method initiates the traversal starting from a given block. ```csharp var walker = new BlockWalker(new MyListener()); walker.Walk(someBlock); ``` -------------------------------- ### Accessing Node's Parent Region (C#) Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/cfg-basics.md Provides examples of how to retrieve the direct parent region of a node using the `ParentRegion` property and all regions a node is situated in using the `GetSituatedRegions` method. ```csharp ControlFlowNode node = ... var directParentRegion = node.ParentRegion; var allRegions = node.GetSituatedRegions(); ``` -------------------------------- ### C# Naming Conventions for Echo Project Source: https://github.com/washi1337/echo/blob/master/CONTRIBUTING.md Demonstrates C# naming conventions for various member types including namespaces, classes, structs, interfaces, fields, methods, properties, events, parameters, and local variables. Adheres to PascalCase, camelCase, and specific interface prefixes. This guide helps maintain code consistency and readability within the Echo project. ```csharp public class ControlFlowGraph public class PEImage { ... } public struct CilOpCode { ... } public interface IPEImage { ... } ``` -------------------------------- ### Traverse AST Nodes with Listener in C# Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/ast-basics.md Implement the IAstListener interface to define actions for entering and exiting specific AST node types during traversal. This example shows a listener for block statements and instruction expressions. An AstNodeWalker is used to perform the traversal. ```csharp class MyListener : AstNodeListener { public virtual void EnterBlockStatement(BlockStatement statement) { Console.WriteLine("Entering scope..."); } public virtual void ExitBlockStatement(BlockStatement statement) { Console.WriteLine("Leaving scope..."); } public virtual void EnterInstructionExpression(InstructionExpression expression) { Console.WriteLine($"Entering {expression}..."); } public virtual void ExitInstructionExpression(InstructionExpression expression) { Console.WriteLine($"Exiting {expression}..."); } /* ... */ } CompilationUnit root = ...; AstNodeWalker.Walk(new MyListener(), root); ``` -------------------------------- ### C# Brace Style: New Line Placement Source: https://github.com/washi1337/echo/blob/master/CONTRIBUTING.md Illustrates the preferred brace style in C# for Echo, where opening and closing braces are placed on new lines and indented. This applies to namespaces, classes, and methods, promoting a consistent and readable code structure. The example contrasts the recommended style with an alternative that places braces on the same line. ```csharp public namespace N { public class T { public void Method() { Console.WriteLine("Hello, world!"); } } } ``` -------------------------------- ### Emulate .NET CIL Bytecode with Virtual Machine Source: https://context7.com/washi1337/echo/llms.txt This C# snippet demonstrates how to load a .NET assembly, create a CIL virtual machine, set up thread and frame states, execute CIL instructions, and access virtual memory. It requires the AsmResolver library for assembly loading and CIL emulation. ```csharp using Echo.Platforms.AsmResolver.Emulation; using AsmResolver.DotNet; using AsmResolver.PE.DotNet.Cil; // Load assembly and method var module = ModuleDefinition.FromFile("Example.dll"); var method = module.ManagedEntryPointMethod; // Create virtual machine var vm = new CilVirtualMachine(module, false); // Setup initial state var thread = vm.CreateThread(); var frame = thread.CallStack.Push(method); // Set method arguments if needed if (method.Signature.ParameterTypes.Count > 0) { var arg0 = new BitVector(32, 42); frame.WriteArgument(0, arg0); } // Execute until completion or limit var result = vm.Execute(maxInstructions: 10000); switch (result.ResultType) { case ExecutionResultType.Success: Console.WriteLine("Execution completed successfully"); if (frame.EvaluationStack.Count > 0) { var returnValue = frame.EvaluationStack.Pop(); Console.WriteLine($"Return value: {returnValue}"); } break; case ExecutionResultType.Exception: Console.WriteLine($"Exception thrown: {result.Exception}"); break; case ExecutionResultType.InstructionLimitExceeded: Console.WriteLine("Instruction limit exceeded"); break; } // Access virtual memory var memory = vm.Memory; var address = 0x12345678; var data = memory.Read(address, 4); Console.WriteLine($"Memory at {address:X8}: {data.ToHexString()}"); // Write to memory var newData = new BitVector(32, 0xDEADBEEF); memory.Write(address, newData); ``` -------------------------------- ### Analyze x86/x64 Native Code with Iced Backend Source: https://context7.com/washi1337/echo/llms.txt This C# snippet illustrates how to set up an x86/x64 architecture, decode native machine code using the Iced backend, and construct a control flow graph (CFG). It demonstrates accessing instruction details and querying register information, requiring the Echo.Platforms.Iced and Iced libraries. ```csharp using Echo.Platforms.Iced; using Echo.ControlFlow.Construction; using Iced.Intel; // Setup x64 architecture var architecture = new X86Architecture(64); // 64-bit mode // Create instruction provider with decoder byte[] code = { 0x48, 0x89, 0x5C, 0x24, 0x08, // mov [rsp+8], rbx 0x55, // push rbp 0x48, 0x8B, 0xEC, // mov rbp, rsp 0x48, 0x83, 0xEC, 0x20, // sub rsp, 20h 0xC3 // ret }; var decoder = new X86DecoderInstructionProvider( architecture, code, baseAddress: 0x140001000 ); // Build CFG var resolver = new X86StaticSuccessorResolver(); var builder = new StaticFlowGraphBuilder( architecture, decoder, resolver ); var cfg = builder.ConstructFlowGraph(entrypoint: 0x140001000); // Access register information var instruction = decoder.GetInstructionAtOffset(0x140001000); var readVars = new List(); architecture.GetReadVariables(instruction, readVars); Console.WriteLine($"Instruction: {instruction}"); Console.WriteLine("Reads from:"); foreach (var variable in readVars) Console.WriteLine($" {variable}"); // Query x86 registers var rax = new X86GeneralRegister(Register.RAX); var eflags = new X86FlagsRegister(X86Flags.CF | X86Flags.ZF); ``` -------------------------------- ### Reading Individual Bits from BitVectorSpan Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/bit-vectors.md Shows how to access and read individual bits (trileans) from a BitVectorSpan. The index provided is relative to the start of the span. ```csharp BitVectorSpan span = ...; Trilean bit = span[6]; // Gets bit 6 from the span. ``` -------------------------------- ### Construct Static Control Flow Graph (C#) Source: https://context7.com/washi1337/echo/llms.txt This snippet demonstrates the fast, static construction of a control flow graph (CFG) from .NET CIL instructions. It loads a .NET assembly, extracts a method's CIL body, constructs the CFG using pattern-based successor resolution, and allows traversal of the graph nodes and instructions. The resulting CFG can be exported to GraphViz DOT format. Dependencies include Echo.ControlFlow.Construction, Echo.Platforms.AsmResolver, and AsmResolver.DotNet. ```csharp using Echo.ControlFlow.Construction; using Echo.Platforms.AsmResolver; using AsmResolver.DotNet; using AsmResolver.DotNet.Code.Cil; // Load a .NET assembly var module = ModuleDefinition.FromFile("Example.dll"); var type = module.TopLevelTypes.First(t => t.Name == "Program"); var method = type.Methods.First(m => m.Name == "Main"); var body = method.CilMethodBody; // Static CFG construction (fast, simple) var cfg = body.ConstructStaticFlowGraph(); // Access the entry point var entryNode = cfg.EntryPoint; Console.WriteLine($"Entry point at offset: {entryNode.Offset}"); // Traverse nodes foreach (var node in cfg.Nodes) { Console.WriteLine($"Block at {node.Offset}:"); foreach (var instruction in node.Contents.Instructions) Console.WriteLine($" {instruction}"); // Access successors foreach (var successor in node.GetSuccessors()) Console.WriteLine($" -> {successor.Offset}"); } // Export to GraphViz DOT format using (var writer = File.CreateText("cfg.dot")) cfg.ToDotGraph(writer); ``` -------------------------------- ### Control Flow Graph Construction (Static) Source: https://context7.com/washi1337/echo/llms.txt This API allows for the fast, static construction of control flow graphs (CFGs) from instruction sequences. It uses pattern-based successor resolution without actual code execution, making it a quick method for understanding program structure. ```APIDOC ## Control Flow Graph Construction (Static) ### Description Fast static construction of control flow graphs from instruction sequences using pattern-based successor resolution. Static analysis examines instruction opcodes to determine possible control flow paths without executing code. ### Method Not Applicable (Code Example) ### Endpoint Not Applicable (Code Example) ### Parameters Not Applicable (Code Example) ### Request Example Not Applicable (Code Example) ### Response #### Success Response (200) - **cfg** (FlowGraph) - The constructed control flow graph. - **entryPoint** (BasicBlock) - The entry point of the control flow graph. #### Response Example ```csharp // Example C# code demonstrating usage using Echo.ControlFlow.Construction; using Echo.Platforms.AsmResolver; using AsmResolver.DotNet; using AsmResolver.DotNet.Code.Cil; // Load a .NET assembly var module = ModuleDefinition.FromFile("Example.dll"); var type = module.TopLevelTypes.First(t => t.Name == "Program"); var method = type.Methods.First(m => m.Name == "Main"); var body = method.CilMethodBody; // Static CFG construction (fast, simple) var cfg = body.ConstructStaticFlowGraph(); // Access the entry point var entryNode = cfg.EntryPoint; Console.WriteLine($"Entry point at offset: {entryNode.Offset}"); // Traverse nodes foreach (var node in cfg.Nodes) { Console.WriteLine($"Block at {node.Offset}:"); foreach (var instruction in node.Contents.Instructions) Console.WriteLine($" {instruction}"); // Access successors foreach (var successor in node.GetSuccessors()) Console.WriteLine($" -> {successor.Offset}"); } // Export to GraphViz DOT format using (var writer = File.CreateText("cfg.dot")) cfg.ToDotGraph(writer); ``` ``` -------------------------------- ### Get Node by Offset - C# Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/dfg-basics.md Explains how to retrieve a specific DataFlowNode by its memory offset. This method performs a linear search. ```csharp var node = dfg.Nodes.GetByOffset(offset: 0x1234); ``` -------------------------------- ### Construct Symbolic Control Flow and Data Flow Graphs (C#) Source: https://context7.com/washi1337/echo/llms.txt This snippet illustrates the construction of a control flow graph (CFG) and a data flow graph (DFG) using symbolic execution on .NET CIL instructions. This method provides more accurate analysis by tracking program state and resolving indirect branches, but is slower than static analysis. It outputs both CFG and DFG, which can be visualized using GraphViz DOT format. Dependencies include Echo.DataFlow, Echo.DataFlow.Construction, and AsmResolver.DotNet. ```csharp using Echo.DataFlow; using Echo.DataFlow.Construction; using AsmResolver.DotNet; // Load method var module = ModuleDefinition.FromFile("Example.dll"); var method = module.ManagedEntryPointMethod; var body = method.CilMethodBody; // Symbolic CFG construction (slower, more accurate, produces DFG) var cfg = body.ConstructSymbolicFlowGraph(out DataFlowGraph dfg); // CFG contains discovered control flow Console.WriteLine($"Found {cfg.Nodes.Count} basic blocks"); // DFG contains data dependencies var offsetMap = dfg.Nodes.CreateOffsetMap(); foreach (var instruction in body.Instructions) { if (offsetMap.TryGetValue(instruction.Offset, out var dfgNode)) { Console.WriteLine($"Instruction at {instruction.Offset}: {instruction}"); // Stack dependencies for (int i = 0; i < dfgNode.StackDependencies.Count; i++) { var dependency = dfgNode.StackDependencies[i]; Console.WriteLine($" Stack slot {i} depends on:"); foreach (var source in dependency) Console.WriteLine($" - Instruction at {source.Node.Offset}"); } // Variable dependencies foreach (var (variable, dependency) in dfgNode.VariableDependencies) { Console.WriteLine($" Variable {variable} depends on:"); foreach (var source in dependency) Console.WriteLine($" - Instruction at {source.Node.Offset}"); } } } // Export DFG to DOT format using (var writer = File.CreateText("dfg.dot")) dfg.ToDotGraph(writer); ``` -------------------------------- ### Create Offset Map for Faster Lookups (C#) Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/cfg-basics.md Demonstrates creating an offset map from the CFG nodes for significantly faster lookups by memory address. This is recommended when performing numerous offset-based node retrievals. ```csharp var offsetMap = cfg.Nodes.CreateOffsetMap(); var n1 = offsetMap[0x0001]; var n2 = offsetMap[0x0004]; var n3 = offsetMap[0x0010]; ``` -------------------------------- ### Get Node by Offset (C#) Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/cfg-basics.md Illustrates how to retrieve a specific ControlFlowNode by its memory offset. This method performs a linear search, so performance might be a consideration for large graphs. ```csharp var node = cfg.Nodes.GetByOffset(offset: 0x1234); ``` -------------------------------- ### Creating and Populating a BasicBlock in C# Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/blocks.md Demonstrates how to instantiate a BasicBlock and add instructions to it. This block represents a sequence of instructions executed as a single unit. Assumes TInstruction is defined elsewhere. ```csharp var block = new BasicBlock(); // Add instructions. block.Instructions.Add(instruction1); block.Instructions.Add(instruction2); block.Instructions.Add(instruction3); ``` -------------------------------- ### C# Trilean Initialization and Implicit Conversion Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/bit-vectors.md Demonstrates how to initialize a Trilean variable in C# and shows implicit conversions from boolean and nullable boolean types to Trilean. ```csharp Trilean a = Trilean.True; Trilean b = true; // Trilean.True Trilean c = false; // Trilean.False Trilean d = null; // Trilean.Unknown ``` -------------------------------- ### Implement IArchitecture Interface for Custom Platforms Source: https://context7.com/washi1337/echo/llms.txt Demonstrates how to implement the `IArchitecture` interface to enable Echo's analysis algorithms on new platforms. This involves defining methods for instruction size, flow control, stack operations, and variable access. It serves as a blueprint for extending Echo's compatibility. ```csharp using Echo.Code; using System.Collections.Generic; // Example custom architecture implementation public class CustomArchitecture : IArchitecture { public long GetOffset(in CustomInstruction instruction) { return instruction.Address; } public int GetSize(in CustomInstruction instruction) { return instruction.Length; } public InstructionFlowControl GetFlowControl(in CustomInstruction instruction) { // Determine flow control attributes var result = InstructionFlowControl.Fallthrough; if (instruction.IsJump || instruction.IsCall) result |= InstructionFlowControl.CanBranch; if (instruction.IsReturn || instruction.IsUnconditionalJump) result |= InstructionFlowControl.IsTerminator; return result; } public int GetStackPushCount(in CustomInstruction instruction) { return instruction.OpCode.StackPushCount; } public int GetStackPopCount(in CustomInstruction instruction) { return instruction.OpCode.StackPopCount; } public void GetReadVariables(in CustomInstruction instruction, ICollection variablesBuffer) { // Add variables read by this instruction if (instruction.OpCode.ReadsRegister) variablesBuffer.Add(new CustomRegister(instruction.SourceRegister)); } public void GetWrittenVariables(in CustomInstruction instruction, ICollection variablesBuffer) { // Add variables written by this instruction if (instruction.OpCode.WritesRegister) variablesBuffer.Add(new CustomRegister(instruction.DestinationRegister)); } } // Usage with graph builders var architecture = new CustomArchitecture(); var instructions = LoadInstructions(); var resolver = new CustomSuccessorResolver(); var builder = new StaticFlowGraphBuilder( architecture, instructions, resolver ); var cfg = builder.ConstructFlowGraph(entrypoint: 0x1000); ``` -------------------------------- ### Iterate Stack Dependencies - C# Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/dfg-basics.md Shows how to iterate through all stack dependencies for a given DataFlowNode. It highlights that each dependency can originate from multiple data sources. ```csharp DataFlowNode node = ...; // Iterate all stack dependencies. for (int i = 0; i < node.StackDependencies.Count; i++) { // Every dependency can have multiple possible data sources. Console.WriteLine($"Stack value {i}"); foreach (var dataSource in dependency) Console.WriteLine($"- Value {dataSource.SlotIndex} of {dataSource.Node}."); } ``` -------------------------------- ### Initialize BitVector with Bits and Known Mask Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/bit-vectors.md Constructs a BitVector with specified bits and a corresponding known mask. A '1' in the known mask indicates the bit is known, while a '0' indicates it is unknown. ```csharp var x = new BitVector(bits: 0b00001111, knownMask: 0b11111111); // Constructs 00001111 var y = new BitVector(bits: 0b00001111, knownMask: 0b11001100); // Constructs 00??11?? var z = new BitVector(bits: 0b00000000, knownMask: 0b00000000); // Constructs ???????? ``` -------------------------------- ### Build Echo Project with .NET CLI Source: https://github.com/washi1337/echo/blob/master/README.md Compiles the Echo project using the .NET Standard 2.0 build tools. This is the primary method for building the core libraries required for a working binary. Platform-specific backends and test projects are optional. ```bash dotnet build ``` -------------------------------- ### Control Flow Graph Construction (Symbolic) Source: https://context7.com/washi1337/echo/llms.txt This API enables the construction of control flow graphs (CFGs) using symbolic execution. It tracks program state to resolve indirect branches and calls, producing both a CFG and a Data Flow Graph (DFG) for more accurate analysis, albeit at a higher performance cost. ```APIDOC ## Control Flow Graph Construction (Symbolic) ### Description Symbolic execution-based CFG construction that tracks program state to resolve indirect branches and calls. Produces both a CFG and a DFG as output, enabling more accurate analysis at the cost of performance. ### Method Not Applicable (Code Example) ### Endpoint Not Applicable (Code Example) ### Parameters Not Applicable (Code Example) ### Request Example Not Applicable (Code Example) ### Response #### Success Response (200) - **cfg** (FlowGraph) - The constructed control flow graph. - **dfg** (DataFlowGraph) - The constructed data flow graph. #### Response Example ```csharp // Example C# code demonstrating usage using Echo.DataFlow; using Echo.DataFlow.Construction; using AsmResolver.DotNet; // Load method var module = ModuleDefinition.FromFile("Example.dll"); var method = module.ManagedEntryPointMethod; var body = method.CilMethodBody; // Symbolic CFG construction (slower, more accurate, produces DFG) var cfg = body.ConstructSymbolicFlowGraph(out DataFlowGraph dfg); // CFG contains discovered control flow Console.WriteLine($"Found {cfg.Nodes.Count} basic blocks"); // DFG contains data dependencies var offsetMap = dfg.Nodes.CreateOffsetMap(); foreach (var instruction in body.Instructions) { if (offsetMap.TryGetValue(instruction.Offset, out var dfgNode)) { Console.WriteLine($"Instruction at {instruction.Offset}: {instruction}"); // Stack dependencies for (int i = 0; i < dfgNode.StackDependencies.Count; i++) { var dependency = dfgNode.StackDependencies[i]; Console.WriteLine($" Stack slot {i} depends on:"); foreach (var source in dependency) Console.WriteLine($" - Instruction at {source.Node.Offset}"); } // Variable dependencies foreach (var (variable, dependency) in dfgNode.VariableDependencies) { Console.WriteLine($" Variable {variable} depends on:"); foreach (var source in dependency) Console.WriteLine($" - Instruction at {source.Node.Offset}"); } } } // Export DFG to DOT format using (var writer = File.CreateText("dfg.dot")) dfg.ToDotGraph(writer); ``` ``` -------------------------------- ### Constructing Lifted Control Flow Graph with Purity Classifier Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/ast-basics.md This code demonstrates how to lift a control flow graph (CFG) into a new CFG containing expression trees, using a platform-specific purity classifier to determine if instructions have side-effects. This is a prerequisite for building a full AST. ```csharp using Echo.Ast.Construction; ControlFlowGraph cfg = ...; IPurityClassifier classifier = ...; var liftedCfg = cfg.Lift(classifier); ``` -------------------------------- ### Static CFG Construction with Instructions List Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/cfg-construction.md Constructs a static control flow graph (CFG) from a list of instructions. It requires an architecture, a list of instructions, and a successor resolver. The output is a CFG. ```csharp using Echo.ControlFlow.Construction; IArchitecture architecture = ...; IStaticSuccessorResolver resolver = ...; IList instructions = ...; var builder = new StaticFlowGraphBuilder( architecture, instructions, resolver ); var cfg = builder.ConstructFlowGraph(); ``` -------------------------------- ### Static CFG Construction with Instruction Provider Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/cfg-construction.md Constructs a static control flow graph (CFG) using an instruction provider, suitable for architectures with undefined function boundaries like x86. It takes an architecture, an instruction decoder, and a successor resolver, with an optional entry point offset. The output is a CFG. ```csharp class X86InstructionDecoder : IStaticInstructionProvider { X86Instruction GetInstructionAtOffset(long offset) { return /* ... Decode instruction at provided offset ... */ } } /* ... */ var decoder = new X86InstructionDecoder(); var builder = new StaticFlowGraphBuilder( architecture, decoder, resolver ); var cfg = builder.ConstructFlowGraph(entryPoint: 0x1234); ``` -------------------------------- ### C# Block Tree Construction from CFG Source: https://context7.com/washi1337/echo/llms.txt Converts a Control Flow Graph (CFG) into a hierarchical block structure. This structure represents scopes, loops, and exception handlers, suitable for code generation or pretty-printing. It requires the AsmResolver library for CFG construction. ```csharp using Echo.ControlFlow.Serialization.Blocks; using Echo.Platforms.AsmResolver; using AsmResolver.DotNet; // Build CFG with exception handling regions var module = ModuleDefinition.FromFile("Example.dll"); var method = module.ManagedEntryPointMethod; var cfg = method.CilMethodBody.ConstructStaticFlowGraph(); // Convert to block tree var blockBuilder = new BlockBuilder(); var rootScope = cfg.ConstructBlocks(); // Traverse block structure void TraverseBlocks(IBlock block, int indent = 0) { string indentation = new string(' ', indent * 2); switch (block) { case BasicBlock basic: Console.WriteLine($"{indentation}Basic Block:"); foreach (var instruction in basic.Instructions) Console.WriteLine($"{indentation} {instruction}"); break; case ScopeBlock scope: Console.WriteLine($"{indentation}Scope Block:"); foreach (var child in scope.Blocks) TraverseBlocks(child, indent + 1); break; case ExceptionHandlerBlock eh: Console.WriteLine($"{indentation}Exception Handler:"); Console.WriteLine($"{indentation} Protected:"); foreach (var child in eh.ProtectedBlock.Blocks) TraverseBlocks(child, indent + 2); Console.WriteLine($"{indentation} Handlers:"); foreach (var handler in eh.Handlers) { Console.WriteLine($"{indentation} {handler.Type}:"); foreach (var child in handler.Contents.Blocks) TraverseBlocks(child, indent + 3); } break; } } TraverseBlocks(rootScope); ``` -------------------------------- ### Creating BitVectorSpan Views Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/bit-vectors.md Demonstrates how to create BitVectorSpan objects from a BitVector. These spans can represent the entire vector or a subrange. Creating spans is an efficient operation as it does not involve copying or heap allocation, providing a stack-allocated view. ```csharp BitVector x = ...; var full = x.AsSpan(); var slice1 = x.AsSpan(bitIndex: 8); var slice2 = x.AsSpan(bitIndex: 8, length: 32); ``` -------------------------------- ### Constructing Block Tree from Control Flow Graph in C# Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/blocks.md Demonstrates the process of constructing a block tree, specifically a root ScopeBlock, from an existing ControlFlowGraph using the ConstructBlocks extension method. Requires the Echo.ControlFlow.Serialization.Blocks namespace. ```csharp using Echo.ControlFlow.Serialization.Blocks; ControlFlowGraph cfg = ...; ScopeBlock rootScope = cfg.ConstructBlocks(); ``` -------------------------------- ### Iterate Instructions within a Node (C#) Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/cfg-basics.md Shows how to access and iterate through the sequence of instructions contained within a ControlFlowNode's basic block. This allows for detailed analysis of the code represented by the node. ```csharp ControlFlowNode node = ...; // Iterate over all instructions within the block. foreach (var instruction in node.Contents.Instructions) Console.WriteLine(instruction); ``` -------------------------------- ### Exporting CFG to DOT with Custom Instruction Formatting (C#) Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/cfg-basics.md Details how to customize the output of the DOT graph serialization by providing a custom `IInstructionFormatter`. This allows for specific formatting of instructions within the graph visualization. ```csharp class MyFormatter : IInstructionFormatter { public string Format(in TInstruction instruction) { // ... } } using var writer = File.CreateText("output.dot"); cfg.ToDotGraph(writer, new MyFormatter()); ``` -------------------------------- ### Iterate Variable Dependencies - C# Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/dfg-basics.md Demonstrates iterating through variable dependencies for a DataFlowNode, showing the variable name and its associated data source nodes. ```csharp DataFlowNode node = ...; foreach (var dependency in node.VariableDependencies) { Console.WriteLine(dependency.Variable); foreach (var dataSource in dependency) Console.WriteLine($" - {dataSource.Node}"); } ``` -------------------------------- ### Parse Binary String to Initialize BitVector Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/bit-vectors.md Initializes a BitVector by parsing a binary string representation. The string can include '0', '1', and '?' characters, where '?' represents an unknown bit. ```csharp var x = BitVector.ParseBinary("00001111"); // Constructs 00001111 var y = BitVector.ParseBinary("00??11??"); // Constructs 00??11?? var z = BitVector.ParseBinary("????????"); // Constructs ???????? ``` -------------------------------- ### Iterate and Access Node Instructions - C# Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/dfg-basics.md Shows how to iterate through all nodes in a DataFlowGraph and access the instruction associated with each node. This is useful for inspecting the components of the graph. ```csharp DataFlowGraph dfg = ...; // Iterate over all nodes in a data flow graph: foreach (var node in dfg.Nodes) Console.WriteLine(node.Instruction); ``` -------------------------------- ### Generate DOT Graph Visualization - C# Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/dfg-basics.md Demonstrates how to serialize a graph (e.g., cfg) into the DOT format using the ToDotGraph extension method, which can then be visualized with tools like GraphViz. ```csharp using var writer = File.CreateText("output.dot"); cfg.ToDotGraph(writer); ``` -------------------------------- ### Initialize BitVector with Specific Bit-Length Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/bit-vectors.md Initializes a new BitVector with a specified bit-length. The `initialize` parameter determines whether the vector is filled with zeroes or unknowns. Note that the bit-length must be a multiple of 8. ```csharp var x = new BitVector(count: 32, initialize: true); // Vector of 32 zeroes. var y = new BitVector(count: 32, initialize: false); // Vector of 32 unknowns. ``` -------------------------------- ### Initialize BitVector from Byte Array Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/bit-vectors.md Initializes a BitVector by converting a byte array. The size of the BitVector will be the number of bytes in the array multiplied by 8. ```csharp BitVector x = new byte[] {1, 2, 3, 4, 5}; // Initializes a 40-bit vector. BitVector y = new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}; // Initializes a 104-bit vector. ``` -------------------------------- ### Creating a Rooted AST Compilation Unit from Lifted CFG Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/ast-basics.md This snippet shows how to convert a lifted AST control flow graph into a single, rooted compilation unit. This represents the entire function body as a unified syntactical tree structure. ```csharp var root = liftedCfg.ToCompilationUnit(); ``` -------------------------------- ### Create Offset Map for Faster Lookups - C# Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/dfg-basics.md Illustrates creating an offset map from a DataFlowGraph's nodes for significantly faster lookups by offset, especially when performing many lookups. ```csharp var offsetMap = dfg.Nodes.CreateOffsetMap(); var n1 = offsetMap[0x0001]; var n2 = offsetMap[0x0004]; var n3 = offsetMap[0x0010]; ``` -------------------------------- ### Creating and Populating a ScopeRegion (C#) Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/cfg-basics.md Shows the process of creating a new `ScopeRegion` and adding nodes to it. This is used for defining simple scopes within the control flow graph. It requires an instance of `ScopeRegion` and `ControlFlowNode`. ```csharp // Define new scope and add it to the graph. var region = new ScopeRegion(); cfg.Regions.Add(region); // Add nodes. region.Nodes.Add(node1); region.Nodes.Add(node2); region.Nodes.Add(node3); // Define the entry point of the scope. region.EntryPoint = node1; ``` -------------------------------- ### Update Node Offsets (C#) Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/cfg-basics.md Explains the necessity and usage of the UpdateOffsets method to ensure all nodes in the CFG have accurate offsets corresponding to their content. This is crucial for correct offset-based lookups. ```csharp cfg.Nodes.UpdateOffsets(); ``` -------------------------------- ### Construct Abstract Syntax Tree C# Source: https://context7.com/washi1337/echo/llms.txt Lifts low-level stack-based instruction sequences to high-level expression-based AST representations. This process includes automatic variable cross-referencing and scoping, making it easier to analyze and manipulate code at a more abstract level. It requires a control flow graph (CFG) and a purity classifier. ```csharp using Echo.Ast; using Echo.Ast.Construction; using Echo.Platforms.AsmResolver; using AsmResolver.DotNet; using AsmResolver.PE.DotNet.Cil; // Build CFG with DFG var module = ModuleDefinition.FromFile("Example.dll"); var method = module.ManagedEntryPointMethod; var body = method.CilMethodBody; var cfg = body.ConstructSymbolicFlowGraph(out var dfg); // Create purity classifier (determines if instructions have side effects) var purityClassifier = new CilPurityClassifier(); // Lift CFG to AST-based CFG var liftedCfg = cfg.Lift(purityClassifier); // Create compilation unit (root AST node) var compilationUnit = liftedCfg.ToCompilationUnit(); // Access the root scope var rootBlock = compilationUnit.Root; Console.WriteLine($"Root block contains {rootBlock.Statements.Count} statements"); // Traverse AST foreach (var statement in rootBlock.Statements) { Console.WriteLine($"Statement: {statement}"); if (statement is AssignmentStatement assignment) { Console.WriteLine($" Assigns to: {assignment.Target}"); Console.WriteLine($" Expression: {assignment.Expression}"); } else if (statement is ExpressionStatement exprStmt) { Console.WriteLine($" Expression: {exprStmt.Expression}"); } } // Variable cross-referencing foreach (var variable in compilationUnit.Variables) { var uses = compilationUnit.GetVariableUses(variable); var writes = compilationUnit.GetVariableWrites(variable); Console.WriteLine($"Variable {variable}: {uses.Count} uses, {writes.Count} writes"); } // Pattern matching example var pattern = Pattern.InstructionExpression() .WithOpCode(CilOpCodes.Call) .WithArguments(Pattern.Any()); var matches = compilationUnit.Root.FindMatches(pattern); Console.WriteLine($"Found {matches.Count} call instructions"); ``` -------------------------------- ### Use LINQ Method Syntax and Separate Chained Calls (C#) Source: https://github.com/washi1337/echo/blob/master/CONTRIBUTING.md When using LINQ, prefer the method syntax over query syntax. For chained method calls, place each call on a new line to enhance readability and maintainability. ```csharp var allClasses = assembly.Modules .SelectMany(m => m.GetAllTypes()) .Where(t => t.IsClass) .ToArray(); ``` -------------------------------- ### Connect Nodes with Edges (C#) Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/cfg-basics.md Demonstrates methods for creating new connections (edges) between ControlFlowNodes. This can be done by directly manipulating edge properties or using the ConnectWith helper method, specifying edge types like Conditional and FallThrough. ```csharp ControlFlowNode node1 = ...; ControlFlowNode node2 = ...; ControlFlowNode node3 = ...; ControlFlowNode node4 = ...; node1.ConnectWith(node2); node2.ConnectWith(node3, ControlFlowEdgeType.Conditional); node2.ConnectWith(node4, ControlFlowEdgeType.FallThrough); ``` -------------------------------- ### Integer Addition on BitVectorSpan Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/bit-vectors.md Shows how to perform integer addition between two BitVectorSpans. The operation handles partially known bits and attempts to infer the certainty of the resulting bits. If certainty cannot be established for all bits, they may be represented as unknown ('?'). ```csharp var x = BitVector.ParseBinary("00010001").AsSpan(); var y = BitVector.ParseBinary("00000001").AsSpan(); x.IntegerAdd(y); // `x` now contains the bit vector `00010010`. var x = BitVector.ParseBinary("00010001").AsSpan(); var y = BitVector.ParseBinary("0000000?").AsSpan(); x.IntegerAdd(y); // `x` now contains the bit vector `000100??`. ``` -------------------------------- ### Bitwise AND Operation on BitVectorSpan Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/bit-vectors.md Illustrates how to perform a bitwise AND operation between two BitVectorSpans. The operation respects trilean logic, correctly handling unknown bits. The result is stored in the span on which the method is called. ```csharp var x = BitVector.ParseBinary("11111100").AsSpan(); var y = BitVector.ParseBinary("11001100").AsSpan(); x.And(y); // `x` now contains the bit vector `11001100`. var x = BitVector.ParseBinary("????????").AsSpan(); var y = BitVector.ParseBinary("11001100").AsSpan(); x.And(y); // `x` now contains the bit vector `??00??00`. ``` -------------------------------- ### Traverse Edges to Target Node (C#) Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/cfg-basics.md Illustrates how to navigate from a ControlFlowEdge to its target ControlFlowNode, enabling traversal of the graph structure. ```csharp ControlFlowEdge edge = ...; ControlFlowNode target = edge.Target; ``` -------------------------------- ### Lift Control Flow Graph to Syntax Tree (C#) Source: https://github.com/washi1337/echo/blob/master/docs/guides/asmresolver/cil-graphs.md Lifts a control flow graph to an abstract syntax tree (AST). This process involves first constructing a static control flow graph and then applying the Lift extension method with a CilPurityClassifier. The result is a CompilationUnit representing the AST. ```csharp MethodDefinition method = ...; CompilationUnit ast = method.CilMethodBody .ConstructStaticFlowGraph() .Lift(new CilPurityClassifier()) .ToCompilationUnit(); ``` -------------------------------- ### C# Trilean Conditional and Negation Logic Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/bit-vectors.md Illustrates how to use a Trilean variable in conditional statements (if-else) and how to negate its value, explaining the behavior for 'false' and 'unknown' states. ```csharp Trilean a = ...; if (a) { // `a` is true. } else { // `a` is false or unknown. } if (!a) { // `a` is false. } else { // `a` is true or unknown. } ``` -------------------------------- ### C# Bit Vector Operations Source: https://context7.com/washi1337/echo/llms.txt Provides low-level bit manipulation functionalities for emulation and symbolic execution. It supports known, partially known, and fully unknown bit patterns. Key operations include arithmetic, logical, shift, rotate, comparison, and sign extension. ```csharp using Echo.Memory; // Create bit vectors with known values var vector1 = new BitVector(32, 0x12345678); var vector2 = new BitVector(32, 0xAABBCCDD); Console.WriteLine($"Vector 1: {vector1.ToHexString()}"); Console.WriteLine($"Vector 2: {vector2.ToHexString()}"); // Arithmetic operations var sum = BitVectorSpan.Add(vector1, vector2); var difference = BitVectorSpan.Subtract(vector1, vector2); var product = BitVectorSpan.Multiply(vector1, vector2); Console.WriteLine($"Sum: {sum.ToHexString()}"); Console.WriteLine($"Difference: {difference.ToHexString()}"); // Logical operations var and = BitVectorSpan.And(vector1, vector2); var or = BitVectorSpan.Or(vector1, vector2); var xor = BitVectorSpan.Xor(vector1, vector2); var not = BitVectorSpan.Not(vector1); // Create partially unknown bit vector var partiallyKnown = new BitVector(32); partiallyKnown.MarkFullyKnown(isKnown: false); // Start unknown partiallyKnown.AsSpan().U8[0] = 0x42; // Set first byte partiallyKnown.MarkKnown(0, 8); // Mark first byte as known Console.WriteLine($"Partially known: {partiallyKnown.ToHexString()}"); Console.WriteLine($"Is fully known: {partiallyKnown.IsFullyKnown}"); // Bit manipulation var shifted = BitVectorSpan.ShiftLeft(vector1, 4); var rotated = BitVectorSpan.RotateRight(vector1, 8); // Comparison bool equal = BitVectorSpan.Equals(vector1, vector2); bool greater = BitVectorSpan.GreaterThan(vector1, vector2, true); // signed comparison // Sign extension var extended = new BitVector(64); BitVectorSpan.SignExtend(vector1, extended, 32); ``` -------------------------------- ### Initialize BitVector using Implicit Conversions Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/bit-vectors.md Creates a BitVector by implicitly converting primitive types like integers, longs, and doubles. The size of the resulting BitVector depends on the type of the converted value (32-bit for int, 64-bit for long and double). ```csharp BitVector y = 1337; // Initializes a 32-bit vector with the bits of the integer 1337. BitVector z = 1337L; // Initializes a 64-bit vector with the bits of the long 1337. BitVector w = 1337.0; // Initializes a 64-bit vector with the bits of the double 1337.0. ``` -------------------------------- ### Pretty Printing a Block Tree using ToString in C# Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/blocks.md Shows the simplest way to format a block tree into a string representation using the built-in ToString method on a ScopeBlock. Assumes TInstruction is defined elsewhere. ```csharp ScopeBlock root = ...; Console.WriteLine(root.ToString()); ``` -------------------------------- ### Prefer 'for' Loops to Avoid Heap Allocations (C#) Source: https://github.com/washi1337/echo/blob/master/CONTRIBUTING.md When possible and index-based access is feasible, prefer 'for' loops over 'foreach' to avoid potential heap allocations from enumerators, especially when the enumerator type is not a struct. ```csharp IList items = ...; for (int i = 0; i < items.Count; i++) { // Use items[i] } ``` -------------------------------- ### Symbolic CFG Construction with Instructions List Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/cfg-construction.md Constructs a control flow graph (CFG) using symbolic analysis, capable of handling indirect jumps and calls by tracking data flow. It requires an architecture, a list of instructions, and a state transitioner. The output is a CFG, and often a Data Flow Graph (DFG) is also populated in the transitioner. ```csharp using Echo.DataFlow.Construction; IArchitecture architecture = ...; StateTransitioner transitioner = ...; IList instructions = ...; var builder = new SymbolicFlowGraphBuilder( architecture, instructions, transitioner ); var cfg = builder.ConstructFlowGraph(); // After building the CFG, a DFG is populated in the transitioner. var dfg = transitioner.DataFlowGraph; ``` -------------------------------- ### Implementing Block Traversal with a Listener in C# Source: https://github.com/washi1337/echo/blob/master/docs/guides/core/blocks.md Shows how to implement the IBlockListener interface to traverse a block tree. The MyListener class overrides methods to define actions upon entering/leaving scope blocks and visiting basic blocks. Assumes TInstruction is defined elsewhere. ```csharp class MyListener : BlockListenerBase { public override void EnterScopeBlock(ScopeBlock scope) { Console.WriteLine("Entering scope..."); } public override void LeaveScopeBlock(ScopeBlock scope) { Console.WriteLine("Leaving scope..."); } public override void VisitBasicBlock(BasicBlock block) { ... } } ``` -------------------------------- ### C# Local Variable Typing with 'var' Source: https://github.com/washi1337/echo/blob/master/CONTRIBUTING.md Explains the C# local variable typing convention in Echo, recommending the use of the `var` keyword for non-primitive types. Primitive types should use their explicit keywords. This promotes concise yet readable code, ensuring that types are clear without unnecessary verbosity. ```csharp int x = 123; string y = "Hello, world!"; var array = new byte[10]; var instance = new MyClass(...); ```