memflow-ffi 0.1.5

C bindings for the memflow physical memory introspection framework
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
#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 ArchitectureObj *X86_32;

extern const ArchitectureObj *X86_32_PAE;

extern const 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.
 */
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.
 */
ConnectorInventory *inventory_scan(void);

/**
 * Create a new inventory with custom path string
 *
 * # Safety
 *
 * `path` must be a valid null terminated string
 */
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(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.
 */
CloneablePhysicalMemoryObj *inventory_create_connector(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.
 */
CloneablePhysicalMemoryObj *connector_clone(const 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(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(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.
 */
PhysicalMemoryObj *downcast_cloneable(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(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(PhysicalMemoryObj *mem, 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(PhysicalMemoryObj *mem, const PhysicalWriteData *data, uintptr_t len);

/**
 * Retrieve metadata about the physical memory object
 */
PhysicalMemoryMetadata phys_metadata(const 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(PhysicalMemoryObj *mem,
                           PhysicalAddress addr,
                           uint8_t *out,
                           uintptr_t len);

/**
 * Read a single 32-bit value from a provided `PhysicalAddress`
 */
uint32_t phys_read_u32(PhysicalMemoryObj *mem, PhysicalAddress addr);

/**
 * Read a single 64-bit value from a provided `PhysicalAddress`
 */
uint64_t phys_read_u64(PhysicalMemoryObj *mem, 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(PhysicalMemoryObj *mem,
                       PhysicalAddress addr,
                       const uint8_t *input,
                       uintptr_t len);

/**
 * Write a single 32-bit value into a provided `PhysicalAddress`
 */
int32_t phys_write_u32(PhysicalMemoryObj *mem, PhysicalAddress addr, uint32_t val);

/**
 * Write a single 64-bit value into a provided `PhysicalAddress`
 */
int32_t phys_write_u64(PhysicalMemoryObj *mem, 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(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(VirtualMemoryObj *mem, 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(VirtualMemoryObj *mem, const 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(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(VirtualMemoryObj *mem, Address addr);

/**
 * Read a single 64-bit value from a provided `Address`
 */
uint64_t virt_read_u64(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(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(VirtualMemoryObj *mem, Address addr, uint32_t val);

/**
 * Write a single 64-bit value into a provided `Address`
 */
int32_t virt_write_u64(VirtualMemoryObj *mem, Address addr, uint64_t val);

uint8_t arch_bits(const ArchitectureObj *arch);

Endianess arch_endianess(const ArchitectureObj *arch);

uintptr_t arch_page_size(const ArchitectureObj *arch);

uintptr_t arch_size_addr(const ArchitectureObj *arch);

uint8_t arch_address_space_bits(const 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(ArchitectureObj *arch);

bool is_x86_arch(const ArchitectureObj *arch);

Address os_process_info_address(const OsProcessInfoObj *obj);

PID os_process_info_pid(const 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 OsProcessInfoObj *obj, char *out, uintptr_t max_len);

const ArchitectureObj *os_process_info_sys_arch(const OsProcessInfoObj *obj);

const ArchitectureObj *os_process_info_proc_arch(const 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(OsProcessInfoObj *obj);

Address os_process_module_address(const OsProcessModuleInfoObj *obj);

Address os_process_module_parent_process(const OsProcessModuleInfoObj *obj);

Address os_process_module_base(const OsProcessModuleInfoObj *obj);

uintptr_t os_process_module_size(const 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 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(OsProcessModuleInfoObj *obj);

#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus

#endif /* MEMFLOW_H */