#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <dlfcn.h>
#include <string.h>
#include "libsyscall_intercept_hook_point.h"
#include "intercept.h"
struct lib_data {
Dl_info info;
unsigned char *mock_trampoline_table;
size_t mock_trampoline_table_size;
const unsigned char *text_start;
const unsigned char *text_end;
unsigned char *asm_wrapper_start;
unsigned char *asm_wrapper_end;
size_t text_size;
};
static void *
xdlsym(void *lib, const char *name, const char *path)
{
void *symbol = dlsym(lib, name);
if (symbol == NULL) {
fprintf(stderr,
"\"%s\" not found in %s: %s\n",
name, path, dlerror());
exit(EXIT_FAILURE);
}
return symbol;
}
static struct lib_data
load_test_lib(const char *path)
{
struct lib_data data;
void *lib = dlopen(path, RTLD_LAZY);
if (lib == NULL) {
fprintf(stderr, "error loading \"%s\": %s\n",
path, dlerror());
exit(EXIT_FAILURE);
}
data.mock_trampoline_table = xdlsym(lib, "trampoline_table", path);
if ((!dladdr(data.mock_trampoline_table, &data.info)) ||
(data.info.dli_fname == NULL) ||
(data.info.dli_fbase == NULL)) {
fprintf(stderr,
"error querying dlinfo for %s: %s\n",
path, dlerror());
exit(EXIT_FAILURE);
}
unsigned char *end = xdlsym(lib, "trampoline_table_end", path);
if (end <= data.mock_trampoline_table) {
fprintf(stderr,
"trampoline_table_end invalid in %s: \"%s\"\n",
path, dlerror());
exit(EXIT_FAILURE);
}
data.mock_trampoline_table_size = end - data.mock_trampoline_table;
data.text_start = xdlsym(lib, "text_start", path);
data.text_end = xdlsym(lib, "text_end", path);
if (data.text_start >= data.text_end) {
fprintf(stderr, "text_start <= text_end in %s\n", path);
exit(EXIT_FAILURE);
}
data.text_size = data.text_end - data.text_start;
data.asm_wrapper_start = dlsym(lib, "asm_wrapper_start");
data.asm_wrapper_end = dlsym(lib, "asm_wrapper_end");
return data;
}
static void
print_hex_diff(const unsigned char *a, const unsigned char *b, size_t size)
{
fputs("result vs. expected:\n", stderr);
size_t offset = 0;
while (offset < size) {
fprintf(stderr,
"0x%04zx: 0x%02hhx 0x%02hhx%s\n", offset, *a, *b,
(*a == *b) ? "" : " <-");
++offset;
++a;
++b;
}
exit(EXIT_FAILURE);
}
int
main(int argc, char **argv)
{
if (argc < 3)
return EXIT_FAILURE;
debug_dumps_on = getenv("INTERCEPT_DEBUG_DUMP") != NULL;
struct lib_data lib_in = load_test_lib(argv[1]);
struct lib_data lib_out = load_test_lib(argv[2]);
if (lib_in.text_size != lib_out.text_size) {
fprintf(stderr,
"text_size mismatch for %s(%zu) and %s(%zu)\n",
argv[1], lib_in.text_size, argv[2], lib_out.text_size);
exit(EXIT_FAILURE);
}
struct intercept_desc patches;
static unsigned char builtin_wrapper_space[0x10000];
unsigned char *asm_wrapper_address = builtin_wrapper_space;
init_patcher();
patches.base_addr = lib_in.info.dli_fbase;
patches.path = lib_in.info.dli_fname;
patches.uses_trampoline_table = true;
patches.trampoline_table = lib_in.mock_trampoline_table;
patches.trampoline_table_size = lib_in.mock_trampoline_table_size;
patches.next_trampoline = patches.trampoline_table;
find_syscalls(&patches);
create_patch_wrappers(&patches, &asm_wrapper_address);
mprotect_asm_wrappers();
activate_patches(&patches);
int exit_code = EXIT_SUCCESS;
if (memcmp(lib_in.text_start, lib_out.text_start,
lib_in.text_size) != 0) {
fputs("Invalid patch\n", stderr);
print_hex_diff(lib_in.text_start, lib_out.text_start,
lib_in.text_size);
exit_code = EXIT_FAILURE;
}
if (lib_out.asm_wrapper_start != NULL &&
memcmp(builtin_wrapper_space, lib_out.asm_wrapper_start,
lib_out.asm_wrapper_end - lib_out.asm_wrapper_start) != 0) {
fputs("Invalid asm wrapper\n", stderr);
print_hex_diff(builtin_wrapper_space,
lib_out.asm_wrapper_start,
lib_out.asm_wrapper_end - lib_out.asm_wrapper_start);
exit_code = EXIT_FAILURE;
}
return exit_code;
}
int
syscall_hook_in_process_allowed(void)
{
return 0;
}