worm is a cross-platform C++20 library that provides several bindings to Windows and POSIX API with intent to simplify interactions with external processes' virtual memory.
It is highly encouraged that you use this library in conjunction with C++20 STL features.
The library is bare-bones and not meant to be extensively used in projects dealing with memory at a low level.
- Simple interface for reading from and writing to external processes' virtual memory
- Compile-time safety - privilege errors are caught compile-time
- Portability - the same feature set is available both for Windows and POSIX-compliant system
- Compliance with STL - the library is built with C++20 features in mind
While using the library, keep in mind that almost all functions in it are potentially throwing (even some constructors).
In most of the examples below, however, there are no try
-catch
blocks in order to reduce visual noise.
Let pid
be the process id of an arbitrary running process.
Prerequisite for each of the examples:
#include <worm.hpp>
Constructing a handle will call OpenProcess
on Windows, or call nothing on POSIX-compliant systems.
worm::ihandle handle(pid);
worm::ohandle handle(pid);
worm::iohandle handle(pid);
Let handle
be an instance of worm::ihandle
, or worm::ohandle
, or worm::iohandle
.
static_assert(decltype(handle)::is_readable::value);
std::vector<worm::memory_region> regions = handle.regions();
Let addr
be the address of an arbitrary virtual memory location of the aforementioned process.
static_assert(decltype(handle)::is_readable::value);
auto const value = handle.read<int>(addr);
unsigned char buf[13];
constexpr std::size_t size = 7;
std::size_t const bytes_read = handle.read_bytes(addr, buf, size);
static_assert(decltype(handle)::is_writable::value);
std::size_t const bytes_written_a = handle.write<unsigned long>(addr, 0xdeadbeef);
unsigned char buf[7]{};
constexpr std::size_t size = 4;
std::size_t const bytes_written_b = handle.write_bytes(addr, buf, size);
A bound value can be one of the following types:
worm::ihandle::bound
- a readable boundworm::ohandle::bound
- a writable boundworm::iohandle::bound
- a readable and writable bound
static_assert(decltype(handle)::is_readable::value);
auto const ibound = handle.bind<int>(addr);
int const value = ibound.read();
static_assert(decltype(handle)::is_writable::value);
auto const obound = handle.bind<int>(addr);
std::size_t const bytes_written = obound.write(1234);
Say we want to find first four addresses that hold (int) 213456
in the first memory region.
static_assert(decltype(handle)::is_readable::value);
constexpr int sought_value = 213456;
auto const available_range = handle.regions().front().range;
// worm::memory_region::range is a contiguous range of addresses
// belonging to the given range, so you have to be careful with
// the bounds in order to read only what you really need. Here,
// we substract the size of readed value in order to not go out
// of bounds of the address space.
decltype(available_range) range{available_range.front(), available_range.back() - sizeof(sought_value)};
// Be careful to capture handles by reference, or else
// they will be recreated, and that might be not what you want.
auto const pred = [&](std::uintptr_t const& address)
{
try
{
return handle.read<std::remove_cv_t<decltype(sought_value)>>(address) == sought_value;
}
catch (std::system_error const&) {} // Suppress errors
return false;
};
for (auto const& address : range | std::views::filter(pred) | std::views::take(4))
{
std::cout << std::hex << address << '\n';
}
If we want to scan the entire available memory, we would define available_range
as follows:
auto const regions = handle.regions();
decltype(worm::memory_region::range) available_range{regions.front().range.front(), regions.back().range.back()};
The following requirements must be met to be able to build the library:
- C++20 support
- CMake 3.26 or newer
See CONTRIBUTING.md for the contribution guidelines.
The library is licensed under the MIT License. A copy of the license is available in the LICENSE file.
A.A.A. (contact at aeverless dot dev)