├── README.md └── jni ├── Android.mk ├── Application.mk ├── InjectModule.c ├── PrintLog.h ├── ptraceInject.c └── ptraceInject.h /README.md: -------------------------------------------------------------------------------- 1 | [TOC] 2 | 3 | 4 | 5 | # 概述 6 | 7 | 本项目是基于arm平台的ptrace注入,可用于手游破解、外挂等领域。 8 | 9 | 10 | 11 | ## dlopen/dlsym原理 12 | 13 | 获取dlopen/dlsym函数在内存空间的地址,通过修改pc程序寄存器的值为获取的函数地址,就可以执行这两个函数,接着讲我们需要注入的so模块路径名写入参数寄存器中,即可完成so库的注入 14 | 15 | 16 | 17 | ## shellcode原理 18 | 19 | 和上面的思路基本一样,只是将dlopen/dlsym操作写到shellcode中,然后将函数地址,参数地址都写到shellcode的变量里,接着将shellcode映射进被注入进程内存,将pc寄存器指向shellcode在内存的起始地即可 20 | 21 | 22 | 23 | # 用法 24 | 25 | 1. clone jni目录 26 | 2. 修改InjectModule.c文件,更改里面的以下参数 27 | * InjectModuleName:被注入的模块绝对路径 28 | * RemoteCallFunc:需要被调用的模块函数 29 | * InjectProcessName:被注入的进程名 30 | 31 | 3. ndk-buil编译 32 | 33 | 4. ./inject 34 | 35 | 36 | 37 | # 模块 38 | 39 | ## ptraceInject.c 40 | 41 | 注入功能模块,所有注入用到的功能:ptrace附加、获取寄存器值等 42 | 43 | 44 | 45 | ## InjectModule.c 46 | 47 | 对外提供注入功能的可执行文件源码 48 | 49 | -------------------------------------------------------------------------------- /jni/Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir) 2 | 3 | include $(CLEAR_VARS) 4 | LOCAL_MODULE := inject 5 | LOCAL_SRC_FILES := ptraceInject.c InjectModule.c 6 | 7 | LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog 8 | 9 | include $(BUILD_EXECUTABLE) -------------------------------------------------------------------------------- /jni/Application.mk: -------------------------------------------------------------------------------- 1 | APP_ABI := armeabi-v7a -------------------------------------------------------------------------------- /jni/InjectModule.c: -------------------------------------------------------------------------------- 1 | /************************************************************ 2 | FileName: InjectModule.c 3 | Description: ptrace注入 4 | ***********************************************************/ 5 | 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 | /************************************************* 22 | Description: 通过进程名称定位到进程的PID 23 | Input: process_name为要定位的进程名称 24 | Output: 无 25 | Return: 返回定位到的进程PID,若为-1,表示定位失败 26 | Others: 无 27 | *************************************************/ 28 | pid_t FindPidByProcessName(const char *process_name) 29 | { 30 | int ProcessDirID = 0; 31 | pid_t pid = -1; 32 | FILE *fp = NULL; 33 | char filename[MAX_PATH] = {0}; 34 | char cmdline[MAX_PATH] = {0}; 35 | 36 | struct dirent * entry = NULL; 37 | 38 | if ( process_name == NULL ) 39 | return -1; 40 | 41 | DIR* dir = opendir( "/proc" ); 42 | if ( dir == NULL ) 43 | return -1; 44 | 45 | while( (entry = readdir(dir)) != NULL ) 46 | { 47 | ProcessDirID = atoi( entry->d_name ); 48 | if ( ProcessDirID != 0 ) 49 | { 50 | snprintf(filename, MAX_PATH, "/proc/%d/cmdline", ProcessDirID); 51 | fp = fopen( filename, "r" ); 52 | if ( fp ) 53 | { 54 | fgets(cmdline, sizeof(cmdline), fp); 55 | fclose(fp); 56 | 57 | if (strncmp(process_name, cmdline, strlen(process_name)) == 0) 58 | { 59 | pid = ProcessDirID; 60 | break; 61 | } 62 | } 63 | } 64 | } 65 | 66 | closedir(dir); 67 | return pid; 68 | } 69 | 70 | int main(int argc, char *argv[]) { 71 | char InjectModuleName[MAX_PATH] = "/data/libIHook.so"; // 注入模块全路径 72 | char RemoteCallFunc[MAX_PATH] = "ModifyIBored"; // 注入模块后调用模块函数名称 73 | char InjectProcessName[MAX_PATH] = "com.estoty.game2048"; // 注入进程名称 74 | 75 | // 当前设备环境判断 76 | #if defined(__i386__) 77 | LOGD("Current Environment x86"); 78 | return -1; 79 | #elif defined(__arm__) 80 | LOGD("Current Environment ARM"); 81 | #else 82 | LOGD("other Environment"); 83 | return -1; 84 | #endif 85 | 86 | pid_t pid = FindPidByProcessName(InjectProcessName); 87 | if (pid == -1) 88 | { 89 | printf("Get Pid Failed"); 90 | return -1; 91 | } 92 | 93 | printf("begin inject process, RemoteProcess pid:%d, InjectModuleName:%s, RemoteCallFunc:%s\n", pid, InjectModuleName, RemoteCallFunc); 94 | int iRet = inject_remote_process(pid, InjectModuleName, RemoteCallFunc, NULL, 0); 95 | //int iRet = inject_remote_process_shellcode(pid, InjectModuleName, RemoteCallFunc, NULL, 0); 96 | 97 | if (iRet == 0) 98 | { 99 | printf("Inject Success\n"); 100 | } 101 | else 102 | { 103 | printf("Inject Failed\n"); 104 | } 105 | printf("end inject,%d\n", pid); 106 | return 0; 107 | } -------------------------------------------------------------------------------- /jni/PrintLog.h: -------------------------------------------------------------------------------- 1 | #ifndef _ANDROID_LOG_PRINT_H_ 2 | #define _ANDROID_LOG_PRINT_H_ 3 | 4 | #include 5 | 6 | #define IS_DEBUG 7 | 8 | #ifdef IS_DEBUG 9 | 10 | #define LOG_TAG ("INJECT") 11 | 12 | #define LOGV(...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) 13 | 14 | #define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG , LOG_TAG, __VA_ARGS__)) 15 | 16 | #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO , LOG_TAG, __VA_ARGS__)) 17 | 18 | #define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN , LOG_TAG, __VA_ARGS__)) 19 | 20 | #define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR , LOG_TAG, __VA_ARGS__)) 21 | 22 | #else 23 | 24 | #define LOGV(LOG_TAG, ...) NULL 25 | 26 | #define LOGD(LOG_TAG, ...) NULL 27 | 28 | #define LOGI(LOG_TAG, ...) NULL 29 | 30 | #define LOGW(LOG_TAG, ...) NULL 31 | 32 | #define LOGE(LOG_TAG, ...) NULL 33 | 34 | #endif 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /jni/ptraceInject.c: -------------------------------------------------------------------------------- 1 | /******************************* 2 | * FileName: ptraceInject.c 3 | * Description: ptrace注入 4 | * *****************************/ 5 | 6 | 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 | #include 21 | 22 | #define CPSR_T_MASK ( 1u << 5 ) 23 | 24 | const char *libc_path = "/system/lib/libc.so"; 25 | const char *linker_path = "/system/bin/linker"; 26 | 27 | 28 | /*************************** 29 | * Description: 使用ptrace Attach附加到指定进程,发送SIGSTOP信号给指定进程让其停止下来并对其进行跟踪。 30 | * 但是被跟踪进程(tracee)不一定会停下来,因为同时attach和传递SIGSTOP可能会将SIGSTOP丢失。 31 | * 所以需要waitpid(2)等待被跟踪进程被停下 32 | * Input: pid表示远程进程的ID 33 | * Output: 无 34 | * Return: 返回0表示attach成功,返回-1表示失败 35 | * Others: 无 36 | * ************************/ 37 | int ptrace_attach(pid_t pid) 38 | { 39 | int status = 0; 40 | if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) 41 | { 42 | LOGD("ptrace attach error, pid:%d", pid); 43 | return -1; 44 | } 45 | 46 | LOGD("attach process pid:%d", pid); 47 | waitpid(pid, &status , WUNTRACED); 48 | return 0; 49 | } 50 | 51 | /************************************************* 52 | * Description: 使用ptrace detach指定进程,完成对指定进程的跟踪操作后,使用该参数即可解除附加 53 | * Input: pid表示远程进程的ID 54 | * Output: 无 55 | * Return: 返回0表示detach成功,返回-1表示失败 56 | * Others: 无 57 | * ***********************************************/ 58 | int ptrace_detach(pid_t pid) 59 | { 60 | if (ptrace(PTRACE_DETACH, pid, NULL, 0) < 0) 61 | { 62 | LOGD("detach process error, pid:%d", pid); 63 | return -1; 64 | } 65 | LOGD("detach process pid:%d", pid); 66 | return 0; 67 | } 68 | 69 | /************************************************* 70 | * Description: ptrace使远程进程继续运行 71 | * Input: pid表示远程进程的ID 72 | * Output: 无 73 | * Return: 返回0表示continue成功,返回-1表示失败 74 | * Others: 无 75 | * ***********************************************/ 76 | int ptrace_continue(pid_t pid) 77 | { 78 | if (ptrace(PTRACE_CONT, pid, NULL, NULL) < 0) 79 | { 80 | LOGD("ptrace cont error, pid:%d", pid); 81 | return -1; 82 | } 83 | return 0; 84 | } 85 | 86 | /************************************************* 87 | * Description: 使用ptrace获取远程进程的寄存器值 88 | * Input: pid表示远程进程的ID,regs为pt_regs结构,存储了寄存器值 89 | * Output: 无 90 | * Return: 返回0表示获取寄存器成功,返回-1表示失败 91 | * Others: 无 92 | * ***********************************************/ 93 | int ptrace_getregs(pid_t pid, struct pt_regs *regs) 94 | { 95 | if (ptrace(PTRACE_GETREGS, pid, NULL, regs) < 0) 96 | { 97 | LOGD("Get Regs error, pid:%d", pid); 98 | return -1; 99 | } 100 | return 0; 101 | } 102 | 103 | /************************************************* 104 | * Description: 使用ptrace设置远程进程的寄存器值 105 | * Input: pid表示远程进程的ID,regs为pt_regs结构,存储需要修改的寄存器值 106 | * Output: 无 107 | * Return: 返回0表示设置寄存器成功,返回-1表示失败 108 | * ***********************************************/ 109 | int ptrace_setregs(pid_t pid, struct pt_regs *regs) 110 | { 111 | if (ptrace(PTRACE_SETREGS, pid, NULL, regs) < 0) 112 | { 113 | LOGD("Set Regs error, pid:%d", pid); 114 | return -1; 115 | } 116 | return 0; 117 | } 118 | 119 | /************************************************* 120 | * Description: 获取返回值,ARM处理器中返回值存放在ARM_r0寄存器中 121 | * Input: regs存储远程进程当前的寄存器值 122 | * Return: 在ARM处理器下返回r0寄存器值 123 | * ***********************************************/ 124 | long ptrace_getret(struct pt_regs * regs) 125 | { 126 | return regs->ARM_r0; 127 | } 128 | 129 | /************************************************* 130 | * Description: 获取当前执行代码的地址,ARM处理器下存放在ARM_pc中 131 | * Input: regs存储远程进程当前的寄存器值 132 | * Return: 在ARM处理器下返回pc寄存器值 133 | * **********************************************/ 134 | long ptrace_getpc(struct pt_regs * regs) 135 | { 136 | return regs->ARM_pc; 137 | } 138 | 139 | /************************************************* 140 | * Description: 使用ptrace从远程进程内存中读取数据 141 | * Input: pid表示远程进程的ID,pSrcBuf表示从远程进程读取数据的内存地址 142 | * pDestBuf表示用于存储读取出数据的地址,size表示读取数据的大小 143 | * Return: 返回0表示读取数据成功 144 | * other: 这里的*_t类型是typedef定义一些基本类型的别名,用于跨平台。例如 145 | * uint8_t表示无符号8位也就是无符号的char类型 146 | * **********************************************/ 147 | int ptrace_readdata(pid_t pid, uint8_t *pSrcBuf, uint8_t *pDestBuf, uint32_t size) 148 | { 149 | uint32_t nReadCount = 0; 150 | uint32_t nRemainCount = 0; 151 | uint8_t *pCurSrcBuf = pSrcBuf; 152 | uint8_t *pCurDestBuf = pDestBuf; 153 | long lTmpBuf = 0; 154 | uint32_t i = 0; 155 | 156 | //每次读取4字节数据 157 | nReadCount = size / sizeof(long); 158 | nRemainCount = size % sizeof(long); 159 | for (i = 0; i < nReadCount; i++) 160 | { 161 | lTmpBuf = ptrace(PTRACE_PEEKTEXT, pid, pCurSrcBuf, 0); 162 | memcpy(pCurDestBuf, (char *)(&lTmpBuf), sizeof(long)); 163 | pCurSrcBuf += sizeof(long); 164 | pCurDestBuf += sizeof(long); 165 | } 166 | //当最后读取的字节不足4字节时调用 167 | if ( nRemainCount > 0 ) 168 | { 169 | lTmpBuf = ptrace(PTRACE_PEEKTEXT, pid, pCurSrcBuf, 0); 170 | memcpy(pCurDestBuf, (char *)(&lTmpBuf), nRemainCount); 171 | } 172 | return 0; 173 | } 174 | 175 | /************************************************* 176 | * Description: 使用ptrace将数据写入到远程进程空间中 177 | * Input: pid表示远程进程的ID,pWriteAddr表示写入数据到远程进程的内存地址 178 | * pWriteData用于存储写入数据的地址,size表示写入数据的大小 179 | * Return: 返回0表示写入数据成功,返回-1表示写入数据失败 180 | * ***********************************************/ 181 | int ptrace_writedata(pid_t pid, uint8_t *pWriteAddr, uint8_t *pWriteData, uint32_t size) 182 | { 183 | uint32_t nWriteCount = 0; 184 | uint32_t nRemainCount = 0; 185 | uint8_t *pCurSrcBuf = pWriteData; 186 | uint8_t *pCurDestBuf = pWriteAddr; 187 | long lTmpBuf = 0; 188 | uint32_t i = 0; 189 | 190 | nWriteCount = size / sizeof(long); 191 | nRemainCount = size % sizeof(long); 192 | 193 | //数据以sizeof(long)字节大小为单位写入到远程进程内存空间中 194 | for (i = 0; i < nWriteCount; i ++) 195 | { 196 | memcpy((void *)(&lTmpBuf), pCurSrcBuf, sizeof(long)); 197 | if (ptrace(PTRACE_POKETEXT, pid, pCurDestBuf, lTmpBuf) < 0) 198 | { 199 | LOGD("Write Remote Memory error, MemoryAddr:0x%lx", (long)pCurDestBuf); 200 | return -1; 201 | } 202 | pCurSrcBuf += sizeof(long); 203 | pCurDestBuf += sizeof(long); 204 | } 205 | if (nRemainCount > 0) 206 | { 207 | //lTmpBuf = ptrace(PTRACE_PEEKTEXT, pid, pCurDestBuf, NULL); 208 | memcpy((void *)(&lTmpBuf), pCurSrcBuf, nRemainCount); 209 | if (ptrace(PTRACE_POKETEXT, pid, pCurDestBuf, lTmpBuf) < 0) 210 | { 211 | LOGD("Write Remote Memory error, MemoryAddr:0x%lx", (long)pCurDestBuf); 212 | return -1; 213 | } 214 | } 215 | return 0; 216 | } 217 | 218 | /************************************************* 219 | * Description: 使用ptrace远程call函数 220 | * Input: pid表示远程进程的ID,ExecuteAddr为远程进程函数的地址 221 | * parameters为函数参数的地址,regs为远程进程call函数前的寄存器环境 222 | * Return: 返回0表示call函数成功,返回-1表示失败 223 | * **********************************************/ 224 | int ptrace_call(pid_t pid, uint32_t ExecuteAddr, long *parameters, long num_params, struct pt_regs* regs) 225 | { 226 | int i=0; 227 | // ARM处理器,函数传递参数,将前四个参数放到r0-r3,剩下的参数压入栈中 228 | for(i=0; iuregs[i] = parameters[i]; 231 | } 232 | if(i < num_params) 233 | { 234 | regs->ARM_sp -= (num_params - i) * sizeof(long); 235 | if (ptrace_writedata(pid, (void *)regs->ARM_sp, (uint8_t *)¶meters[i], (num_params - i) * sizeof(long)) == -1) 236 | { 237 | return -1; 238 | } 239 | } 240 | 241 | //修改程序计数器 242 | regs->ARM_pc = ExecuteAddr; 243 | 244 | //判断指令集 245 | // 与BX跳转指令类似,判断跳转的地址位[0]是否为1,如果为1,则将CPST寄存器的标志T置位,解释为Thumb代码 246 | if (regs->ARM_pc & 1) 247 | { 248 | /*Thumb*/ 249 | regs->ARM_pc &= (~1u); 250 | regs->ARM_cpsr |= CPSR_T_MASK; 251 | } 252 | else 253 | { 254 | /* ARM*/ 255 | regs->ARM_cpsr &= ~CPSR_T_MASK; 256 | } 257 | 258 | regs->ARM_lr = 0; 259 | 260 | //设置好寄存器后,开始运行进程 261 | if (ptrace_setregs(pid, regs) == -1 || ptrace_continue(pid) == -1) 262 | { 263 | LOGD("ptrace set regs or continue error, pid:%d", pid); 264 | return -1; 265 | } 266 | 267 | //对于ptrace_continue运行的进程,他会在三种情况下进入暂停状态:1.下一次系统调用 2.子进程出现异常 3.子进程退出 268 | //参数WUNTRACED表示当进程进入暂停状态后,立即返回 269 | //将存放返回地址的lr寄存器设置为0,执行返回的时候就会发生错误,从子进程暂停 270 | int stat = 0; 271 | waitpid(pid, &stat, WUNTRACED); 272 | LOGD("ptrace call ret status is %d\n", stat); 273 | //0xb7f表示子进程进入暂停状态 274 | while (stat != 0xb7f) 275 | { 276 | if (ptrace_continue(pid) == -1) 277 | { 278 | LOGD("ptrace call error"); 279 | return -1; 280 | } 281 | waitpid(pid, &stat, WUNTRACED); 282 | } 283 | // 获取远程进程的寄存器值,方便获取返回值 284 | if (ptrace_getregs(pid, regs) == -1) 285 | { 286 | LOGD("After call getregs error"); 287 | return -1; 288 | } 289 | return 0; 290 | } 291 | 292 | /************************************************* 293 | * Description: 在指定进程中搜索对应模块的基址 294 | * Input: pid表示远程进程的ID,若为-1表示自身进程,ModuleName表示要搜索的模块的名称 295 | * Return: 返回0表示获取模块基址失败,返回非0为要搜索的模块基址 296 | * **********************************************/ 297 | void* GetModuleBaseAddr(pid_t pid, const char* ModuleName) 298 | { 299 | char szFileName[50] = {0}; 300 | FILE *fp = NULL; 301 | char szMapFileLine[1024] = {0}; 302 | char *ModulePath, *MapFileLineItem; 303 | long ModuleBaseAddr = 0; 304 | 305 | // 读取"/proc/pid/maps"可以获得该进程加载的模块 306 | if (pid < 0) 307 | { 308 | snprintf(szFileName, sizeof(szFileName), "/proc/self/maps"); 309 | } 310 | else 311 | { 312 | snprintf(szFileName, sizeof(szFileName), "/proc/%d/maps", pid); 313 | } 314 | 315 | fp = fopen(szFileName, "r"); 316 | if (fp != NULL) 317 | { 318 | while (fgets(szMapFileLine, sizeof(szMapFileLine), fp)) 319 | { 320 | if (strstr(szMapFileLine, ModuleName)) 321 | { 322 | MapFileLineItem = strtok(szMapFileLine, " \t"); 323 | char *Addr = strtok(szMapFileLine, "-"); 324 | ModuleBaseAddr = strtoul(Addr, NULL, 16 ); 325 | 326 | if (ModuleBaseAddr == 0x8000) 327 | { 328 | ModuleBaseAddr = 0; 329 | } 330 | break; 331 | } 332 | } 333 | fclose(fp); 334 | } 335 | return (void *)ModuleBaseAddr; 336 | } 337 | 338 | /************************************************* 339 | * Description: 获取远程进程与本进程都加载的模块中函数的地址 340 | * Input: pid表示远程进程的ID,ModuleName表示模块名称,LocalFuncAddr表示本地进程中该函数的地址 341 | * Return: 返回远程进程中对应函数的地址 342 | * ***********************************************/ 343 | void* GetRemoteFuncAddr(pid_t pid, const char *ModuleName, void *LocalFuncAddr) 344 | { 345 | void *LocalModuleAddr, *RemoteModuleAddr, *RemoteFuncAddr; 346 | LocalModuleAddr = GetModuleBaseAddr(-1, ModuleName); 347 | RemoteModuleAddr = GetModuleBaseAddr(pid, ModuleName); 348 | RemoteFuncAddr = (void *)((long)LocalFuncAddr - (long)LocalModuleAddr + (long)RemoteModuleAddr); 349 | return RemoteFuncAddr; 350 | } 351 | 352 | /************************************************* 353 | * 通过远程直接调用dlopen\dlsym的方法ptrace注入so模块到远程进程中 354 | * Input: pid表示远程进程的ID,LibPath为被远程注入的so模块路径,FunctionName为远程注入的模块后调用的函数 355 | * FuncParameter指向被远程调用函数的参数(若传递字符串,需要先将字符串写入到远程进程空间中),NumParameter为参数的个数 356 | * Return: 返回0表示注入成功,返回-1表示失败 357 | * ***********************************************/ 358 | int inject_remote_process(pid_t pid, char *LibPath, char *FunctionName, long *FuncParameter, long NumParameter) 359 | { 360 | int iRet = -1; 361 | struct pt_regs CurrentRegs, OriginalRegs; 362 | void *mmap_addr, *dlopen_addr, *dlsym_addr, *dlclose_addr, *dlerror_addr; 363 | void *RemoteMapMemoryAddr, *RemoteModuleAddr, *RemoteModuleFuncAddr; 364 | long parameters[6]; 365 | 366 | /* 1. 附加到远程进程上*/ 367 | if (ptrace_attach(pid) == -1) 368 | { 369 | return iRet; 370 | } 371 | 372 | /* 2. 获取远程进程的寄存器值并保存下来,为了完成注入模块后的程序恢复执行做准备*/ 373 | if (ptrace_getregs(pid, &CurrentRegs) == -1) 374 | { 375 | ptrace_detach(pid); 376 | return iRet; 377 | } 378 | LOGD("ARM_r0:0x%lx, ARM_r1:0x%lx, ARM_r2:0x%lx, ARM_r3:0x%lx, ARM_r4:0x%lx, \ 379 | ARM_r5:0x%lx, ARM_r6:0x%lx, ARM_r7:0x%lx, ARM_r8:0x%lx, ARM_r9:0x%lx, \ 380 | ARM_r10:0x%lx, ARM_ip:0x%lx, ARM_sp:0x%lx, ARM_lr:0x%lx, ARM_pc:0x%lx", 381 | CurrentRegs.ARM_r0, CurrentRegs.ARM_r1, CurrentRegs.ARM_r2, CurrentRegs.ARM_r3, CurrentRegs.ARM_r4, 382 | CurrentRegs.ARM_r5, CurrentRegs.ARM_r6, CurrentRegs.ARM_r7, CurrentRegs.ARM_r8, CurrentRegs.ARM_r9, 383 | CurrentRegs.ARM_r10, CurrentRegs.ARM_ip, CurrentRegs.ARM_sp, CurrentRegs.ARM_lr, CurrentRegs.ARM_pc); 384 | memcpy(&OriginalRegs, &CurrentRegs, sizeof(CurrentRegs)); 385 | 386 | /* 3. 在远程进程内部开辟一遍内存空间存放一些常量数据,为远程进程执行函数调用提供参数地址 387 | * 这里需要知道,我们为什么不直接传递进去常量?这是因为我们现在传递的值是我们当前这个注入工具内存空间的值, 388 | * 相应的内存地址也是我们注入工具的,远程进程是访问不到的,所以我们需要将这些参数都在传递到远程进程空间中去*/ 389 | mmap_addr = GetRemoteFuncAddr(pid, libc_path, (void *)mmap); 390 | LOGD("mmap RemoteFuncAddr:0x%lx", (long)mmap_addr); 391 | 392 | //参数 393 | parameters[0] = 0;//设置NULL表示让系统自己选择内存位置进行分配 394 | parameters[1] = 0x1000;//分配内存空间大小为1个内存页 395 | parameters[2] = PROT_READ | PROT_WRITE | PROT_EXEC;//分配的内存区域的权限是可读、可写、可执行的 396 | parameters[3] = MAP_ANONYMOUS | MAP_PRIVATE;//匿名映射,表示不受文件支持,下面两个参数可以为0 397 | parameters[4] = 0;//文件标识符,这里为0表示不映射文件内容 398 | parameters[5] = 0;//文件映射偏移量 399 | 400 | //调用mmap函数 401 | if (ptrace_call(pid, (long)mmap_addr, parameters, 6, &CurrentRegs) == -1) 402 | { 403 | LOGD("Call Remote mmap Func Failed"); 404 | ptrace_detach(pid); 405 | return iRet; 406 | } 407 | 408 | //获取分配出的内存区域的地址 409 | RemoteMapMemoryAddr = (void *)ptrace_getret(&CurrentRegs); 410 | LOGD("Remote Process Map Memory Addr:0x%lx", (long)RemoteMapMemoryAddr); 411 | 412 | /* 4. 让远程进程执行dlopen加载so库到内存中。 413 | * 这里需要先将dlopen参数中的so库路径传递到远程进程的内存空间中,这样它调用dlopen的时候才可以从自己的内存空间中获取相应常量值*/ 414 | 415 | //在远程进程新开辟的内存空间中写入so库路径 416 | if (ptrace_writedata(pid, RemoteMapMemoryAddr, LibPath, strlen(LibPath) + 1) == -1) 417 | { 418 | LOGD("Write LibPath:%s to RemoteProcess error", LibPath); 419 | ptrace_detach(pid); 420 | return iRet; 421 | } 422 | 423 | //参数 424 | parameters[0] = (long)RemoteMapMemoryAddr; 425 | parameters[1] = RTLD_NOW| RTLD_GLOBAL; 426 | 427 | dlopen_addr = GetRemoteFuncAddr(pid, linker_path, (void *)dlopen); 428 | LOGD("dlopen RemoteFuncAddr:0x%lx", (long)dlopen_addr); 429 | dlerror_addr = GetRemoteFuncAddr(pid, linker_path, (void *)dlerror); 430 | LOGD("dlerror RemoteFuncAddr:0x%lx", (long)dlerror_addr); 431 | dlclose_addr = GetRemoteFuncAddr(pid, linker_path, (void *)dlclose); 432 | LOGD("dlclose RemoteFuncAddr:0x%lx", (long)dlclose_addr); 433 | if (ptrace_call(pid, (long)dlopen_addr, parameters, 2, &CurrentRegs) == -1) 434 | { 435 | LOGD("Call Remote dlopen Func Failed"); 436 | ptrace_detach(pid); 437 | return iRet; 438 | } 439 | 440 | //获取远程进程内存中被加载进去模块的地址 441 | RemoteModuleAddr = (void *)ptrace_getret(&CurrentRegs); 442 | LOGD("Remote Process load module Addr:0x%lx", (long)RemoteModuleAddr); 443 | 444 | // dlopen 错误 445 | if ((long)RemoteModuleAddr == 0x0) 446 | { 447 | LOGD("dlopen error"); 448 | if (ptrace_call(pid, (long)dlerror_addr, parameters, 0, &CurrentRegs) == -1) 449 | { 450 | LOGD("Call Remote dlerror Func Failed"); 451 | ptrace_detach(pid); 452 | return iRet; 453 | } 454 | char *Error = (void *)ptrace_getret(&CurrentRegs); 455 | char LocalErrorInfo[1024] = {0}; 456 | ptrace_readdata(pid, Error, LocalErrorInfo, 1024); 457 | LOGD("dlopen error:%s", LocalErrorInfo); 458 | ptrace_detach(pid); 459 | return iRet; 460 | } 461 | 462 | /* 5.远程进程调用被加载进去模块的函数。 463 | * 先将参数传递进远程进程空间,然后利用dlsym函数搜索函数位置,最后在进行调用*/ 464 | if (ptrace_writedata(pid, RemoteMapMemoryAddr + strlen(LibPath) + 2, FunctionName, strlen(FunctionName) + 1) == -1) 465 | { 466 | LOGD("Write FunctionName:%s to RemoteProcess error", FunctionName); 467 | ptrace_detach(pid); 468 | return iRet; 469 | } 470 | 471 | //设置dlsym参数 472 | parameters[0] = (long)RemoteModuleAddr; 473 | parameters[1] = (long)(RemoteMapMemoryAddr + strlen(LibPath) + 2); 474 | LOGD("Func Name:%x\n", parameters[1]); 475 | 476 | //调用dlsym函数并获取返回的函数地址 477 | dlsym_addr = GetRemoteFuncAddr(pid, linker_path, (void *)dlsym); 478 | LOGD("dlsym RemoteFuncAddr:0x%lx", (long)dlsym_addr); 479 | if (ptrace_call(pid, (long)dlsym_addr, parameters, 2, &CurrentRegs) == -1) 480 | { 481 | LOGD("Call Remote dlsym Func Failed"); 482 | ptrace_detach(pid); 483 | return iRet; 484 | } 485 | RemoteModuleFuncAddr = (void *)ptrace_getret(&CurrentRegs); 486 | LOGD("Remote Process ModuleFunc Addr:0x%lx", (long)RemoteModuleFuncAddr); 487 | 488 | /* 6. 在远程进程中调用加载进去模块的函数,这里为了简单起见,没有选择传入参数,所以省去写入参数到远程进空间的步骤*/ 489 | if (ptrace_call(pid, (long)RemoteModuleFuncAddr, FuncParameter, NumParameter, &CurrentRegs) == -1) 490 | { 491 | LOGD("Call Remote injected Func Failed"); 492 | ptrace_detach(pid); 493 | return iRet; 494 | } 495 | 496 | /* 7. 恢复远程进程的执行操作*/ 497 | if (ptrace_setregs(pid, &OriginalRegs) == -1) 498 | { 499 | LOGD("Recover reges failed"); 500 | ptrace_detach(pid); 501 | return iRet; 502 | } 503 | LOGD("Recover Regs Success"); 504 | ptrace_getregs(pid, &CurrentRegs); 505 | if (memcmp(&OriginalRegs, &CurrentRegs, sizeof(CurrentRegs)) != 0) 506 | { 507 | LOGD("Set Regs Error"); 508 | } 509 | 510 | if (ptrace_detach(pid) == -1) 511 | { 512 | LOGD("ptrace detach failed"); 513 | return iRet; 514 | } 515 | 516 | return 0; 517 | } 518 | 519 | /************************************************* 520 | Description: 通过shellcode方式ptrace注入so模块到远程进程中 521 | Input: pid表示远程进程的ID,LibPath为被远程注入的so模块路径,FunctionName为远程注入的模块后调用的函数 522 | FuncParameter指向被远程调用函数的参数(若传递字符串,需要先将字符串写入到远程进程空间中),NumParameter为参数的个数 523 | Output: 无 524 | Return: 返回0表示注入成功,返回-1表示失败 525 | Others: 无 526 | *************************************************/ 527 | int inject_remote_process_shellcode(pid_t pid, char *LibPath, char *FunctionName, long *FuncParameter, long NumParameter) 528 | { 529 | int iRet = -1; 530 | struct pt_regs CurrentRegs, OriginalRegs; // CurrentRegs表示远程进程中当前的寄存器值,OriginalRegs存储注入前的寄存器值,方便恢复 531 | void *mmap_addr, *dlopen_addr, *dlsym_addr, *dlclose_addr, *dlerror_addr; // 远程进程中需要调用函数的地址 532 | void *RemoteMapMemoryAddr, *RemoteModuleAddr, *RemoteModuleFuncAddr; // RemoteMapMemoryAddr为远程进程空间中映射的内存基址,RemoteModuleAddr为远程注入的so模块加载基址,RemoteModuleFuncAddr为注入模块中需要调用的函数地址 533 | long parameters[10]; 534 | int i; 535 | 536 | uint8_t *dlopen_param1_ptr, *dlsym_param2_ptr, *saved_r0_pc_ptr, *inject_param_ptr, *remote_code_start_ptr, *local_code_start_ptr, *local_code_end_ptr; 537 | 538 | extern uint32_t _dlopen_addr_s, _dlopen_param1_s, _dlopen_param2_s, _dlsym_addr_s, \ 539 | _dlsym_param2_s, _dlclose_addr_s, _inject_start_s, _inject_end_s, _inject_function_param_s, \ 540 | _saved_cpsr_s, _saved_r0_pc_s; 541 | 542 | uint32_t code_length; 543 | 544 | // Attach远程进程 545 | if (ptrace_attach(pid) == -1) 546 | return iRet; 547 | 548 | // 获取远程进程的寄存器值 549 | if (ptrace_getregs(pid, &CurrentRegs) == -1) 550 | { 551 | ptrace_detach(pid); 552 | return iRet; 553 | } 554 | 555 | LOGD("ARM_r0:0x%lx, ARM_r1:0x%lx, ARM_r2:0x%lx, ARM_r3:0x%lx, ARM_r4:0x%lx, ARM_r5:0x%lx, ARM_r6:0x%lx, ARM_r7:0x%lx, ARM_r8:0x%lx, ARM_r9:0x%lx, ARM_r10:0x%lx, ARM_ip:0x%lx, ARM_sp:0x%lx, ARM_lr:0x%lx, ARM_pc:0x%lx", \ 556 | CurrentRegs.ARM_r0, CurrentRegs.ARM_r1, CurrentRegs.ARM_r2, CurrentRegs.ARM_r3, CurrentRegs.ARM_r4, CurrentRegs.ARM_r5, CurrentRegs.ARM_r6, CurrentRegs.ARM_r7, CurrentRegs.ARM_r8, CurrentRegs.ARM_r9, CurrentRegs.ARM_r10, CurrentRegs.ARM_ip, CurrentRegs.ARM_sp, CurrentRegs.ARM_lr, CurrentRegs.ARM_pc); 557 | 558 | // 保存远程进程空间中当前的上下文寄存器环境 559 | memcpy(&OriginalRegs, &CurrentRegs, sizeof(CurrentRegs)); 560 | 561 | // 获取mmap函数在远程进程中的地址 562 | mmap_addr = GetRemoteFuncAddr(pid, libc_path, (void *)mmap); 563 | LOGD("mmap RemoteFuncAddr:0x%lx", (long)mmap_addr); 564 | 565 | // 设置mmap的参数 566 | // void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offsize); 567 | parameters[0] = 0; // 设置为NULL表示让系统自动选择分配内存的地址 568 | parameters[1] = 0x4000; // 映射内存的大小 569 | parameters[2] = PROT_READ | PROT_WRITE | PROT_EXEC; // 表示映射内存区域可读可写可执行 570 | parameters[3] = MAP_ANONYMOUS | MAP_PRIVATE; // 建立匿名映射 571 | parameters[4] = 0; // 若需要映射文件到内存中,则为文件的fd 572 | parameters[5] = 0; //文件映射偏移量 573 | 574 | // 调用远程进程的mmap函数,建立远程进程的内存映射 575 | if (ptrace_call(pid, (long)mmap_addr, parameters, 6, &CurrentRegs) == -1) 576 | { 577 | LOGD("Call Remote mmap Func Failed"); 578 | ptrace_detach(pid); 579 | return iRet; 580 | } 581 | 582 | // 获取mmap函数执行后的返回值,也就是内存映射的起始地址 583 | RemoteMapMemoryAddr = (void *)ptrace_getret(&CurrentRegs); 584 | LOGD("Remote Process Map Memory Addr:0x%lx", (long)RemoteMapMemoryAddr); 585 | 586 | // 分别获取dlopen、dlsym、dlclose等函数的地址 587 | dlopen_addr = GetRemoteFuncAddr(pid, linker_path, (void *)dlopen); 588 | dlsym_addr = GetRemoteFuncAddr(pid, linker_path, (void *)dlsym); 589 | dlclose_addr = GetRemoteFuncAddr(pid, linker_path, (void *)dlclose); 590 | dlerror_addr = GetRemoteFuncAddr(pid, linker_path, (void *)dlerror); 591 | 592 | LOGD("dlopen RemoteFuncAddr:0x%lx", (long)dlopen_addr); 593 | LOGD("dlsym RemoteFuncAddr:0x%lx", (long)dlsym_addr); 594 | LOGD("dlclose RemoteFuncAddr:0x%lx", (long)dlclose_addr); 595 | LOGD("dlerror RemoteFuncAddr:0x%lx", (long)dlerror_addr); 596 | 597 | remote_code_start_ptr = RemoteMapMemoryAddr;// + 0x1000; //+ 0x3C00; // 远程进程中存放shellcode代码的起始地址 598 | local_code_start_ptr = (uint8_t *)&_inject_start_s; // 本地进程中shellcode的起始地址 599 | local_code_end_ptr = (uint8_t *)&_inject_end_s; // 本地进程中shellcode的结束地址 600 | 601 | _dlopen_addr_s = (uint32_t)dlopen_addr; 602 | _dlsym_addr_s = (uint32_t)dlsym_addr; 603 | _dlclose_addr_s = (uint32_t)dlclose_addr; 604 | 605 | LOGD("Inject Code Start:0x%x, end:0x%x", (int)local_code_start_ptr, (int)local_code_end_ptr); 606 | 607 | // 计算shellcode中一些变量的存放起始地址 608 | code_length = (uint32_t)&_inject_end_s - (uint32_t)&_inject_start_s; 609 | LOGD("Inject Code length: %d", code_length); 610 | dlopen_param1_ptr = local_code_start_ptr + code_length;// + 0x20; 611 | LOGD("local dlopen first parameter addr is 0x%x", dlopen_param1_ptr); 612 | dlsym_param2_ptr = dlopen_param1_ptr + MAX_PATH; 613 | LOGD("local dlsym second parameter addr is 0x%x", dlsym_param2_ptr); 614 | saved_r0_pc_ptr = dlsym_param2_ptr + MAX_PATH; 615 | inject_param_ptr = saved_r0_pc_ptr + MAX_PATH; 616 | 617 | // 写入dlopen的参数LibPath 618 | strcpy( dlopen_param1_ptr, LibPath ); 619 | _dlopen_param1_s = REMOTE_ADDR( dlopen_param1_ptr, local_code_start_ptr, remote_code_start_ptr ); 620 | LOGD("Remote dlopen first parameter addr is 0x%x", _dlopen_param1_s); 621 | 622 | // 写入dlsym的第二个参数,需要调用的函数名称 623 | strcpy( dlsym_param2_ptr, FunctionName ); 624 | _dlsym_param2_s = REMOTE_ADDR( dlsym_param2_ptr, local_code_start_ptr, remote_code_start_ptr ); 625 | LOGD("Remote dlsym second parameter addr is 0x%x", _dlsym_param2_s); 626 | 627 | //保存cpsr寄存器 628 | _saved_cpsr_s = OriginalRegs.ARM_cpsr; 629 | 630 | //保存r0-pc寄存器 631 | memcpy( saved_r0_pc_ptr, &(OriginalRegs.ARM_r0), 16 * 4 ); // r0 ~ r15 632 | _saved_r0_pc_s = REMOTE_ADDR( saved_r0_pc_ptr, local_code_start_ptr, remote_code_start_ptr ); 633 | LOGD("Remote r0-pc registers addr is 0x%x", _saved_r0_pc_s); 634 | 635 | memcpy( inject_param_ptr, FuncParameter, NumParameter ); 636 | _inject_function_param_s = REMOTE_ADDR( inject_param_ptr, local_code_start_ptr, remote_code_start_ptr ); 637 | LOGD("My fuction parameter addr is 0x%x", _inject_function_param_s); 638 | 639 | ptrace_writedata( pid, remote_code_start_ptr, local_code_start_ptr, 0x400 ); 640 | LOGD("wriate data complete"); 641 | 642 | memcpy( &CurrentRegs, &OriginalRegs, sizeof(CurrentRegs) ); 643 | LOGD("cpoy register addr complete"); 644 | // CurrentRegs.ARM_sp = (long)remote_code_start_ptr; 645 | CurrentRegs.ARM_pc = (long)remote_code_start_ptr; 646 | ptrace_setregs( pid, &CurrentRegs ); 647 | LOGD("set register addr complete"); 648 | ptrace_detach( pid ); 649 | LOGD("injected complete"); 650 | return 0; 651 | -------------------------------------------------------------------------------- /jni/ptraceInject.h: -------------------------------------------------------------------------------- 1 | /********************************** 2 | * FileName: ptraceInject.h 3 | * Decription: ptrace注入 4 | * ********************************/ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #define MAX_PATH 0x100 11 | 12 | /* 功能1:通过ptrace远程调用dlopen/dlsym方式注入模块到远程进程 */ 13 | int inject_remote_process(pid_t pid, char *LibPath, char *FunctionName, long *FuncParameter, long NumParameter); 14 | 15 | /* 功能2:通过shellcode方式注入模块到远程进程*/ 16 | int inject_remote_process_shellcode(pid_t pid, char *LibPath, char *FunctionName, long *FuncParameter, long NumParameter); 17 | --------------------------------------------------------------------------------