save progress
This commit is contained in:
@@ -7,6 +7,7 @@ using System.Security.Cryptography;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using StellaOps.BinaryIndex.Disassembly;
|
||||
using StellaOps.BinaryIndex.Normalization;
|
||||
using StellaOps.BinaryIndex.Semantic;
|
||||
|
||||
namespace StellaOps.BinaryIndex.DeltaSig;
|
||||
|
||||
@@ -17,18 +18,49 @@ public sealed class DeltaSignatureGenerator : IDeltaSignatureGenerator
|
||||
{
|
||||
private readonly DisassemblyService _disassemblyService;
|
||||
private readonly NormalizationService _normalizationService;
|
||||
private readonly IIrLiftingService? _irLiftingService;
|
||||
private readonly ISemanticGraphExtractor? _graphExtractor;
|
||||
private readonly ISemanticFingerprintGenerator? _fingerprintGenerator;
|
||||
private readonly ILogger<DeltaSignatureGenerator> _logger;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new delta signature generator without semantic analysis support.
|
||||
/// </summary>
|
||||
public DeltaSignatureGenerator(
|
||||
DisassemblyService disassemblyService,
|
||||
NormalizationService normalizationService,
|
||||
ILogger<DeltaSignatureGenerator> logger)
|
||||
: this(disassemblyService, normalizationService, null, null, null, logger)
|
||||
{
|
||||
_disassemblyService = disassemblyService;
|
||||
_normalizationService = normalizationService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new delta signature generator with optional semantic analysis support.
|
||||
/// </summary>
|
||||
public DeltaSignatureGenerator(
|
||||
DisassemblyService disassemblyService,
|
||||
NormalizationService normalizationService,
|
||||
IIrLiftingService? irLiftingService,
|
||||
ISemanticGraphExtractor? graphExtractor,
|
||||
ISemanticFingerprintGenerator? fingerprintGenerator,
|
||||
ILogger<DeltaSignatureGenerator> logger)
|
||||
{
|
||||
_disassemblyService = disassemblyService ?? throw new ArgumentNullException(nameof(disassemblyService));
|
||||
_normalizationService = normalizationService ?? throw new ArgumentNullException(nameof(normalizationService));
|
||||
_irLiftingService = irLiftingService;
|
||||
_graphExtractor = graphExtractor;
|
||||
_fingerprintGenerator = fingerprintGenerator;
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether semantic analysis is available.
|
||||
/// </summary>
|
||||
public bool SemanticAnalysisAvailable =>
|
||||
_irLiftingService is not null &&
|
||||
_graphExtractor is not null &&
|
||||
_fingerprintGenerator is not null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<DeltaSignature> GenerateSignaturesAsync(
|
||||
Stream binaryStream,
|
||||
@@ -94,11 +126,14 @@ public sealed class DeltaSignatureGenerator : IDeltaSignatureGenerator
|
||||
}
|
||||
|
||||
// Generate signature from normalized bytes
|
||||
var signature = GenerateSymbolSignature(
|
||||
var signature = await GenerateSymbolSignatureAsync(
|
||||
normalized,
|
||||
symbolName,
|
||||
symbolInfo.Section ?? ".text",
|
||||
options);
|
||||
instructions,
|
||||
binary.Architecture,
|
||||
options,
|
||||
ct);
|
||||
|
||||
symbolSignatures.Add(signature);
|
||||
|
||||
@@ -218,6 +253,136 @@ public sealed class DeltaSignatureGenerator : IDeltaSignatureGenerator
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<SymbolSignature> GenerateSymbolSignatureAsync(
|
||||
NormalizedFunction normalized,
|
||||
string symbolName,
|
||||
string scope,
|
||||
IReadOnlyList<DisassembledInstruction> originalInstructions,
|
||||
CpuArchitecture architecture,
|
||||
SignatureOptions? options = null,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(normalized);
|
||||
ArgumentNullException.ThrowIfNull(symbolName);
|
||||
ArgumentNullException.ThrowIfNull(scope);
|
||||
ArgumentNullException.ThrowIfNull(originalInstructions);
|
||||
|
||||
options ??= new SignatureOptions();
|
||||
|
||||
// Get normalized bytes for hashing
|
||||
var normalizedBytes = GetNormalizedBytes(normalized);
|
||||
|
||||
// Compute the main hash
|
||||
var hashHex = ComputeHash(normalizedBytes, options.HashAlgorithm);
|
||||
|
||||
// Compute chunk hashes for resilience
|
||||
ImmutableArray<ChunkHash>? chunks = null;
|
||||
if (options.IncludeChunks && normalizedBytes.Length >= options.ChunkSize)
|
||||
{
|
||||
chunks = ComputeChunkHashes(normalizedBytes, options.ChunkSize, options.HashAlgorithm);
|
||||
}
|
||||
|
||||
// Compute CFG metrics using proper CFG analysis
|
||||
int? bbCount = null;
|
||||
string? cfgEdgeHash = null;
|
||||
if (options.IncludeCfg && normalized.Instructions.Length > 0)
|
||||
{
|
||||
// Use first instruction's address as start address
|
||||
var startAddress = normalized.Instructions[0].OriginalAddress;
|
||||
var cfgMetrics = CfgExtractor.ComputeMetrics(
|
||||
normalized.Instructions.ToList(),
|
||||
startAddress);
|
||||
|
||||
bbCount = cfgMetrics.BasicBlockCount;
|
||||
cfgEdgeHash = cfgMetrics.EdgeHash;
|
||||
}
|
||||
|
||||
// Compute semantic fingerprint if enabled and services available
|
||||
string? semanticHashHex = null;
|
||||
ImmutableArray<string>? semanticApiCalls = null;
|
||||
|
||||
if (options.IncludeSemantic && SemanticAnalysisAvailable && originalInstructions.Count > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
var semanticFingerprint = await ComputeSemanticFingerprintAsync(
|
||||
originalInstructions,
|
||||
symbolName,
|
||||
architecture,
|
||||
ct);
|
||||
|
||||
if (semanticFingerprint is not null)
|
||||
{
|
||||
semanticHashHex = semanticFingerprint.GraphHashHex;
|
||||
semanticApiCalls = semanticFingerprint.ApiCalls;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(
|
||||
ex,
|
||||
"Failed to compute semantic fingerprint for {Symbol}, continuing without semantic data",
|
||||
symbolName);
|
||||
}
|
||||
}
|
||||
|
||||
return new SymbolSignature
|
||||
{
|
||||
Name = symbolName,
|
||||
Scope = scope,
|
||||
HashAlg = options.HashAlgorithm,
|
||||
HashHex = hashHex,
|
||||
SizeBytes = normalizedBytes.Length,
|
||||
CfgBbCount = bbCount,
|
||||
CfgEdgeHash = cfgEdgeHash,
|
||||
Chunks = chunks,
|
||||
SemanticHashHex = semanticHashHex,
|
||||
SemanticApiCalls = semanticApiCalls
|
||||
};
|
||||
}
|
||||
|
||||
private async Task<SemanticFingerprint?> ComputeSemanticFingerprintAsync(
|
||||
IReadOnlyList<DisassembledInstruction> instructions,
|
||||
string functionName,
|
||||
CpuArchitecture architecture,
|
||||
CancellationToken ct)
|
||||
{
|
||||
if (_irLiftingService is null || _graphExtractor is null || _fingerprintGenerator is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check if architecture is supported
|
||||
if (!_irLiftingService.SupportsArchitecture(architecture))
|
||||
{
|
||||
_logger.LogDebug(
|
||||
"Architecture {Arch} not supported for semantic analysis",
|
||||
architecture);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Lift to IR
|
||||
var startAddress = instructions.Count > 0 ? instructions[0].Address : 0UL;
|
||||
var lifted = await _irLiftingService.LiftToIrAsync(
|
||||
instructions,
|
||||
functionName,
|
||||
startAddress,
|
||||
architecture,
|
||||
ct: ct);
|
||||
|
||||
// Extract semantic graph
|
||||
var graph = await _graphExtractor.ExtractGraphAsync(lifted, ct: ct);
|
||||
|
||||
// Generate fingerprint
|
||||
var fingerprint = await _fingerprintGenerator.GenerateAsync(
|
||||
graph,
|
||||
startAddress,
|
||||
ct: ct);
|
||||
|
||||
return fingerprint;
|
||||
}
|
||||
|
||||
private static byte[] GetNormalizedBytes(NormalizedFunction normalized)
|
||||
{
|
||||
// Concatenate all normalized instruction bytes
|
||||
|
||||
Reference in New Issue
Block a user