Proctal

Documentation

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);