using X86Disassembler.Analysers.DecompilerTypes;
using X86Disassembler.PE;
using X86Disassembler.X86;
namespace X86Disassembler.Analysers;
///
/// Main engine for decompiling x86 code
///
public class DecompilerEngine
{
///
/// The PE file being analyzed
///
private readonly PeFile _peFile;
///
/// Dictionary of analyzed functions by address
///
private readonly Dictionary _functions = [];
///
/// Dictionary of exported function names by address
///
private readonly Dictionary _exportedFunctions = [];
///
/// Creates a new decompiler engine for the specified PE file
///
/// The PE file to decompile
public DecompilerEngine(PeFile peFile)
{
_peFile = peFile;
// Initialize the exported functions dictionary
foreach (var export in peFile.ExportedFunctions)
{
_exportedFunctions[export.AddressRva] = export.Name;
}
}
///
/// Decompiles a function at the specified address
///
/// The address of the function to decompile
/// The decompiled function
public Function DecompileFunction(ulong address)
{
// Check if we've already analyzed this function
if (_functions.TryGetValue(address, out var existingFunction))
{
return existingFunction;
}
// Find the code section containing this address
var codeSection = _peFile.SectionHeaders.Find(s =>
s.ContainsCode() &&
address >= s.VirtualAddress &&
address < s.VirtualAddress + s.VirtualSize);
if (codeSection == null)
{
throw new InvalidOperationException($"No code section found containing address 0x{address:X8}");
}
// Get the section data
int sectionIndex = _peFile.SectionHeaders.IndexOf(codeSection);
byte[] codeBytes = _peFile.GetSectionData(sectionIndex);
// Create a disassembler for the code section
var disassembler = new BlockDisassembler(codeBytes, codeSection.VirtualAddress);
// Disassemble the function
var asmFunction = disassembler.DisassembleFromAddress((uint)address);
// Create an analyzer context
var context = new AnalyzerContext(asmFunction);
// Run the analyzers
var loopAnalyzer = new LoopAnalyzer();
loopAnalyzer.AnalyzeLoops(context);
var dataFlowAnalyzer = new DataFlowAnalyzer();
dataFlowAnalyzer.AnalyzeDataFlow(context);
// Get the function name from exports if available
string functionName = _exportedFunctions.TryGetValue(address, out var name)
? name
: $"func_{address:X8}";
// Analyze the function
var functionAnalyzer = new FunctionAnalyzer(context);
var function = functionAnalyzer.AnalyzeFunction(address, functionName);
// Analyze control flow structures
var controlFlowAnalyzer = new ControlFlowAnalyzer(context);
controlFlowAnalyzer.AnalyzeControlFlow(function);
// Store the function in our cache
_functions[address] = function;
return function;
}
///
/// Generates C-like pseudocode for a decompiled function
///
/// The function to generate pseudocode for
/// The generated pseudocode
public string GeneratePseudocode(Function function)
{
// Create a pseudocode generator
var generator = new PseudocodeGenerator();
// Generate the pseudocode
return generator.GeneratePseudocode(function);
}
///
/// Decompiles all exported functions in the PE file
///
/// A dictionary of decompiled functions by address
public Dictionary DecompileAllExportedFunctions()
{
foreach (var export in _peFile.ExportedFunctions)
{
// Skip forwarded exports
if (export.IsForwarder)
{
continue;
}
try
{
DecompileFunction(export.AddressRva);
}
catch (Exception ex)
{
Console.WriteLine($"Error decompiling function {export.Name} at 0x{export.AddressRva:X8}: {ex.Message}");
}
}
return _functions;
}
}