1
0
mirror of synced 2024-11-28 17:40:51 +01:00

feat: Make it easier to apply multiple yara rules at once

This commit is contained in:
WerWolv 2023-01-27 12:17:10 +01:00
parent 1cf9f7e990
commit 800ffb5e56
2 changed files with 182 additions and 192 deletions

View File

@ -35,7 +35,6 @@ namespace hex::plugin::builtin {
std::vector<std::string> m_consoleMessages;
void reloadRules();
void applyRules();
void clearResult();
};

View File

@ -20,8 +20,6 @@ namespace hex::plugin::builtin {
ViewYara::ViewYara() : View("hex.builtin.view.yara.name") {
yr_initialize();
this->reloadRules();
ContentRegistry::FileHandler::add({ ".yar" }, [](const auto &path) {
for (const auto &destPath : fs::getDefaultPaths(fs::ImHexPath::Yara)) {
if (fs::copyFile(path, destPath / path.filename(), std::fs::copy_options::overwrite_existing)) {
@ -44,26 +42,40 @@ namespace hex::plugin::builtin {
ImGui::TextUnformatted("hex.builtin.view.yara.header.rules"_lang);
ImGui::Separator();
if (this->m_rules.empty()) {
ImGui::TextFormattedColored(ImVec4(0.92F, 0.25F, 0.2F, 1.0F), "{}", "hex.builtin.view.yara.no_rules"_lang);
if (ImGui::Button("hex.builtin.view.yara.reload"_lang)) this->reloadRules();
} else {
ImGui::BeginDisabled(this->m_matcherTask.isRunning());
{
if (ImGui::BeginCombo("hex.builtin.view.yara.header.rules"_lang, hex::toUTF8String(this->m_rules[this->m_selectedRule].first).c_str())) {
if (ImGui::BeginListBox("##rules", ImVec2(-FLT_MIN, ImGui::GetTextLineHeightWithSpacing() * 5))) {
for (u32 i = 0; i < this->m_rules.size(); i++) {
const bool selected = (this->m_selectedRule == i);
if (ImGui::Selectable(hex::toUTF8String(this->m_rules[i].first).c_str(), selected))
if (ImGui::Selectable(hex::toUTF8String(this->m_rules[i].first).c_str(), selected)) {
this->m_selectedRule = i;
}
}
ImGui::EndListBox();
}
if (selected)
ImGui::SetItemDefaultFocus();
if (ImGui::IconButton(ICON_VS_ADD, ImGui::GetStyleColorVec4(ImGuiCol_Text))) {
std::vector<std::fs::path> paths;
for (const auto &path : fs::getDefaultPaths(fs::ImHexPath::Yara)) {
std::error_code error;
for (const auto &entry : std::fs::recursive_directory_iterator(path, error)) {
if (!entry.is_regular_file()) continue;
if (entry.path().extension() != ".yara" && entry.path().extension() != ".yar") continue;
paths.push_back(entry);
}
ImGui::EndCombo();
}
View::showFileChooserPopup(paths, { { "Yara File", "yara" }, { "Yara File", "yar" } }, [this](const auto &path) {
this->m_rules.push_back({ path.filename(), path });
});
}
ImGui::SameLine();
if (ImGui::Button("hex.builtin.view.yara.reload"_lang)) this->reloadRules();
if (ImGui::IconButton(ICON_VS_REMOVE, ImGui::GetStyleColorVec4(ImGuiCol_Text))) {
if (this->m_selectedRule < this->m_rules.size()) {
this->m_rules.erase(this->m_rules.begin() + this->m_selectedRule);
this->m_selectedRule = std::min(this->m_selectedRule, (u32)this->m_rules.size() - 1);
}
}
ImGui::NewLine();
if (ImGui::Button("hex.builtin.view.yara.match"_lang)) this->applyRules();
@ -71,14 +83,11 @@ namespace hex::plugin::builtin {
ImGui::BeginDisabled(this->m_matches.empty());
if (ImGui::Button("hex.builtin.view.yara.reset"_lang)) this->clearResult();
ImGui::EndDisabled();
}
ImGui::EndDisabled();
if (this->m_matcherTask.isRunning()) {
ImGui::SameLine();
ImGui::TextSpinner("hex.builtin.view.yara.matching"_lang);
}
}
ImGui::NewLine();
ImGui::TextUnformatted("hex.builtin.view.yara.header.matches"_lang);
@ -165,40 +174,32 @@ namespace hex::plugin::builtin {
this->m_consoleMessages.clear();
}
void ViewYara::reloadRules() {
this->m_rules.clear();
for (const auto &path : fs::getDefaultPaths(fs::ImHexPath::Yara)) {
if (!fs::exists(path))
continue;
std::error_code error;
for (const auto &entry : std::fs::recursive_directory_iterator(path, error)) {
const auto &extension = entry.path().extension();
if (entry.is_regular_file() && (extension == ".yar" || extension == ".yara")) {
this->m_rules.emplace_back(std::fs::relative(entry.path(), path), entry.path());
}
}
}
}
void ViewYara::applyRules() {
this->m_matcherTask = TaskManager::createTask("hex.builtin.view.yara.matching", 0, [this](auto &task) {
if (!ImHexApi::Provider::isValid()) return;
struct ResultContext {
Task *task = nullptr;
std::vector<YaraMatch> newMatches;
std::vector<std::string> consoleMessages;
};
ResultContext resultContext;
resultContext.task = &task;
for (const auto &[fileName, filePath] : this->m_rules) {
YR_COMPILER *compiler = nullptr;
yr_compiler_create(&compiler);
ON_SCOPE_EXIT {
yr_compiler_destroy(compiler);
};
auto currFilePath = hex::toUTF8String(fs::toShortPath(this->m_rules[this->m_selectedRule].second));
auto currFilePath = hex::toUTF8String(fs::toShortPath(filePath));
yr_compiler_set_include_callback(
compiler,
[](const char *includeName, const char *, const char *, void *userData) -> const char * {
auto currFilePath = static_cast<const char *>(userData);
fs::File file(std::fs::path(currFilePath).parent_path() / includeName, fs::File::Mode::Read);
fs::File file(std::fs::path(static_cast<const char *>(userData)).parent_path() / includeName, fs::File::Mode::Read);
if (!file.isValid())
return nullptr;
@ -296,16 +297,6 @@ namespace hex::plugin::builtin {
return &context.currBlock;
};
struct ResultContext {
Task *task = nullptr;
std::vector<YaraMatch> newMatches;
std::vector<std::string> consoleMessages;
};
ResultContext resultContext;
resultContext.task = &task;
yr_rules_scan_mem_blocks(
rules, &iterator, 0, [](YR_SCAN_CONTEXT *context, int message, void *data, void *userData) -> int {
auto &results = *static_cast<ResultContext *>(userData);
@ -343,7 +334,7 @@ namespace hex::plugin::builtin {
&resultContext,
0);
}
TaskManager::doLater([this, resultContext] {
for (const auto &match : this->m_matches) {
ImHexApi::HexEditor::removeBackgroundHighlight(match.highlightId);