-
Notifications
You must be signed in to change notification settings - Fork 19
Delegates
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.
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);
}
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>>());
}
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
});
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
});
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);