gyp icon indicating copy to clipboard operation
gyp copied to clipboard

Can you manipulate A Rule's condition when represented as an AST

Open hop-along-polly opened this issue 2 years ago • 2 comments

After parsing a Yara Ruleset into a ast.RuleSet is there a way to manipulate a rule's condition?

Take this sample ruleset

rule rule_1 {
    strings:
        $header_v2 = {50 02}
        $header_v3 = {50 03}
        $header_v4 = {50 04}
        $header_v5 = {50 05}

    condition: (
        for any of them: ($ at 0)
    )
}

rule rule_2 {
    strings:
        $pattern_v4_4 = {8c 05 65 23 61 6c [0-32] 90}
        $pattern_v4_5 = {8c 06 65 52 65 63 [0-32] 90}

    condition:
        any of them
}

I would like to make rule_2's condition rule_1 and any of them however I can't find an ast.Condition or any similar struct to do this. Here is the code I have so far for getting the rules condition. Now that I have it is there a way to modify it?

r2 := r.Rules[1]
for _, cond := range r2.Condition.Children() {
    fmt.Println("Condition", cond)
}

hop-along-polly avatar May 12 '23 18:05 hop-along-polly

Hey @hop-along-polly

You can create a new condition and replace the old one. Here is how to do it:

First, create a new condition. This code snippet creates an ast.Operation which represents the logical AND of rule_1 and any of them:

c := &ast.Operation{
    Operator: ast.OpAnd,
    Operands: []ast.Expression{
        &ast.Identifier{Identifier: "rule_1"},
        &ast.Of{
            Quantifier: ast.KeywordAny,
            Strings:    ast.KeywordThem,
        },
    },
}

This ast.Operation is the equivalent of the YARA expression rule_1 and any of them.

Once you have created this new condition, you can replace the existing condition in the rule. Assuming that the rule you want to modify is the second one in your ruleset (indexed at 1 in the slice), you can do:

rs.Rules[1].Condition = c

This will replace the condition of the second rule with your new condition. If we write the source of the ruleset we will get:

rule rule_1 {
  strings:
    $header_v2 = { 50 02 }
    $header_v3 = { 50 03 }
    $header_v4 = { 50 04 }
    $header_v5 = { 50 05 }
  condition:
    (for any of them : ($ at 0))
}

rule rule_2 {
  strings:
    $pattern_v4_4 = { 8C 05 65 23 61 6C [0-32] 90 }
    $pattern_v4_5 = { 8C 06 65 52 65 63 [0-32] 90 }
  condition:
    rule_1 and any of them
}

Additionally you could just modify the condition in place instead of replacing it. Please let me know if you need any further clarification.

gazunder avatar May 13 '23 22:05 gazunder

I have a similar question for overwriting a Rules string values. It seems you can't use an ast.TextString as an ast.String value. Is it similar to conditions where I need to use smaller abstractions to build up to the correct implementation of the ast.String interface?

hop-along-polly avatar May 19 '23 17:05 hop-along-polly