Skip to content

Commit 91e23ac

Browse files
author
Dorian Eikenberg
committed
WIP: vmi_mmap_guest_2
1 parent 313c231 commit 91e23ac

24 files changed

+278
-250
lines changed

plugins/inmemoryscanner/src/lib/IYaraInterface.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
#define INMEMORYSCANNER_IYARAINTERFACE_H
33

44
#include "Common.h"
5-
#include <exception>
5+
#include <span>
6+
#include <stdexcept>
67
#include <string>
78
#include <vector>
89
#include <vmicore/vmi/IMemoryMapping.h>
@@ -20,8 +21,8 @@ namespace InMemoryScanner
2021
public:
2122
virtual ~IYaraInterface() = default;
2223

23-
virtual std::unique_ptr<std::vector<Rule>>
24-
scanMemory(const std::vector<VmiCore::MappedRegion>& mappedRegions) = 0;
24+
virtual std::vector<Rule> scanMemory(VmiCore::addr_t regionBase,
25+
std::span<const VmiCore::MappedRegion> mappedRegions) = 0;
2526

2627
protected:
2728
IYaraInterface() = default;

plugins/inmemoryscanner/src/lib/Scanner.cpp

Lines changed: 42 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
#include "Scanner.h"
22
#include "Common.h"
33
#include "Filenames.h"
4+
#include <algorithm>
45
#include <fmt/core.h>
56
#include <future>
6-
#include <iterator>
7-
#include <span>
87
#include <vmicore/callback.h>
98
#include <vmicore/os/PagingDefinitions.h>
109

@@ -49,20 +48,19 @@ namespace InMemoryScanner
4948

5049
bool Scanner::shouldRegionBeScanned(const MemoryRegion& memoryRegionDescriptor)
5150
{
52-
bool verdict = true;
5351
if (configuration->isScanAllRegionsActivated())
5452
{
5553
return true;
5654
}
5755
if (memoryRegionDescriptor.isSharedMemory && !memoryRegionDescriptor.isProcessBaseImage)
5856
{
59-
verdict = false;
6057
logger->info("Skipping: Is shared memory and not the process base image.");
58+
return false;
6159
}
62-
return verdict;
60+
return true;
6361
}
6462

65-
std::vector<uint8_t> Scanner::constructPaddedMemoryRegion(const std::vector<MappedRegion>& regions)
63+
std::vector<uint8_t> Scanner::constructPaddedMemoryRegion(std::span<const MappedRegion> regions)
6664
{
6765
std::vector<uint8_t> result;
6866

@@ -74,22 +72,24 @@ namespace InMemoryScanner
7472
std::size_t regionSize = 0;
7573
for (const auto& region : regions)
7674
{
77-
regionSize += region.mapping.size();
75+
regionSize += region.asSpan().size();
7876
regionSize += pageSizeInBytes;
7977
}
8078
// last region should not have succeeding padding page
8179
regionSize -= pageSizeInBytes;
8280

8381
result.reserve(regionSize);
8482
// copy first region
85-
std::copy(regions.front().mapping.begin(), regions.front().mapping.end(), std::back_inserter(result));
83+
auto frontRegionSpan = regions.front().asSpan();
84+
std::ranges::copy(frontRegionSpan.begin(), frontRegionSpan.end(), std::back_inserter(result));
8685

8786
for (std::size_t i = 1; i < regions.size(); i++)
8887
{
8988
const auto& region = regions[i];
9089
// padding page
9190
result.insert(result.end(), pageSizeInBytes, 0);
92-
std::copy(region.mapping.begin(), region.mapping.end(), std::back_inserter(result));
91+
auto regionSpan = region.asSpan();
92+
std::ranges::copy(regionSpan.begin(), regionSpan.end(), std::back_inserter(result));
9393
}
9494

9595
return result;
@@ -105,47 +105,48 @@ namespace InMemoryScanner
105105
{"Size", memoryRegionDescriptor.size},
106106
{"Module", memoryRegionDescriptor.moduleName}});
107107

108-
if (shouldRegionBeScanned(memoryRegionDescriptor))
108+
if (!shouldRegionBeScanned(memoryRegionDescriptor))
109109
{
110-
auto memoryMapping = pluginInterface->mapProcessMemoryRegion(
111-
memoryRegionDescriptor.base, dtb, bytesToNumberOfPages(memoryRegionDescriptor.size));
112-
auto mappedRegions = memoryMapping->getMappedRegions().lock();
110+
return;
111+
}
113112

114-
if (mappedRegions->empty())
115-
{
116-
logger->debug("Extracted memory region has size 0, skipping");
117-
}
118-
else
119-
{
120-
if (configuration->isDumpingMemoryActivated())
121-
{
122-
logger->debug("Start dumpVadRegionToFile", {{"Size", memoryMapping->getSizeInGuest()}});
113+
auto memoryMapping = pluginInterface->mapProcessMemoryRegion(
114+
memoryRegionDescriptor.base, dtb, bytesToNumberOfPages(memoryRegionDescriptor.size));
115+
auto mappedRegions = memoryMapping->getMappedRegions();
123116

124-
auto paddedRegion = constructPaddedMemoryRegion(*mappedRegions);
117+
if (mappedRegions.empty())
118+
{
119+
logger->debug("Extracted memory region has size 0, skipping");
120+
return;
121+
}
125122

126-
dumping->dumpMemoryRegion(processName, pid, memoryRegionDescriptor, paddedRegion);
127-
}
123+
if (configuration->isDumpingMemoryActivated())
124+
{
125+
logger->debug("Start dumpVadRegionToFile", {{"Size", memoryRegionDescriptor.size}});
128126

129-
logger->debug("Start scanMemory", {{"Size", memoryMapping->getSizeInGuest()}});
127+
auto paddedRegion = constructPaddedMemoryRegion(mappedRegions);
130128

131-
// The semaphore protects the yara rules from being accessed more than YR_MAX_THREADS (32 atm.) times in
132-
// parallel.
133-
semaphore.wait();
134-
auto results = yaraInterface->scanMemory(*mappedRegions);
135-
semaphore.notify();
129+
dumping->dumpMemoryRegion(processName, pid, memoryRegionDescriptor, paddedRegion);
130+
}
136131

137-
logger->debug("End scanMemory");
132+
logger->debug("Start scanMemory", {{"Size", memoryRegionDescriptor.size}});
138133

139-
if (!results->empty())
140-
{
141-
for (const auto& result : *results)
142-
{
143-
pluginInterface->sendInMemDetectionEvent(result.ruleName);
144-
}
145-
outputXml.addResult(processName, pid, memoryRegionDescriptor.base, *results);
146-
logInMemoryResultToTextFile(processName, pid, memoryRegionDescriptor.base, *results);
147-
}
134+
// The semaphore protects the yara rules from being accessed more than YR_MAX_THREADS (32 atm.) times in
135+
// parallel.
136+
semaphore.wait();
137+
auto results = yaraInterface->scanMemory(memoryRegionDescriptor.base, mappedRegions);
138+
semaphore.notify();
139+
140+
logger->debug("End scanMemory");
141+
142+
if (!results.empty())
143+
{
144+
for (const auto& result : results)
145+
{
146+
pluginInterface->sendInMemDetectionEvent(result.ruleName);
148147
}
148+
outputXml.addResult(processName, pid, memoryRegionDescriptor.base, results);
149+
logInMemoryResultToTextFile(processName, pid, memoryRegionDescriptor.base, results);
149150
}
150151
}
151152

plugins/inmemoryscanner/src/lib/Scanner.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "Semaphore.h"
88
#include <condition_variable>
99
#include <memory>
10+
#include <span>
1011
#include <vmicore/plugins/PluginInterface.h>
1112
#include <yara/limits.h> // NOLINT(modernize-deprecated-headers)
1213

@@ -41,7 +42,7 @@ namespace InMemoryScanner
4142

4243
[[nodiscard]] bool shouldRegionBeScanned(const VmiCore::MemoryRegion& memoryRegionDescriptor);
4344

44-
static std::vector<uint8_t> constructPaddedMemoryRegion(const std::vector<VmiCore::MappedRegion>& regions);
45+
static std::vector<uint8_t> constructPaddedMemoryRegion(std::span<const VmiCore::MappedRegion> regions);
4546

4647
void scanMemoryRegion(pid_t pid,
4748
uint64_t dtb,

plugins/inmemoryscanner/src/lib/YaraInterface.cpp

Lines changed: 53 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,42 @@
11
#include "YaraInterface.h"
2-
#include <fmt/core.h>
2+
#include <format>
33

4+
using VmiCore::addr_t;
45
using VmiCore::MappedRegion;
5-
using BlockIteratorPair = std::pair<std::vector<YR_MEMORY_BLOCK>::iterator, std::vector<YR_MEMORY_BLOCK>::iterator>;
6+
using VmiCore::PagingDefinitions::pageSizeInBytes;
7+
8+
namespace
9+
{
10+
struct YaraIteratorContext
11+
{
12+
std::vector<YR_MEMORY_BLOCK> blocks;
13+
std::size_t index;
14+
};
15+
16+
YR_MEMORY_BLOCK* get_next_block(YR_MEMORY_BLOCK_ITERATOR* iterator)
17+
{
18+
if (auto* iteratorContext = static_cast<YaraIteratorContext*>(iterator->context);
19+
++iteratorContext->index < iteratorContext->blocks.size())
20+
{
21+
return &iteratorContext->blocks[iteratorContext->index];
22+
}
23+
24+
return nullptr;
25+
}
26+
27+
YR_MEMORY_BLOCK* get_first_block(YR_MEMORY_BLOCK_ITERATOR* iterator)
28+
{
29+
auto* iteratorContext = static_cast<YaraIteratorContext*>(iterator->context);
30+
iteratorContext->index = 0;
31+
32+
return &iteratorContext->blocks[iteratorContext->index];
33+
}
34+
35+
const uint8_t* fetch_block_data(YR_MEMORY_BLOCK* block)
36+
{
37+
return static_cast<const uint8_t*>(block->context);
38+
}
39+
}
640

741
namespace InMemoryScanner
842
{
@@ -11,74 +45,52 @@ namespace InMemoryScanner
1145
auto err = yr_initialize();
1246
if (err != ERROR_SUCCESS)
1347
{
14-
throw YaraException("Cannot initialize Yara. Error code: " + std::to_string(err));
48+
throw YaraException(std::format("Cannot initialize Yara. Error code: {}", err));
1549
}
1650

1751
err = yr_rules_load(rulesFile.c_str(), &rules);
1852
if (err != ERROR_SUCCESS)
1953
{
20-
throw YaraException("Cannot load rules. Error code: " + std::to_string(err));
54+
throw YaraException(std::format("Cannot load rules. Error code: {}", err));
2155
}
2256
}
2357

2458
YaraInterface::~YaraInterface()
2559
{
26-
yr_rules_destroy(rules);
27-
yr_finalize();
28-
}
29-
30-
YR_MEMORY_BLOCK* get_next_block(YR_MEMORY_BLOCK_ITERATOR* iterator)
31-
{
32-
auto* blockVectorIterators = reinterpret_cast<BlockIteratorPair*>(iterator->context);
33-
blockVectorIterators->first++;
34-
35-
if (blockVectorIterators->first == blockVectorIterators->second)
60+
if (rules)
3661
{
37-
return nullptr;
62+
yr_rules_destroy(rules);
63+
yr_finalize();
3864
}
39-
40-
return &*blockVectorIterators->first;
41-
}
42-
43-
YR_MEMORY_BLOCK* get_first_block(YR_MEMORY_BLOCK_ITERATOR* iterator)
44-
{
45-
return &*reinterpret_cast<BlockIteratorPair*>(iterator->context)->first;
4665
}
4766

48-
const uint8_t* fetch_block_data(YR_MEMORY_BLOCK* block)
67+
std::vector<Rule> YaraInterface::scanMemory(addr_t regionBase, std::span<const MappedRegion> mappedRegions)
4968
{
50-
return reinterpret_cast<const uint8_t*>(block->context);
51-
}
69+
std::vector<Rule> results;
5270

53-
std::unique_ptr<std::vector<Rule>> YaraInterface::scanMemory(const std::vector<MappedRegion>& mappedRegions)
54-
{
55-
auto results = std::make_unique<std::vector<Rule>>();
56-
57-
std::vector<YR_MEMORY_BLOCK> blocks;
58-
blocks.reserve(mappedRegions.size());
71+
YaraIteratorContext iteratorContext{};
72+
iteratorContext.blocks.reserve(mappedRegions.size());
5973
for (const auto& mappedRegion : mappedRegions)
6074
{
61-
blocks.emplace_back(mappedRegion.mapping.size(),
62-
mappedRegion.guestBaseVA - mappedRegions.front().guestBaseVA,
63-
reinterpret_cast<void*>(mappedRegion.mapping.data()),
64-
&fetch_block_data);
75+
iteratorContext.blocks.emplace_back(mappedRegion.num_pages * pageSizeInBytes,
76+
mappedRegion.guestBaseVA - regionBase,
77+
mappedRegion.mappingBase,
78+
&fetch_block_data);
6579
}
66-
auto blockIterators = std::make_pair(blocks.begin(), blocks.end());
6780
#ifdef LIBYARA_4_1
68-
YR_MEMORY_BLOCK_ITERATOR iterator{.context = &blockIterators,
81+
YR_MEMORY_BLOCK_ITERATOR iterator{.context = &iteratorContext,
6982
.first = &get_first_block,
7083
.next = &get_next_block,
7184
.file_size = nullptr,
7285
.last_error = ERROR_SUCCESS};
7386
#else
7487
YR_MEMORY_BLOCK_ITERATOR iterator{
75-
.context = &blockIterators, .first = &get_first_block, .next = &get_next_block};
88+
.context = &iteratorContext, .first = &get_first_block, .next = &get_next_block};
7689
#endif
7790

78-
auto err = yr_rules_scan_mem_blocks(rules, &iterator, 0, yaraCallback, results.get(), 0);
79-
if (err != ERROR_SUCCESS)
91+
if (auto err = yr_rules_scan_mem_blocks(rules, &iterator, 0, yaraCallback, &results, 0); err != ERROR_SUCCESS)
8092
{
81-
throw YaraException("Error scanning memory. Error code: " + std::to_string(err));
93+
throw YaraException(std::format("Error scanning memory. Error code: {}", err));
8294
}
8395

8496
return results;

plugins/inmemoryscanner/src/lib/YaraInterface.h

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@
22

33
#include "Common.h"
44
#include "IYaraInterface.h"
5-
#include <memory>
65
#include <string>
7-
#include <vector>
86
#include <yara.h>
97

108
namespace InMemoryScanner
@@ -14,9 +12,32 @@ namespace InMemoryScanner
1412
public:
1513
explicit YaraInterface(const std::string& rulesFile);
1614

15+
YaraInterface(const YaraInterface& other) = delete;
16+
17+
YaraInterface(YaraInterface&& other) noexcept : rules(other.rules)
18+
{
19+
other.rules = nullptr;
20+
}
21+
22+
YaraInterface& operator=(const YaraInterface& other) = delete;
23+
24+
YaraInterface& operator=(YaraInterface&& other) noexcept
25+
{
26+
if (this == &other)
27+
{
28+
return *this;
29+
}
30+
31+
rules = other.rules;
32+
other.rules = nullptr;
33+
34+
return *this;
35+
}
36+
1737
~YaraInterface() override;
1838

19-
std::unique_ptr<std::vector<Rule>> scanMemory(const std::vector<VmiCore::MappedRegion>& mappedRegions) override;
39+
std::vector<Rule> scanMemory(VmiCore::addr_t regionBase,
40+
std::span<const VmiCore::MappedRegion> mappedRegions) override;
2041

2142
private:
2243
YR_RULES* rules = nullptr;

plugins/inmemoryscanner/test/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
add_executable(inmemoryscanner-test
22
FakeYaraInterface.cpp
33
Scanner_unittest.cpp
4-
YaraInterface_unitttest.cpp)
4+
YaraInterface_unittest.cpp)
55
target_link_libraries(inmemoryscanner-test inmemoryscanner-obj pthread)
66

77
# Setup bundled google test framework

plugins/inmemoryscanner/test/FakeYaraInterface.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44

55
namespace InMemoryScanner
66
{
7-
std::unique_ptr<std::vector<Rule>>
8-
FakeYaraInterface::scanMemory([[maybe_unused]] const std::vector<VmiCore::MappedRegion>& mappedRegions)
7+
std::vector<Rule>
8+
FakeYaraInterface::scanMemory([[maybe_unused]] VmiCore::addr_t regionBase,
9+
[[maybe_unused]] std::span<const VmiCore::MappedRegion> mappedRegions)
910
{
1011
concurrentThreads++;
1112
if (concurrentThreads > YR_MAX_THREADS)
@@ -14,6 +15,6 @@ namespace InMemoryScanner
1415
}
1516
std::this_thread::sleep_for(std::chrono::seconds(1));
1617
concurrentThreads--;
17-
return std::make_unique<std::vector<Rule>>();
18+
return {};
1819
}
1920
}

0 commit comments

Comments
 (0)