Skip to content

Commit

Permalink
Add scan timeout
Browse files Browse the repository at this point in the history
  • Loading branch information
Dorian Eikenberg committed Feb 28, 2024
1 parent b70ab31 commit 8e9d29d
Show file tree
Hide file tree
Showing 10 changed files with 41 additions and 9 deletions.
2 changes: 2 additions & 0 deletions plugins/inmemoryscanner/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ For this, add the following parts to the _VMICore_ config and tweak them to your
| `plugins` | Add your plugin here by the exact name of your shared library (e.g. `libinmemoryscanner.so`). All plugin specific config keys should be added as sub-keys under this name. |
| `scan_all_regions` | Optional boolean (defaults to `false`). Indicates whether to eagerly scan all memory regions as opposed to ignoring shared memory. |
| `signature_file` | Path to the compiled signatures with which to scan the memory regions. |
| `scan_timeout` | Timeout in seconds that determines when libyara will cancel the scan process for a single memory region. |

Example configuration:

Expand All @@ -145,6 +146,7 @@ plugin_system:
dump_memory: false
scan_all_regions: false
output_path: ""
scan_timeout: 10
ignored_processes:
- SearchUI.exe
- system
Expand Down
6 changes: 6 additions & 0 deletions plugins/inmemoryscanner/src/lib/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ namespace InMemoryScanner
outputPath = rootNode["output_path"].as<std::string>();
dumpMemory = rootNode["dump_memory"].as<bool>(false);
scanAllRegions = rootNode["scan_all_regions"].as<bool>(false);
scanTimeout = rootNode["scan_timeout"].as<int>(10);

auto ignoredProcessesVec =
rootNode["ignored_processes"].as<std::vector<std::string>>(std::vector<std::string>());
Expand All @@ -43,6 +44,11 @@ namespace InMemoryScanner
return outputPath;
}

int Config::getScanTimeout() const
{
return scanTimeout;
}

bool Config::isProcessIgnored(const std::string& processName) const
{
return ignoredProcesses.find(processName) != ignoredProcesses.end();
Expand Down
5 changes: 5 additions & 0 deletions plugins/inmemoryscanner/src/lib/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ namespace InMemoryScanner

[[nodiscard]] virtual std::filesystem::path getOutputPath() const = 0;

[[nodiscard]] virtual int getScanTimeout() const = 0;

[[nodiscard]] virtual bool isProcessIgnored(const std::string& processName) const = 0;

[[nodiscard]] virtual bool isScanAllRegionsActivated() const = 0;
Expand All @@ -51,6 +53,8 @@ namespace InMemoryScanner

[[nodiscard]] std::filesystem::path getOutputPath() const override;

[[nodiscard]] int getScanTimeout() const override;

[[nodiscard]] bool isProcessIgnored(const std::string& processName) const override;

[[nodiscard]] bool isScanAllRegionsActivated() const override;
Expand All @@ -66,5 +70,6 @@ namespace InMemoryScanner
std::set<std::string> ignoredProcesses;
bool dumpMemory{};
bool scanAllRegions{};
int scanTimeout;
};
}
5 changes: 5 additions & 0 deletions plugins/inmemoryscanner/src/lib/IYaraInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ namespace InMemoryScanner
using std::runtime_error::runtime_error;
};

class YaraTimeoutException final : public YaraException
{
using YaraException::YaraException;
};

class IYaraInterface
{
public:
Expand Down
2 changes: 1 addition & 1 deletion plugins/inmemoryscanner/src/lib/InMemory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ namespace InMemoryScanner
{
configuration->overrideDumpMemoryFlag(dumpMemoryArgument.getValue());
}
auto yara = std::make_unique<YaraInterface>(configuration->getSignatureFile());
auto yara = std::make_unique<YaraInterface>(configuration->getSignatureFile(), configuration->getScanTimeout());
auto dumping = std::make_unique<Dumping>(pluginInterface, configuration);
scanner = std::make_unique<Scanner>(pluginInterface, configuration, std::move(yara), std::move(dumping));
}
Expand Down
7 changes: 7 additions & 0 deletions plugins/inmemoryscanner/src/lib/Scanner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,13 @@ namespace InMemoryScanner
*processInformation->fullName,
memoryRegionDescriptor);
}
catch (const YaraTimeoutException&)
{
logger->warning("Scan timeout reached",
{{"Process", *processInformation->fullName},
{"BaseVA", memoryRegionDescriptor.base},
{"Size", memoryRegionDescriptor.size}});
}
catch (const std::exception& exc)
{
logger->error("Error scanning memory region of process",
Expand Down
9 changes: 7 additions & 2 deletions plugins/inmemoryscanner/src/lib/YaraInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ namespace

namespace InMemoryScanner
{
YaraInterface::YaraInterface(const std::string& rulesFile)
YaraInterface::YaraInterface(const std::string& rulesFile, int scanTimeout) : scanTimeout(scanTimeout)
{
auto err = yr_initialize();
if (err != ERROR_SUCCESS)
Expand Down Expand Up @@ -89,9 +89,14 @@ namespace InMemoryScanner
SCAN_FLAGS_PROCESS_MEMORY | SCAN_FLAGS_REPORT_RULES_MATCHING,
yaraCallback,
&results,
0);
scanTimeout);
err != ERROR_SUCCESS)
{
if (err == ERROR_SCAN_TIMEOUT)
{
throw YaraTimeoutException("Scan timeout");
}

throw YaraException(fmt::format("Error scanning memory. Error code: {}", err));
}

Expand Down
3 changes: 2 additions & 1 deletion plugins/inmemoryscanner/src/lib/YaraInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace InMemoryScanner
class YaraInterface : public IYaraInterface
{
public:
explicit YaraInterface(const std::string& rulesFile);
YaraInterface(const std::string& rulesFile, int scanTimeout);

YaraInterface(const YaraInterface& other) = delete;

Expand Down Expand Up @@ -39,6 +39,7 @@ namespace InMemoryScanner
std::vector<Rule> scanMemory(std::span<const VmiCore::MappedRegion> mappedRegions) override;

private:
int scanTimeout;
YR_RULES* rules = nullptr;

static int yaraCallback(YR_SCAN_CONTEXT* context, int message, void* message_data, void* user_data);
Expand Down
10 changes: 5 additions & 5 deletions plugins/inmemoryscanner/test/YaraInterface_unittest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ namespace InMemoryScanner
all of them
}
)";
auto yaraInterface = YaraInterface(compileYaraRules(rules));
auto yaraInterface = YaraInterface(compileYaraRules(rules), 0);
auto subRegion1 = constructPageWithContent("ABCD");
std::vector<VmiCore::MappedRegion> memoryRegions{{0x0, subRegion1}};

Expand All @@ -84,7 +84,7 @@ namespace InMemoryScanner
all of them
}
)";
auto yaraInterface = YaraInterface(compileYaraRules(rules));
auto yaraInterface = YaraInterface(compileYaraRules(rules), 0);
auto subRegion1 = constructPageWithContent("ABCD", true);
auto subRegion2 = constructPageWithContent("DCBA", false);
std::vector<VmiCore::MappedRegion> memoryRegions{{0x0, subRegion1}, {pageSizeInBytes, subRegion2}};
Expand All @@ -107,7 +107,7 @@ namespace InMemoryScanner
all of them
}
)";
auto yaraInterface = YaraInterface(compileYaraRules(rules));
auto yaraInterface = YaraInterface(compileYaraRules(rules), 0);
auto subRegion1 = constructPageWithContent("ABCD");
auto subRegion2 = constructPageWithContent("DCBA");
std::vector<VmiCore::MappedRegion> memoryRegion1{{0x0, subRegion1}};
Expand All @@ -133,7 +133,7 @@ namespace InMemoryScanner
all of them
}
)";
auto yaraInterface = YaraInterface(compileYaraRules(rules));
auto yaraInterface = YaraInterface(compileYaraRules(rules), 0);
auto subRegion1 = constructPageWithContent("ABCD");
auto subRegion2 = constructPageWithContent("DCBA");
std::vector<VmiCore::MappedRegion> memoryRegions{{0x0, subRegion1}, {4 * pageSizeInBytes, subRegion2}};
Expand Down Expand Up @@ -168,7 +168,7 @@ namespace InMemoryScanner
all of them
}
)";
auto yaraInterface = YaraInterface(compileYaraRules(rules));
auto yaraInterface = YaraInterface(compileYaraRules(rules), 0);
auto subRegion1 = constructPageWithContent("ABCD");
auto subRegion2 = constructPageWithContent("DCBA");
auto subRegion3 = constructPageWithContent("EFGH");
Expand Down
1 change: 1 addition & 0 deletions plugins/inmemoryscanner/test/mock_Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace InMemoryScanner
MOCK_METHOD(void, parseConfiguration, (const VmiCore::Plugin::IPluginConfig&), (override));
MOCK_METHOD(std::filesystem::path, getSignatureFile, (), (const, override));
MOCK_METHOD(std::filesystem::path, getOutputPath, (), (const, override));
MOCK_METHOD(int, getScanTimeout, (), (const, override));
MOCK_METHOD(bool, isProcessIgnored, (const std::string& processName), (const, override));
MOCK_METHOD(bool, isScanAllRegionsActivated, (), (const, override));
MOCK_METHOD(bool, isDumpingMemoryActivated, (), (const, override));
Expand Down

0 comments on commit 8e9d29d

Please sign in to comment.