├── .gitignore ├── CMakeLists.txt ├── Hook ├── CMakeLists.txt ├── hook.cpp └── include │ └── Logger.h ├── Inject ├── CMakeLists.txt ├── include │ ├── PtraceInject.h │ └── Utils │ │ ├── PtraceUtils.h │ │ └── Utils.h └── inject.cpp ├── LICENSE ├── README.md ├── build.sh ├── clean.sh ├── outputs ├── arm64-v8a │ └── libHook.so ├── armeabi-v7a │ └── libHook.so ├── x86 │ ├── Inject │ └── libHook.so └── x86_64 │ ├── Inject │ └── libHook.so └── res ├── log_Android11_arm32_succeed.txt ├── log_Android11_arm64_failed.txt ├── log_Android11_arm64_fixed_succeed.txt ├── log_Android11_x86_succeed.txt ├── log_Android9_arm32_failed.txt └── log_Android9_arm64_succeed.txt /.gitignore: -------------------------------------------------------------------------------- 1 | # CMake 2 | build/ 3 | .idea/ 4 | .vscode/ 5 | .DS_Store 6 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.2.2) # 最低CMake版本要求 2 | 3 | ##################### ⬇Android设置⬇ ##################### 4 | set(CMAKE_SYSTEM_NAME ANDROID) # 设置目标编译平台参数 Android 5 | set(CMAKE_SYSTEM_VERSION 28) # 系统版本 6 | set(ANDROID_PLATFORM 28) # 平台版本 7 | set(ANDROID_ABI arm64-v8a) # 设置目标构架 armeabi-v7a arm64-v8a x86 x86_64 8 | ## 9 | ## 由于ANDROID_ABI一次编译只能设置一种架构 10 | ## 因此该参数在build.sh脚本中单独设置 并且每种架构编译一次 11 | ## 12 | set(ANDROID_NDK /Users/hongqing/Library/Android/sdk/ndk/ollvm) # 设置ndk路径 13 | set(CMAKE_TOOLCHAIN_FILE /Users/hongqing/Library/Android/sdk/ndk/ollvm/build/cmake/android.toolchain.cmake) # 设置交叉编译链的cmake配置 14 | ##################### ⬆Android设置⬆ ##################### 15 | 16 | project(NativeSurface VERSION 0.1.0) # 工程名称 + 版本 17 | 18 | ##################### ⬇项目相关参数设置⬇ ##################### 19 | set(CMAKE_CXX_STANDARD 17) # c++ 标准 20 | set(CMAKE_CXX_FLAGS "-fno-rtti -fno-exceptions -DNDEBUG -fvisibility=hidden -Wno-narrowing -fdeclspec -pthread -w -s -fexceptions -Wall -O3" 21 | ) # 参数 22 | ##################### ⬆项目相关参数设置⬆ ##################### 23 | 24 | ##################### ⬇子模块设置⬇ ##################### 25 | add_subdirectory(Inject) 26 | add_subdirectory(Hook) 27 | ##################### ⬆子模块设置⬆ ##################### -------------------------------------------------------------------------------- /Hook/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | ##################### ⬇输出文件重定向⬇ ##################### 3 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY 4 | /${CMAKE_SOURCE_DIR}/outputs/${CMAKE_ANDROID_ARCH_ABI}/ 5 | ) # 重定向输出产物(动态库) 6 | ##################### ⬆输出文件重定向⬆ ##################### 7 | 8 | 9 | ##################### ⬇CMake头文件设置⬇ ##################### 10 | FILE(GLOB_RECURSE FILE_INCLUDES # 遍历子目录下所有符合情况的头文件 11 | ${CMAKE_CURRENT_SOURCE_DIR}/*.h* 12 | ) 13 | include_directories( # 设置全局头文件目录 使其他源码文件可在任意目录<头文件.h> 14 | ${CMAKE_CURRENT_SOURCE_DIR}/include/ 15 | ) 16 | ##################### ⬆CMake头文件设置⬆ ##################### 17 | 18 | 19 | ##################### ⬇CMake源文件设置⬇ ##################### 20 | FILE(GLOB_RECURSE FILE_SOURCES # 遍历子目录下所有符合情况的源文件 21 | ${CMAKE_CURRENT_SOURCE_DIR}/*.c* 22 | ) 23 | ##################### ⬆CMake源文件设置⬆ ##################### 24 | 25 | 26 | ##################### ⬇添加产物⬇ ##################### 27 | add_library(Hook SHARED # 生成动态库 28 | ${FILE_INCLUDES} # 头文件 29 | ${FILE_SOURCES} # 源文件 30 | ) 31 | ##################### ⬆添加产物 ⬆ ##################### 32 | 33 | ##################### ⬇连接库文件⬇ ##################### 34 | target_link_libraries(Hook PRIVATE 35 | log 36 | ) 37 | ##################### ⬆连接库文件⬆ ##################### -------------------------------------------------------------------------------- /Hook/hook.cpp: -------------------------------------------------------------------------------- 1 | // system lib 2 | #include 3 | 4 | // user lib 5 | #include 6 | 7 | extern "C"{ 8 | // 如果功能需要被dlsym调用出来,那么传入的应该是函数的symbpls 9 | // 因此 如果编译选项开启了-fvisibility=hidden 10 | // 那么就需要用__attribute__((visibility ("default")))修饰被调用的功能 以确保功能可以被外部调用 11 | // 同时用extern "C"保证以c风格编译(c风格编译,symbols是函数名本身) 12 | // 而不是c++风格编译(c++风格编译后,symbaps为__ZXXX_XX格式) 13 | // 或者自行ida查看symbols 14 | __attribute__((visibility ("default"))) void hello(){ 15 | LOGD("This fun comed from libHook.so::hello ~~"); 16 | } 17 | } 18 | 19 | // 先atmain函数执行的 最高执行权重函数 20 | __unused __attribute__((constructor)) void constructor_main(){ 21 | LOGD("Inject Ok"); 22 | 23 | int pid = getpid(); 24 | 25 | LOGD("Hello I'am from libHook.so ~~ from pid:%d", pid); 26 | 27 | LOGD("Inject Finished"); 28 | } 29 | 30 | // 主函数 31 | int main(){ // nothing to do 32 | return 0; 33 | } -------------------------------------------------------------------------------- /Hook/include/Logger.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // 日志 4 | #define LOG_TAG "SSAGEHOOK" 5 | #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) 6 | #define LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__) 7 | #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) 8 | #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) 9 | -------------------------------------------------------------------------------- /Inject/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | ##################### ⬇输出文件重定向⬇ ##################### 3 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY 4 | /${CMAKE_SOURCE_DIR}/outputs/${CMAKE_ANDROID_ARCH_ABI}/ 5 | ) # 重定向输出产物(可执行文件) 6 | ##################### ⬆输出文件重定向⬆ ##################### 7 | 8 | 9 | ##################### ⬇CMake头文件设置⬇ ##################### 10 | FILE(GLOB_RECURSE FILE_INCLUDES # 遍历子目录下所有符合情况的头文件 11 | ${CMAKE_CURRENT_SOURCE_DIR}/*.h* 12 | ) 13 | include_directories( # 设置全局头文件目录 使其他源码文件可在任意目录<头文件.h> 14 | ${CMAKE_CURRENT_SOURCE_DIR}/include/ 15 | ${CMAKE_CURRENT_SOURCE_DIR}/include/Utils/ 16 | ) 17 | ##################### ⬆CMake头文件设置⬆ ##################### 18 | 19 | 20 | ##################### ⬇CMake源文件设置⬇ ##################### 21 | FILE(GLOB_RECURSE FILE_SOURCES # 遍历子目录下所有符合情况的源文件 22 | ${CMAKE_CURRENT_SOURCE_DIR}/*.c* 23 | ) 24 | ##################### ⬆CMake源文件设置⬆ ##################### 25 | 26 | 27 | ##################### ⬇添加产物⬇ ##################### 28 | add_executable(Inject # 生成动态库 29 | ${FILE_INCLUDES} # 头文件 30 | ${FILE_SOURCES} # 源文件 31 | ) 32 | ##################### ⬆添加产物 ⬆ ##################### -------------------------------------------------------------------------------- /Inject/include/PtraceInject.h: -------------------------------------------------------------------------------- 1 | // system lib 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | // user lib 16 | #include 17 | 18 | // TODO: 更优雅的处理SELinux问题 19 | // TODO: 适配armeabi-v7a和x86_64 20 | 21 | /** 22 | * @brief 通过远程直接调用dlopen/dlsym的方法ptrace注入so模块到远程进程中 23 | * 24 | * @param pid pid表示远程进程的ID 25 | * @param LibPath LibPath为被远程注入的so模块路径 26 | * @param FunctionName FunctionName为远程注入的模块后调用的函数 27 | * @param parameter FuncParameter指向被远程调用函数的参数(若传递字符串,需要先将字符串写入到远程进程空间中) 28 | * @param NumParameter NumParameter为参数的个数 29 | * @return int 返回0表示注入成功,返回-1表示失败 30 | */ 31 | int inject_remote_process(pid_t pid, char *LibPath, char *FunctionName, char *FlagSELinux){ 32 | int iRet = -1; 33 | long parameters[6]; 34 | // attach到目标进程 35 | if (ptrace_attach(pid) != 0){ 36 | return iRet; 37 | } 38 | 39 | /** 40 | * @brief 开始主要步骤 41 | */ 42 | do{ 43 | // CurrentRegs 当前寄存器 44 | // OriginalRegs 保存注入前寄存器 45 | struct pt_regs CurrentRegs, OriginalRegs; 46 | if (ptrace_getregs(pid, &CurrentRegs) != 0){ 47 | break; 48 | } 49 | // 保存原始寄存器 50 | memcpy(&OriginalRegs, &CurrentRegs, sizeof(CurrentRegs)); 51 | 52 | // 获取mmap函数在远程进程中的地址 以便为libxxx.so分配内存 53 | // 由于mmap函数在libc.so库中 为了将libxxx.so加载到目标进程中 就需要使用目标进程的mmap函数 所以需要查找到libc.so库在目标进程的起始地址 54 | void *mmap_addr = get_mmap_address(pid); 55 | printf("[+] mmap RemoteFuncAddr:0x%lx\n", (uintptr_t)mmap_addr); 56 | 57 | // mmap映射 <-- 设置mmap的参数 58 | // void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offsize); 59 | parameters[0] = 0; // 设置为NULL表示让系统自动选择分配内存的地址 60 | parameters[1] = 0x3000; // 映射内存的大小 61 | parameters[2] = PROT_READ | PROT_WRITE | PROT_EXEC; // 表示映射内存区域 可读|可写|可执行 62 | parameters[3] = MAP_ANONYMOUS | MAP_PRIVATE; // 建立匿名映射 63 | parameters[4] = 0; // 若需要映射文件到内存中,则为文件的fd 64 | parameters[5] = 0; //文件映射偏移量 65 | 66 | // 调用远程进程的mmap函数 建立远程进程的内存映射 在目标进程中为libxxx.so分配内存 67 | if (ptrace_call(pid, (uintptr_t)mmap_addr, parameters, 6, &CurrentRegs) == -1){ 68 | printf("[-] Call Remote mmap Func Failed, err:%s\n", strerror(errno)); 69 | break; 70 | } 71 | 72 | // 打印一下 73 | printf("[+] ptrace_call mmap success, return value=%lX, pc=%lX\n", ptrace_getret(&CurrentRegs), ptrace_getpc(&CurrentRegs)); 74 | 75 | // 获取mmap函数执行后的返回值,也就是内存映射的起始地址 76 | // 从寄存器中获取mmap函数的返回值 即申请的内存首地址 77 | void *RemoteMapMemoryAddr = (void *)ptrace_getret(&CurrentRegs); 78 | printf("[+] Remote Process Map Memory Addr:0x%lx\n", (uintptr_t)RemoteMapMemoryAddr); 79 | 80 | // 分别获取dlopen、dlsym、dlclose等函数的地址 81 | void *dlopen_addr, *dlsym_addr, *dlclose_addr, *dlerror_addr; 82 | dlopen_addr = get_dlopen_address(pid); 83 | dlsym_addr = get_dlsym_address(pid); 84 | dlclose_addr = get_dlclose_address(pid); 85 | dlerror_addr = get_dlerror_address(pid); 86 | 87 | // 打印一下 88 | printf("[+] Get imports: dlopen: %x, dlsym: %x, dlclose: %x, dlerror: %x\n", dlopen_addr, dlsym_addr, dlclose_addr, dlerror_addr); 89 | 90 | // 打印注入so的路径 91 | printf("[+] LibPath = %s\n", LibPath); 92 | 93 | // 将要加载的so库路径写入到远程进程内存空间中 94 | /** 95 | * pid 开始写入数据的地址 写入内容 写入数据大小 96 | */ 97 | if (ptrace_writedata(pid, (uint8_t *) RemoteMapMemoryAddr, (uint8_t *) LibPath,strlen(LibPath) + 1) == -1) { 98 | printf("[-] Write LibPath:%s to RemoteProcess error\n", LibPath); 99 | break; 100 | } 101 | 102 | // 设置dlopen的参数,返回值为模块加载的地址 103 | // void *dlopen(const char *filename, int flag); 104 | parameters[0] = (uintptr_t) RemoteMapMemoryAddr; // 写入的libPath 105 | parameters[1] = RTLD_NOW | RTLD_GLOBAL; // dlopen的标识 106 | 107 | // 执行dlopen 载入so 108 | if (ptrace_call(pid, (uintptr_t) dlopen_addr, parameters, 2, &CurrentRegs) == -1) { 109 | printf("[+] Call Remote dlopen Func Failed\n"); 110 | break; 111 | } 112 | 113 | // RemoteModuleAddr为远程进程加载注入模块的地址 114 | void *RemoteModuleAddr = (void *) ptrace_getret(&CurrentRegs); 115 | printf("[+] ptrace_call dlopen success, Remote Process load module Addr:0x%lx\n",(long) RemoteModuleAddr); 116 | 117 | // dlopen 错误 118 | if ((long) RemoteModuleAddr == 0x0){ 119 | printf("[-] dlopen error\n"); 120 | if (ptrace_call(pid, (uintptr_t) dlerror_addr, parameters, 0, &CurrentRegs) == -1) { 121 | printf("[-] Call Remote dlerror Func Failed\n"); 122 | break; 123 | } 124 | char *Error = (char *) ptrace_getret(&CurrentRegs); 125 | char LocalErrorInfo[1024] = {0}; 126 | ptrace_readdata(pid, (uint8_t *) Error, (uint8_t *) LocalErrorInfo, 1024); 127 | printf("[-] dlopen error:%s\n", LocalErrorInfo); 128 | break; 129 | } 130 | 131 | // 判断是否传入symbols 132 | if (strcmp(FunctionName,"symbols") != 0){ 133 | printf("[+] func symbols is %s\n", FunctionName); 134 | // 传入了函数的symbols 135 | printf("[+] Have func !!\n"); 136 | // 将so库中需要调用的函数名称写入到远程进程内存空间中 137 | if (ptrace_writedata(pid, (uint8_t *) RemoteMapMemoryAddr + strlen(LibPath) + 2,(uint8_t *) FunctionName, strlen(FunctionName) + 1) == -1) { 138 | printf("[-] Write FunctionName:%s to RemoteProcess error\n", FunctionName); 139 | break; 140 | } 141 | 142 | // 设置dlsym的参数,返回值为远程进程内函数的地址 调用XXX功能 143 | // void *dlsym(void *handle, const char *symbol); 144 | parameters[0] = (uintptr_t) RemoteModuleAddr; 145 | parameters[1] = (uintptr_t) ((uint8_t *) RemoteMapMemoryAddr + strlen(LibPath) + 2); 146 | //调用dlsym 147 | if (ptrace_call(pid, (uintptr_t) dlsym_addr, parameters, 2, &CurrentRegs) == -1) { 148 | printf("[-] Call Remote dlsym Func Failed\n"); 149 | break; 150 | } 151 | 152 | // RemoteModuleFuncAddr为远程进程空间内获取的函数地址 153 | void *RemoteModuleFuncAddr = (void *) ptrace_getret(&CurrentRegs); 154 | printf("[+] ptrace_call dlsym success, Remote Process ModuleFunc Addr:0x%lx\n",(uintptr_t) RemoteModuleFuncAddr); 155 | 156 | // 调用远程进程到某功能 不支持参数传递 !! 157 | if (ptrace_call(pid, (uintptr_t) RemoteModuleFuncAddr, parameters, 0,&CurrentRegs) == -1) { 158 | printf("[-] Call Remote injected Func Failed\n"); 159 | break; 160 | } 161 | } else { 162 | // 没有传入函数的symbols 163 | printf("[+] No func !!\n"); 164 | } 165 | 166 | if (ptrace_setregs(pid, &OriginalRegs) == -1) { 167 | printf("[-] Recover reges failed\n"); 168 | break; 169 | } 170 | 171 | printf("[+] Recover Regs Success\n"); 172 | 173 | ptrace_getregs(pid, &CurrentRegs); 174 | if (memcmp(&OriginalRegs, &CurrentRegs, sizeof(CurrentRegs)) != 0) { 175 | printf("[-] Set Regs Error\n"); 176 | } 177 | iRet = 0; 178 | } while (false); 179 | 180 | // 解除attach 181 | ptrace_detach(pid); 182 | 183 | // 如果原SELinux状态为严格 则恢复状态 184 | if (strcmp(FlagSELinux,"Enforcing") == 0){ 185 | if (set_selinux_state(1)){ 186 | printf("[+] SELinux has been rec\n"); 187 | } 188 | } 189 | 190 | return iRet; 191 | } 192 | 193 | // so注入所需要的一些核心数据 组成一个数据结构 194 | struct process_inject{ 195 | pid_t pid; 196 | char lib_path[1024]; 197 | char func_symbols[1024]; 198 | char orig_selinux[1024]; 199 | } process_inject = {0, "", "symbols","Permissive"}; 200 | 201 | /** 202 | * @brief 参数处理 203 | * -p 目标进程pid 204 | * -n 目标App包名 205 | * -f 是否开启App 206 | * -so 注入的so路径 207 | * -func 指定启用so中的某功能 208 | * 209 | * @param argc 210 | * @param argv 211 | */ 212 | void handle_parameter(int argc, char *argv[]){ 213 | pid_t pid = 0; 214 | int index = 0; 215 | char *pkg_name = NULL; 216 | char *lib_path = NULL; 217 | char *func_symbols = NULL; 218 | bool start_app_flag = false; 219 | 220 | while (index < argc){ // 循环判断参数 221 | 222 | if (strcmp("-f", argv[index]) == 0){ // 是否强制开启App 223 | start_app_flag = true; // 强制开启App 224 | } 225 | 226 | if (strcmp("-p", argv[index]) == 0){ // 判断是否传入pid参数 227 | if (index + 1 >= argc){ 228 | printf("[-] Missing parameter -p\n"); 229 | exit(-1); 230 | } 231 | index++; 232 | pid = atoi(argv[index]); // pid 233 | } 234 | 235 | if (strcmp("-n", argv[index]) == 0){ // 判断是否传入App包名 236 | if (index + 1 >= argc){ 237 | printf("[-] Missing parameter -n\n"); 238 | exit(-1); 239 | } 240 | index++; 241 | pkg_name = argv[index]; // 包名 242 | 243 | if (start_app_flag){ // 如果强制开启App参数开启 244 | start_app(pkg_name); // 启动App 245 | sleep(1); 246 | } 247 | } 248 | 249 | if (strcmp("-so", argv[index]) == 0){ // 判断是否传入so路径 250 | if (index + 1 >= argc){ 251 | printf("[-] Missing parameter -so\n"); 252 | exit(-1); 253 | } 254 | index++; 255 | lib_path = argv[index]; // so路径 256 | } 257 | 258 | if (strcmp("-symbols", argv[index]) == 0){ // 判断是否传入so路径 259 | if (index + 1 >= argc){ 260 | printf("[-] Missing parameter -func\n"); 261 | exit(-1); 262 | } 263 | index++; 264 | func_symbols = argv[index]; // so中的某功能 265 | } 266 | 267 | index++; 268 | } 269 | 270 | // 开始参数处理 271 | 272 | // 如果有包名 则通过包名获取pid 273 | if (pkg_name != NULL){ 274 | printf("[+] pkg_name is %s\n", pkg_name); 275 | if (get_pid_by_name(&pid, pkg_name)){ 276 | printf("[+] get_pid_by_name pid is %d\n", pid); 277 | } 278 | } 279 | 280 | // 处理pid 281 | if (pid == 0){ 282 | printf("[-] not found target & get_pid_by_name pid faild !\n"); 283 | exit(0); 284 | } else { 285 | process_inject.pid = pid; // pid传给inject数据结构 286 | } 287 | 288 | // 处理so路径 289 | if (lib_path != NULL){ // 如果有so路径 290 | printf("[+] lib_path is %s\n", lib_path); 291 | strcpy(process_inject.lib_path, strdup(lib_path)); // 传递so路径到inject数据结构 292 | } 293 | 294 | // 处理功能名称 295 | if (func_symbols != NULL){ // 如果有功能名称 296 | printf("[+] symbols is %s\n", func_symbols); 297 | strcpy(process_inject.func_symbols,strdup(func_symbols)); // 传递功能名称到inject数据结构 298 | } 299 | } 300 | 301 | /** 302 | * @brief 初始化Inject 303 | * 304 | * @param argc 305 | * @param argv 306 | * @return int 307 | */ 308 | int init_inject(int argc, char *argv[]){ 309 | 310 | // 参数处理 311 | handle_parameter(argc, argv); 312 | 313 | printf("[+] handle_parameter is OK\n"); 314 | 315 | // SELinux处理 316 | if (process_selinux.enforce == 1){ // 为严格模式 317 | printf("[-] SELinux is Enforcing\n"); 318 | strcpy(process_inject.orig_selinux, strdup("Enforcing")); 319 | if (set_selinux_state(0)){ 320 | printf("[+] Selinux has been changed to Permissive\n"); 321 | } 322 | } else { // 已经为宽容模式 或者 关闭状态 323 | printf("[+] SELinux is Permissive or Disabled\n"); 324 | strcpy(process_inject.orig_selinux, strdup("Permissive"));// 设置flag 325 | } 326 | 327 | return inject_remote_process(process_inject.pid, process_inject.lib_path, process_inject.func_symbols, process_inject.orig_selinux); 328 | } -------------------------------------------------------------------------------- /Inject/include/Utils/PtraceUtils.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 让Ptrace注入兼容多平台的主要步骤在这里 3 | */ 4 | 5 | // system lib 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | // user lib 21 | #include 22 | 23 | // 各构架预定义 24 | #if defined(__aarch64__) // 真机64位 25 | #define pt_regs user_pt_regs 26 | #define uregs regs 27 | #define ARM_pc pc 28 | #define ARM_sp sp 29 | #define ARM_cpsr pstate 30 | #define ARM_lr regs[30] 31 | #define ARM_r0 regs[0] 32 | // 这两个宏定义比较有意思 意思就是在 arm64下 33 | // 强制 PTRACE_GETREGS 为 PTRACE_GETREGSET 这种 34 | #define PTRACE_GETREGS PTRACE_GETREGSET 35 | #define PTRACE_SETREGS PTRACE_SETREGSET 36 | #elif defined(__x86_64__) // ??未知架构 37 | #define pt_regs user_regs_struct 38 | #define eax rax 39 | #define esp rsp 40 | #define eip rip 41 | #elif defined(__i386__) // 模拟器 42 | #define pt_regs user_regs_struct 43 | #endif 44 | 45 | // 其余预定义 46 | #define CPSR_T_MASK (1u << 5) 47 | 48 | /** ============== 分界线 ============== 49 | */ 50 | 51 | /** 52 | * @brief 使用ptrace Attach附加到指定进程,发送SIGSTOP信号给指定进程让其停止下来并对其进行跟踪。 53 | * 但是被跟踪进程(tracee)不一定会停下来,因为同时attach和传递SIGSTOP可能会将SIGSTOP丢失。 54 | * 所以需要waitpid(2)等待被跟踪进程被停下 55 | * 56 | * @param pid pid表示远程进程的ID 57 | * @return int 返回0表示attach成功,返回-1表示失败 58 | */ 59 | int ptrace_attach(pid_t pid){ 60 | int status = 0; 61 | if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0){ 62 | printf("[-] ptrace attach process error, pid:%d, err:%s\n", pid, strerror(errno)); 63 | return -1; 64 | } 65 | 66 | printf("[+] attach porcess success, pid:%d\n", pid); 67 | waitpid(pid, &status, WUNTRACED); 68 | 69 | return 0; 70 | } 71 | 72 | /** 73 | * @brief ptrace使远程进程继续运行 74 | * 75 | * @param pid pid表示远程进程的ID 76 | * @return int 返回0表示continue成功,返回-1表示失败 77 | */ 78 | int ptrace_continue(pid_t pid){ 79 | if (ptrace(PTRACE_CONT, pid, NULL, NULL) < 0){ 80 | printf("[-] ptrace continue process error, pid:%d, err:%ss\n", pid, strerror(errno)); 81 | return -1; 82 | } 83 | 84 | printf("[+] ptrace continue process success, pid:%d\n", pid); 85 | return 0; 86 | } 87 | 88 | /** 89 | * @brief 使用ptrace detach指定进程,完成对指定进程的跟踪操作后,使用该参数即可解除附加 90 | * 91 | * @param pid pid表示远程进程的ID 92 | * @return int 返回0表示detach成功,返回-1表示失败 93 | */ 94 | int ptrace_detach(pid_t pid){ 95 | if (ptrace(PTRACE_DETACH, pid, NULL, 0) < 0){ 96 | printf("[-] detach process error, pid:%d, err:%s\n", pid, strerror(errno)); 97 | return -1; 98 | } 99 | 100 | printf("[+] detach process success, pid:%d\n", pid); 101 | return 0; 102 | } 103 | 104 | /** 105 | * @brief 使用ptrace获取远程进程的寄存器值 106 | * 107 | * @param pid pid表示远程进程的ID 108 | * @param regs regs为pt_regs结构,存储了寄存器值 109 | * @return int 返回0表示获取寄存器成功,返回-1表示失败 110 | */ 111 | int ptrace_getregs(pid_t pid, struct pt_regs *regs){ 112 | #if defined(__aarch64__) 113 | int regset = NT_PRSTATUS; 114 | struct iovec ioVec; 115 | 116 | ioVec.iov_base = regs; 117 | ioVec.iov_len = sizeof(*regs); 118 | if (ptrace(PTRACE_GETREGSET, pid, (void *)regset, &ioVec) < 0){ 119 | printf("[-] ptrace_getregs: Can not get register values, io %llx, %d\n", ioVec.iov_base,ioVec.iov_len); 120 | return -1; 121 | } 122 | 123 | return 0; 124 | #else 125 | if (ptrace(PTRACE_GETREGS, pid, NULL, regs) < 0){ 126 | printf("[-] Get Regs error, pid:%d, err:%s\n", pid, strerror(errno)); 127 | return -1; 128 | } 129 | #endif 130 | return 0; 131 | } 132 | 133 | /** 134 | * @brief 使用ptrace设置远程进程的寄存器值 135 | * 136 | * @param pid pid表示远程进程的ID 137 | * @param regs regs为pt_regs结构 存储需要修改的寄存器值 138 | * @return int 返回0表示设置寄存器成功 返回-1表示失败 139 | */ 140 | int ptrace_setregs(pid_t pid, struct pt_regs *regs){ 141 | #if defined(__aarch64__) 142 | int regset = NT_PRSTATUS; 143 | struct iovec ioVec; 144 | 145 | ioVec.iov_base = regs; 146 | ioVec.iov_len = sizeof(*regs); 147 | if (ptrace(PTRACE_SETREGSET, pid, (void *)regset, &ioVec) < 0){ 148 | perror("[-] ptrace_setregs: Can not get register values"); 149 | return -1; 150 | } 151 | 152 | return 0; 153 | #else 154 | if (ptrace(PTRACE_SETREGS, pid, NULL, regs) < 0){ 155 | printf("[-] Set Regs error, pid:%d, err:%s\n", pid, strerror(errno)); 156 | return -1; 157 | } 158 | #endif 159 | return 0; 160 | } 161 | 162 | /** 163 | * @brief 获取返回值,ARM处理器中返回值存放在ARM_r0寄存器中 164 | * @param regs regs存储远程进程当前的寄存器值 165 | * @return 在ARM处理器下返回r0寄存器值 166 | */ 167 | long ptrace_getret(struct pt_regs *regs) { 168 | #if defined(__i386__) || defined(__x86_64__) // 模拟器&x86_64 169 | return regs->eax; 170 | #elif defined(__arm__) || defined(__aarch64__) // 真机 171 | return regs->ARM_r0; 172 | #else 173 | printf("Not supported Environment %s\n", __FUNCTION__); 174 | #endif 175 | } 176 | 177 | /** 178 | * @brief 获取当前执行代码的地址 ARM处理器下存放在ARM_pc中 179 | * @param regs regs存储远程进程当前的寄存器值 180 | * @return 在ARM处理器下返回pc寄存器值 181 | */ 182 | long ptrace_getpc(struct pt_regs *regs) { 183 | #if defined(__i386__) || defined(__x86_64__) 184 | return regs->eip; 185 | #elif defined(__arm__) || defined(__aarch64__) 186 | return regs->ARM_pc; 187 | #else 188 | printf("Not supported Environment %s\n", __FUNCTION__); 189 | #endif 190 | } 191 | 192 | /** 193 | * @brief 获取mmap函数在远程进程中的地址 194 | * 195 | * @param pid pid表示远程进程的ID 196 | * @return void* mmap函数在远程进程中的地址 197 | */ 198 | void *get_mmap_address(pid_t pid){ 199 | return get_remote_func_addr(pid, process_libs.libc_path, (void *)mmap); 200 | } 201 | 202 | /** 203 | * @brief 获取dlopen函数在远程进程中的地址 204 | * @param pid pid表示远程进程的ID 205 | * @return void* dlopen函数在远程进程中的地址 206 | */ 207 | void *get_dlopen_address(pid_t pid) { 208 | void *dlopen_addr; 209 | char sdk_ver[32]; 210 | memset(sdk_ver, 0, sizeof(sdk_ver)); 211 | __system_property_get("ro.build.version.sdk", sdk_ver); 212 | 213 | printf("[+] linker_path value:%s\n",process_libs.linker_path); 214 | if (atoi(sdk_ver) <= 23) { // 安卓7 215 | dlopen_addr = get_remote_func_addr(pid, process_libs.linker_path, (void *) dlopen); 216 | } else { 217 | dlopen_addr = get_remote_func_addr(pid, process_libs.libdl_path, (void *) dlopen); 218 | } 219 | printf("[+] dlopen RemoteFuncAddr:0x%lx\n", (uintptr_t) dlopen_addr); 220 | return dlopen_addr; 221 | } 222 | 223 | /** 224 | * @brief 获取dlclose函数在远程进程中的地址 225 | * @param pid pid表示远程进程的ID 226 | * @return void* dlclose函数在远程进程中的地址 227 | */ 228 | void *get_dlclose_address(pid_t pid) { 229 | void *dlclose_addr; 230 | char sdk_ver[32]; 231 | memset(sdk_ver, 0, sizeof(sdk_ver)); 232 | __system_property_get("ro.build.version.sdk", sdk_ver); 233 | 234 | if (atoi(sdk_ver) <= 23) { 235 | dlclose_addr = get_remote_func_addr(pid, process_libs.linker_path, (void *) dlclose); 236 | } else { 237 | dlclose_addr = get_remote_func_addr(pid, process_libs.libdl_path, (void *) dlclose); 238 | } 239 | printf("[+] dlclose RemoteFuncAddr:0x%lx\n", (uintptr_t) dlclose_addr); 240 | return dlclose_addr; 241 | } 242 | 243 | /** 244 | * @brief 获取dlsym函数在远程进程中的地址 245 | * @param pid pid表示远程进程的ID 246 | * @return void* dlsym函数在远程进程中的地址 247 | */ 248 | void *get_dlsym_address(pid_t pid) { 249 | void *dlsym_addr; 250 | char sdk_ver[32]; 251 | memset(sdk_ver, 0, sizeof(sdk_ver)); 252 | __system_property_get("ro.build.version.sdk", sdk_ver); 253 | 254 | if (atoi(sdk_ver) <= 23) { 255 | dlsym_addr = get_remote_func_addr(pid, process_libs.linker_path, (void *) dlsym); 256 | } else { 257 | dlsym_addr = get_remote_func_addr(pid, process_libs.libdl_path, (void *) dlsym); 258 | } 259 | printf("[+] dlsym RemoteFuncAddr:0x%lx\n", (uintptr_t) dlsym_addr); 260 | return dlsym_addr; 261 | } 262 | 263 | /** 264 | * @brief 获取dlerror函数在远程进程中的地址 265 | * @param pid pid表示远程进程的ID 266 | * @return void* dlerror函数在远程进程中的地址 267 | */ 268 | void *get_dlerror_address(pid_t pid) { 269 | void *dlerror_addr; 270 | char sdk_ver[32]; 271 | memset(sdk_ver, 0, sizeof(sdk_ver)); 272 | __system_property_get("ro.build.version.sdk", sdk_ver); 273 | 274 | if (atoi(sdk_ver) <= 23) { 275 | dlerror_addr = get_remote_func_addr(pid, process_libs.linker_path, (void *) dlerror); 276 | } else { 277 | dlerror_addr = get_remote_func_addr(pid, process_libs.libdl_path, (void *) dlerror); 278 | } 279 | printf("[+] dlerror RemoteFuncAddr:0x%lx\n", (uintptr_t) dlerror_addr); 280 | return dlerror_addr; 281 | } 282 | 283 | /** 284 | * @brief 使用ptrace从远程进程内存中读取数据 285 | * 这里的*_t类型是typedef定义一些基本类型的别名,用于跨平台。例如uint8_t表示无符号8位也就是无符号的char类型 286 | * @param pid pid表示远程进程的ID 287 | * @param pSrcBuf pSrcBuf表示从远程进程读取数据的内存地址 288 | * @param pDestBuf pDestBuf表示用于存储读取出数据的地址 289 | * @param size size表示读取数据的大小 290 | * @return 返回0表示读取数据成功 291 | */ 292 | int ptrace_readdata(pid_t pid, uint8_t *pSrcBuf, uint8_t *pDestBuf, size_t size) { 293 | long nReadCount = 0; 294 | long nRemainCount = 0; 295 | uint8_t *pCurSrcBuf = pSrcBuf; 296 | uint8_t *pCurDestBuf = pDestBuf; 297 | long lTmpBuf = 0; 298 | long i = 0; 299 | 300 | nReadCount = size / sizeof(long); 301 | nRemainCount = size % sizeof(long); 302 | 303 | for (i = 0; i < nReadCount; i++) { 304 | lTmpBuf = ptrace(PTRACE_PEEKTEXT, pid, pCurSrcBuf, 0); 305 | memcpy(pCurDestBuf, (char *) (&lTmpBuf), sizeof(long)); 306 | pCurSrcBuf += sizeof(long); 307 | pCurDestBuf += sizeof(long); 308 | } 309 | 310 | if (nRemainCount > 0) { 311 | lTmpBuf = ptrace(PTRACE_PEEKTEXT, pid, pCurSrcBuf, 0); 312 | memcpy(pCurDestBuf, (char *) (&lTmpBuf), nRemainCount); 313 | } 314 | 315 | return 0; 316 | } 317 | 318 | /** 319 | * @brief 使用ptrace将数据写入到远程进程空间中 320 | * 321 | * @param pid pid表示远程进程的ID 322 | * @param pWriteAddr pWriteAddr表示写入数据到远程进程的内存地址 323 | * @param pWriteData pWriteData用于存储写入数据的地址 324 | * @param size size表示写入数据的大小 325 | * @return int 返回0表示写入数据成功,返回-1表示写入数据失败 326 | */ 327 | int ptrace_writedata(pid_t pid, uint8_t *pWriteAddr, uint8_t *pWriteData, size_t size){ 328 | 329 | long nWriteCount = 0; 330 | long nRemainCount = 0; 331 | uint8_t *pCurSrcBuf = pWriteData; 332 | uint8_t *pCurDestBuf = pWriteAddr; 333 | long lTmpBuf = 0; 334 | long i = 0; 335 | 336 | nWriteCount = size / sizeof(long); 337 | nRemainCount = size % sizeof(long); 338 | 339 | // 先讲数据以sizeof(long)字节大小为单位写入到远程进程内存空间中 340 | for (i = 0; i < nWriteCount; i++){ 341 | memcpy((void *)(&lTmpBuf), pCurSrcBuf, sizeof(long)); 342 | if (ptrace(PTRACE_POKETEXT, pid, (void *)pCurDestBuf, (void *)lTmpBuf) < 0){ // PTRACE_POKETEXT表示从远程内存空间写入一个sizeof(long)大小的数据 343 | printf("[-] Write Remote Memory error, MemoryAddr:0x%lx, err:%s\n", (uintptr_t)pCurDestBuf, strerror(errno)); 344 | return -1; 345 | } 346 | pCurSrcBuf += sizeof(long); 347 | pCurDestBuf += sizeof(long); 348 | } 349 | // 将剩下的数据写入到远程进程内存空间中 350 | if (nRemainCount > 0){ 351 | lTmpBuf = ptrace(PTRACE_PEEKTEXT, pid, pCurDestBuf, NULL); //先取出原内存中的数据,然后将要写入的数据以单字节形式填充到低字节处 352 | memcpy((void *)(&lTmpBuf), pCurSrcBuf, nRemainCount); 353 | if (ptrace(PTRACE_POKETEXT, pid, pCurDestBuf, lTmpBuf) < 0){ 354 | printf("[-] Write Remote Memory error, MemoryAddr:0x%lx, err:%s\n", (uintptr_t)pCurDestBuf, strerror(errno)); 355 | return -1; 356 | } 357 | } 358 | return 0; 359 | } 360 | 361 | /** 362 | * @brief 使用ptrace远程call函数 363 | * 364 | * @param pid pid表示远程进程的ID 365 | * @param ExecuteAddr ExecuteAddr为远程进程函数的地址 366 | * @param parameters parameters为函数参数的地址 367 | * @param num_params regs为远程进程call函数前的寄存器环境 368 | * @param regs 369 | * @return 返回0表示call函数成功,返回-1表示失败 370 | */ 371 | int ptrace_call(pid_t pid, uintptr_t ExecuteAddr, long *parameters, long num_params,struct pt_regs *regs){ 372 | #if defined(__i386__) // 模拟器 373 | // 写入参数到堆栈 374 | regs->esp -= (num_params) * sizeof(long); // 分配栈空间,栈的方向是从高地址到低地址 375 | if (0 != ptrace_writedata(pid, (uint8_t *)regs->esp, (uint8_t *)parameters,(num_params) * sizeof(long))){ 376 | return -1; 377 | } 378 | 379 | long tmp_addr = 0x0; 380 | regs->esp -= sizeof(long); 381 | if (0 != ptrace_writedata(pid, (uint8_t *)regs->esp, (uint8_t *)&tmp_addr, sizeof(tmp_addr))){ 382 | return -1; 383 | } 384 | 385 | //设置eip寄存器为需要调用的函数地址 386 | regs->eip = ExecuteAddr; 387 | 388 | // 开始执行 389 | if (-1 == ptrace_setregs(pid, regs) || -1 == ptrace_continue(pid)){ 390 | printf("[-] ptrace set regs or continue error, pid:%d\n", pid); 391 | return -1; 392 | } 393 | 394 | int stat = 0; 395 | // 对于使用ptrace_cont运行的子进程,它会在3种情况下进入暂停状态:①下一次系统调用;②子进程退出;③子进程的执行发生错误。 396 | // 参数WUNTRACED表示当进程进入暂停状态后,立即返回 397 | waitpid(pid, &stat, WUNTRACED); 398 | 399 | // 判断是否成功执行函数 400 | printf("[+] ptrace call ret status is %d\n", stat); 401 | while (stat != 0xb7f){ 402 | if (ptrace_continue(pid) == -1){ 403 | printf("[-] ptrace call error"); 404 | return -1; 405 | } 406 | waitpid(pid, &stat, WUNTRACED); 407 | } 408 | 409 | // 获取远程进程的寄存器值,方便获取返回值 410 | if (ptrace_getregs(pid, regs) == -1){ 411 | printf("[-] After call getregs error"); 412 | return -1; 413 | } 414 | 415 | #elif defined(__x86_64__) // ?? 416 | int num_param_registers = 6; 417 | // x64处理器,函数传递参数,将整数和指针参数前6个参数从左到右保存在寄存器rdi,rsi,rdx,rcx,r8和r9 418 | // 更多的参数则按照从右到左的顺序依次压入堆栈。 419 | if (num_params > 0) 420 | regs->rdi = parameters[0]; 421 | if (num_params > 1) 422 | regs->rsi = parameters[1]; 423 | if (num_params > 2) 424 | regs->rdx = parameters[2]; 425 | if (num_params > 3) 426 | regs->rcx = parameters[3]; 427 | if (num_params > 4) 428 | regs->r8 = parameters[4]; 429 | if (num_params > 5) 430 | regs->r9 = parameters[5]; 431 | 432 | if (num_param_registers < num_params){ 433 | regs->esp -= (num_params - num_param_registers) * sizeof(long); // 分配栈空间,栈的方向是从高地址到低地址 434 | if (0 != ptrace_writedata(pid, (uint8_t *)regs->esp, (uint8_t *)¶meters[num_param_registers], (num_params - num_param_registers) * sizeof(long))){ 435 | return -1; 436 | } 437 | } 438 | 439 | long tmp_addr = 0x0; 440 | regs->esp -= sizeof(long); 441 | if (0 != ptrace_writedata(pid, (uint8_t *)regs->esp, (uint8_t *)&tmp_addr, sizeof(tmp_addr))){ 442 | return -1; 443 | } 444 | 445 | //设置eip寄存器为需要调用的函数地址 446 | regs->eip = ExecuteAddr; 447 | 448 | // 开始执行 449 | if (-1 == ptrace_setregs(pid, regs) || -1 == ptrace_continue(pid)){ 450 | printf("[-] ptrace set regs or continue error, pid:%d", pid); 451 | return -1; 452 | } 453 | 454 | int stat = 0; 455 | // 对于使用ptrace_cont运行的子进程,它会在3种情况下进入暂停状态:①下一次系统调用;②子进程退出;③子进程的执行发生错误。 456 | // 参数WUNTRACED表示当进程进入暂停状态后,立即返回 457 | waitpid(pid, &stat, WUNTRACED); 458 | 459 | // 判断是否成功执行函数 460 | printf("ptrace call ret status is %lX\n", stat); 461 | while (stat != 0xb7f){ 462 | if (ptrace_continue(pid) == -1){ 463 | printf("[-] ptrace call error"); 464 | return -1; 465 | } 466 | waitpid(pid, &stat, WUNTRACED); 467 | } 468 | 469 | #elif defined(__arm__) || defined(__aarch64__) // 真机 470 | #if defined(__arm__) // 32位真机 471 | int num_param_registers = 4; 472 | #elif defined(__aarch64__) // 64位真机 473 | int num_param_registers = 8; 474 | #endif 475 | int i = 0; 476 | // ARM处理器,函数传递参数,将前四个参数放到r0-r3,剩下的参数压入栈中 477 | for (i = 0; i < num_params && i < num_param_registers; i++){ 478 | regs->uregs[i] = parameters[i]; 479 | } 480 | 481 | if (i < num_params){ 482 | regs->ARM_sp -= (num_params - i) * sizeof(long); // 分配栈空间,栈的方向是从高地址到低地址 483 | if (ptrace_writedata(pid, (uint8_t *)(regs->ARM_sp), (uint8_t *)¶meters[i], (num_params - i) * sizeof(long)) == -1) 484 | return -1; 485 | } 486 | 487 | regs->ARM_pc = ExecuteAddr; //设置ARM_pc寄存器为需要调用的函数地址 488 | // 与BX跳转指令类似,判断跳转的地址位[0]是否为1,如果为1,则将CPST寄存器的标志T置位,解释为Thumb代码 489 | // 若为0,则将CPSR寄存器的标志T复位,解释为ARM代码 490 | if (regs->ARM_pc & 1){ 491 | /* thumb */ 492 | regs->ARM_pc &= (~1u); 493 | regs->ARM_cpsr |= CPSR_T_MASK; 494 | } else { 495 | /* arm */ 496 | regs->ARM_cpsr &= ~CPSR_T_MASK; 497 | } 498 | 499 | regs->ARM_lr = 0; 500 | 501 | // Android 7.0以上修正lr为libc.so的起始地址 getprop获取ro.build.version.sdk 502 | long lr_val = 0; 503 | char sdk_ver[32]; 504 | memset(sdk_ver, 0, sizeof(sdk_ver)); 505 | __system_property_get("ro.build.version.sdk", sdk_ver); 506 | // printf("ro.build.version.sdk: %s", sdk_ver); 507 | if (atoi(sdk_ver) <= 23){ 508 | lr_val = 0; 509 | } else { // Android 7.0 510 | static long start_ptr = 0; 511 | if (start_ptr == 0){ 512 | start_ptr = (long)get_module_base_addr(pid, process_libs.libc_path); 513 | } 514 | lr_val = start_ptr; 515 | } 516 | regs->ARM_lr = lr_val; 517 | 518 | if (ptrace_setregs(pid, regs) == -1 || ptrace_continue(pid) == -1){ 519 | printf("[-] ptrace set regs or continue error, pid:%d\n", pid); 520 | return -1; 521 | } 522 | 523 | int stat = 0; 524 | // 对于使用ptrace_cont运行的子进程,它会在3种情况下进入暂停状态:①下一次系统调用;②子进程退出;③子进程的执行发生错误。 525 | // 参数WUNTRACED表示当进程进入暂停状态后,立即返回 526 | // 将ARM_lr(存放返回地址)设置为0,会导致子进程执行发生错误,则子进程进入暂停状态 527 | waitpid(pid, &stat, WUNTRACED); 528 | 529 | // 判断是否成功执行函数 530 | printf("[+] ptrace call ret status is %d\n", stat); 531 | while ((stat & 0xFF) != 0x7f){ 532 | if (ptrace_continue(pid) == -1){ 533 | printf("[-] ptrace call error\n"); 534 | return -1; 535 | } 536 | waitpid(pid, &stat, WUNTRACED); 537 | } 538 | 539 | // 获取远程进程的寄存器值,方便获取返回值 540 | if (ptrace_getregs(pid, regs) == -1){ 541 | printf("[-] After call getregs error\n"); 542 | return -1; 543 | } 544 | 545 | #else // 设备不符合注入器构架 546 | printf("[-] Not supported Environment %s\n", __FUNCTION__); 547 | #endif 548 | return 0; 549 | } 550 | -------------------------------------------------------------------------------- /Inject/include/Utils/Utils.h: -------------------------------------------------------------------------------- 1 | // system lib 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | // 系统lib路径 22 | struct process_libs{ 23 | const char *libc_path; 24 | const char *linker_path; 25 | const char *libdl_path; 26 | } process_libs = {"","",""}; 27 | 28 | // selinux状态 29 | struct process_selinux{ 30 | const char *selinux_mnt; 31 | int enforce; 32 | } process_selinux = {nullptr, -1}; 33 | 34 | /** 35 | * @brief 处理各架构预定义的库文件 36 | */ 37 | __unused __attribute__((constructor(101))) void handle_libs(){ // __attribute__((constructor))修饰 最先执行 38 | char sdk_ver[32]; 39 | __system_property_get("ro.build.version.sdk", sdk_ver); 40 | // 系统lib路径 41 | #if defined(__aarch64__) || defined(__x86_64__) 42 | // 在安卓10(包含安卓10)以上 lib路径有所变动 43 | if ( atoi(sdk_ver) >= __ANDROID_API_Q__){ 44 | process_libs.libc_path = "/apex/com.android.runtime/lib64/bionic/libc.so"; 45 | process_libs.linker_path = "/apex/com.android.runtime/bin/linker64"; 46 | process_libs.libdl_path = "/apex/com.android.runtime/lib64/bionic/libdl.so"; 47 | } else { 48 | process_libs.libc_path = "/system/lib64/libc.so"; 49 | process_libs.linker_path = "/system/bin/linker64"; 50 | process_libs.libdl_path = "/system/lib64/libdl.so"; 51 | } 52 | #else 53 | // 在安卓10(包含安卓10)以上 lib路径有所变动 54 | if (atoi(sdk_ver) >= __ANDROID_API_Q__){ 55 | process_libs.libc_path = "/apex/com.android.runtime/lib/bionic/libc.so"; 56 | process_libs.linker_path = "/apex/com.android.runtime/bin/linker"; 57 | process_libs.libdl_path = "/apex/com.android.runtime/lib/bionic/libdl.so"; 58 | } else { 59 | process_libs.libc_path = "/system/lib/libc.so"; 60 | process_libs.linker_path = "/system/bin/linker"; 61 | process_libs.libdl_path = "/system/lib/libdl.so"; 62 | } 63 | #endif 64 | printf("[+] libc_path is %s\n", process_libs.libc_path); 65 | printf("[+] linker_path is %s\n", process_libs.linker_path); 66 | printf("[+] libdl_path is %s\n", process_libs.libdl_path); 67 | printf("[+] system libs is OK\n"); 68 | } 69 | 70 | /** 71 | * @brief 处理各SELinux判断的初始化 72 | */ 73 | __unused __attribute__((constructor(102))) void handle_selinux_init(){ // 执行优先级 102 切记执行优先级越低 越先执行 74 | // code from AOSP 75 | char buf[BUFSIZ], *p; 76 | FILE *fp = nullptr; 77 | struct statfs sfbuf; 78 | int rc; 79 | char *bufp; 80 | int exists = 0; 81 | 82 | if (process_selinux.selinux_mnt){ // 如果selinux_state有值了 就终止下面的行为 83 | return; 84 | } 85 | 86 | /* We check to see if the preferred mount point for selinux file 87 | * system has a selinuxfs. */ 88 | do { 89 | rc = statfs("/sys/fs/selinux", &sfbuf); 90 | } while (rc < 0 && errno == EINTR); 91 | if (rc == 0) { 92 | if ((uint32_t)sfbuf.f_type == (uint32_t)SELINUX_MAGIC) { 93 | process_selinux.selinux_mnt = strdup("/sys/fs/selinux"); // 为 selinux_mnt 赋值 94 | return; 95 | } 96 | } 97 | 98 | /* Drop back to detecting it the long way. */ 99 | fp = fopen("/proc/filesystems", "r"); 100 | if (!fp){ 101 | return; 102 | } 103 | 104 | while ((bufp = fgets(buf, sizeof buf - 1, fp)) != nullptr) { 105 | if (strstr(buf, "selinuxfs")) { 106 | exists = 1; 107 | break; 108 | } 109 | } 110 | 111 | if (!exists){ 112 | goto out; 113 | } 114 | 115 | fclose(fp); 116 | 117 | /* At this point, the usual spot doesn't have an selinuxfs so 118 | * we look around for it */ 119 | fp = fopen("/proc/mounts", "r"); 120 | if (!fp){ 121 | goto out; 122 | } 123 | 124 | while ((bufp = fgets(buf, sizeof buf - 1, fp)) != nullptr) { 125 | char *tmp; 126 | p = strchr(buf, ' '); 127 | if (!p){ 128 | goto out; 129 | } 130 | p++; 131 | tmp = strchr(p, ' '); 132 | if (!tmp){ 133 | goto out; 134 | } 135 | if (!strncmp(tmp + 1, "selinuxfs ", 10)) { 136 | *tmp = '\0'; 137 | break; 138 | } 139 | } 140 | 141 | /* If we found something, dup it */ 142 | if (bufp){ 143 | process_selinux.selinux_mnt = strdup(p); 144 | } 145 | 146 | out: 147 | if (fp){ 148 | fclose(fp); 149 | } 150 | 151 | return; 152 | } 153 | 154 | /** 155 | * @brief 检测SELinux是否为宽容模式 如果不是 则设置为宽容模式 156 | */ 157 | __unused __attribute__((constructor(103))) void handle_selinux_detect() { 158 | // code from AOSP 159 | int fd, ret; 160 | char path[PATH_MAX]; 161 | char buf[20]; 162 | 163 | if (!process_selinux.selinux_mnt) { // selinux_mnt不为空 164 | errno = ENOENT; 165 | printf("[-] selinux_mnt is nullptr\n"); 166 | return ; 167 | } 168 | 169 | snprintf(path, sizeof path, "%s/enforce", process_selinux.selinux_mnt); 170 | fd = open(path, O_RDONLY); 171 | if (fd < 0){ // 如果打开文件失败 那么终止 172 | printf("[-] Failed to open enforce\n"); 173 | return ; 174 | } 175 | 176 | memset(buf, 0, sizeof buf); 177 | ret = read(fd, buf, sizeof buf - 1); 178 | close(fd); 179 | if (ret < 0){ // 如果值小于0 那么返回 180 | printf("[-] SELinux ret error\n"); 181 | return ; 182 | } 183 | 184 | // 将buf写入到enforce 185 | if (sscanf(buf, "%d", (int*)&process_selinux.enforce) != 1){ // 如果失败 则终止 186 | printf("[-] sscanf error\n"); 187 | return ; 188 | } 189 | printf("[+] handle_selinux_init is OK\n"); 190 | return ; 191 | } 192 | 193 | /** 194 | * 195 | * @param value SELinux的状态值 0为宽容模式Permissive 1为严格模式Enforcing 196 | * @return 197 | */ 198 | bool set_selinux_state(int value) { 199 | bool succ = true; 200 | int fd; 201 | char path[PATH_MAX]; 202 | char buf[20]; 203 | 204 | if (!process_selinux.selinux_mnt) { 205 | errno = ENOENT; 206 | return -1; 207 | } 208 | 209 | snprintf(path, sizeof path, "%s/enforce", process_selinux.selinux_mnt); 210 | fd = open(path, O_RDWR); 211 | if (fd < 0) 212 | return -1; 213 | 214 | snprintf(buf, sizeof buf, "%d", (int)value); 215 | int ret = write(fd, buf, strlen(buf)); 216 | close(fd); 217 | if (ret < 0) 218 | succ = false; 219 | return succ; 220 | } 221 | 222 | /** 223 | * @brief Get the pid by pkg_name 224 | * 成功返回 true 225 | * 失败返回 false 226 | * 227 | * @param pid 228 | * @param task_name 229 | * @return true 230 | * @return false 231 | */ 232 | bool get_pid_by_name(pid_t *pid, char *task_name){ 233 | DIR *dir; 234 | struct dirent *ptr; 235 | FILE *fp; 236 | char filepath[50]; 237 | char cur_task_name[50]; 238 | char buf[1024]; 239 | 240 | dir = opendir("/proc"); 241 | if (NULL != dir){ 242 | while ((ptr = readdir(dir)) != NULL){ //循环读取/proc下的每一个文件/文件夹 243 | //如果读取到的是"."或者".."则跳过,读取到的不是文件夹名字也跳过 244 | if ((strcmp(ptr->d_name, ".") == 0) || (strcmp(ptr->d_name, "..") == 0)) 245 | continue; 246 | if (DT_DIR != ptr->d_type) 247 | continue; 248 | 249 | sprintf(filepath, "/proc/%s/cmdline", ptr->d_name); //生成要读取的文件的路径 250 | fp = fopen(filepath, "r"); 251 | if (NULL != fp){ 252 | if (fgets(buf, 1024 - 1, fp) == NULL){ 253 | fclose(fp); 254 | continue; 255 | } 256 | sscanf(buf, "%s", cur_task_name); 257 | //如果文件内容满足要求则打印路径的名字(即进程的PID) 258 | if (strstr(task_name, cur_task_name)){ 259 | *pid = atoi(ptr->d_name); 260 | return true; 261 | } 262 | fclose(fp); 263 | } 264 | } 265 | closedir(dir); 266 | } 267 | 268 | return false; 269 | } 270 | 271 | /** 272 | * @brief Get the app start activity object 273 | * 获取应用的android.intent.action.MAIN 274 | * 275 | * @param pkg_name // 获取的应用包名 276 | * @param start_activity_name // 存放启动的 main activity 277 | */ 278 | void get_app_start_activity(char *pkg_name, char *start_activity_name){ 279 | char cmdstring[1024] = "dumpsys package "; 280 | char cmd_string[1024] = {0}; 281 | char temp_file[] = "tmp_XXXXXX"; 282 | 283 | strcat(cmdstring, pkg_name); 284 | int fd; 285 | 286 | if ((fd = mkstemp(temp_file)) == -1){ 287 | printf("[-] create tmp file failed.\n"); 288 | } 289 | 290 | sprintf(cmd_string, "%s > %s", cmdstring, temp_file); 291 | system(cmd_string); 292 | 293 | FILE *fp = fdopen(fd, "r"); 294 | if (fp == NULL){ 295 | printf("[-] can not load file!"); 296 | return; 297 | } 298 | char line[1024]; 299 | while (!feof(fp)){ 300 | fgets(line, 1024, fp); 301 | if (strstr(line, "android.intent.action.MAIN")){ 302 | fgets(line, 1024, fp); 303 | char *p; 304 | //选取第二个 305 | int index = 1; 306 | p = strtok(line, " "); 307 | while (p){ 308 | if (index == 2){ 309 | strcpy(start_activity_name, p); 310 | } 311 | index++; 312 | p = strtok(NULL, " "); 313 | } 314 | break; 315 | } 316 | } 317 | fclose(fp); 318 | unlink(temp_file); 319 | return; 320 | } 321 | 322 | /** 323 | * @brief 输入App包名 利用 am 命令 启动App 324 | * 325 | * @param pkg_name 326 | */ 327 | void start_app(char *pkg_name){ 328 | char start_activity_name[1024] = {0}; 329 | get_app_start_activity(pkg_name, start_activity_name); 330 | printf("[+] app_start_activity is %s\n", start_activity_name); 331 | char start_cmd[1024] = "am start "; 332 | strcat(start_cmd, start_activity_name); 333 | printf("[+] %s\n", start_cmd); 334 | system(start_cmd); 335 | } 336 | 337 | /** 338 | * @brief 在指定进程中搜索对应模块的基址 339 | * 340 | * @param pid pid表示远程进程的ID 若为-1表示自身进程 341 | * @param ModuleName ModuleName表示要搜索的模块的名称 342 | * @return void* 返回0表示获取模块基址失败,返回非0为要搜索的模块基址 343 | */ 344 | void *get_module_base_addr(pid_t pid, const char *ModuleName){ 345 | FILE *fp = NULL; 346 | long ModuleBaseAddr = 0; 347 | char szFileName[50] = {0}; 348 | char szMapFileLine[1024] = {0}; 349 | 350 | // 读取"/proc/pid/maps"可以获得该进程加载的模块 351 | if (pid < 0){ 352 | // 枚举自身进程模块 353 | snprintf(szFileName, sizeof(szFileName), "/proc/self/maps"); 354 | } else { 355 | snprintf(szFileName, sizeof(szFileName), "/proc/%d/maps", pid); 356 | } 357 | 358 | fp = fopen(szFileName, "r"); 359 | 360 | if (fp != NULL){ 361 | while (fgets(szMapFileLine, sizeof(szMapFileLine), fp)){ 362 | if (strstr(szMapFileLine, ModuleName)){ 363 | char *Addr = strtok(szMapFileLine, "-"); 364 | ModuleBaseAddr = strtoul(Addr, NULL, 16); 365 | 366 | if (ModuleBaseAddr == 0x8000) 367 | ModuleBaseAddr = 0; 368 | 369 | break; 370 | } 371 | } 372 | 373 | fclose(fp); 374 | } 375 | 376 | return (void *)ModuleBaseAddr; 377 | } 378 | 379 | /** 380 | * @brief 获取远程进程与本进程都加载的模块中函数的地址 381 | * 382 | * @param pid pid表示远程进程的ID 383 | * @param ModuleName ModuleName表示模块名称 384 | * @param LocalFuncAddr LocalFuncAddr表示本地进程中该函数的地址 385 | * @return void* 返回远程进程中对应函数的地址 386 | */ 387 | void *get_remote_func_addr(pid_t pid, const char *ModuleName, void *LocalFuncAddr){ 388 | void *LocalModuleAddr, *RemoteModuleAddr, *RemoteFuncAddr; 389 | //获取本地某个模块的起始地址 390 | LocalModuleAddr = get_module_base_addr(-1, ModuleName); 391 | //获取远程pid的某个模块的起始地址 392 | RemoteModuleAddr = get_module_base_addr(pid, ModuleName); 393 | // local_addr - local_handle的值为指定函数(如mmap)在该模块中的偏移量,然后再加上remote_handle,结果就为指定函数在目标进程的虚拟地址 394 | RemoteFuncAddr = (void *)((uintptr_t)LocalFuncAddr - (uintptr_t)LocalModuleAddr + (uintptr_t)RemoteModuleAddr); 395 | 396 | printf("[+] [get_remote_func_addr] lmod=0x%lX, rmod=0x%lX, lfunc=0x%lX, rfunc=0x%lX\n", LocalModuleAddr, RemoteModuleAddr, LocalFuncAddr, RemoteFuncAddr); 397 | return RemoteFuncAddr; 398 | } 399 | 400 | -------------------------------------------------------------------------------- /Inject/inject.cpp: -------------------------------------------------------------------------------- 1 | // user lib 2 | #include 3 | 4 | // 由于Inject是命令行工具 因此 替换全部的LOG为printf 以方便观察注入流程 5 | int main(int argc, char *argv[]) { 6 | 7 | printf("[+] Start Inject\n"); 8 | 9 | // 开始注入 10 | 11 | /** 以下是Inject命令行工具的参数 12 | ** 部分参数选填 13 | * -p 目标进程pid <-- 不传pid就传包名 14 | * -n 目标App包名 <-- 不传包名就传pid 15 | * -f 是否开启App <-- 看你要不要强制唤醒App 16 | * ---- // 由于 -f 参数需要创建中间文件 因此 请务必在Inject工具目录执行该工具 17 | * ---- // 即 /data/local/tmp/Inject -f -n XXX <-- 错误 18 | * ---- // 即 cd /data/local/tmp && ./Inject -f -n XXX <-- 正确 19 | * -so 注入的so路径 <-- 必填 本来就是so注入工具 只能是绝对路径!! 20 | * -symbols 指定启用so中的某功能 <-- 选填 可以指定so中某功能的symbols 也可以通过__attribute__((constructor))让so注入后自行初始化 21 | */ 22 | if (init_inject(argc, argv) == 0){ 23 | printf("[+] Finish Inject\n"); 24 | } else { 25 | printf("[-] Inject Erro\n"); 26 | } 27 | /** 28 | * eg: 29 | * cd /data/local/tmp && ./Inject -f -n bin.mt.plus -so /data/local/tmp/libHook.so -symbols hello 30 | */ 31 | 32 | return 0; 33 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 SsageParuders 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Android Ptrace Inject 2 | 3 | ![](https://img.shields.io/badge/Android-Build-green) 4 | ![](https://img.shields.io/badge/Android%204~12-Support-green) 5 | ![](https://img.shields.io/badge/arm64--v8a-Support-green) 6 | ![](https://img.shields.io/badge/x86-Support-green) 7 | 8 | > 中文可以参考我的注释内容进行理解
9 | > 我写的注释相对来说比较全面了 10 | 11 | ## How to build 12 | 13 | - Make sure you have `CMake` and `Ninja` in your PATH 14 | 15 | - Edit CMakeLists.txt. Set [`ANDROID_NDK`](https://github.com/SsageParuders/AndroidPtraceInject/blob/dfcee37e0c302d70e81c323c326e21c7f9bfa08e/CMakeLists.txt#L12) and [`CMAKE_TOOLCHAIN_FILE`](https://github.com/SsageParuders/AndroidPtraceInject/blob/dfcee37e0c302d70e81c323c326e21c7f9bfa08e/CMakeLists.txt#L13) for yourself. 16 | 17 | - If your OS is Windows, read `build.sh` and make it to be a `build.bat`. 18 | 19 | Also, don't forget to change [`CMAKE_RUNTIME_OUTPUT_DIRECTORY`](https://github.com/SsageParuders/AndroidPtraceInject/blob/dfcee37e0c302d70e81c323c326e21c7f9bfa08e/Inject/CMakeLists.txt#L4) and [`CMAKE_LIBRARY_OUTPUT_DIRECTORY`](https://github.com/SsageParuders/AndroidPtraceInject/blob/dfcee37e0c302d70e81c323c326e21c7f9bfa08e/Hook/CMakeLists.txt#L4) in Windows styles. 20 | 21 | - If you want to build all ABIs, u can annotation [ANDROID_ABI on CMakeLists.txt](https://github.com/SsageParuders/AndroidPtraceInject/blob/dfcee37e0c302d70e81c323c326e21c7f9bfa08e/CMakeLists.txt#L7), and run build.sh 22 | ```shell 23 | git clone https://github.com/SsageParuders/AndroidPtraceInject.git 24 | cd AndroidPtraceInject 25 | mkdir build 26 | chmod +x build.sh 27 | ./build.sh 28 | ``` 29 | - Or you can don't run build.sh and don't annotation [ANDROID_ABI on CMakeLists.txt](https://github.com/SsageParuders/AndroidPtraceInject/blob/dfcee37e0c302d70e81c323c326e21c7f9bfa08e/CMakeLists.txt#L7). 30 | ```shell 31 | git clone https://github.com/SsageParuders/AndroidPtraceInject.git 32 | cd AndroidPtraceInject 33 | mkdir build 34 | cd build 35 | cmake .. -G Ninja 36 | cmake --build . 37 | ``` 38 | 39 | ## How to use 40 | 41 | ```shell 42 | # Here are the parameters of the Inject command line tool: 43 | # Some parameters are optional. 44 | # -p process 's pid <-- optional 45 | # -n process 's package name <-- optional 46 | # -f whether to start App <-- optional 47 | # ---- // /data/local/tmp/Inject -f -n XXX <-- error 48 | # ---- // cd /data/local/tmp && ./Inject -f -n XXX <-- right 49 | # -so so path for injection <-- mandatory 50 | # -symbols specify a symbol in so <-- optional 51 | # For examples: 52 | cd /data/local/tmp && ./Inject -f -n bin.mt.plus -so /data/local/tmp/libHook.so -symbols hello 53 | ``` 54 | 55 | # TODO LIST 56 | 57 | ## Finished 58 | 59 | - [x] First Inject Succeeded 60 | 61 | - [x] Handle Parameter 62 | 63 | - [x] Handle SELinux 64 | 65 | - [x] Handle Libs 66 | 67 | - [x] Succeed Inject for arm64-v8a 68 | 69 | - [x] Succeed Inject for Android 9 and Android 11 70 | 71 | - [x] Adapt to all Android versions 72 | 73 | - [x] Succeed Inject for x86 74 | 75 | ## Future 76 | 77 | - [ ] Fix bugs for armeabi-v7a 78 | 79 | - [ ] Adapt to the ABIs of each device, such as armeabi-v7a and x86_64 80 | 81 | # Credits 82 | 83 | [Adrill](https://github.com/mustime/Adrill) By mustime 84 | 85 | [SharkInject](https://github.com/bigGreenPeople/SharkInject) By bigGreenPeople 86 | 87 | [androidinject](https://github.com/mergerly/androidinject) By mergerly 88 | 89 | [TinyInjector](https://github.com/shunix/TinyInjector) By shunix 90 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | 2 | ## 目标架构数组 3 | abi_array=(armeabi-v7a arm64-v8a x86) 4 | 5 | ## 进入build目录 6 | cd build 7 | 8 | if [ $? -ne 0 ]; then 9 | echo "\033[41;37mFAILED to cd build !!\033[0m\n" 10 | else 11 | echo "\033[42;35mSUCCEED to cd build !!\033[0m\n" 12 | fi 13 | 14 | ## 遍历架构数组 编译目标架构产物 15 | for (( i=0; i < ${#abi_array[@]}; i++)) do 16 | 17 | ## 清空cmake中间文件 18 | rm -rf * 19 | 20 | if [ $? -ne 0 ]; then 21 | echo "\033[41;37mFAILED to clean !!\033[0m\n" 22 | else 23 | echo "\033[42;35mSUCCEED to clean !!\033[0m\n" 24 | fi 25 | 26 | echo "\n\033[44;37mStart to build ABI of "${abi_array[i]}"\033[0m"; 27 | 28 | ## 生存编译配置文件 29 | cmake .. \ 30 | -DANDROID_ABI=${abi_array[i]} \ 31 | -G Ninja 32 | 33 | if [ $? -ne 0 ]; then 34 | echo "\033[41;37mFAILED to Configuring and Generating Build files !!\033[0m\n" 35 | else 36 | echo "\033[42;35mSUCCEED to Configuring and Generating Build files !!\033[0m\n" 37 | fi 38 | 39 | ## 编译 40 | cmake --build . 41 | 42 | if [ $? -ne 0 ]; then 43 | echo "\033[41;37mFAILED to build !!\033[0m\n" 44 | else 45 | echo "\033[42;35mSUCCEED to build !!\033[0m\n" 46 | fi 47 | 48 | ## 清空cmake中间文件 49 | rm -rf * 50 | 51 | if [ $? -ne 0 ]; then 52 | echo "\033[41;37mFAILED to clean !!\033[0m\n" 53 | else 54 | echo "\033[42;35mSUCCEED to clean !!\033[0m\n" 55 | fi 56 | 57 | done; 58 | 59 | ## 离开build目录 60 | cd .. 61 | 62 | if [ $? -ne 0 ]; then 63 | echo "\033[41;37mFAILED to exit build !!\033[0m\n" 64 | else 65 | echo "\033[42;35mSUCCEED to exit build !!\033[0m\n" 66 | fi -------------------------------------------------------------------------------- /clean.sh: -------------------------------------------------------------------------------- 1 | ## 清除产物 2 | find outputs -type f -delete 3 | 4 | if [ $? -ne 0 ]; then 5 | echo "\033[41;37mFAILED to cd clean outputs !!\033[0m" 6 | else 7 | echo "\033[42;35mSUCCEED to clean outputs !!\033[0m" 8 | fi -------------------------------------------------------------------------------- /outputs/arm64-v8a/libHook.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SsageParuders/AndroidPtraceInject/357eb720dff36e1f974abadc76426e73e44a74df/outputs/arm64-v8a/libHook.so -------------------------------------------------------------------------------- /outputs/armeabi-v7a/libHook.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SsageParuders/AndroidPtraceInject/357eb720dff36e1f974abadc76426e73e44a74df/outputs/armeabi-v7a/libHook.so -------------------------------------------------------------------------------- /outputs/x86/Inject: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SsageParuders/AndroidPtraceInject/357eb720dff36e1f974abadc76426e73e44a74df/outputs/x86/Inject -------------------------------------------------------------------------------- /outputs/x86/libHook.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SsageParuders/AndroidPtraceInject/357eb720dff36e1f974abadc76426e73e44a74df/outputs/x86/libHook.so -------------------------------------------------------------------------------- /outputs/x86_64/Inject: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SsageParuders/AndroidPtraceInject/357eb720dff36e1f974abadc76426e73e44a74df/outputs/x86_64/Inject -------------------------------------------------------------------------------- /outputs/x86_64/libHook.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SsageParuders/AndroidPtraceInject/357eb720dff36e1f974abadc76426e73e44a74df/outputs/x86_64/libHook.so -------------------------------------------------------------------------------- /res/log_Android11_arm32_succeed.txt: -------------------------------------------------------------------------------- 1 | /* 2 | 安卓11居然是正常的 什么鬼 3 | */ 4 | [+] libc_path is /apex/com.android.runtime/lib/bionic/libc.so 5 | [+] linker_path is /apex/com.android.runtime/bin/linker 6 | [+] libdl_path is /apex/com.android.runtime/lib/bionic/libdl.so 7 | [+] system libs is OK 8 | [+] handle_selinux_init is OK 9 | [+] Start Inject 10 | [+] app_start_activity is com.xiaoyou.ToramOnline.aligames.ue/com.xiaoyougame.toramquick.SplashActivity 11 | [+] am start com.xiaoyou.ToramOnline.aligames.ue/com.xiaoyougame.toramquick.SplashActivity 12 | Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.xiaoyou.ToramOnline.aligames.ue/com.xiaoyougame.toramquick.SplashActivity } 13 | [+] pkg_name is com.xiaoyou.ToramOnline.aligames.ue 14 | [+] get_pid_by_name pid is 26584 15 | [+] lib_path is /data/local/tmp/libHook32.so 16 | [+] handle_parameter is OK 17 | [+] SELinux is Permissive or Disabled 18 | [+] attach porcess success, pid:26584 19 | [+] [get_remote_func_addr] lmod=0xE9568000, rmod=0xE8C64000, lfunc=0xE95D871D, rfunc=0xE8CD471D 20 | [+] mmap RemoteFuncAddr:0xe8cd471d 21 | [+] ptrace continue process success, pid:26584 22 | [+] ptrace call ret status is 2943 23 | [+] ptrace_call mmap success, return value=CC280000, pc=E8C64000 24 | [+] Remote Process Map Memory Addr:0xcc280000 25 | [+] linker_path value:/apex/com.android.runtime/bin/linker 26 | [+] [get_remote_func_addr] lmod=0xE96AB000, rmod=0xEB04C000, lfunc=0xE96AC849, rfunc=0xEB04D849 27 | [+] dlopen RemoteFuncAddr:0xeb04d849 28 | [+] [get_remote_func_addr] lmod=0xE96AB000, rmod=0xEB04C000, lfunc=0xE96AC85B, rfunc=0xEB04D85B 29 | [+] dlsym RemoteFuncAddr:0xeb04d85b 30 | [+] [get_remote_func_addr] lmod=0xE96AB000, rmod=0xEB04C000, lfunc=0xE96AC877, rfunc=0xEB04D877 31 | [+] dlclose RemoteFuncAddr:0xeb04d877 32 | [+] [get_remote_func_addr] lmod=0xE96AB000, rmod=0xEB04C000, lfunc=0xE96AC853, rfunc=0xEB04D853 33 | [+] dlerror RemoteFuncAddr:0xeb04d853 34 | [+] Get imports: dlopen: eb04d849, dlsym: eb04d85b, dlclose: eb04d877, dlerror: eb04d853 35 | [+] LibPath = /data/local/tmp/libHook32.so 36 | [+] ptrace continue process success, pid:26584 37 | [+] ptrace call ret status is 2943 38 | [+] ptrace_call dlopen success, Remote Process load module Addr:0x8130affb 39 | [+] No func !! 40 | [+] Recover Regs Success 41 | [+] detach process success, pid:26584 42 | [+] Finish Inject -------------------------------------------------------------------------------- /res/log_Android11_arm64_failed.txt: -------------------------------------------------------------------------------- 1 | [+] Start Inject 2 | [+] app_start_activity is bin.mt.plus/.Main 3 | [+] am start bin.mt.plus/.Main 4 | Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=bin.mt.plus/.Main } 5 | [+] pkg_name is bin.mt.plus 6 | [+] get_pid_by_name pid is 23218 7 | [+] lib_path is /data/local/tmp/libHook.so 8 | [+] symbols is hello 9 | [+] handle_parameter is OK 10 | [+] The state of the SELinux is Permissive 11 | [+] SELinux is Permissive 12 | [+] handle_selinux is OK 13 | /* 14 | 到这里说明 15 | 启动App --> 参数处理 --> SELinux状态处理没问题 16 | */ 17 | [+] attach porcess success, pid:23218 18 | /* 19 | 附加没问题 20 | */ 21 | [+] [get_remote_func_addr] lmod=0x0, rmod=0x0, lfunc=0x7291E6EF30, rfunc=0x7291E6EF30 22 | /* 23 | 这获取远程地址有问题 得看看 24 | */ 25 | [+] mmap RemoteFuncAddr:0x7291e6ef30 26 | [+] ptrace continue process success, pid:23218 27 | [+] ptrace call ret status is 2943 28 | [+] ptrace_call mmap success, return value=0, pc=7291E6EF30 29 | [+] Remote Process Map Memory Addr:0x0 30 | [+] linker_path value:/system/bin/linker64 31 | [+] [get_remote_func_addr] lmod=0x0, rmod=0x0, lfunc=0x7291D4E014, rfunc=0x7291D4E014 32 | [+] dlopen RemoteFuncAddr:0x7291d4e014 33 | [+] [get_remote_func_addr] lmod=0x0, rmod=0x0, lfunc=0x7291D4E040, rfunc=0x7291D4E040 34 | [+] dlsym RemoteFuncAddr:0x7291d4e040 35 | [+] [get_remote_func_addr] lmod=0x0, rmod=0x0, lfunc=0x7291D4E084, rfunc=0x7291D4E084 36 | [+] dlclose RemoteFuncAddr:0x7291d4e084 37 | [+] [get_remote_func_addr] lmod=0x0, rmod=0x0, lfunc=0x7291D4E02C, rfunc=0x7291D4E02C 38 | [+] dlerror RemoteFuncAddr:0x7291d4e02c 39 | [+] Get imports: dlopen: 91d4e014, dlsym: 91d4e040, dlclose: 91d4e084, dlerror: 91d4e02c 40 | [+] LibPath = /data/local/tmp/libHook.so 41 | [-] Write Remote Memory error, MemoryAddr:0x0, err:I/O error 42 | [-] Write LibPath:/data/local/tmp/libHook.so to RemoteProcess error 43 | [+] detach process success, pid:23218 44 | [-] Inject Erro -------------------------------------------------------------------------------- /res/log_Android11_arm64_fixed_succeed.txt: -------------------------------------------------------------------------------- 1 | [+] libc_path is /apex/com.android.runtime/lib64/bionic/libc.so 2 | [+] linker_path is /apex/com.android.runtime/bin/linker64 3 | [+] libdl_path is /apex/com.android.runtime/lib64/bionic/libdl.so 4 | [+] system libs is OK 5 | [+] Start Inject 6 | [+] app_start_activity is bin.mt.plus/.Main 7 | [+] am start bin.mt.plus/.Main 8 | Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=bin.mt.plus/.Main } 9 | [+] pkg_name is bin.mt.plus 10 | [+] get_pid_by_name pid is 21968 11 | [+] lib_path is /data/local/tmp/libHook.so 12 | [+] symbols is hello 13 | [+] handle_parameter is OK 14 | [+] SELinux is Permissive 15 | [+] handle_selinux is OK 16 | [+] attach porcess success, pid:21968 17 | [+] [get_remote_func_addr] lmod=0x702E6D0000, rmod=0x7AFF5D0000, lfunc=0x702E7A6F30, rfunc=0x7AFF6A6F30 18 | [+] mmap RemoteFuncAddr:0x7aff6a6f30 19 | [+] ptrace continue process success, pid:21968 20 | [+] ptrace call ret status is 2943 21 | [+] ptrace_call mmap success, return value=7A6A246000, pc=7AFF5D0000 22 | [+] Remote Process Map Memory Addr:0x7a6a246000 23 | [+] linker_path value:/apex/com.android.runtime/bin/linker64 24 | [+] [get_remote_func_addr] lmod=0x702E6BB000, rmod=0x7AFEA1A000, lfunc=0x702E6BC014, rfunc=0x7AFEA1B014 25 | [+] dlopen RemoteFuncAddr:0x7afea1b014 26 | [+] [get_remote_func_addr] lmod=0x702E6BB000, rmod=0x7AFEA1A000, lfunc=0x702E6BC040, rfunc=0x7AFEA1B040 27 | [+] dlsym RemoteFuncAddr:0x7afea1b040 28 | [+] [get_remote_func_addr] lmod=0x702E6BB000, rmod=0x7AFEA1A000, lfunc=0x702E6BC084, rfunc=0x7AFEA1B084 29 | [+] dlclose RemoteFuncAddr:0x7afea1b084 30 | [+] [get_remote_func_addr] lmod=0x702E6BB000, rmod=0x7AFEA1A000, lfunc=0x702E6BC02C, rfunc=0x7AFEA1B02C 31 | [+] dlerror RemoteFuncAddr:0x7afea1b02c 32 | [+] Get imports: dlopen: fea1b014, dlsym: fea1b040, dlclose: fea1b084, dlerror: fea1b02c 33 | [+] LibPath = /data/local/tmp/libHook.so 34 | [+] ptrace continue process success, pid:21968 35 | [+] ptrace call ret status is 2943 36 | [+] ptrace_call dlopen success, Remote Process load module Addr:0x1577767b54bbbe6f 37 | [+] func symbols is hello 38 | [+] Have func !! 39 | [+] ptrace continue process success, pid:21968 40 | [+] ptrace call ret status is 2943 41 | [+] ptrace_call dlsym success, Remote Process ModuleFunc Addr:0x7a0d7e0748 42 | [+] ptrace continue process success, pid:21968 43 | [+] ptrace call ret status is 2943 44 | [+] Recover Regs Success 45 | [+] detach process success, pid:21968 46 | [+] Finish Inject -------------------------------------------------------------------------------- /res/log_Android11_x86_succeed.txt: -------------------------------------------------------------------------------- 1 | [+] libc_path is /apex/com.android.runtime/lib/bionic/libc.so 2 | [+] linker_path is /apex/com.android.runtime/bin/linker 3 | [+] libdl_path is /apex/com.android.runtime/lib/bionic/libdl.so 4 | [+] system libs is OK 5 | [+] handle_selinux_init is OK 6 | [+] Start Inject 7 | [+] app_start_activity is bin.mt.plus/.Main 8 | [+] am start bin.mt.plus/.Main 9 | Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=bin.mt.plus/.Main } 10 | [+] pkg_name is bin.mt.plus 11 | [+] get_pid_by_name pid is 12332 12 | [+] lib_path is /data/local/tmp/libHook.so 13 | [+] symbols is hello 14 | [+] handle_parameter is OK 15 | [-] SELinux is Enforcing 16 | [+] Selinux has been changed to Permissive 17 | [+] attach porcess success, pid:12332 18 | [+] [get_remote_func_addr] lmod=0xEA0EF000, rmod=0xF33D7000, lfunc=0xEA17D1D0, rfunc=0xF34651D0 19 | [+] mmap RemoteFuncAddr:0xf34651d0 20 | [+] ptrace continue process success, pid:12332 21 | [+] ptrace call ret status is 2943 22 | [+] ptrace_call mmap success, return value=E657A000, pc=0 23 | [+] Remote Process Map Memory Addr:0xe657a000 24 | [+] linker_path value:/apex/com.android.runtime/bin/linker 25 | [+] [get_remote_func_addr] lmod=0xEA099000, rmod=0xF1661000, lfunc=0xEA09AA50, rfunc=0xF1662A50 26 | [+] dlopen RemoteFuncAddr:0xf1662a50 27 | [+] [get_remote_func_addr] lmod=0xEA099000, rmod=0xF1661000, lfunc=0xEA09AAB0, rfunc=0xF1662AB0 28 | [+] dlsym RemoteFuncAddr:0xf1662ab0 29 | [+] [get_remote_func_addr] lmod=0xEA099000, rmod=0xF1661000, lfunc=0xEA09AB40, rfunc=0xF1662B40 30 | [+] dlclose RemoteFuncAddr:0xf1662b40 31 | [+] [get_remote_func_addr] lmod=0xEA099000, rmod=0xF1661000, lfunc=0xEA09AA80, rfunc=0xF1662A80 32 | [+] dlerror RemoteFuncAddr:0xf1662a80 33 | [+] Get imports: dlopen: f1662a50, dlsym: f1662ab0, dlclose: f1662b40, dlerror: f1662a80 34 | [+] LibPath = /data/local/tmp/libHook.so 35 | [+] ptrace continue process success, pid:12332 36 | [+] ptrace call ret status is 2943 37 | [+] ptrace_call dlopen success, Remote Process load module Addr:0xcbd0795b 38 | [+] func symbols is hello 39 | [+] Have func !! 40 | [+] ptrace continue process success, pid:12332 41 | [+] ptrace call ret status is 2943 42 | [+] ptrace_call dlsym success, Remote Process ModuleFunc Addr:0xc421d5c0 43 | [+] ptrace continue process success, pid:12332 44 | [+] ptrace call ret status is 2943 45 | [+] Recover Regs Success 46 | [+] detach process success, pid:12332 47 | [+] SELinux has been rec 48 | [+] Finish Inject -------------------------------------------------------------------------------- /res/log_Android9_arm32_failed.txt: -------------------------------------------------------------------------------- 1 | [+] libc_path is /system/lib/libc.so 2 | [+] linker_path is /system/bin/linker 3 | [+] libdl_path is /system/lib/libdl.so 4 | [+] system libs is OK 5 | [+] handle_selinux_init is OK 6 | [+] Start Inject 7 | [+] app_start_activity is com.xiaoyou.ToramOnline.aligames.uu/com.xiaoyougame.toramquick.SplashActivity 8 | [+] am start com.xiaoyou.ToramOnline.aligames.uu/com.xiaoyougame.toramquick.SplashActivity 9 | Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.xiaoyou.ToramOnline.aligames.uu/com.xiaoyougame.toramquick.SplashActivity } 10 | [+] pkg_name is com.xiaoyou.ToramOnline.aligames.uu 11 | [+] get_pid_by_name pid is 12621 12 | [+] lib_path is /data/local/tmp/lobHook32.so 13 | [+] handle_parameter is OK 14 | [+] SELinux is Permissive or Disabled 15 | [+] attach porcess success, pid:12621 16 | [+] [get_remote_func_addr] lmod=0xF25C7000, rmod=0xE6588000, lfunc=0xF25F0235, rfunc=0xE65B1235 17 | [+] mmap RemoteFuncAddr:0xe65b1235 18 | [+] ptrace continue process success, pid:12621 19 | [+] ptrace call ret status is 2943 20 | [+] ptrace_call mmap success, return value=0, pc=E6588024 21 | [+] Remote Process Map Memory Addr:0x0 22 | [+] linker_path value:/system/bin/linker 23 | [+] [get_remote_func_addr] lmod=0xF26F0000, rmod=0xE4ECD000, lfunc=0xF26F0D15, rfunc=0xE4ECDD15 24 | [+] dlopen RemoteFuncAddr:0xe4ecdd15 25 | [+] [get_remote_func_addr] lmod=0xF26F0000, rmod=0xE4ECD000, lfunc=0xF26F0D27, rfunc=0xE4ECDD27 26 | [+] dlsym RemoteFuncAddr:0xe4ecdd27 27 | [+] [get_remote_func_addr] lmod=0xF26F0000, rmod=0xE4ECD000, lfunc=0xF26F0D43, rfunc=0xE4ECDD43 28 | [+] dlclose RemoteFuncAddr:0xe4ecdd43 29 | [+] [get_remote_func_addr] lmod=0xF26F0000, rmod=0xE4ECD000, lfunc=0xF26F0D1F, rfunc=0xE4ECDD1F 30 | [+] dlerror RemoteFuncAddr:0xe4ecdd1f 31 | [+] Get imports: dlopen: e4ecdd15, dlsym: e4ecdd27, dlclose: e4ecdd43, dlerror: e4ecdd1f 32 | [+] LibPath = /data/local/tmp/lobHook32.so 33 | [-] Write Remote Memory error, MemoryAddr:0x0, err:I/O error 34 | [-] Write LibPath:/data/local/tmp/lobHook32.so to RemoteProcess error 35 | [+] detach process success, pid:12621 36 | [-] Inject Erro -------------------------------------------------------------------------------- /res/log_Android9_arm64_succeed.txt: -------------------------------------------------------------------------------- 1 | [+] Start Inject 2 | [+] app_start_activity is bin.mt.plus/.Main 3 | [+] am start bin.mt.plus/.Main 4 | Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=bin.mt.plus/.Main } 5 | [+] pkg_name is bin.mt.plus 6 | [+] get_pid_by_name pid is 25990 7 | [+] lib_path is /data/local/tmp/libHook.so 8 | [+] symbols is hello 9 | [+] handle_parameter is OK 10 | [+] The state of the SELinux is Enforcing 11 | [-] SELinux is Enforcing 12 | [+] Selinux has been changed to Permissive 13 | [+] handle_selinux is OK 14 | [+] attach porcess success, pid:25990 15 | [+] [get_remote_func_addr] lmod=0x7E76D0C000, rmod=0x6FCB8D7000, lfunc=0x7E76D87428, rfunc=0x6FCB952428 16 | [+] mmap RemoteFuncAddr:0x6fcb952428 17 | [+] ptrace continue process success, pid:25990 18 | [+] ptrace call ret status is 1151 19 | [+] ptrace_call mmap success, return value=6FCB33D000, pc=6FCB8D7000 20 | [+] Remote Process Map Memory Addr:0x6fcb33d000 21 | [+] linker_path value:/system/bin/linker64 22 | [+] [get_remote_func_addr] lmod=0x7E76CCB000, rmod=0x6FCC080000, lfunc=0x7E76CCBEF8, rfunc=0x6FCC080EF8 23 | [+] dlopen RemoteFuncAddr:0x6fcc080ef8 24 | [+] [get_remote_func_addr] lmod=0x7E76CCB000, rmod=0x6FCC080000, lfunc=0x7E76CCBF24, rfunc=0x6FCC080F24 25 | [+] dlsym RemoteFuncAddr:0x6fcc080f24 26 | [+] [get_remote_func_addr] lmod=0x7E76CCB000, rmod=0x6FCC080000, lfunc=0x7E76CCBF68, rfunc=0x6FCC080F68 27 | [+] dlclose RemoteFuncAddr:0x6fcc080f68 28 | [+] [get_remote_func_addr] lmod=0x7E76CCB000, rmod=0x6FCC080000, lfunc=0x7E76CCBF10, rfunc=0x6FCC080F10 29 | [+] dlerror RemoteFuncAddr:0x6fcc080f10 30 | [+] Get imports: dlopen: cc080ef8, dlsym: cc080f24, dlclose: cc080f68, dlerror: cc080f10 31 | [+] LibPath = /data/local/tmp/libHook.so 32 | [+] ptrace continue process success, pid:25990 33 | [+] ptrace call ret status is 1151 34 | [+] ptrace_call dlopen success, Remote Process load module Addr:0x4d53e2726eff68e5 35 | [+] func symbols is hello 36 | [+] Have func !! 37 | [+] ptrace continue process success, pid:25990 38 | [+] ptrace call ret status is 1151 39 | [+] ptrace_call dlsym success, Remote Process ModuleFunc Addr:0x6f2a8b5748 40 | [+] ptrace continue process success, pid:25990 41 | [+] ptrace call ret status is 1151 42 | [+] Recover Regs Success 43 | [+] detach process success, pid:25990 44 | [+] SELinux has been rec 45 | [+] Finish Inject --------------------------------------------------------------------------------