You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

521 lines
14 KiB
C

#ifndef MEMFLOW_H
#define MEMFLOW_H
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
/**
* Identifies the byte order of a architecture
*
* This enum is used when reading/writing to/from the memory of a target system.
* The memory will be automatically converted to the endianess memflow is currently running on.
*
* See the [wikipedia article](https://en.wikipedia.org/wiki/Endianness) for more information on the subject.
*/
enum Endianess
#ifdef __cplusplus
: uint8_t
#endif // __cplusplus
{
/**
* Little Endianess
*/
LittleEndian,
/**
* Big Endianess
*/
BigEndian,
};
#ifndef __cplusplus
typedef uint8_t Endianess;
#endif // __cplusplus
typedef struct ArchitectureObj ArchitectureObj;
typedef struct CloneablePhysicalMemoryObj CloneablePhysicalMemoryObj;
/**
* Holds an inventory of available connectors.
*/
typedef struct ConnectorInventory ConnectorInventory;
typedef struct OsProcessInfoObj OsProcessInfoObj;
typedef struct OsProcessModuleInfoObj OsProcessModuleInfoObj;
typedef struct PhysicalMemoryObj PhysicalMemoryObj;
typedef struct PhysicalReadData PhysicalReadData;
typedef struct PhysicalWriteData PhysicalWriteData;
typedef struct VirtualMemoryObj VirtualMemoryObj;
typedef struct VirtualReadData VirtualReadData;
typedef struct VirtualWriteData VirtualWriteData;
/**
* This type represents a address on the target system.
* It internally holds a `u64` value but can also be used
* when working in 32-bit environments.
*
* This type will not handle overflow for 32-bit or 64-bit addresses / lengths.
*/
typedef uint64_t Address;
/**
* A address with the value of zero.
*
* # Examples
*
* ```
* use memflow::types::Address;
*
* println!("address: {}", Address::NULL);
* ```
*/
#define Address_NULL 0
/**
* Describes the type of a page using a bitflag.
*/
typedef uint8_t PageType;
/**
* The page explicitly has no flags.
*/
#define PageType_NONE (uint8_t)0
/**
* The page type is not known.
*/
#define PageType_UNKNOWN (uint8_t)1
/**
* The page contains page table entries.
*/
#define PageType_PAGE_TABLE (uint8_t)2
/**
* The page is a writeable page.
*/
#define PageType_WRITEABLE (uint8_t)4
/**
* The page is read only.
*/
#define PageType_READ_ONLY (uint8_t)8
/**
* The page is not executable.
*/
#define PageType_NOEXEC (uint8_t)16
/**
* This type represents a wrapper over a [address](address/index.html)
* with additional information about the containing page in the physical memory domain.
*
* This type will mostly be used by the [virtual to physical address translation](todo.html).
* When a physical address is translated from a virtual address the additional information
* about the allocated page the virtual address points to can be obtained from this structure.
*
* Most architectures have support multiple page sizes (see [huge pages](todo.html))
* which will be represented by the containing `page` of the `PhysicalAddress` struct.
*/
typedef struct PhysicalAddress {
Address address;
PageType page_type;
uint8_t page_size_log2;
} PhysicalAddress;
typedef struct PhysicalMemoryMetadata {
uintptr_t size;
bool readonly;
} PhysicalMemoryMetadata;
/**
* Type alias for a PID.
*/
typedef uint32_t PID;
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
extern const struct ArchitectureObj *X86_32;
extern const struct ArchitectureObj *X86_32_PAE;
extern const struct ArchitectureObj *X86_64;
void log_init(int32_t level_num);
/**
* Helper to convert `Address` to a `PhysicalAddress`
*
* This will create a `PhysicalAddress` with `UNKNOWN` PageType.
*/
struct PhysicalAddress addr_to_paddr(Address address);
/**
* Create a new connector inventory
*
* This function will try to find connectors using PATH environment variable
*
* Note that all functions go through each directories, and look for a `memflow` directory,
* and search for libraries in those.
*
* # Safety
*
* ConnectorInventory is inherently unsafe, because it loads shared libraries which can not be
* guaranteed to be safe.
*/
struct ConnectorInventory *inventory_scan(void);
/**
* Create a new inventory with custom path string
*
* # Safety
*
* `path` must be a valid null terminated string
*/
struct ConnectorInventory *inventory_scan_path(const char *path);
/**
* Add a directory to an existing inventory
*
* # Safety
*
* `dir` must be a valid null terminated string
*/
int32_t inventory_add_dir(struct ConnectorInventory *inv, const char *dir);
/**
* Create a connector with given arguments
*
* This creates an instance of a `CloneablePhysicalMemory`. To use it for physical memory
* operations, please call `downcast_cloneable` to create a instance of `PhysicalMemory`.
*
* Regardless, this instance needs to be freed using `connector_free`.
*
* # Arguments
*
* * `name` - name of the connector to use
* * `args` - arguments to be passed to the connector upon its creation
*
* # Safety
*
* Both `name`, and `args` must be valid null terminated strings.
*
* Any error strings returned by the connector must not be outputed after the connector gets
* freed, because that operation could cause the underlying shared library to get unloaded.
*/
struct CloneablePhysicalMemoryObj *inventory_create_connector(struct ConnectorInventory *inv,
const char *name,
const char *args);
/**
* Clone a connector
*
* This method is useful when needing to perform multithreaded operations, as a connector is not
* guaranteed to be thread safe. Every single cloned instance also needs to be freed using
* `connector_free`.
*
* # Safety
*
* `conn` has to point to a a valid `CloneablePhysicalMemory` created by one of the provided
* functions.
*/
struct CloneablePhysicalMemoryObj *connector_clone(const struct CloneablePhysicalMemoryObj *conn);
/**
* Free a connector instance
*
* # Safety
*
* `conn` has to point to a valid `CloneablePhysicalMemoryObj` created by one of the provided
* functions.
*
* There has to be no instance of `PhysicalMemory` created from the input `conn`, because they
* will become invalid.
*/
void connector_free(struct CloneablePhysicalMemoryObj *conn);
/**
* Free a connector inventory
*
* # Safety
*
* `inv` must point to a valid `ConnectorInventory` that was created using one of the provided
* functions.
*/
void inventory_free(struct ConnectorInventory *inv);
/**
* Downcast a cloneable physical memory into a physical memory object.
*
* This function will take a `cloneable` and turn it into a `PhysicalMemoryObj`, which then can be
* used by physical memory functions.
*
* Please note that this does not free `cloneable`, and the reference is still valid for further
* operations.
*/
struct PhysicalMemoryObj *downcast_cloneable(struct CloneablePhysicalMemoryObj *cloneable);
/**
* Free a `PhysicalMemoryObj`
*
* This will free a reference to a `PhysicalMemoryObj`. If the physical memory object was created
* using `downcast_cloneable`, this will NOT free the cloneable reference.
*
* # Safety
*
* `mem` must point to a valid `PhysicalMemoryObj` that was created using one of the provided
* functions.
*/
void phys_free(struct PhysicalMemoryObj *mem);
/**
* Read a list of values
*
* This will perform `len` physical memory reads on the provided `data`. Using lists is preferable
* for performance, because then the underlying connectors can batch those operations.
*
* # Safety
*
* `data` must be a valid array of `PhysicalReadData` with the length of at least `len`
*/
int32_t phys_read_raw_list(struct PhysicalMemoryObj *mem,
struct PhysicalReadData *data,
uintptr_t len);
/**
* Write a list of values
*
* This will perform `len` physical memory writes on the provided `data`. Using lists is preferable
* for performance, because then the underlying connectors can batch those operations.
*
* # Safety
*
* `data` must be a valid array of `PhysicalWriteData` with the length of at least `len`
*/
int32_t phys_write_raw_list(struct PhysicalMemoryObj *mem,
const struct PhysicalWriteData *data,
uintptr_t len);
/**
* Retrieve metadata about the physical memory object
*/
struct PhysicalMemoryMetadata phys_metadata(const struct PhysicalMemoryObj *mem);
/**
* Read a single value into `out` from a provided `PhysicalAddress`
*
* # Safety
*
* `out` must be a valid pointer to a data buffer of at least `len` size.
*/
int32_t phys_read_raw_into(struct PhysicalMemoryObj *mem,
struct PhysicalAddress addr,
uint8_t *out,
uintptr_t len);
/**
* Read a single 32-bit value from a provided `PhysicalAddress`
*/
uint32_t phys_read_u32(struct PhysicalMemoryObj *mem, struct PhysicalAddress addr);
/**
* Read a single 64-bit value from a provided `PhysicalAddress`
*/
uint64_t phys_read_u64(struct PhysicalMemoryObj *mem, struct PhysicalAddress addr);
/**
* Write a single value from `input` into a provided `PhysicalAddress`
*
* # Safety
*
* `input` must be a valid pointer to a data buffer of at least `len` size.
*/
int32_t phys_write_raw(struct PhysicalMemoryObj *mem,
struct PhysicalAddress addr,
const uint8_t *input,
uintptr_t len);
/**
* Write a single 32-bit value into a provided `PhysicalAddress`
*/
int32_t phys_write_u32(struct PhysicalMemoryObj *mem, struct PhysicalAddress addr, uint32_t val);
/**
* Write a single 64-bit value into a provided `PhysicalAddress`
*/
int32_t phys_write_u64(struct PhysicalMemoryObj *mem, struct PhysicalAddress addr, uint64_t val);
/**
* Free a virtual memory object reference
*
* This function frees the reference to a virtual memory object.
*
* # Safety
*
* `mem` must be a valid reference to a virtual memory object.
*/
void virt_free(struct VirtualMemoryObj *mem);
/**
* Read a list of values
*
* This will perform `len` virtual memory reads on the provided `data`. Using lists is preferable
* for performance, because then the underlying connectors can batch those operations, and virtual
* translation function can cut down on read operations.
*
* # Safety
*
* `data` must be a valid array of `VirtualReadData` with the length of at least `len`
*/
int32_t virt_read_raw_list(struct VirtualMemoryObj *mem,
struct VirtualReadData *data,
uintptr_t len);
/**
* Write a list of values
*
* This will perform `len` virtual memory writes on the provided `data`. Using lists is preferable
* for performance, because then the underlying connectors can batch those operations, and virtual
* translation function can cut down on read operations.
*
* # Safety
*
* `data` must be a valid array of `VirtualWriteData` with the length of at least `len`
*/
int32_t virt_write_raw_list(struct VirtualMemoryObj *mem,
const struct VirtualWriteData *data,
uintptr_t len);
/**
* Read a single value into `out` from a provided `Address`
*
* # Safety
*
* `out` must be a valid pointer to a data buffer of at least `len` size.
*/
int32_t virt_read_raw_into(struct VirtualMemoryObj *mem, Address addr, uint8_t *out, uintptr_t len);
/**
* Read a single 32-bit value from a provided `Address`
*/
uint32_t virt_read_u32(struct VirtualMemoryObj *mem, Address addr);
/**
* Read a single 64-bit value from a provided `Address`
*/
uint64_t virt_read_u64(struct VirtualMemoryObj *mem, Address addr);
/**
* Write a single value from `input` into a provided `Address`
*
* # Safety
*
* `input` must be a valid pointer to a data buffer of at least `len` size.
*/
int32_t virt_write_raw(struct VirtualMemoryObj *mem,
Address addr,
const uint8_t *input,
uintptr_t len);
/**
* Write a single 32-bit value into a provided `Address`
*/
int32_t virt_write_u32(struct VirtualMemoryObj *mem, Address addr, uint32_t val);
/**
* Write a single 64-bit value into a provided `Address`
*/
int32_t virt_write_u64(struct VirtualMemoryObj *mem, Address addr, uint64_t val);
uint8_t arch_bits(const struct ArchitectureObj *arch);
Endianess arch_endianess(const struct ArchitectureObj *arch);
uintptr_t arch_page_size(const struct ArchitectureObj *arch);
uintptr_t arch_size_addr(const struct ArchitectureObj *arch);
uint8_t arch_address_space_bits(const struct ArchitectureObj *arch);
/**
* Free an architecture reference
*
* # Safety
*
* `arch` must be a valid heap allocated reference created by one of the API's functions.
*/
void arch_free(struct ArchitectureObj *arch);
bool is_x86_arch(const struct ArchitectureObj *arch);
Address os_process_info_address(const struct OsProcessInfoObj *obj);
PID os_process_info_pid(const struct OsProcessInfoObj *obj);
/**
* Retreive name of the process
*
* This will copy at most `max_len` characters (including the null terminator) into `out` of the
* name.
*
* # Safety
*
* `out` must be a buffer with at least `max_len` size
*/
uintptr_t os_process_info_name(const struct OsProcessInfoObj *obj, char *out, uintptr_t max_len);
const struct ArchitectureObj *os_process_info_sys_arch(const struct OsProcessInfoObj *obj);
const struct ArchitectureObj *os_process_info_proc_arch(const struct OsProcessInfoObj *obj);
/**
* Free a OsProcessInfoObj reference
*
* # Safety
*
* `obj` must point to a valid `OsProcessInfoObj`, and was created using one of the API's
* functions.
*/
void os_process_info_free(struct OsProcessInfoObj *obj);
Address os_process_module_address(const struct OsProcessModuleInfoObj *obj);
Address os_process_module_parent_process(const struct OsProcessModuleInfoObj *obj);
Address os_process_module_base(const struct OsProcessModuleInfoObj *obj);
uintptr_t os_process_module_size(const struct OsProcessModuleInfoObj *obj);
/**
* Retreive name of the module
*
* This will copy at most `max_len` characters (including the null terminator) into `out` of the
* name.
*
* # Safety
*
* `out` must be a buffer with at least `max_len` size
*/
uintptr_t os_process_module_name(const struct OsProcessModuleInfoObj *obj,
char *out,
uintptr_t max_len);
/**
* Free a OsProcessModuleInfoObj reference
*
* # Safety
*
* `obj` must point to a valid `OsProcessModuleInfoObj`, and was created using one of the API's
* functions.
*/
void os_process_module_free(struct OsProcessModuleInfoObj *obj);
#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
#endif /* MEMFLOW_H */