Skip to content

Delegates

Gabe Stocco edited this page Aug 1, 2020 · 28 revisions

The OAT Analyzer has 4 Custom Delegate extensibility points and each built in operator also has a delegate that can be overridden. These allow you to extend the functionality of the Analyzer to your own custom operations and arbitrary complex objects.

Property Parsing

The property parsing delegate provides a way to parse object types that Logical Analyzer doesn't support natively. For example, parsing Dictionaries and Lists that are not string based.

public delegate (bool Processed, object? Result) PropertyExtractionDelegate(object? obj, string index);

As an example, in Attack Surface Analyzer we extend Logical Analyzer property parsing to support our usage of TpmAlgId in dictionaries. link

public static (bool, object?) ParseCustomAsaProperties(object? obj, string index)
{
    switch (obj)
    {
        case Dictionary<(TpmAlgId, uint), byte[]> algDict:
            var elements = Convert.ToString(index, CultureInfo.InvariantCulture)?
                .Trim('(').Trim(')').Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            if (Enum.TryParse(typeof(TpmAlgId), elements.First(), out object? result) &&
                result is TpmAlgId Algorithm && uint.TryParse(elements.Last(), out uint Index) &&
                algDict.TryGetValue((Algorithm, Index), out byte[]? byteArray))
            {
                return (true, byteArray);
            }
            else
            {
                return (true, null);
            }
    }
    return (false, null);
}

Value Extraction

The value extraction property provides an extension mechanism to provide a way to turn an object into extracted strings for Logical Analyzer to compare.

public delegate (bool Processed, 
    IEnumerable<string> valsExtracted, 
    IEnumerable<KeyValuePair<string, string>> dictExtracted)
        ObjectToValuesDelegate(object? obj);

In Attack Surface Analyzer we also extend Value extraction to support our usage of TpmAlgId in dictionaries. link

public static (bool Processed, 
    IEnumerable<string> valsExtracted, 
    IEnumerable<KeyValuePair<string, string>> dictExtracted) 
        ParseCustomAsaObjectValues(object? obj)
{
    if (obj is Dictionary<(TpmAlgId, uint), byte[]> algDict)
    {
        return (true,Array.Empty<string>(), algDict.ToList()
            .Select(x => 
                new KeyValuePair<string, string>(x.Key.ToString(), Convert.ToBase64String(x.Value)))
                    .ToList());
    }
    return (false, Array.Empty<string>(), Array.Empty<KeyValuePair<string,string>>());
}

Custom Operation

The Custom Operation Delegate allows you to extend Logical Analyzer with your own custom operation or operations. Custom operations are also provided with the set of captures of previously evaluated clauses in the same rule.

To create a custom Operation create a new OatOperation object and set the OperationDelegate.

public delegate OperationResult OperationDelegate
    (Clause clause, object? before, object? after, IEnumerable<ClauseCapture>? captures);

For example

OperationResult ReturnsTrueOperationDelegate(clause, before, after, captures) =>
{
    return new OperationResult(true, null);
}

In the tests we test extending with a custom Operation

var analyzer = new Analyzer();
analyzer.SetOperation(new OatOperation(Operation.Custom, analyzer)
{
    CustomOperation = "RETURN_TRUE",
    OperationDelegate = ReturnsTrueOperationDelegate
});

Rule Validation

Along with your operation delegate you should also add a validation delegate for your custom operation.

public delegate IEnumerable<Violation> Violations ValidationDelegate(Rule rule, Clause clause);

The tests contain this example of adding a validation delegate.

private IEnumerable<Violation> ReturnTrueValidationDelegate(Rule rule, Clause clause)
{
    if ((clause.Data?.Count > 0))
    {
        yield return new Violation("RETURNS_TRUE doesn't take data", rule, clause);
    }
    if (clause.DictData?.Count > 0)
    {
        yield return new Violation("RETURNS_TRUE doesn't take data", rule, clause);
    }
}

var analyzer = new Analyzer();
analyzer.SetOperation(new OatOperation(Operation.Custom, analyzer)
{
    CustomOperation = "RETURN_TRUE",
    OperationDelegate = ReturnsTrueOperationDelegate,
    ValidationDelegate = ReturnsTrueValidationDelegate
});

Overriding Built-In Operations

You can also override the built-in operations.

To override the built-in Operator you want to modify just set the Operation appropriately and call SetOperation as normal.

var analyzer = new Analyzer();
analyzer.SetOperation(YourCustomOperation);
Clone this wiki locally