Library for injecting a shared library into a Linux, Windows and macOS process.
More...
#include <sys/types.h>
#include <stdarg.h>
#include <stdint.h>
Go to the source code of this file.
|
#define | INJERR_SUCCESS 0 /* linux, windows, macos */ |
|
#define | INJERR_OTHER -1 /* linux, windows, macos */ |
|
#define | INJERR_NO_MEMORY -2 /* linux, windows, macos */ |
|
#define | INJERR_NO_PROCESS -3 /* linux, windows, macos */ |
|
#define | INJERR_NO_LIBRARY -4 /* linux */ |
|
#define | INJERR_NO_FUNCTION -4 /* linux */ |
|
#define | INJERR_ERROR_IN_TARGET -5 /* linux, windows, macos */ |
|
#define | INJERR_FILE_NOT_FOUND -6 /* linux, windows, macos */ |
|
#define | INJERR_INVALID_MEMORY_AREA -7 /* linux, macos */ |
|
#define | INJERR_PERMISSION -8 /* linux, windows, macos */ |
|
#define | INJERR_UNSUPPORTED_TARGET -9 /* linux, windows, macos */ |
|
#define | INJERR_INVALID_ELF_FORMAT -10 /* linux */ |
|
#define | INJERR_WAIT_TRACEE -11 /* linux */ |
|
#define | INJERR_FUNCTION_MISSING -12 /* linux, windows, macos */ |
|
#define | INJECTOR_HAS_REMOTE_CALL_FUNCS 1 |
|
#define | INJECTOR_HAS_INJECT_IN_CLONED_THREAD 1 |
|
|
typedef pid_t | injector_pid_t |
| Platform-dependent process id type (pid_t on Unix. DWORD on Windows)
|
|
typedef struct injector | injector_t |
|
|
int | injector_attach (injector_t **injector, injector_pid_t pid) |
| Attach to the specified process. More...
|
|
int | injector_detach (injector_t *injector) |
| Detach from the attached process and destroy the specified handle. More...
|
|
int | injector_inject (injector_t *injector, const char *path, void **handle) |
| Inject the specified shared library into the target process. More...
|
|
int | injector_uninject (injector_t *injector, void *handle) |
| Uninject the shared library specified by handle . More...
|
|
int | injector_call (injector_t *injector, void *handle, const char *name) |
| Call the specified function taking no arguments in the target process (Linux and macOS only) More...
|
|
const char * | injector_error (void) |
| Get the message of the last error. More...
|
|
int | injector_remote_func_addr (injector_t *injector, void *handle, const char *name, size_t *func_addr_out) |
| Get the function address in the target process (Linux and Windows only) More...
|
|
int | injector_remote_call (injector_t *injector, intptr_t *retval, size_t func_addr,...) |
| Call the function in the target process (Linux and Windows only) More...
|
|
int | injector_remote_vcall (injector_t *injector, intptr_t *retval, size_t func_addr, va_list ap) |
| Call the function in the target process (Linux and Windows only) More...
|
|
int | injector_inject_w (injector_t *injector, const wchar_t *path, void **handle) |
| Same with injector_inject except the type of the path argument. (Windows only) More...
|
|
int | injector_inject_in_cloned_thread (injector_t *injector, const char *path, void **handle) |
| Inject the specified shared library into the target process by the clone system call. (Linux x86_64 only) More...
|
|
Library for injecting a shared library into a Linux, Windows and macOS process.
◆ injector_attach()
Attach to the specified process.
- Parameters
-
[out] | injector | the address where the newly created injector handle will be stored |
[in] | pid | the process id to be attached |
- Returns
- zero on success. Otherwise, error code
◆ injector_call()
int injector_call |
( |
injector_t * |
injector, |
|
|
void * |
handle, |
|
|
const char * |
name |
|
) |
| |
Call the specified function taking no arguments in the target process (Linux and macOS only)
- Parameters
-
[in] | injector | the injector handle specifying the target process |
[in] | handle | the module handle created by injector_inject or special-handles such as RTLD_DEFAULT |
[in] | name | the function name |
The handle
and name
arguments are passed to dlsym
(Linux, macOS) and then the return value of dlsym
is called without arguments in the target process.
This is same with the combination of injector_remote_func_addr() and injector_remote_call() without extra arguments.
- Note
- (Linux only) If the function in the target process internally calls non-async-signal-safe functions, it may stop the target process or cause unexpected behaviour.
- See also
- injector_remote_func_addr(), injector_remote_call(), injector_remote_vcall()
◆ injector_detach()
int injector_detach |
( |
injector_t * |
injector | ) |
|
Detach from the attached process and destroy the specified handle.
- Parameters
-
[in] | injector | the injector handle to destroy |
- Returns
- zero on success. Otherwise, error code
◆ injector_error()
const char* injector_error |
( |
void |
| ) |
|
Get the message of the last error.
◆ injector_inject()
int injector_inject |
( |
injector_t * |
injector, |
|
|
const char * |
path, |
|
|
void ** |
handle |
|
) |
| |
Inject the specified shared library into the target process.
- Parameters
-
[in] | injector | the injector handle specifying the target process |
[in] | path | the path name of the shared library |
[out] | handle | the address where the newly created module handle will be stored |
- Returns
- zero on success. Otherwise, error code
Note on Linux: This calls functions inside of the target process interrupted by ptrace()
. If the target process is interrupted while holding a non-reentrant lock and injector calls a function requiring the same lock, the process stops forever. If the lock type is reentrant, the status guarded by the lock may become inconsistent. As far as I checked, dlopen()
internally calls malloc()
requiring non-reentrant locks. dlopen()
also uses a reentrant lock to guard information about loaded files.
◆ injector_inject_in_cloned_thread()
int injector_inject_in_cloned_thread |
( |
injector_t * |
injector, |
|
|
const char * |
path, |
|
|
void ** |
handle |
|
) |
| |
Inject the specified shared library into the target process by the clone
system call. (Linux x86_64 only)
- Parameters
-
[in] | injector | the injector handle specifying the target process |
[in] | path | the path name of the shared library |
[out] | handle | the address where the newly created module handle will be stored |
- Returns
- zero on success. Otherwise, error code
This calls dlopen()
in a thread created by
clone(). Note that no wonder there are unexpected pitfalls because some resources allocated in
pthread_create() lack in the clone()-ed
thread. Use it at your own risk.
◆ injector_inject_w()
int injector_inject_w |
( |
injector_t * |
injector, |
|
|
const wchar_t * |
path, |
|
|
void ** |
handle |
|
) |
| |
Same with injector_inject
except the type of the path
argument. (Windows only)
- Parameters
-
[in] | injector | the injector handle specifying the target process |
[in] | path | the path name of the shared library |
[out] | handle | the address where the newly created module handle will be stored |
- Returns
- zero on success. Otherwise, error code
◆ injector_remote_call()
int injector_remote_call |
( |
injector_t * |
injector, |
|
|
intptr_t * |
retval, |
|
|
size_t |
func_addr, |
|
|
|
... |
|
) |
| |
Call the function in the target process (Linux and Windows only)
- Parameters
-
[in] | injector | the injector handle specifying the target process |
[out] | retval | NULL or the address where the return value of the function call will be stored |
[in] | func_addr | the function address in the target process |
[in] | ... | arguments passed to the function |
- Returns
- zero on success. Otherwise, error code
- Note
- If the function in the target process internally calls non-async-signal-safe functions, it may stop the target process or cause unexpected behaviour.
- See also
- injector_remote_func_addr(), injector_remote_vcall()
◆ injector_remote_func_addr()
int injector_remote_func_addr |
( |
injector_t * |
injector, |
|
|
void * |
handle, |
|
|
const char * |
name, |
|
|
size_t * |
func_addr_out |
|
) |
| |
Get the function address in the target process (Linux and Windows only)
- Parameters
-
[in] | injector | the injector handle specifying the target process |
[in] | handle | the module handle created by injector_inject or special-handles such as RTLD_DEFAULT |
[in] | name | the function name |
[out] | func_addr_out | the address where the function address in the target process will be stored |
- Returns
- zero on success. Otherwise, error code
Example
Inject libfoo.so and then call foo_func(1, 2, 3) in it.
void *handle;
return;
}
size_t func_addr;
return;
}
intptr_t retval;
return;
}
printf("The return value of foo_func(1, 2, 3) is %ld.\n", retval);
int injector_remote_call(injector_t *injector, intptr_t *retval, size_t func_addr,...)
Call the function in the target process (Linux and Windows only)
int injector_remote_func_addr(injector_t *injector, void *handle, const char *name, size_t *func_addr_out)
Get the function address in the target process (Linux and Windows only)
int injector_inject(injector_t *injector, const char *path, void **handle)
Inject the specified shared library into the target process.
◆ injector_remote_vcall()
int injector_remote_vcall |
( |
injector_t * |
injector, |
|
|
intptr_t * |
retval, |
|
|
size_t |
func_addr, |
|
|
va_list |
ap |
|
) |
| |
Call the function in the target process (Linux and Windows only)
- Parameters
-
[in] | injector | the injector handle specifying the target process |
[out] | retval | NULL or the address where the return value of the function call will be stored |
[in] | func_addr | the function address in the target process |
[in] | ap | arguments passed to the function |
- Returns
- zero on success. Otherwise, error code
- Note
- If the function in the target process internally calls non-async-signal-safe functions, it may stop the target process or cause unexpected behaviour.
- See also
- injector_remote_func_addr(), injector_remote_call()
◆ injector_uninject()
int injector_uninject |
( |
injector_t * |
injector, |
|
|
void * |
handle |
|
) |
| |
Uninject the shared library specified by handle
.
- Parameters
-
[in] | injector | the injector handle specifying the target process |
[in] | handle | the module handle created by injector_inject |
- Returns
- zero on success. Otherwise, error code