Overview
With this API your program can access memory, execute code, pause execution and watch for memory accesses in other programs.
What it looks like
The API is available as a C library. You need to link your
program with libproctal.so and include
proctal.h in your code.
The C library contains functions that operate on a handle that
you create.
proctal_t proctal = proctal_open();
proctal_pid_set(proctal, 12345);
int output = 42;
void *address = proctal_allocate(proctal, sizeof(output));
proctal_write(proctal, address, &output, sizeof(output));
int input;
proctal_read(proctal, address, &input, sizeof(input));
proctal_deallocate(proctal, address);
You may create and use more than one handle to access different
programs, provided that you do not use the same handle in
multiple threads.
Errors are reported through a function dedicated to returning
error codes.
int code = proctal_error(proctal);
You need to destroy the handle when you're done with it.
proctal_close(proctal);
Why use this
While the command line interface is designed as a generic tool for
humans, the C library is meant to be as efficient as possible
for the machine.
If you were to create a script that runs the search command
several times, passing the output of a previous run to the next
one, the tool would have to convert the bits in memory to
readable text characters and then back to bits when they're
piped to the next command which results in a lot of computing
power being wasted in just converting data back and forth. For
a one off program this performance bottleneck can be ignored
but if you are creating your own specialized tool or extending
an existing program, it makes more sense to use the library.
Example
This is a tool built with the library that can make a program print Hello, world!.
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <proctal.h>
int main (int argc, char **argv)
{
if (argc != 2) {
fprintf(stderr, "Usage: %s PID\n", argv[0]);
return 1;
}
int pid = atoi(argv[1]);
if (pid == 0) {
fprintf(stderr, "Given PID is not valid\n");
return 1;
}
const char output[] = "Hello, world!\n";
char code[] = {
// mov rsi, <address>
0x48, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// mov rax, 1
0x48, 0xc7, 0xc0, 0x01, 0x00, 0x00, 0x00,
// mov rdi, 1
0x48, 0xc7, 0xc7, 0x01, 0x00, 0x00, 0x00,
// mov rdx, 14
0x48, 0xc7, 0xc2, 0x0e, 0x00, 0x00, 0x00,
// syscall
0x0f, 0x05
};
proctal_t proctal = proctal_open();
if (proctal_error(proctal)) {
fprintf(stderr, "Failed to open Proctal.\n");
proctal_close(proctal);
return EXIT_FAILURE;
}
proctal_pid_set(proctal, pid);
void *allocated_memory = proctal_allocate(proctal, sizeof output);
if (proctal_error(proctal)) {
fprintf(stderr, "Failed to allocate memory in process %d.\n", proctal_pid(proctal));
proctal_close(proctal);
return EXIT_FAILURE;
}
proctal_write(proctal, allocated_memory, output, sizeof output);
if (proctal_error(proctal)) {
fprintf(stderr, "Failed to write to memory in process %d.\n", proctal_pid(proctal));
proctal_deallocate(proctal, allocated_memory);
proctal_close(proctal);
return EXIT_FAILURE;
}
code[2] = (char) ((uintptr_t) allocated_memory >> 8 * 0 & 0xFF);
code[3] = (char) ((uintptr_t) allocated_memory >> 8 * 1 & 0xFF);
code[4] = (char) ((uintptr_t) allocated_memory >> 8 * 2 & 0xFF);
code[5] = (char) ((uintptr_t) allocated_memory >> 8 * 3 & 0xFF);
code[6] = (char) ((uintptr_t) allocated_memory >> 8 * 4 & 0xFF);
code[7] = (char) ((uintptr_t) allocated_memory >> 8 * 5 & 0xFF);
code[8] = (char) ((uintptr_t) allocated_memory >> 8 * 6 & 0xFF);
code[9] = (char) ((uintptr_t) allocated_memory >> 8 * 7 & 0xFF);
proctal_execute(proctal, code, sizeof code);
if (proctal_error(proctal)) {
fprintf(stderr, "Failed to execute code in process %d.\n", proctal_pid(proctal));
proctal_deallocate(proctal, allocated_memory);
proctal_close(proctal);
return EXIT_FAILURE;
}
proctal_deallocate(proctal, allocated_memory);
proctal_close(proctal);
return EXIT_SUCCESS;
}