Skip to content

Commit

Permalink
WIP: vmi_mmap_guest_2
Browse files Browse the repository at this point in the history
  • Loading branch information
Dorian Eikenberg committed Jan 2, 2024
1 parent dbe6a38 commit e7d4585
Show file tree
Hide file tree
Showing 12 changed files with 73 additions and 93 deletions.
4 changes: 2 additions & 2 deletions plugins/inmemoryscanner/src/lib/Scanner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,14 +119,14 @@ namespace InMemoryScanner
{
if (configuration->isDumpingMemoryActivated())
{
logger->debug("Start dumpVadRegionToFile", {{"Size", memoryMapping->getSizeInGuest()}});
logger->debug("Start dumpVadRegionToFile", {{"Size", memoryRegionDescriptor.size}});

auto paddedRegion = constructPaddedMemoryRegion(*mappedRegions);

dumping->dumpMemoryRegion(processName, pid, memoryRegionDescriptor, paddedRegion);
}

logger->debug("Start scanMemory", {{"Size", memoryMapping->getSizeInGuest()}});
logger->debug("Start scanMemory", {{"Size", memoryRegionDescriptor.size}});

// The semaphore protects the yara rules from being accessed more than YR_MAX_THREADS (32 atm.) times in
// parallel.
Expand Down
9 changes: 7 additions & 2 deletions vmicore/src/include/vmicore/vmi/IMemoryMapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,17 @@

#include "MappedRegion.h"
#include <memory>
#include <stdexcept>
#include <vector>

namespace VmiCore
{
class MemoryMappingError : public std::runtime_error
{
public:
explicit MemoryMappingError(const std::string& message) : runtime_error(message) {}
};

class IMemoryMapping
{
public:
Expand All @@ -22,8 +29,6 @@ namespace VmiCore

virtual std::weak_ptr<std::vector<MappedRegion>> getMappedRegions() = 0;

virtual std::size_t getSizeInGuest() = 0;

virtual void unmap() = 0;

protected:
Expand Down
2 changes: 1 addition & 1 deletion vmicore/src/include/vmicore/vmi/MappedRegion.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#define VMICORE_MAPPEDREGION_H

#include "../types.h"
#include <cstddef>
#include <cstdint>
#include <span>

namespace VmiCore
Expand Down
7 changes: 3 additions & 4 deletions vmicore/src/lib/plugins/PluginSystem.cpp
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
#include "PluginSystem.h"
#include <bit>
#include "../vmi/MemoryMapping.h"
#include <bit>
#include <cstdint>
#include <dlfcn.h>
#include <fmt/core.h>
#include <utility>
#include <vmicore/filename.h>
#include <vmicore/os/PagingDefinitions.h>

namespace VmiCore
{
namespace
{
bool isInstanciated = false;
constexpr char const* paddingLogFile = "memoryExtractionPaddingLog.txt";
}

PluginSystem::PluginSystem(std::shared_ptr<IConfigParser> configInterface,
Expand Down Expand Up @@ -47,7 +45,8 @@ namespace VmiCore
std::unique_ptr<IMemoryMapping>
PluginSystem::mapProcessMemoryRegion(addr_t baseVA, addr_t dtb, std::size_t numberOfPages) const
{
return std::make_unique<MemoryMapping>(baseVA, vmiInterface->mmapGuest(baseVA, dtb, numberOfPages), loggingLib);
return std::make_unique<MemoryMapping>(
loggingLib, vmiInterface, vmiInterface->mmapGuest(baseVA, dtb, numberOfPages));
}

void PluginSystem::registerProcessStartEvent(
Expand Down
16 changes: 11 additions & 5 deletions vmicore/src/lib/vmi/LibvmiInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,19 +183,25 @@ namespace VmiCore
return true;
}

std::vector<void*> LibvmiInterface::mmapGuest(addr_t baseVA, addr_t dtb, std::size_t numberOfPages)
mapped_regions_t LibvmiInterface::mmapGuest(addr_t baseVA, addr_t dtb, std::size_t numberOfPages)
{
auto accessPointers = std::vector<void*>(numberOfPages);
mapped_regions_t regions{};
auto accessContext = createVirtualAddressAccessContext(baseVA, dtb);
std::lock_guard<std::mutex> lock(libvmiLock);
if (vmi_mmap_guest(vmiInstance, &accessContext, numberOfPages, PROT_READ, accessPointers.data()) != VMI_SUCCESS)
std::lock_guard lock(libvmiLock);
if (vmi_mmap_guest_2(vmiInstance, &accessContext, numberOfPages, PROT_READ, &regions) != VMI_SUCCESS)
{
throw VmiException(fmt::format("{}: Unable to create memory mapping for VA {:#x} with number of pages {}",
__func__,
baseVA,
numberOfPages));
}
return accessPointers;
return regions;
}

void LibvmiInterface::freeMappedRegions(const mapped_regions_t& mappedRegions)
{
// TODO: update signature of vmi_free_mapped_regions
vmi_free_mapped_regions(vmiInstance, const_cast<mapped_regions_t*>(&mappedRegions));
}

void LibvmiInterface::write8PA(addr_t physicalAddress, uint8_t value)
Expand Down
9 changes: 7 additions & 2 deletions vmicore/src/lib/vmi/LibvmiInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#define LIBVMI_EXTRA_JSON

#include "libvmi/libvmi_extra.h"
#include <gsl/pointers>
#include <json-c/json.h>

namespace VmiCore
Expand All @@ -33,7 +34,9 @@ namespace VmiCore

virtual void clearEvent(vmi_event_t& event, bool deallocate) = 0;

virtual std::vector<void*> mmapGuest(addr_t baseVA, addr_t dtb, std::size_t numberOfPages) = 0;
virtual mapped_regions_t mmapGuest(addr_t baseVA, addr_t dtb, std::size_t numberOfPages) = 0;

virtual void freeMappedRegions(const mapped_regions_t& mappedRegions) = 0;

virtual void write8PA(addr_t physicalAddress, uint8_t value) = 0;

Expand Down Expand Up @@ -81,7 +84,9 @@ namespace VmiCore
[[nodiscard]] bool
readXVA(addr_t virtualAddress, addr_t cr3, std::vector<uint8_t>& content, std::size_t size) override;

std::vector<void*> mmapGuest(addr_t baseVA, addr_t dtb, std::size_t numberOfPages) override;
mapped_regions_t mmapGuest(addr_t baseVA, addr_t dtb, std::size_t numberOfPages) override;

void freeMappedRegions(const mapped_regions_t& mappedRegions) override;

void write8PA(addr_t physicalAddress, uint8_t value) override;

Expand Down
94 changes: 31 additions & 63 deletions vmicore/src/lib/vmi/MemoryMapping.cpp
Original file line number Diff line number Diff line change
@@ -1,57 +1,19 @@
#include "MemoryMapping.h"
#include <cerrno>
#include <cstring>
#include <sys/mman.h>

#include "vmicore/os/PagingDefinitions.h"

#include <cstdint>
#include <vmicore/filename.h>
#include <vmicore/os/PagingDefinitions.h>

namespace VmiCore
{
MemoryMapping::MemoryMapping(addr_t guestBaseVA,
const std::vector<void*>& accessPointers,
const std::shared_ptr<ILogging>& logging)
: logger(logging->newNamedLogger(FILENAME_STEM)), mappings(std::make_shared<std::vector<MappedRegion>>())
MemoryMapping::MemoryMapping(const std::shared_ptr<ILogging>& logging,
std::shared_ptr<ILibvmiInterface> vmiInterface,
mapped_regions_t mappedRegions)
: logger(logging->newNamedLogger(FILENAME_STEM)),
vmiInterface(std::move(vmiInterface)),
libvmiMappings(mappedRegions)
{
// find coherent regions that are not interrupted by NULL access pointers
std::size_t numPagesInRegion = 0;
void* currentBase = nullptr;

for (std::size_t i = 0; i < accessPointers.size(); i++)
{
auto* accessPointer = accessPointers[i];

if (accessPointer != nullptr)
{
mappingSize += PagingDefinitions::pageSizeInBytes;

// new region starts
if (currentBase == nullptr)
{
currentBase = accessPointer;
}
numPagesInRegion++;
}
// current region ends
else if (currentBase != nullptr)
{
mappings->emplace_back(guestBaseVA + (i - numPagesInRegion) * PagingDefinitions::pageSizeInBytes,
std::span(reinterpret_cast<uint8_t*>(currentBase),
numPagesInRegion * PagingDefinitions::pageSizeInBytes));
numPagesInRegion = 0;
currentBase = nullptr;
}
}

// current region is mapped until the end of the array
if (currentBase != nullptr)
{
mappings->emplace_back(guestBaseVA +
(accessPointers.size() - numPagesInRegion) * PagingDefinitions::pageSizeInBytes,
std::span(reinterpret_cast<uint8_t*>(currentBase),
numPagesInRegion * PagingDefinitions::pageSizeInBytes));
}

sizeInGuest = accessPointers.size() * PagingDefinitions::pageSizeInBytes;
}

MemoryMapping::~MemoryMapping()
Expand All @@ -64,27 +26,33 @@ namespace VmiCore

std::weak_ptr<std::vector<MappedRegion>> MemoryMapping::getMappedRegions()
{
return mappings;
}
if (!isMapped)
{
throw MemoryMappingError("Cannot retrieve mappings for regions that have already been unmapped");
}

size_t MemoryMapping::getSizeInGuest()
{
return sizeInGuest;
if (!mappings)
{
mappings = std::make_shared<std::vector<MappedRegion>>();
mappings->reserve(libvmiMappings.size);

for (std::size_t i = 0; i < libvmiMappings.size; i++)
{
mappings->emplace_back(
libvmiMappings.regions[i].start_va,
std::span(static_cast<uint8_t*>(libvmiMappings.regions[i].access_ptr),
libvmiMappings.regions[i].num_pages * PagingDefinitions::pageSizeInBytes));
}
}

return mappings;
}

void MemoryMapping::unmap()
{
if (!mappings->empty())
if (isMapped)
{
for (auto region : *mappings)
{
if (munmap(region.mapping.data(), region.mapping.size()) != 0)
{
logger->warning("Failed to unmap guest memory",
{{"Pointer", reinterpret_cast<uint64_t>(region.mapping.data())},
{"Error", std::strerror(errno)}}); // NOLINT(concurrency-mt-unsafe)
}
}
vmiInterface->freeMappedRegions(libvmiMappings);

isMapped = false;
}
Expand Down
15 changes: 6 additions & 9 deletions vmicore/src/lib/vmi/MemoryMapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
#define VMICORE_MEMORYMAPPING_H

#include "../io/ILogging.h"
#include <memory>
#include <vector>
#include "LibvmiInterface.h"
#include <vmicore/types.h>
#include <vmicore/vmi/IMemoryMapping.h>

Expand All @@ -12,9 +11,9 @@ namespace VmiCore
class MemoryMapping final : public IMemoryMapping
{
public:
MemoryMapping(addr_t guestBaseVA,
const std::vector<void*>& accessPointers,
const std::shared_ptr<ILogging>& logging);
MemoryMapping(const std::shared_ptr<ILogging>& logging,
std::shared_ptr<ILibvmiInterface> vmiInterface,
mapped_regions_t mappedRegions);

~MemoryMapping() override;

Expand All @@ -28,15 +27,13 @@ namespace VmiCore

std::weak_ptr<std::vector<MappedRegion>> getMappedRegions() override;

size_t getSizeInGuest() override;

void unmap() override;

private:
std::unique_ptr<ILogger> logger;
std::shared_ptr<ILibvmiInterface> vmiInterface;
mapped_regions_t libvmiMappings;
std::shared_ptr<std::vector<MappedRegion>> mappings;
std::size_t sizeInGuest = 0;
std::size_t mappingSize = 0;
bool isMapped = true;
};
} // VmiCore
Expand Down
2 changes: 0 additions & 2 deletions vmicore/test/include/vmicore_test/vmi/mock_MemoryMapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ namespace VmiCore
public:
MOCK_METHOD(std::weak_ptr<std::vector<MappedRegion>>, getMappedRegions, (), (override));

MOCK_METHOD(std::size_t, getSizeInGuest, (), (override));

MOCK_METHOD(void, unmap, (), (override));
};
}
Expand Down
3 changes: 2 additions & 1 deletion vmicore/test/lib/vmi/MemoryMapping_UnitTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
using testing::NiceMock;
using VmiCore::PagingDefinitions::numberOfPageIndexBits;
using VmiCore::PagingDefinitions::pageSizeInBytes;

/*
namespace VmiCore
{
constexpr uint64_t testBaseVA = 0x123 << numberOfPageIndexBits;
Expand Down Expand Up @@ -121,3 +121,4 @@ namespace VmiCore
EXPECT_EQ(*memoryMapping.getMappedRegions().lock(), expectedMappedRegions);
}
}
*/
1 change: 0 additions & 1 deletion vmicore/test/lib/vmi/ProcessesMemoryState.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
#include <plugins/PluginSystem.h>
#include <vmicore/os/PagingDefinitions.h>
#include <vmicore_test/io/mock_Logger.h>
#include <vmicore/os/PagingDefinitions.h>

namespace VmiCore
{
Expand Down
4 changes: 3 additions & 1 deletion vmicore/test/lib/vmi/mock_LibvmiInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ namespace VmiCore

MOCK_METHOD(bool, readXVA, (uint64_t, uint64_t, std::vector<uint8_t>&, std::size_t), (override));

MOCK_METHOD(std::vector<void*>, mmapGuest, (addr_t, addr_t, std::size_t), (override));
MOCK_METHOD(mapped_regions_t, mmapGuest, (addr_t, addr_t, std::size_t), (override));

MOCK_METHOD(void, freeMappedRegions, (const mapped_regions_t&), (override));

MOCK_METHOD(void, write8PA, (uint64_t, uint8_t), (override));

Expand Down

0 comments on commit e7d4585

Please sign in to comment.