Simple C/C++ library for signature scanning on Linux.
This library is for matching byte patterns (signatures) in the memory of a
process. It’s able to scan the memory of the current process, or an external
process using the process_vm_readv
function.
It only supports linux, since it parses the /proc/PID/maps
file to get the start
and end addresses of the loaded modules.
The library asumes all signatures are in IDA (DE AD ? EF
) or x64Dbg
(DE AD ?? EF
) format. See also the sigmaker plugin.
For more information on signature scanning and on how this library works, check out my Signature scanning in C blog entry.
To try the example, simply clone the repository, compile it, and run
libsigscan-test.out
. Please see src/main.c and the Usage section for an example
on how to use it.
$ git clone https://github.com/8dcc/libsigscan
$ cd libsigscan
$ make
$ ./libsigscan-test.out
If you want to try the external example, run the following two commands in separate terminals after compiling.
$ ./libsigscan-test-external.out # Simulates target process, keep it open
$ sudo ./libsigscan-test.out # Scans the other process, needs root
If you want to use this library, simply copy the detour source and headers to
your project, #include
the header in your source files and compile the
libsigscan.c
source with the rest of your code.
For a full example, see src/main.c. For more information on how to compile it, see the Makefile.
The library is pretty simple and consists of one main function for signature scanning, and some wrappers for it. There are also some utilities that may be used independently. All the functions are documented in the header, but I will explain them here as well.
This utility function can be used to get the PID of a process by name.
#include "libsigscan.h"
int pid = sigscan_pidof("my-test.out");
This is the main function of the library. It scans all the modules loaded by the
process with the specified pid
, whose name matches the specified regex
.
It uses POSIX Extended Regular Expression (ERE) syntax, so keep that in mind
before escaping certain characters like +
, ?
, etc. See also BRE vs. ERE.
Also note that it skips modules starting with [
in /proc/PID/maps
, like heap,
stack, etc.
#include "libsigscan.h"
#define MODULE_REGEX ".+/libc\\.so\\.6"
#define SIGNATURE "DE AD BE EF ? ? CA FE"
/*
* Search for a signature in the modules loaded by "my-test.out" whose name
* matches the regex.
*/
int pid = sigscan_pidof("my-test.out");
void* match = sigscan_pid_module(pid, MODULE_REGEX, SIGNATURE);
These functions are just wrappers for sigscan_pid_module
.
The sigscan_pid
function can be used to search for a pattern in all modules
loaded by the process with the specified PID. Same as using NULL
as the second
parameter of sigscan_pid_module
.
The sigscan_module
function can be used to search for a pattern in the modules
loaded by the current process, whose name matches a regex. Same as using
SIGSCAN_PID_SELF
as the first parameter of sigscan_pid_module
.
The sigscan
function can be used to search for a pattern in all modules loaded
by the current process. Same as using SIGSCAN_PID_SELF
and NULL
as the first and
second parameters of sigscan_pid_module
.
These functions are used internally by the library when calling
sigscan_pid_module
. They are exposed, so the user can call them whenever
necessary.
The sigscan_get_module_bounds
function parses the /proc/PID/maps
file (see
proc(5)) to get the start and end addresses of the modules loaded by the process
with the specified PID, whose name matches the specified regex. Similarly to
sigscan_pid_module
, it accepts SIGSCAN_PID_SELF
as its first parameter, and NULL
as its second parameter.
It returns a linked list of SigscanModuleBounds
structures, and each element
contains the start and end addresses of a readable memory chunk. The caller is
responsible for freeing this linked list by calling sigscan_free_module_bounds
.
If you are having any unexpected problems with this library (e.g. it’s not able
to find a signature that you know to be there), try compiling the libsigscan.c
source with LIBSIGSCAN_DEBUG
defined. You can easily do this by adding the
following compilation option to your CFLAGS
.
-CFLAGS=-std=gnu99 -Wall -Wextra -Wpedantic
+CFLAGS=-std=gnu99 -Wall -Wextra -Wpedantic -DLIBSIGSCAN_DEBUG
Now the library will print some useful information to stderr
. For example:
my-user-program: Searching in all modules matching regex "^.*module\.o$"... libsigscan: Couldn't get any module bounds matching regex "^.*module\.o$" in /proc/364195/maps
In that example, you might want to look at the output of cat /proc/self/maps
and
see if, for example, the module.o
line ends with (deleted)
. In that case, you
should remove the $
from the regex.
If any other unexpected errors occur, please report them with as much information as possible.