Scanning memory
There are 2 ways that you can scan over the contents in memory.
Scanning over values
This method allows you to iterate over all addresses in memory
that could be dereferenced to a value of a specified size.
Before you can start iterating, you will want to specify the
size of the contents at the addresses. You do that by calling
proctal_scan_address_size_set.
Here's how you would specify iterating over addresses that
could hold a value of the size of an int:
proctal_scan_address_size_set(proctal, sizeof(int));
Something that you may be aware of is that on x86 ints should
be at a memory address which is some multiple of 4. Proctal
also lets you specify alignment restrictions with a call to
proctal_scan_address_align_set.
This is how you would specify iterating over addresses aligned
where ints must be:
proctal_scan_address_align_set(proctal, alignof(int));
You can also specify at which memory regions the iterator
should go through. You can set that with a call to
proctal_scan_address_region_set.
Here's how you would tell Proctal to only iterate over
addresses in the heap and the stack:
proctal_scan_address_region_set(proctal, PROCTAL_REGION_HEAP | PROCTAL_REGION_STACK);
The following macros are defined to identify regions:
PROCTAL_REGION_STACK
PROCTAL_REGION_HEAP
PROCTAL_REGION_PROGRAM_CODE
You can also specify whether you want to iterate over readable,
writable or executable memory addresses. For that you can call
proctal_scan_address_read_set,
proctal_scan_address_write_set and
proctal_scan_address_execute_set, respectively.
Here's how you would only iterate over readable addresses:
proctal_scan_address_execute_set(proctal, 0);
proctal_scan_address_write_set(proctal, 0);
proctal_scan_address_read_set(proctal, 1);
Those are all the options. To begin iterating you must call proctal_scan_address_start.
proctal_scan_address_start(proctal);
Check the Error handling
page to learn how to deal with an error.
And now each call to proctal_scan_address_next
will return you the current address and move on to the next
one.
void *address;
while (proctal_scan_address_next(proctal, &address)) {}
As you can see, proctal_scan_address_next
expects you to pass a pointer where it can store the address.
The return value is used to indicate success or failure.
When the return value is 1, it means that the function has
provided you with an address. When it returns 0 it can mean two
things. Either the function has iterated over all addresses or
it has hit an error.
void *address;
while (proctal_scan_address_next(proctal, &address)) {
// Use address.
}
// Check if the loop finished because of an error.
if (proctal_error(proctal)) {
// Error handling.
}
When you're done using the iterator, you have to call proctal_scan_address_stop.
proctal_scan_address_stop(proctal);
This method is the simplest and easiest to use but comes at a performance penalty. It can get really slow to iterate over gigabytes of data. The next method works on a lower level with fewer function calls that is much faster but not as easy to use.
Scanning over regions
This method iterates over regions of memory. Programs have
their memory organized by regions. You may have regions for
program code, heap, libraries, stack and so on.
Before you start iterating you can specify what type of regions
are iterated over by calling
proctal_scan_region_mask_set.
Here's how you tell Proctal to iterate over stack memory regions:
proctal_scan_region_mask_set(proctal, PROCTAL_REGION_STACK);
You can also specify whether you want to iterate over readable,
writable or executable memory addresses. For that you can call
proctal_scan_region_read_set,
proctal_scan_region_write_set and
proctal_scan_region_execute_set, respectively.
Here's how you would only iterate over readable addresses:
proctal_scan_region_execute_set(proctal, 0);
proctal_scan_region_write_set(proctal, 0);
proctal_scan_region_read_set(proctal, 1);
Those are all the options. To begin iterating you must call proctal_scan_region_start.
proctal_scan_region_start(proctal);
Check the Error handling
page to learn how to deal with an error.
And now each call to proctal_scan_region_next
will return you the starting and ending address of the current
region and move on to the next one.
void *start;
void *end;
while (proctal_scan_region_next(proctal, &start, &end)) {}
As you can see, proctal_scan_region_next expects
you to pass pointers where it can store the start and end
addresses. The return value is used to indicate success or
failure.
When the return value is 1, it means that the function has
provided you with addresses. When it returns 0 it can mean two
things. Either the function has iterated over all regions or it
has hit an error.
void *start;
void *end;
while (proctal_scan_region_next(proctal, &start, &end)) {
// Use address.
}
// Check if the loop finished because of an error.
if (proctal_error(proctal)) {
// Error handling.
}
When you're done using the iterator, you have to call proctal_scan_region_stop.
proctal_scan_region_stop(proctal);