Skip to content

Commit

Permalink
Add inline documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
Dorian Eikenberg authored and rageagainsthepc committed Dec 13, 2023
1 parent bf7b3ef commit 415c625
Show file tree
Hide file tree
Showing 14 changed files with 203 additions and 2 deletions.
3 changes: 3 additions & 0 deletions vmicore/src/include/vmicore/filename.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ constexpr ::std::string_view filenameStem(const ::std::source_location& sourceLo
return {fileName, lastDotAt(fileName)};
}

/**
* Retrieves the name of the current source file without the extension at compile time.
*/
#define FILENAME_STEM filenameStem(::std::source_location::current())

#endif // VMICORE_FILENAME_H
7 changes: 7 additions & 0 deletions vmicore/src/include/vmicore/io/ILogger.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,19 @@ namespace VmiCore
{
constexpr auto WRITE_TO_FILE_TAG = "writeToFileTag";

/**
* Structured log field. Use this for providing variable context information.
*/
using CxxLogField = std::pair<std::string_view, std::variant<std::string_view, bool, int64_t, uint64_t, double>>;

class ILogger
{
public:
virtual ~ILogger() = default;

/**
* Bind additional default context information. Will be attached to every log call.
*/
virtual void bind(const std::initializer_list<CxxLogField>& fields) = 0;

virtual void debug(std::string_view message) const = 0;
Expand Down
16 changes: 16 additions & 0 deletions vmicore/src/include/vmicore/os/ActiveProcessInformation.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,33 @@

namespace VmiCore
{
/// OS-agnostic representation of a process.
struct ActiveProcessInformation
{
/// The base address of the process struct in the kernel.
uint64_t base;
/// The pointer to the top level paging structure.
uint64_t processDtb;
/// The pointer to the user top level paging structure. Will be the same value as processDtb if either there is
/// no support for kernel page table isolation or it is turned off.
uint64_t processUserDtb;
/// The process ID.
pid_t pid;
/// The Process ID of the parent process. Note that a value of zero could mean that either the parent has got a
/// PID of zero or there is no parent at all.
pid_t parentPid;
/// The name of the process. Possibly truncated to a fixed amount of characters which is usually a restriction
/// of the process struct memory layout.
std::string name;
/// The full name of the process without any length restrictions. Extracted from a location other than the
/// process struct.
std::unique_ptr<std::string> fullName;
/// The file path of the executable this process has been started from, if any.
std::unique_ptr<std::string> processPath;
/// An object that provides on-demand extraction of memory region descriptors. Parses kernel structures used for
/// tracking memory allocations of processes.
std::unique_ptr<IMemoryRegionExtractor> memoryRegionExtractor;
/// Indicates whether the process is a 32bit process or a 64bit process.
bool is32BitProcess;
};
}
Expand Down
3 changes: 3 additions & 0 deletions vmicore/src/include/vmicore/os/IMemoryRegionExtractor.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ namespace VmiCore
public:
virtual ~IMemoryRegionExtractor() = default;

/**
* Provides a representation of all memory regions for a specific process. Does not guarantee any ordering.
*/
[[nodiscard]] virtual std::unique_ptr<std::vector<MemoryRegion>> extractAllMemoryRegions() const = 0;

protected:
Expand Down
10 changes: 10 additions & 0 deletions vmicore/src/include/vmicore/os/IPageProtection.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,20 @@ namespace VmiCore
public:
virtual ~IPageProtection() = default;

/**
* Get an OS-agnostic representation of protection values.
*/
[[nodiscard]] virtual ProtectionValues get() const = 0;

/**
* Get protection values in exactly the same representation as they have been extracted from memory. Not
* OS-agnostic, but may provide more information.
*/
[[nodiscard]] virtual uint64_t getRaw() const = 0;

/**
* Returns a string representation of the protection values.
*/
[[nodiscard]] virtual std::string toString() const = 0;

protected:
Expand Down
18 changes: 18 additions & 0 deletions vmicore/src/include/vmicore/os/MemoryRegion.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,30 @@ namespace VmiCore
{
}

/// The start address of the memory region.
addr_t base;
/// The size of the memory region in bytes.
std::size_t size;
/**
* If the memory region is file-backed, contains the path of the file on disk. If an exception occurred during
* extraction, will contain the special string "unknownFilename". Will be an empty string otherwise.
*
* @note For linux guests, this string might be empty or partially extracted if an error is encountered instead
* of being set to "unknownFilename". This behavior might be adjusted in the future for increased consistency.
*/
std::string moduleName;
/// An object representing the protection values for the memory region. See
/// <a href=./IPageProtection.h>IPageProtection.h</a> for details.
std::unique_ptr<IPageProtection> protection;
/// Indicates whether this memory region can be shared between processes.
bool isSharedMemory;
/// Indicates whether this memory is marked for deletion. Always false for linux guests.
bool isBeingDeleted;
/**
* Indicates whether this memory region represents the executable the process has been initiated from.
*
* @note Currently always false for linux guests.
*/
bool isProcessBaseImage;
};
}
Expand Down
20 changes: 18 additions & 2 deletions vmicore/src/include/vmicore/plugins/IPlugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,37 @@

namespace VmiCore::Plugin
{
// Will be verified by VMICore in order to ensure ABI compatibility.
/**
* Will be verified by VMICore in order to ensure ABI compatibility. Has to be an exact match.
*/
extern const uint8_t API_VERSION;

/**
* An abstract class that has to be implemented by the main plugin class.
*/
class IPlugin
{
public:
virtual ~IPlugin() = default;

// Called right before shutting down the application. Is allowed to throw.
/**
* Called right before shutting down the application. Is allowed to throw.
*/
virtual void unload() = 0;

protected:
IPlugin() = default;
};

/**
* Entry point for plugin initialization. Will be called by the plugin host (VMICore).
*
* @param pluginInterface An object containing all API functions that are exposed to plugins.
* @param config The plugin specific configuration. See <a href=./IPluginConfig.h>IPluginConfig.h</a href> for
* details.
* @param args Commandline arguments passed to this specific plugin. Elements are whitespace separated.
* @return An instance of the plugin. Has to implement the IPlugin interface. Lifetime will be managed by VMICore.
*/
extern std::unique_ptr<IPlugin>
init(PluginInterface* pluginInterface, std::shared_ptr<IPluginConfig> config, std::vector<std::string> args);
}
Expand Down
25 changes: 25 additions & 0 deletions vmicore/src/include/vmicore/plugins/IPluginConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,28 @@

namespace VmiCore::Plugin
{
/**
* Defines methods for retrieving plugin specific configuration options. See the
* <a href=../../../../../plugins/Readme.md>plugin readme</a> for details on how to pass configuration options to a
* plugin.
*/
class IPluginConfig
{
public:
virtual ~IPluginConfig() = default;

/**
* Returns plugin config as a string. Useful if the config should be parsed by the plugin separately.
*/
[[nodiscard]] virtual std::string asString() const = 0;

#ifdef YAML_CPP_SUPPORT
/**
* Retrieve the plugin config as a yaml-cpp node. VMICore and the plugin should have the same yaml-cpp version,
* otherwise the behavior is undefined. Currently, there is no way to verify matching versions at run time.
*
* @return A reference to a yaml node that represents the root of the plugin config.
*/
[[nodiscard]] virtual const YAML::Node& rootNode() const = 0;
#else
// Keep vtable ordinals consistent
Expand All @@ -30,8 +44,19 @@ namespace VmiCore::Plugin
}
#endif

/**
* Returns the path of the main config file used by VMICore.
*/
[[nodiscard]] virtual std::filesystem::path mainConfigFileLocation() const = 0;

/**
* If the plugin has a separate config file instead of an inline config, the path to it can be obtained via
* this function.
*
* @return An optional file path. The key "config_file" has to defined in the VMICore config file for the
* specific plugin. Will return std::nullopt otherwise. If the path is absolute it will be returned as is, if it
* is relative it will be interpreted relative to the location of the main plugin file.
*/
[[nodiscard]] virtual std::optional<std::filesystem::path> configFilePath() const = 0;

protected:
Expand Down
68 changes: 68 additions & 0 deletions vmicore/src/include/vmicore/plugins/PluginInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,42 +16,110 @@

namespace VmiCore::Plugin
{
/**
* Contains all functionality that is exposed to plugins.
*/
class PluginInterface
{
public:
constexpr static uint8_t API_VERSION = 15;

virtual ~PluginInterface() = default;

/**
* Reads a region of contiguous virtual memory from a process. The starting offset as well as the size must be
* 4kb page aligned.
*
* @return A unique pointer to a byte vector containing the memory content. Subregions that could not be
* extracted (e.g. because they are paged out) will be replaced by a single all zero padding page.
*/
[[nodiscard]] virtual std::unique_ptr<std::vector<uint8_t>>
readProcessMemoryRegion(pid_t pid, addr_t address, size_t numberOfBytes) const = 0;

/**
* Obtain a vector containing an OS-agnostic representation of all currently running processes.
* The vector is a snapshot of the current state, it won't receive any updates.
*/
[[nodiscard]] virtual std::unique_ptr<std::vector<std::shared_ptr<const ActiveProcessInformation>>>
getRunningProcesses() const = 0;

/**
* Subscribe to process start events. The supplied lambda function will be called once the event occurs.
*
* @param startCallback It is recommended to create the lambda with the help of VMICORE_SETUP_MEMBER_CALLBACK
* from <a href="file:../callback.h">callback.h</a>
*/
virtual void registerProcessStartEvent(
const std::function<void(std::shared_ptr<const ActiveProcessInformation>)>& startCallback) = 0;

/**
* Subscribe to process termination events. The supplied lambda function will be called once the event occurs.
*
* @param terminationCallback It is recommended to create the lambda with the help of
* VMICORE_SETUP_MEMBER_CALLBACK from <a href="file:../callback.h">callback.h</a>
*/
virtual void registerProcessTerminationEvent(
const std::function<void(std::shared_ptr<const ActiveProcessInformation>)>& terminationCallback) = 0;

/**
* Create a software breakpoint at the given virtual address. The breakpoint will be protected, so that
* it won't be visible to the guest through reading the memory. Multiple breakpoints per address are allowed and
* will not interfere with each other. If the breakpoint is hit, the supplied callback will be called.
*
* @param targetVA Target address to place the breakpoint on.
* @param processInformation The process information for the target process. Can be obtained via
* getRunningProcesses().
* @param callbackFunction It is recommended to create the lambda with the help of VMICORE_SETUP_MEMBER_CALLBACK
* from <a href="file:../callback.h">callback.h</a>
* @return Shared pointer to a breakpoint object. Can be used to delete the breakpoint.
*/
[[nodiscard]] virtual std::shared_ptr<IBreakpoint>
createBreakpoint(uint64_t targetVA,
const ActiveProcessInformation& processInformation,
const std::function<BpResponse(IInterruptEvent&)>& callbackFunction) = 0;

/**
* Retrieves the path to the directory where plugins are supposed to store any files that are generated
* throughout the course of a run. However, it is generally discouraged to store files directly. Instead,
* the writeToFile or the logging APIs should be used.
*/
[[nodiscard]] virtual std::unique_ptr<std::string> getResultsDir() const = 0;

/**
* Creates a new logger with a given name.
*/
[[nodiscard]] virtual std::unique_ptr<ILogger> newNamedLogger(std::string_view name) const = 0;

/**
* Saves content to a file with the given name. Does not append. Saving the same file more than once is
* undefined behavior. Use the other overload for raw data.
*/
virtual void writeToFile(const std::string& filename, const std::string& message) const = 0;

/**
* Saves content to a file with the given name. Does not append. Saving the same file more than once is
* undefined behavior. Use the other overload for strings.
*/
virtual void writeToFile(const std::string& filename, const std::vector<uint8_t>& data) const = 0;

/**
* Only useful if using a gRPC connection, does nothing otherwise. Will send an error event via a separate
* channel which indicates that the run is not successful.
*/
virtual void sendErrorEvent(std::string_view message) const = 0;

/**
* Only useful if using a gRPC connection, does nothing otherwise. Will send an inmemory scanner detection event
* via a gRPC channel.
*/
virtual void sendInMemDetectionEvent(std::string_view message) const = 0;

/**
* Gives access to low level introspection API. Interface is limited to a subset of calls that are deemed
* non-invasive in order to avoid interfering with other plugins. Note that any call made through the
* introspection API object will acquire an API-wide lock because the underlying implementation is not
* considered thread safe.
*/
[[nodiscard]] virtual std::shared_ptr<IIntrospectionAPI> getIntrospectionAPI() const = 0;

protected:
Expand Down
4 changes: 4 additions & 0 deletions vmicore/src/include/vmicore/vmi/BpResponse.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@

namespace VmiCore
{
/// An enum containing possible responses for breakpoint event user callbacks.
enum class BpResponse
{
/// Continue with regular workflow.
Continue,
/// Remove the breakpoint after handling the current event. Similar to calling <tt>breakpoint.remove()</tt>.
/// However, <tt>breakpoint.remove()</tt> should not be used in event callbacks.
Deactivate,
};
}
Expand Down
11 changes: 11 additions & 0 deletions vmicore/src/include/vmicore/vmi/IBreakpoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,24 @@

namespace VmiCore
{
/**
* An abstract handle of a breakpoint that has been inserted into the guest.
*/
class IBreakpoint
{
public:
virtual ~IBreakpoint() = default;

/**
* Retrieve the target gpa the breakpoint has been placed on.
*/
[[nodiscard]] virtual addr_t getTargetPA() const = 0;

/**
* Remove the breakpoint. This will only guarantee that the creator of this breakpoint stops receiving
* callbacks. The actual physical breakpoint might still exist in the guest depending on whether there are
* multiple breakpoint objects subscribed to the same physical breakpoint or just a single one.
*/
virtual void remove() = 0;

protected:
Expand Down
4 changes: 4 additions & 0 deletions vmicore/src/include/vmicore/vmi/IIntrospectionAPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@

namespace VmiCore
{
/**
* A thin, thread-safe wrapper around all low level introspection functionality that is deemed safe to access
* without interfering with VMICore or other plugins.
*/
class IIntrospectionAPI
{
public:
Expand Down
Loading

0 comments on commit 415c625

Please sign in to comment.