android清除任务列表
2016-08-23 16:18
465 查看
注意:清除任务列表必须在root权限下进行
要想实现对任务列表的清除,我们要反射函数removeTask来实现。但是只有包含系统签名的文件才能实现对任务列表的清除,所以难点就在怎么突破这种验证。
我的思路:
1.首先找到包含权限"android.permission.GET_TASKS"和"android.permission.REORDER_TASKS"的系统文件。
2.编写反射清除任务列表的代码,并生成apk。
3.ptrace找到的系统进程,并将我们的apk注入到其中。
实现框架:
通过将系统进程作为傀儡进程来突破系统签名验证,
实现过程:
首先找到包含两种权限的系统进程,可以在packages.xml中去找,我找的是com.android.systemui这个文件,其包含两种权限,并且是常驻进程,那就那它开刀了。
先编写注入代码:
下面编写实现加载指定apk的代码:
有了这些操作,下一步就是要编写我们自己的反射代码了,创建一个空项目,如下:
运行我们的代码:
然后查看手机看到:
成功实现了对任务列表的清空。
要想实现对任务列表的清除,我们要反射函数removeTask来实现。但是只有包含系统签名的文件才能实现对任务列表的清除,所以难点就在怎么突破这种验证。
我的思路:
1.首先找到包含权限"android.permission.GET_TASKS"和"android.permission.REORDER_TASKS"的系统文件。
2.编写反射清除任务列表的代码,并生成apk。
3.ptrace找到的系统进程,并将我们的apk注入到其中。
实现框架:
通过将系统进程作为傀儡进程来突破系统签名验证,
实现过程:
首先找到包含两种权限的系统进程,可以在packages.xml中去找,我找的是com.android.systemui这个文件,其包含两种权限,并且是常驻进程,那就那它开刀了。
先编写注入代码:
#include <stdio.h> #include <stdlib.h> #include <sys/ptrace.h> #include <sys/wait.h> #include <sys/mman.h> #include <dlfcn.h> #include <dirent.h> #include <unistd.h> #include <string.h> #include <elf.h> #include <getopt.h> // FIXME(ssx): add #cgo CFLAG in header //#define GOLANG 1 #define CPSR_T_MASK ( 1u << 5 ) #if defined(__amd64__) #include <sys/reg.h> #include <sys/user.h> #include <sys/syscall.h> #define LOGD(fmt, args...) {printf("[D] "); printf(fmt, ##args); } #define LOGI(fmt, args...) {printf("[I] "); printf(fmt, ##args); } #define LOGE(fmt, args...) {printf("[E] "); printf(fmt, ##args); exit(1);} const char *libc_path = "/lib/x86_64-linux-gnu/libc-2.13.so"; const char *linker_path = "/lib/x86_64-linux-gnu/ld-2.13.so"; #elif defined(__i386__) #define pt_regs user_regs_struct #define LOGD(fmt, args...) {printf("[D] "); printf(fmt, ##args); printf("\n");} #define LOGI(fmt, args...) {printf("[I] "); printf(fmt, ##args); printf("\n");} #define LOGE(fmt, args...) {printf("[E] "); printf(fmt, ##args); printf("\n"); exit(1);} const char *libc_path = "/system/lib/libc.so"; const char *linker_path = "/system/bin/linker"; #elif defined(__arm__) #include <android/log.h> #include <asm/user.h> #include <asm/ptrace.h> #define LOG_TAG "INJECT" #define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args) #define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, fmt, ##args) #define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args) const char *libc_path = "/system/lib/libc.so"; const char *linker_path = "/system/bin/linker"; #else #error "Unsupported platform" #endif #define DEBUG_PRINT(format,args...) LOGD(format, ##args) typedef unsigned long ulong; int ptrace_readdata(pid_t pid, const uint8_t *src, uint8_t *buf, size_t size){ uint32_t i, j, remain; uint8_t *laddr; union u { long val; char chars[sizeof(long)]; } d; j = size / sizeof(ulong); remain = size % sizeof(ulong); laddr = buf; for (i = 0; i < j; i ++) { d.val = ptrace(PTRACE_PEEKTEXT, pid, src, 0); memcpy(laddr, d.chars, sizeof(ulong)); src += sizeof(ulong); laddr += sizeof(ulong); } if (remain > 0) { d.val = ptrace(PTRACE_PEEKTEXT, pid, src, 0); memcpy(laddr, d.chars, remain); } return 0; } int ptrace_writedata(pid_t pid, uint8_t *dest, const uint8_t *data, size_t size) { uint32_t i, j, remain; const uint8_t *laddr; union u { long val; char chars[sizeof(long)]; } d; j = size / sizeof(ulong); remain = size % sizeof(ulong); laddr = data; for (i = 0; i < j; i ++) { memcpy(d.chars, laddr, sizeof(ulong)); ptrace(PTRACE_POKETEXT, pid, dest, d.val); dest += sizeof(ulong); laddr += sizeof(ulong); } if (remain > 0) { d.val = ptrace(PTRACE_PEEKTEXT, pid, dest, 0); for (i = 0; i < remain; i ++) { d.chars[i] = *laddr ++; } ptrace(PTRACE_POKETEXT, pid, dest, d.val); } return 0; } #if defined(__arm__) int ptrace_call(pid_t pid, ulong addr, long *params, uint32_t num_params, struct pt_regs* regs) { uint32_t i; for (i = 0; i < num_params && i < 4; i ++) { regs->uregs[i] = params[i]; } // // push remained params onto stack // if (i < num_params) { regs->ARM_sp -= (num_params - i) * sizeof(long); ptrace_writedata(pid, (void *)regs->ARM_sp, (uint8_t *)¶ms[i], (num_params - i) * sizeof(long)); } regs->ARM_pc = addr; if (regs->ARM_pc & 1) { /* thumb */ regs->ARM_pc &= (~1u); regs->ARM_cpsr |= CPSR_T_MASK; } else { /* arm */ regs->ARM_cpsr &= ~CPSR_T_MASK; } regs->ARM_lr = 0; if (ptrace_setregs(pid, regs) == -1 || ptrace_continue(pid) == -1) { printf("error\n"); return -1; } int stat = 0; waitpid(pid, &stat, WUNTRACED); while (stat != 0xb7f) { if (ptrace_continue(pid) == -1) { printf("error\n"); return -1; } waitpid(pid, &stat, WUNTRACED); } return 0; } #elif defined(__i386__) long ptrace_call(pid_t pid, ulong addr, long *params, uint32_t num_params, struct pt_regs * regs) { regs->esp -= (num_params) * sizeof(long) ; ptrace_writedata(pid, (void *)regs->esp, (uint8_t *)params, (num_params) * sizeof(long)); long tmp_addr = 0x00; regs->esp -= sizeof(long); ptrace_writedata(pid, regs->esp, (char *)&tmp_addr, sizeof(tmp_addr)); regs->eip = addr; if (ptrace_setregs(pid, regs) == -1 || ptrace_continue(pid) == -1) { printf("error\n"); return -1; } int stat = 0; waitpid(pid, &stat, WUNTRACED); while (stat != 0xb7f) { // ? if (ptrace_continue(pid) == -1) { printf("error\n"); return -1; } waitpid(pid, &stat, WUNTRACED); } return 0; } #elif defined(__amd64__) long ptrace_call(pid_t pid, ulong addr, long *params, uint32_t num_params, struct pt_regs * regs) { regs->rsp -= num_params * sizeof(long); ptrace_writedata(pid, (void*)regs->rsp, (uint8_t *)params, num_params * sizeof(long)); ulong tmp_addr = 0x00; regs->rsp -= sizeof(ulong); ptrace_writedata(pid, (void*)regs->rsp, (char*)&tmp_addr, sizeof(tmp_addr)); regs->rip = addr; if (ptrace_setregs(pid, regs) == -1 || ptrace_continue( pid) == -1) { printf("error\n"); return -1; } int stat = 0; waitpid(pid, &stat, WUNTRACED); while (stat != 0xb7f) { if (ptrace_continue(pid) == -1) { printf("error\n"); return -1; } waitpid(pid, &stat, WUNTRACED); } return 0; } #else #error "Not supported" #endif int ptrace_getregs(pid_t pid, struct pt_regs * regs){ if (ptrace(PTRACE_GETREGS, pid, NULL, regs) < 0) { perror("ptrace_getregs: Can not get register values"); return -1; } return 0; } int ptrace_setregs(pid_t pid, struct pt_regs * regs){ if (ptrace(PTRACE_SETREGS, pid, NULL, regs) < 0) { perror("ptrace_setregs: Can not set register values"); return -1; } return 0; } int ptrace_continue(pid_t pid){ if (ptrace(PTRACE_CONT, pid, NULL, 0) < 0) { perror("ptrace_cont"); return -1; } return 0; } int ptrace_attach(pid_t pid){ if (ptrace(PTRACE_ATTACH, pid, NULL, 0) < 0) { perror("ptrace_attach"); return -1; } int status = 0; waitpid(pid, &status , WUNTRACED); return 0; } int ptrace_detach(pid_t pid){ if (ptrace(PTRACE_DETACH, pid, NULL, 0) < 0) { perror("ptrace_detach"); return -1; } return 0; } ulong get_module_base(pid_t pid, const char* module_name){ FILE *fp; ulong addr = 0; char *pch; char filename[32]; char line[1024]; if (pid < 0) { /* self process */ snprintf(filename, sizeof(filename), "/proc/self/maps", pid); } else { snprintf(filename, sizeof(filename), "/proc/%d/maps", pid); } fp = fopen(filename, "rb"); if (fp != NULL) { while (fgets(line, sizeof(line), fp)) { if (strstr(line, module_name)) { pch = strtok(line, "-" ); addr = strtoul(pch, NULL, 16); if (addr == 0x8000) addr = 0; break; } } fclose(fp) ; } return addr; } void* get_remote_addr(pid_t target_pid, const char* module_name, ulong local_addr){ ulong local_handle, remote_handle; local_handle = get_module_base(-1, module_name); remote_handle = get_module_base(target_pid, module_name); printf("[+] [%s] get_remote_addr: local[%p], remote[%p]\n", module_name, local_handle, remote_handle); ulong ret_addr = local_addr + remote_handle - local_handle; #if defined(__i386__) if (!strcmp(module_name, libc_path)) { ret_addr += 2; } #endif return (void*)ret_addr; } int find_pid_of(const char *process_name){ int id; pid_t pid = -1; DIR* dir; FILE *fp; char filename[32]; char cmdline[256]; struct dirent * entry; if (process_name == NULL) return -1; dir = opendir("/proc"); if (dir == NULL) return -1; while((entry = readdir(dir)) != NULL) { id = atoi(entry->d_name); if (id != 0) { sprintf(filename, "/proc/%d/cmdline", id); fp = fopen(filename, "r"); if (fp) { fgets(cmdline, sizeof(cmdline), fp); fclose(fp); if (strcmp(process_name, cmdline) == 0) { /* process found */ pid = id; break; } } } } closedir(dir); return pid; } long ptrace_retval(struct pt_regs * regs) { #if defined(__arm__) return regs->ARM_r0; #elif defined(__i386__) return regs->eax; #elif defined(__amd64__) return regs->rax; #else #error "Not supported" #endif } long ptrace_ip(struct pt_regs * regs) { #if defined(__arm__) return regs->ARM_pc; #elif defined(__i386__) return regs->eip; #elif defined(__amd64__) return regs->rip; #else #error "Not supported" #endif } int ptrace_call_wrapper(pid_t target_pid, const char * func_name, void * func_addr, long * parameters, int param_num, struct pt_regs * regs) { printf("[+] Calling %s in target process.\n", func_name); if (ptrace_call(target_pid, (ulong)func_addr, parameters, param_num, regs) == -1) return -1; printf("[+] Over call Start getregs.\n"); if (ptrace_getregs(target_pid, regs) == -1) return -1; printf("[+] Target process returned from %s, return value=%x, pc=%x \n", func_name, ptrace_retval(regs), ptrace_ip(regs)); return 0; } int inject_remote_process(pid_t target_pid, const char *library_path, char *function_name, char *param, size_t param_size) { int ret = -1; void *mmap_addr, *dlopen_addr, *dlsym_addr, *dlclose_addr, *dlerror_addr; void *local_handle, *remote_handle, *dlhandle; uint8_t *map_base = 0; uint8_t *dlopen_param1_ptr, *dlsym_param2_ptr, *saved_r0_pc_ptr, *inject_param_ptr, *remote_code_ptr, *local_code_ptr; struct pt_regs regs, original_regs; extern ulong _dlopen_addr_s, _dlopen_param1_s, _dlopen_param2_s, _dlsym_addr_s, \ _dlsym_param2_s, _dlclose_addr_s, _inject_start_s, _inject_end_s, _inject_function_param_s, \ _saved_cpsr_s, _saved_r0_pc_s; uint32_t code_length; long parameters[10]; printf("[+] Injecting process: %d\n", target_pid); if (ptrace_attach(target_pid) == -1) goto exit; if (ptrace_getregs(target_pid, ®s) == -1) goto exit; /* save original registers */ memcpy(&original_regs, ®s, sizeof(regs)); mmap_addr = get_remote_addr(target_pid, libc_path, (ulong)mmap); printf("[+] Remote mmap address: %x\n", mmap_addr); /* call mmap */ parameters[0] = 0; // addr parameters[1] = 0x4000; // size parameters[2] = PROT_READ | PROT_WRITE | PROT_EXEC; // prot parameters[3] = MAP_ANONYMOUS | MAP_PRIVATE; // flags parameters[4] = 0; //fd parameters[5] = 0; //offset if (ptrace_call_wrapper(target_pid, "mmap", mmap_addr, parameters, 6, ®s) == -1) goto exit; map_base = (uint8_t*)ptrace_retval(®s); dlopen_addr = get_remote_addr(target_pid, linker_path, (ulong)dlopen ); dlsym_addr = get_remote_addr(target_pid, linker_path, (ulong)dlsym ); dlclose_addr = get_remote_addr(target_pid, linker_path, (ulong)dlclose ); dlerror_addr = get_remote_addr(target_pid, linker_path, (ulong)dlerror ); printf("[+] Get imports: \n\tdlopen: %p, \n\tdlsym: %p, \n\tdlclose: %p, \n\tdlerror: %p\n", dlopen_addr, dlsym_addr, dlclose_addr, dlerror_addr); printf("library path = %s\n", library_path); ptrace_writedata(target_pid, map_base, library_path, strlen(library_path) + 1); parameters[0] = (long)map_base; parameters[1] = RTLD_NOW| RTLD_GLOBAL; if (ptrace_call_wrapper(target_pid, "dlopen", dlopen_addr, parameters, 2, ®s) == -1) goto exit; void* sohandle = (void*)ptrace_retval(®s); #define FUNCTION_NAME_ADDR_OFFSET 0x100 ptrace_writedata(target_pid, map_base + FUNCTION_NAME_ADDR_OFFSET, function_name, strlen(function_name) + 1); parameters[0] = (long)sohandle; parameters[1] = (long)(map_base + FUNCTION_NAME_ADDR_OFFSET); if (ptrace_call_wrapper(target_pid, "dlsym", dlsym_addr, parameters, 2, ®s) == -1) goto exit; void* hook_entry_addr = (void*)ptrace_retval(®s); printf("hook_entry_addr = %p\n", hook_entry_addr); #define FUNCTION_PARAM_ADDR_OFFSET 0x200 ptrace_writedata(target_pid, map_base + FUNCTION_PARAM_ADDR_OFFSET, param, strlen(param) + 1); parameters[0] = (long)(map_base + FUNCTION_PARAM_ADDR_OFFSET); if (ptrace_call_wrapper(target_pid, "hook_entry", hook_entry_addr, parameters, 1, ®s) == -1) goto exit; //printf("Press enter to dlclose and detach\n"); //getchar(); parameters[0] = (long)sohandle; if (ptrace_call_wrapper(target_pid, "dlclose", dlclose, parameters, 1, ®s) == -1) goto exit; /* restore */ printf("detach\n"); ptrace_setregs(target_pid, &original_regs); ptrace_detach(target_pid); ret = 0; exit: return ret; } int main( int argc, char** argv ) { int target_pid; char *param = "param"; char* sopath="/data/local/tmp/libpackage.so"; target_pid = find_pid_of("com.android.systemui"); inject_remote_process(target_pid, sopath, "hook_entry", param, strlen(param)); return 0; }这个用的是网上的代码,没什么可讲的,不理解的可以去网上搜搜,讲解很详细。
下面编写实现加载指定apk的代码:
#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <android/log.h> #include <elf.h> #include <fcntl.h> #include <jni.h> #include <dlfcn.h> int invoke_dex_method(const char* dexPath, const char* dexOptDir, const char* className, const char* methodName, int argc, char *argv[]); int hook_entry(char * a){ printf("Hook success, pid = %d\n", getpid()); printf("Hello %s\n", a); int ret = invoke_dex_method("/data/app-release.apk","/data/data/com.android.systemui/cache","com/tencent/qlauncher/home/classtaskjar/HookCallback","dexInject",0,NULL); printf("Hello %d\n",ret); return 0; } JNIEnv* (*getJNIEnv)(); /** * PARAM: * dexPath要注入的apk/jar路径 * dexOptDir 缓存路径,注意需要目标应用进程中可写的目录 * className 执行方法所在类名 * methodName 执行的方法名 * argc 参数之流这里没有使用 * argv 参数之流这里没有使用 */ int invoke_dex_method(const char* dexPath, const char* dexOptDir, const char* className, const char* methodName, int argc, char *argv[]) { printf("Invoke dex Start"); //获取JNIEnv void* handle = dlopen("/system/lib/libandroid_runtime.so", RTLD_NOW); getJNIEnv = dlsym(handle, "_ZN7android14AndroidRuntime9getJNIEnvEv"); JNIEnv* env = getJNIEnv(); //调用ClassLoader中的getSystemClassLoader方法获取当前进程的ClassLoader jclass classloaderClass = (*env)->FindClass(env,"java/lang/ClassLoader"); jmethodID getsysloaderMethod = (*env)->GetStaticMethodID(env,classloaderClass, "getSystemClassLoader", "()Ljava/lang/ClassLoader;"); jobject loader = (*env)->CallStaticObjectMethod(env, classloaderClass, getsysloaderMethod); //以进程现有的ClassLoader、要注入的dex路径为参数构造注入后的DexClassLoader jstring dexpath = (*env)->NewStringUTF(env, dexPath); jstring dex_odex_path = (*env)->NewStringUTF(env,dexOptDir); jclass dexLoaderClass = (*env)->FindClass(env,"dalvik/system/DexClassLoader"); jmethodID initDexLoaderMethod = (*env)->GetMethodID(env, dexLoaderClass, "<init>", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/ClassLoader;)V"); jobject dexLoader = (*env)->NewObject(env, dexLoaderClass, initDexLoaderMethod,dexpath,dex_odex_path,NULL,loader); //获取新出炉的DexClassLoader中findClass方法加载dex中要执行代码所在类 jmethodID findclassMethod = (*env)->GetMethodID(env,dexLoaderClass,"findClass","(Ljava/lang/String;)Ljava/lang/Class;"); jstring javaClassName = (*env)->NewStringUTF(env,className); jclass javaClientClass = (*env)->CallObjectMethod(env,dexLoader,findclassMethod,javaClassName); if (!javaClientClass) { printf("Failed to load target class %s", className); return -1; } //获取注入dex中要执行的方法 jmethodID start_inject_method = (*env)->GetStaticMethodID(env, javaClientClass, methodName, "()V"); if (!start_inject_method) { printf("Failed to load target method %s", methodName); return -1; } //执行之注意目标方法必须是静态公有的 (*env)->CallStaticVoidMethod(env,javaClientClass,start_inject_method); printf("Invoke dex OK"); }这里有一点需要注意:我们在/data/data/com.android.systemui文件夹下是不存在cache这个文件夹的,我们可以新建一个文件夹,需要可写属性,并且要将其用户组改为com.android.systemui相同的,如图:
有了这些操作,下一步就是要编写我们自己的反射代码了,创建一个空项目,如下:
public class HookCallback { public static void dexInject(){ Log.d("clear_task", "this is dex code,welcome to HookTool~"); ActivityManager mActivityManager = null; Method mRemoveTask; try { Class<?> ActivityThread = Class.forName("android.app.ActivityThread"); // Method[] methods = ActivityThread.getMethods(); // for (Method method : methods) { // Log.e("clear_task", method.getName()); // } Method method = ActivityThread.getMethod("currentActivityThread"); Object currentActivityThread = method.invoke(ActivityThread);//获取currentActivityThread 对象 Method method2 = currentActivityThread.getClass().getMethod("getApplication"); Context CONTEXT_INSTANCE =(Context)method2.invoke(currentActivityThread);//获取 Context对象 Log.e("clear_task","CONTEXT_INSTANCE:"+CONTEXT_INSTANCE); Class<?> activityManagerClass = Class.forName("android.app.ActivityManager"); mActivityManager = (ActivityManager) CONTEXT_INSTANCE.getSystemService(Context.ACTIVITY_SERVICE); mRemoveTask = activityManagerClass.getMethod("removeTask", new Class[] { int.class, int.class }); mRemoveTask.setAccessible(true); Log.e("clear_task","dexInject start"); List<ActivityManager.RecentTaskInfo> recents = mActivityManager.getRecentTasks(Integer.MAX_VALUE, ActivityManager.RECENT_IGNORE_UNAVAILABLE); // Start from 1, since we don't want to kill ourselves! for( int i=1; i < recents.size(); i++ ) { Log.e("clear_task","invoke start --------"); mRemoveTask.invoke(mActivityManager, recents.get(i).persistentId, 0 ); Log.e("clear_task","dexInject --------"); } } catch (Exception e) { e.printStackTrace(); } } }然后将它们拷贝到虚拟机中,运行看效果:
运行我们的代码:
然后查看手机看到:
成功实现了对任务列表的清空。
相关文章推荐
- Android应用程序设置让程序不出现在近期任务列表中
- Android 任务和回退堆栈---清除回退堆栈
- Android 单个App显示多个任务列表预览视图
- android 获取进程、服务、任务列表
- Android 之Overview Screen(任务列表)
- 怎么样清除android手机长按home键后,出现的最近运行的6个任务中的指定一个的图标
- 【Android 基础】任务列表上小程序独立显示原理浅析
- Android获取手机最近任务列表
- Android之——获取进程总数、内存、任务列表
- Android:近期任务列表(Recent App)的两个知识点
- 对Android近期任务列表(Recent Applications)的简单分析
- 对Android近期任务列表(Recent Applications)的简单分析
- Android近期任务列表 Recent Applicatoins 分析 + Android PackageManager
- android 获取进程、服务、任务列表
- Android中如何让任务列表不显示我们的应用
- Android 任务和回退堆栈---清除回退堆栈
- 对Android近期任务列表(Recent Applications)的简单分析
- 怎么获得android的近期任务列表?
- Android 之Overview Screen(任务列表)
- 对Android近期任务列表(Recent Applications)的简单分析