aboutsummaryrefslogtreecommitdiff
path: root/lib/substitute.h
diff options
context:
space:
mode:
Diffstat (limited to 'lib/substitute.h')
-rw-r--r--lib/substitute.h112
1 files changed, 99 insertions, 13 deletions
diff --git a/lib/substitute.h b/lib/substitute.h
index 444c5df..11141bf 100644
--- a/lib/substitute.h
+++ b/lib/substitute.h
@@ -1,7 +1,7 @@
/*
libsubstitute - https://github.com/comex/substitute
- This header file is in the public domain (or in any jusrisdiction where the
- former is ineffective, CC0 1.0).
+ This header file itself is in the public domain (or in any jusrisdiction
+ where the former is ineffective, CC0 1.0).
*/
#pragma once
@@ -13,14 +13,50 @@
extern "C" {
#endif
-/* TODO add numbers */
+/* Error codes */
enum {
+ /* TODO add numbers */
SUBSTITUTE_OK = 0,
+
+ /* substitute_hook_functions: can't patch a function because it's too short-
+ * i.e. there's an unconditional return instruction inside the patch region
+ * (and not at its end) */
+ SUBSTITUTE_ERR_FUNC_TOO_SHORT,
+
+ /* substitute_hook_functions: can't patch a function because one of the
+ * instructions within the patch region is one of a few special problematic
+ * cases - if you get this on real code, the library should probably be
+ * updated to handle that case properly */
+ SUBSTITUTE_ERR_FUNC_BAD_INSN_AT_START,
+
+ /* substitute_hook_functions: can't patch a function because the (somewhat
+ * cursory) jump analysis found a jump later in the function to within the
+ * patch region at the beginning */
+ SUBSTITUTE_ERR_FUNC_JUMPS_TO_START,
+
+ /* mmap or mprotect failure other than ENOMEM (preserved in errno on return
+ * from the substitute_* function). Most likely to come up with
+ * substitute_hook_functions, if the kernel is preventing pages from being
+ * marked executable. */
+ SUBSTITUTE_ERR_VM,
+
+ /* substitute_interpose_imports: couldn't redo relocation for an import
+ * because the type was unknown */
+ SUBSTITUTE_ERR_UNKNOWN_RELOCATION_TYPE,
};
-int substitute_hook_function(void *function, void *replacement, int options, void *result);
+struct substitute_function_hook {
+ void *function;
+ void *replacement;
+ void *old_ptr; /* optional: out pointer to function pointer to call old impl */
+};
+
+/* TODO doc */
+int substitute_hook_functions(const struct substitute_function_hook *hooks,
+ size_t nhooks,
+ int options);
-#if 1 /* declare substitute_find_syms? */
+#if 1 /* declare dynamic linker-related stuff? */
#ifdef __APPLE__
#include <mach-o/nlist.h>
@@ -45,7 +81,7 @@ struct substitute_image {
/* Look up an image currently loaded into the process.
*
* @filename the executable/library path (c.f. dyld(3) on Darwin)
- * @return a handle, or NULL if the image wasn't found
+ * @return a handle, or NULL if the image wasn't found
*/
struct substitute_image *substitute_open_image(const char *filename);
@@ -58,27 +94,77 @@ void substitute_close_image(struct substitute_image *handle);
/* Look up private symbols in an image currently loaded into the process.
*
* @handle handle opened with substitute_open_image
- * @names an array of symbol names to search for
- * @nlist an array of substitute_sym *, one per name; on return, each entry
- * will be a pointer into the symbol table for that image, or NULL if the
- * symbol wasn't found
- * @count number of names
+ * @names an array of symbol names to search for
+ * @syms an array of substitute_sym *, one per name; on return, each entry
+ * will be a pointer into the symbol table for that image, or NULL if
+ * the symbol wasn't found
+ * @nsyms number of names
*
* @return SUBSTITUTE_OK (maybe errors in the future)
*/
int substitute_find_private_syms(struct substitute_image *handle,
const char **names,
substitute_sym **syms,
- size_t count);
+ size_t nsyms);
/* Get a pointer corresponding to a loaded symbol table entry.
* @handle handle containing the symbol
- * @sym symbol
+ * @sym symbol
* @return the pointer - on ARM, this can be | 1 for Thumb, like everything
* else
*/
void *substitute_sym_to_ptr(struct substitute_image *handle, substitute_sym *sym);
+struct substitute_import_hook {
+ /* The symbol name - this is raw, so C++ symbols are mangled, and on OS X
+ * most symbols have '_' prepended. */
+ const char *name;
+ /* The new import address. */
+ void *replacement;
+ /* Optional: out pointer to old value. if there are multiple imports for
+ * the same symbol, only one address is returned (hopefully they are all
+ * equal) */
+ void *old_ptr;
+};
+
+/* Directly modify the GOT/PLT entries from a specified image corresponding to
+ * specified symbols.
+ *
+ * This can be used to 'hook' functions or even exported variables. Compared
+ * to substitute_hook_functions, it has the following advantages:
+ *
+ * - Because it does not require the ability to patch executable code;
+ * accordingly, it can (from a technical rather than policy perspective) be
+ * used in sandboxed environments like iOS or PaX MPROTECT.
+ * - On platforms without RELRO or similar, it is thread safe, as the patches
+ * are done using atomic instructions.
+ * - It does not require architecture specific code.
+ * - It can be used to modify a single library's view of the world without
+ * affecting the rest of the program.
+ *
+ * ...and the following disadvantages:
+ *
+ * - It only works for exported functions, and even then will not catch calls
+ * from a library to its own exported functions.
+ * - At present, it *only* works for a single importing library at a time.
+ * Although it is not difficult on most platforms to iterate loaded libraries
+ * in order to hook all of them, substitute does not currently provide this
+ * functionality, traversing all libraries' symbol tables may be slow, and in
+ * any case there is the matter of new importers being loaded after the fact.
+ *
+ * @handle handle of the importing library
+ * @hooks see struct substitute_import_hook
+ * @nhooks number of hooks
+ * @options options - pass 0.
+ * @return SUBSTITUTE_OK
+ * SUBSTITUTE_ERR_UNKNOWN_RELOCATION_TYPE
+ * SUBSTITUTE_ERR_VM - in the future with RELRO on Linux
+ */
+int substitute_interpose_imports(const struct substitute_image *handle,
+ const struct substitute_import_hook *hooks,
+ size_t nhooks, int options);
+
+
#endif /* 1 */
#ifdef __cplusplus