Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interchangeable strings and variables sections #184

Merged
merged 4 commits into from
Aug 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion include/yaramod/parser/value.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "yaramod/types/rule.h"
#include "yaramod/types/regexp.h"
#include "yaramod/types/token_stream.h"
#include "yaramod/types/sections_summary.h"

#pragma once

Expand Down Expand Up @@ -52,7 +53,8 @@ class Value
TokenIt,
RegexpRangePair, //20
RegexpClassRecord,
std::vector<Variable> //22
std::vector<Variable>, //22
std::shared_ptr<SectionsSummary>
>;

/// @name Constructors
Expand Down Expand Up @@ -112,6 +114,11 @@ class Value
return std::move(moveValue<std::shared_ptr<Rule::StringsTrie>>());
}

std::shared_ptr<SectionsSummary>&& getSectionsSummary()
{
return std::move(moveValue<std::shared_ptr<SectionsSummary>>());
}

std::shared_ptr<StringModifier>&& getStringMod()
{
return std::move(moveValue<std::shared_ptr<StringModifier>>());
Expand Down
1 change: 1 addition & 0 deletions include/yaramod/types/rule.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ class Rule
void setName(const std::string& name);
void setMetas(const std::vector<Meta>& metas);
void setVariables(const std::vector<Variable>& variables);
void setStringsTrie(const std::shared_ptr<StringsTrie>&& strings);
void setTags(const std::vector<std::string>& tags);
void setCondition(const Expression::Ptr& condition);
void setLocation(const Location& location) { _location = location; }
Expand Down
57 changes: 57 additions & 0 deletions include/yaramod/types/sections_summary.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
* @file src/types/sections_summary.h
* @brief Declaration of class Variable.
* @copyright (c) 2021 Avast Software, licensed under the MIT license
*/

#pragma once

#include "yaramod/types/rule.h"
#include "yaramod/types/variable.h"

namespace yaramod {

/**
* Class representing sections summary
* in the YARA rules.
*/
class SectionsSummary
{
public:
/// @name Constructors
/// @{
SectionsSummary(std::shared_ptr<Rule::StringsTrie> default_strings, std::vector<Variable> default_variables)
: _strings(default_strings), _variables(default_variables), _is_strings_set(false), _is_variables_set(false) {}
SectionsSummary(const SectionsSummary& section_summary) = default;
SectionsSummary(SectionsSummary&& section_summary) = default;
/// @}

/// @name Assignment
/// @{
SectionsSummary& operator=(const SectionsSummary&) = default;
SectionsSummary& operator=(SectionsSummary&&) = default;
/// @}

/// @name Getter methods
/// @{
const std::shared_ptr<Rule::StringsTrie> getStringsTrie() const;
const std::vector<Variable> getVariables() const;
/// @}

bool isStringsTrieSet() { return _is_strings_set; }
bool isVariablesSet() { return _is_variables_set; }

/// @name Setter methods
/// @{
void setStringsTrie(const std::shared_ptr<Rule::StringsTrie> strings);
void setVariables(const std::vector<Variable> variables);
/// @}

private:
bool _is_strings_set;
bool _is_variables_set;
std::shared_ptr<Rule::StringsTrie> _strings; ///< Strings
std::vector<Variable> _variables; ///< Variables
};

}
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ set(SOURCES
types/modules/module_pool.cpp
types/plain_string.cpp
types/rule.cpp
types/sections_summary.cpp
types/token.cpp
types/token_stream.cpp
types/yara_file.cpp
Expand Down
68 changes: 54 additions & 14 deletions src/parser/parser_driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -465,14 +465,46 @@ void ParserDriver::defineGrammar()
};

if (_features & Features::AvastOnly)
{
_parser.rule("sections_summary") // std::shared_ptr<SectionsSummary>
.production("sections_summary", "variables", [&](auto&& args) -> Value {
auto section_summary = std::move(args[0].getSectionsSummary());
if (section_summary->isVariablesSet())
{
error_handle(currentFileContext()->getLocation(), "Duplicate variables section.");
}
section_summary->setVariables(args[1].getVariables());
return section_summary;
})
.production("sections_summary", "strings", [&](auto&& args) -> Value {
auto section_summary = std::move(args[0].getSectionsSummary());
if (section_summary->isStringsTrieSet())
{
error_handle(currentFileContext()->getLocation(), "Duplicate strings section.");
}
section_summary->setStringsTrie(std::move(args[1].getStringsTrie()));
return section_summary;
})
.production([&](auto&&) -> Value {
auto variables = std::vector<Variable>();
auto strings = std::make_shared<Rule::StringsTrie>();
setCurrentStrings(strings);

return std::make_shared<SectionsSummary>(strings, variables);
})
;

_parser.rule("rule") // {}
.production(
"rule_mods", "RULE", common_last_rule, "ID", common_rule_init, "tags", "LCB", "metas", "strings", "variables", "condition" , "RCB", [&](auto&& args) -> Value {
"rule_mods", "RULE", common_last_rule, "ID", common_rule_init, "tags", "LCB", "metas", "sections_summary", "condition" , "RCB", [&](auto&& args) -> Value {
auto rule = createCommonRule(args);
auto variables = std::move(args[9].getVariables());
rule.setVariables(std::move(variables));
rule.setCondition(std::move(args[10].getExpression()));
args[11].getTokenIt()->setType(TokenType::RULE_END);
auto sections_summary = std::move(args[8].getSectionsSummary());
auto variables = sections_summary->getVariables();

rule.setVariables(variables);
rule.setStringsTrie(std::move(sections_summary->getStringsTrie()));
rule.setCondition(std::move(args[9].getExpression()));
args[10].getTokenIt()->setType(TokenType::RULE_END);

for(auto iter = variables.begin(); iter != variables.end(); iter++) {
removeLocalSymbol(iter->getKey());
Expand All @@ -482,18 +514,33 @@ void ParserDriver::defineGrammar()
return {};
})
;
}
else
{
_parser.rule("strings_optional")
.production("strings", [&](auto&& args) -> Value {
return std::move(args[0].getStringsTrie());
})
.production([&](auto&&) -> Value {
auto strings = std::make_shared<Rule::StringsTrie>();
setCurrentStrings(strings);
return strings;
})
;

_parser.rule("rule") // {}
.production(
"rule_mods", "RULE", common_last_rule, "ID", common_rule_init, "tags", "LCB", "metas", "strings", "condition" , "RCB", [&](auto&& args) -> Value {
"rule_mods", "RULE", common_last_rule, "ID", common_rule_init, "tags", "LCB", "metas", "strings_optional", "condition" , "RCB", [&](auto&& args) -> Value {
auto rule = createCommonRule(args);
rule.setStringsTrie(std::move(args[8].getStringsTrie()));
rule.setCondition(std::move(args[9].getExpression()));
args[10].getTokenIt()->setType(TokenType::RULE_END);

addRule(std::move(rule));
return {};
})
;
}

_parser.rule("rule_mods") // vector<TokenIt>
.production("rule_mods", "PRIVATE", [](auto&& args) -> Value {
Expand Down Expand Up @@ -574,7 +621,6 @@ void ParserDriver::defineGrammar()
args[1].getTokenIt()->setType(TokenType::COLON_BEFORE_NEWLINE);
return std::move(args[2]);
})
.production([](auto&&) -> Value { return std::vector<Variable>(); })
;

_parser.rule("variables_body") // vector<Variable>
Expand Down Expand Up @@ -607,11 +653,6 @@ void ParserDriver::defineGrammar()
args[1].getTokenIt()->setType(TokenType::COLON_BEFORE_NEWLINE);
return std::move(args[2]);
})
.production([&](auto&&) -> Value {
auto strings = std::make_shared<Rule::StringsTrie>();
setCurrentStrings(strings);
return strings;
})
;

_parser.rule("strings_body") // shared_ptr<StringsTrie>
Expand Down Expand Up @@ -2469,9 +2510,8 @@ Rule ParserDriver::createCommonRule(std::vector<yaramod::Value>& args)
const std::vector<TokenIt> tags = std::move(args[5].getMultipleTokenIt());
args[6].getTokenIt()->setType(TokenType::RULE_BEGIN);
std::vector<Meta> metas = std::move(args[7].getMetas());
std::shared_ptr<Rule::StringsTrie> strings = std::move(args[8].getStringsTrie());
return Rule(_lastRuleTokenStream, name, std::move(mod_private), std::move(mod_global),
std::move(metas), std::move(strings), std::vector<Variable>(), NULL, std::move(tags));
std::move(metas), std::make_shared<Rule::StringsTrie>(), std::vector<Variable>(), NULL, std::move(tags));
}

} //namespace yaramod
10 changes: 10 additions & 0 deletions src/types/rule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,16 @@ void Rule::setVariables(const std::vector<Variable>& variables)
_variables = variables;
}

/**
* Sets the condition expression of the YARA rule.
*
* @param condition Condition expression.
*/
void Rule::setStringsTrie(const std::shared_ptr<StringsTrie>&& strings)
{
_strings = strings;
}

/**
* Sets the tags of the rule.
*
Expand Down
55 changes: 55 additions & 0 deletions src/types/sections_summary.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/**
* @file src/types/sections_summary.cpp
* @brief Implementation of class SectionsSummary.
* @copyright (c) 2021 Avast Software, licensed under the MIT license
*/

#include "yaramod/types/sections_summary.h"
#include "yaramod/types/rule.h"
#include "yaramod/types/variable.h"

namespace yaramod {

/**
* Returns StringsTrie.
*
* @return StringsTrie.
*/
const std::shared_ptr<Rule::StringsTrie> SectionsSummary::getStringsTrie() const
{
return std::move(_strings);
}

/**
* Returns vector of variables.
*
* @return Vector of variables.
*/
const std::vector<Variable> SectionsSummary::getVariables() const
{
return _variables;
}

/**
* Set the StringsTrie.
*
* @param key Key.
*/
void SectionsSummary::setStringsTrie(const std::shared_ptr<Rule::StringsTrie> strings)
{
_is_strings_set = true;
_strings = std::move(strings);
}

/**
* Set the vector of variables.
*
* @param value Value.
*/
void SectionsSummary::setVariables(const std::vector<Variable> variables)
{
_is_variables_set = true;
_variables = variables;
}

}
30 changes: 30 additions & 0 deletions tests/cpp/parser_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1803,6 +1803,36 @@ std::string expected = R"(rule rule1
EXPECT_EQ(expected, driver.getParsedFile().getTextFormatted());
}

TEST_F(ParserTests,
RuleWithUnorderedSections) {
prepareInput(
R"(rule rule1
{
variables:
var = 23
strings:
$1 = "Hello World!"
condition:
true
}
)");
EXPECT_TRUE(driver.parse(input));
ASSERT_EQ(1u, driver.getParsedFile().getRules().size());

std::string expected = R"(rule rule1
{
variables:
var = 23
strings:
$1 = "Hello World!"
condition:
true
}
)";

EXPECT_EQ(expected, driver.getParsedFile().getTextFormatted());
}

TEST_F(ParserTests,
GlobalRuleModifierWorks) {
prepareInput(
Expand Down
25 changes: 25 additions & 0 deletions tests/python/test_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,31 @@ def test_rule_with_variables(self):
self.assertTrue(rule.variables[4].value.symbol.is_structure)
self.assertEqual(rule.variables[4].value.symbol.name, 'time')

def test_rule_with_unordered_sections(self):
yara_file = yaramod.Yaramod(yaramod.Features.Avast).parse_string('''
rule rule_with_unordered_sections
{
variables:
var = 25.8
strings:
$1 = "Hello World!"
condition:
true
}''')

expected = r'''
rule rule_with_unordered_sections
{
variables:
var = 25.8
strings:
$1 = "Hello World!"
condition:
true
}
'''
self.assertEqual(expected, yara_file.text_formatted)

def test_rule_with_variable_and_string(self):
yara_file = yaramod.Yaramod(yaramod.Features.Avast).parse_string('''
import "time"
Expand Down