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
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 */
|