android_ptrace_inject

##0x1 前文
注入,Windows平台下一个极其有意思的一门技术,作为绝大多数Hook方案的前奏,当然是各种姿势都有,限于本人能力之有限,会逐渐记录移动端安全相关的学习过程,也希望看到本篇的朋友,能学到一些东西。废话不说了,走起!(以下代码可能存在高度风险性,请勿用于非法用途,一切使用中造成的任何后果,均与本人以及所参考的文章作者无关,继续阅读默认你同意且遵守本括号中的描述)

##0x2 ptrace
ptrace是linux系统下用于调试进程用的,具体描述如下:

AME
ptrace - process trace
SYNOPSIS
#include <sys/ptrace.h>
long ptrace(enum __ptrace_request request, pid_t pid,
void *addr, void *data);
DESCRIPTION
The ptrace() system call provides a means by which one process (the "tracer") may observe and control the execution of another process (the "tracee"), and examine and change the tracee's memory and registers. It is primarily used to implement breakpoint debugging and system call tracing.

重点在于第一个参数,可取的值如下

PTRACE_ME
PTRACE_PEEKTEXT
PTRACE_PEEKDATA
PTRACE_PEEKUSER
PTRACE_POKETEXT
PTRACE_POKEDATA
PTRACE_POKEUSER
PTRACE_GETREGS
PTRACE_GETFPREGS,
PTRACE_SETREGS
PTRACE_SETFPREGS
PTRACE_CONT
PTRACE_SYSCALL,
PTRACE_SINGLESTEP
PTRACE_DETACH

0x3 ptrace注入原理

ptrace注入的原理就是,首先attach到指定进程,这里需要给一个进程的pid,然后通过修改 IP ,指向一段load so的代码,之后获取要执行的函数地址,然后转入执行。大致有两种方式实现:一种是调用dlopen\dlsym然后执行到我们的so模块内,第二种是直接注入一段shellcode。
类似于 Windows 下的debug模式进程的注入 ,具体可以参考 http://blog.csdn.net/wowolook/article/details/10055329

0x4 测试截图

首先将编译好的inject 程序拷贝到 /data目录下(android虚拟机或者实体机,需要root权限) ,之后使用 chmod 777 inject,然后输入 ./inject回车

注入成功!

日志

需要注意本代码中注入的进程是 com.example.yllen.myapplication,所以当前进程列表中是要存在这个的,实际测试中可以替换为你需要注入的进程名称,或者可以稍微改改支持命令行输入进程名称的,想必聪明的你肯定分分钟搞定。

##0x5 注入流程

1. ptrace_attach(pid) 附加到进程
2. ptrace_getregs(pid,&CurrentRegs) 保存主线程上下文
3. GetRemoteFuncAddr(pid,libc_path,(void*)mmap); 获取mmap的地址,用来分配一段内存,主要存放so路径、要执行的远程函数名称
4.设置mmap的参数,然后调用
5.获取 dlopen、dlsym、dlclose、dlerror函数的地址
// 分别获取dlopen、dlsym、dlclose等函数的地址
dlopen_addr = GetRemoteFuncAddr(pid, linker_path, (void *)dlopen);
dlsym_addr = GetRemoteFuncAddr(pid, linker_path, (void *)dlsym);
dlclose_addr = GetRemoteFuncAddr(pid, linker_path, (void *)dlclose);
dlerror_addr = GetRemoteFuncAddr(pid, linker_path, (void *)dlerror);
6. ptrace_writedata(pid,RemoteMapMemoryAddr,LibPath,strlen(LibPath)+1) 写入要注入的so文件路径
7.设置dlopen函数的参数,然后调用,读取返回值(r0)得到起始地址
8.ptrace_writedata(pid, RemoteMapMemoryAddr + strlen(LibPath) + 2, FunctionName, strlen(FunctionName) + 1) 吸入要执行的函数地址,然后调用dlsym,通过读取返回值(r0)得到函数地址
9.传递参数(如果有),调用函数
10. 通过上述步骤,使得自己的函数在指定进程内执行,之后调用ptrace_detach断开进程连接
注:上文所述的ptrace_xx函数都是封装好的ptrace功能函数

##0x6 源代码

下面就是源码了。
源文件由4个部分组成,分别为inject.h 、inject.c、main.c、PrintLog.h构成

  1. inject.h 、inject.c 注入功能
  2. main.c 发起注入
  3. PrintLog.h 打印日志的封装

由于本人对arm汇编并不熟练,所以shellcode版的代码就不贴了,等日后逐渐熟练会一一进行分析。

以下代码为dlopen/dlsym 版ptrace 注入,至于如何防御,等以后有机会再补充。

先是简单的 PrintLog.h

/*PrintLog.h*/
#ifndef _ANDROID_LOG_PRINT_H_
#define _ANDROID_LOG_PRINT_H_
#include <android/log.h>
#define IS_DEBUG
#ifdef IS_DEBUG
#define LOG_TAG ("INJECT")
#define LOGV(...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
#define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG , LOG_TAG, __VA_ARGS__))
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO , LOG_TAG, __VA_ARGS__))
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN , LOG_TAG, __VA_ARGS__))
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR , LOG_TAG, __VA_ARGS__))
#else
#define LOGV(LOG_TAG, ...) NULL
#define LOGD(LOG_TAG, ...) NULL
#define LOGI(LOG_TAG, ...) NULL
#define LOGW(LOG_TAG, ...) NULL
#define LOGE(LOG_TAG, ...) NULL
#endif
#endif

接下来是 inject.h

/*inject.h */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define MAX_PATH 0x100
// dlopen dlsym 注入
int inject_remote_process(pid_t pid,char* LibPath,char* FunctionName,long* FuncParameter ,long NumParameter);

/*inject.c*/
#include <stdio.h>
#include <stdlib.h>
#include <asm/user.h>
#include <asm/ptrace.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <dlfcn.h>
#include <dirent.h>
#include <unistd.h>
#include <string.h>
#include <elf.h>
#include <utils/PrintLog.h>
#include <inject.h>
#define CPSR_T_MASK ( 1u << 5 )
const char *libc_path = "/system/lib/libc.so";
const char *linker_path = "/system/bin/linker";
/*************************************************
Description: ptrace使远程进程继续运行
Input: pid表示远程进程的ID
Output: 无
Return: 返回0表示continue成功,返回-1表示失败
Others: 无
*************************************************/
int ptrace_continue(pid_t pid)
{
if (ptrace(PTRACE_CONT, pid, NULL, NULL) < 0)
{
LOGD("ptrace cont error, pid:%d", pid);
return -1;
}
return 0;
}
/*************************************************
Description: 使用ptrace Attach到指定进程
Input: pid表示远程进程的ID
Output: 无
Return: 返回0表示attach成功,返回-1表示失败
Others: 无
*************************************************/
int ptrace_attach(pid_t pid)
{
int status = 0;
if (ptrace(PTRACE_ATTACH, pid, NULL, 0) < 0) {
LOGD("attach process error, pid:%d", pid);
return -1;
}
LOGD("attach process pid:%d", pid);
waitpid(pid, &status , WUNTRACED);
return 0;
}
/*************************************************
Description: 使用ptrace detach指定进程
Input: pid表示远程进程的ID
Output: 无
Return: 返回0表示detach成功,返回-1表示失败
Others: 无
*************************************************/
int ptrace_detach(pid_t pid)
{
if (ptrace(PTRACE_DETACH, pid, NULL, 0) < 0) {
LOGD("detach process error, pid:%d", pid);
return -1;
}
LOGD("detach process pid:%d", pid);
return 0;
}
/*************************************************
Description: 使用ptrace获取远程进程的寄存器值
Input: pid表示远程进程的ID,regs为pt_regs结构,存储了寄存器值
Output: 无
Return: 返回0表示获取寄存器成功,返回-1表示失败
Others: 无
*************************************************/
int ptrace_getregs(pid_t pid, struct pt_regs *regs)
{
if (ptrace(PTRACE_GETREGS, pid, NULL, regs) < 0)
{
LOGD("Get Regs error, pid:%d", pid);
return -1;
}
return 0;
}
/*************************************************
Description: 使用ptrace设置远程进程的寄存器值
Input: pid表示远程进程的ID,regs为pt_regs结构,存储需要修改的寄存器值
Output: 无
Return: 返回0表示设置寄存器成功,返回-1表示失败
Others: 无
*************************************************/
int ptrace_setregs(pid_t pid, struct pt_regs *regs)
{
if (ptrace(PTRACE_SETREGS, pid, NULL, regs) < 0)
{
LOGD("Set Regs error, pid:%d", pid);
return -1;
}
return 0;
}
/*************************************************
Description: 获取返回值,ARM处理器中返回值存放在ARM_r0寄存器中
Input: regs存储远程进程当前的寄存器值
Output: 无
Return: 在ARM处理器下返回r0寄存器值
Others: 无
*************************************************/
long ptrace_getret(struct pt_regs * regs)
{
return regs->ARM_r0;
}
/*************************************************
Description: 获取当前执行代码的地址,ARM处理器下存放在ARM_pc中
Input: regs存储远程进程当前的寄存器值
Output: 无
Return: 在ARM处理器下返回pc寄存器值
Others: 无
*************************************************/
long ptrace_getpc(struct pt_regs * regs)
{
return regs->ARM_pc;
}
/*************************************************
Description: 使用ptrace从远程进程内存中读取数据
Input: pid表示远程进程的ID,pSrcBuf表示从远程进程读取数据的内存地址
pDestBuf表示用于存储读取出数据的地址,size表示读取数据的大小
Output: 无
Return: 返回0表示读取数据成功
Others: 无
*************************************************/
int ptrace_readdata(pid_t pid, uint8_t *pSrcBuf, uint8_t *pDestBuf, uint32_t size)
{
uint32_t nReadCount = 0;
uint32_t nRemainCount = 0;
uint8_t *pCurSrcBuf = pSrcBuf;
uint8_t *pCurDestBuf = pDestBuf;
long lTmpBuf = 0;
uint32_t i = 0;
nReadCount = size / sizeof(long);
nRemainCount = size % sizeof(long);
for (i = 0; i < nReadCount; i ++ )
{
lTmpBuf = ptrace(PTRACE_PEEKTEXT, pid, pCurSrcBuf, 0);
memcpy(pCurDestBuf, (char *)(&lTmpBuf), sizeof(long));
pCurSrcBuf += sizeof(long);
pCurDestBuf += sizeof(long);
}
if ( nRemainCount > 0 )
{
lTmpBuf = ptrace(PTRACE_PEEKTEXT, pid, pCurSrcBuf, 0);
memcpy(pCurDestBuf, (char *)(&lTmpBuf), nRemainCount);
}
return 0;
}
//
/*************************************************
Description: 使用ptrace将数据写入到远程进程空间中
Input: pid表示远程进程的ID,pWriteAddr表示写入数据到远程进程的内存地址
pWriteData用于存储写入数据的地址,size表示写入数据的大小
Output: 无
Return: 返回0表示写入数据成功,返回-1表示写入数据失败
Others: 无
*************************************************/
int ptrace_writedata(pid_t pid, uint8_t *pWriteAddr, uint8_t *pWriteData, uint32_t size)
{
uint32_t nWriteCount = 0;
uint32_t nRemainCount = 0;
uint8_t *pCurSrcBuf = pWriteData;
uint8_t *pCurDestBuf = pWriteAddr;
long lTmpBuf = 0;
uint32_t i = 0;
nWriteCount = size / sizeof(long);
nRemainCount = size % sizeof(long);
// 先讲数据以sizeof(long)字节大小为单位写入到远程进程内存空间中
for (i = 0; i < nWriteCount; i ++)
{
memcpy((void *)(&lTmpBuf), pCurSrcBuf, sizeof(long));
if (ptrace(PTRACE_POKETEXT, pid, pCurDestBuf, lTmpBuf) < 0) // PTRACE_POKETEXT表示从远程内存空间写入一个sizeof(long)大小的数据
{
LOGD("Write Remote Memory error, MemoryAddr:0x%lx", (long)pCurDestBuf);
return -1;
}
pCurSrcBuf += sizeof(long);
pCurDestBuf += sizeof(long);
}
// 将剩下的数据写入到远程进程内存空间中
if (nRemainCount > 0)
{
lTmpBuf = ptrace(PTRACE_PEEKTEXT, pid, pCurDestBuf, NULL); //先取出原内存中的数据,然后将要写入的数据以单字节形式填充到低字节处
memcpy((void *)(&lTmpBuf), pCurSrcBuf, nRemainCount);
if (ptrace(PTRACE_POKETEXT, pid, pCurDestBuf, lTmpBuf) < 0)
{
LOGD("Write Remote Memory error, MemoryAddr:0x%lx", (long)pCurDestBuf);
return -1;
}
}
return 0;
}
/*************************************************
Description: 使用ptrace远程call函数
Input: pid表示远程进程的ID,ExecuteAddr为远程进程函数的地址
parameters为函数参数的地址,regs为远程进程call函数前的寄存器环境
Output: 无
Return: 返回0表示call函数成功,返回-1表示失败
Others: 无
*************************************************/
int ptrace_call(pid_t pid, uint32_t ExecuteAddr, long *parameters, long num_params, struct pt_regs* regs)
{
int i = 0;
// ARM处理器,函数传递参数,将前四个参数放到r0-r3,剩下的参数压入栈中
for (i = 0; i < num_params && i < 4; i ++) {
regs->uregs[i] = parameters[i];
}
if (i < num_params) {
regs->ARM_sp -= (num_params - i) * sizeof(long) ; // 分配栈空间,栈的方向是从高地址到低地址
if (ptrace_writedata(pid, (void *)regs->ARM_sp, (uint8_t *)&parameters[i], (num_params - i) * sizeof(long)) == -1)
return -1;
}
regs->ARM_pc = ExecuteAddr; //设置ARM_pc寄存器为需要调用的函数地址
// 与BX跳转指令类似,判断跳转的地址位[0]是否为1,如果为1,则将CPST寄存器的标志T置位,解释为Thumb代码
// 若为0,则将CPSR寄存器的标志T复位,解释为ARM代码
if (regs->ARM_pc & 1) {
/* thumb */
regs->ARM_pc &= (~1u);
regs->ARM_cpsr |= CPSR_T_MASK;
} else {
/* arm */
regs->ARM_cpsr &= ~CPSR_T_MASK;
}
regs->ARM_lr = 0;
if (ptrace_setregs(pid, regs) == -1 || ptrace_continue(pid) == -1) {
LOGD("ptrace set regs or continue error, pid:%d", pid);
return -1;
}
int stat = 0;
// 对于使用ptrace_cont运行的子进程,它会在3种情况下进入暂停状态:①下一次系统调用;②子进程退出;③子进程的执行发生错误。
// 参数WUNTRACED表示当进程进入暂停状态后,立即返回
// 将ARM_lr(存放返回地址)设置为0,会导致子进程执行发生错误,则子进程进入暂停状态
waitpid(pid, &stat, WUNTRACED);
// 判断是否成功执行函数
LOGD("ptrace call ret status is %d\n", stat);
while (stat != 0xb7f) {
if (ptrace_continue(pid) == -1) {
LOGD("ptrace call error");
return -1;
}
waitpid(pid, &stat, WUNTRACED);
}
// 获取远程进程的寄存器值,方便获取返回值
if (ptrace_getregs(pid, regs) == -1)
{
LOGD("After call getregs error");
return -1;
}
return 0;
}
/*************************************************
Description: 在指定进程中搜索对应模块的基址
Input: pid表示远程进程的ID,若为-1表示自身进程,ModuleName表示要搜索的模块的名称
Output: 无
Return: 返回0表示获取模块基址失败,返回非0为要搜索的模块基址
Others: 无
*************************************************/
void* GetModuleBaseAddr(pid_t pid, const char* ModuleName)
{
FILE *fp = NULL;
long ModuleBaseAddr = 0;
char *ModulePath, *MapFileLineItem;
char szFileName[50] = {0};
char szMapFileLine[1024] = {0};
char szProcessInfo[1024] = {0};
// 读取"/proc/pid/maps"可以获得该进程加载的模块
if (pid < 0) {
// 枚举自身进程模块
snprintf(szFileName, sizeof(szFileName), "/proc/self/maps");
} else {
snprintf(szFileName, sizeof(szFileName), "/proc/%d/maps", pid);
}
fp = fopen(szFileName, "r");
if (fp != NULL)
{
while (fgets(szMapFileLine, sizeof(szMapFileLine), fp)) {
if (strstr(szMapFileLine, ModuleName))
{
MapFileLineItem = strtok(szMapFileLine, " \t"); // 基址信息
char *Addr = strtok(szMapFileLine, "-");
ModuleBaseAddr = strtoul(Addr, NULL, 16 );
if (ModuleBaseAddr == 0x8000)
ModuleBaseAddr = 0;
break;
}
}
fclose(fp) ;
}
return (void *)ModuleBaseAddr;
}
/*************************************************
Description: 获取远程进程与本进程都加载的模块中函数的地址
Input: pid表示远程进程的ID,ModuleName表示模块名称,LocalFuncAddr表示本地进程中该函数的地址
Output: 无
Return: 返回远程进程中对应函数的地址
Others: 无
*************************************************/
void* GetRemoteFuncAddr(pid_t pid, const char *ModuleName, void *LocalFuncAddr)
{
void *LocalModuleAddr, *RemoteModuleAddr, *RemoteFuncAddr;
LocalModuleAddr = GetModuleBaseAddr(-1, ModuleName);
RemoteModuleAddr = GetModuleBaseAddr(pid, ModuleName);
RemoteFuncAddr = (void *)((long)LocalFuncAddr - (long)LocalModuleAddr + (long)RemoteModuleAddr);
return RemoteFuncAddr;
}
/*************************************************
Description: 通过远程直接调用dlopen\dlsym的方法ptrace注入so模块到远程进程中
Input: pid表示远程进程的ID,LibPath为被远程注入的so模块路径,FunctionName为远程注入的模块后调用的函数
FuncParameter指向被远程调用函数的参数(若传递字符串,需要先将字符串写入到远程进程空间中),NumParameter为参数的个数
Output: 无
Return: 返回0表示注入成功,返回-1表示失败
Others: 无
*************************************************/
int inject_remote_process(pid_t pid,char* LibPath,char* FunctionName,long* FuncParameter ,long NumParameter)
{
int iRet = -1;
struct pt_regs CurrentRegs,OriginalRegs; //备份原始寄存器
void *mmap_addr,*dlopen_addr,*dlsym_addr,*dlclose_addr,*dlerror_addr;
void *RemoteMapMemoryAddr, *RemoteModuleAddr, *RemoteModuleFuncAddr; //远程进程内存映射地址(保存调用参数),模块地址, 远程函数地址
long parameters[6];
//1. attach到进程
if(ptrace_attach(pid) == -1)
return iRet;
//2. 保存当前环境
if(ptrace_getregs(pid,&CurrentRegs) == -1)
{
ptrace_detach(pid);
return iRet;
}
memcpy(&OriginalRegs,&CurrentRegs,sizeof(struct pt_regs));
//3.获取远程mmap函数地址
//map() creates a new mapping in the virtual address space of the calling process.
//void *mmap(void *addr, size_t length, int prot, int flags,
// int fd, off_t offset);
mmap_addr = GetRemoteFuncAddr(pid,libc_path,(void*)mmap);
LOGD("[+]mmap RemoteFuncAddr:0x%lx", (long)mmap_addr);
//4. 设置mmap函数参数
parameters[0] = 0;
parameters[1] = 0x1000;
parameters[2] = PROT_READ | PROT_WRITE | PROT_EXEC; //内存属性
parameters[3] = MAP_ANONYMOUS | MAP_PRIVATE; //匿名映射
parameters[4] = 0;
parameters[5] = 0;
if(ptrace_call(pid , (long)mmap_addr , parameters , 6 , &CurrentRegs))
{
LOGD("Call Remote mmap Func Failed");
ptrace_detach(pid);
return iRet;
}
RemoteMapMemoryAddr = (void*)ptrace_getret(&CurrentRegs); //获取分配内存的起始地址
LOGD("[+]Remote Process Map Memory Addr:0x%lx", (long)RemoteMapMemoryAddr);
// 分别获取dlopen、dlsym、dlclose等函数的地址
dlopen_addr = GetRemoteFuncAddr(pid, linker_path, (void *)dlopen);
dlsym_addr = GetRemoteFuncAddr(pid, linker_path, (void *)dlsym);
dlclose_addr = GetRemoteFuncAddr(pid, linker_path, (void *)dlclose);
dlerror_addr = GetRemoteFuncAddr(pid, linker_path, (void *)dlerror);
LOGD("[+]dlopen RemoteFuncAddr:0x%lx", (long)dlopen_addr);
LOGD("[+]dlsym RemoteFuncAddr:0x%lx", (long)dlsym_addr);
LOGD("[+]dlclose RemoteFuncAddr:0x%lx", (long)dlclose_addr);
LOGD("[+]dlerror RemoteFuncAddr:0x%lx", (long)dlerror_addr);
if(ptrace_writedata(pid,RemoteMapMemoryAddr,LibPath,strlen(LibPath)+1) == -1)
{
LOGD("Write LibPath:%s to RemoteProcess error", LibPath);
ptrace_detach(pid);
return iRet;
}
// loadlibrary
// 设置dlopen的参数,返回值为模块加载的地址
// void *dlopen(const char *filename, int flag);
parameters[0] = (long)RemoteMapMemoryAddr;
parameters[1] = RTLD_NOW| RTLD_GLOBAL;
if (ptrace_call(pid, (long)dlopen_addr, parameters, 2, &CurrentRegs) == -1)
{
LOGD("Call Remote dlopen Func Failed");
ptrace_detach(pid);
return iRet;
}
// RemoteModuleAddr为远程进程加载注入模块的地址
RemoteModuleAddr = (void *)ptrace_getret(&CurrentRegs);
LOGD("Remote Process load module Addr:0x%lx", (long)RemoteModuleAddr);
if ((long)RemoteModuleAddr == 0x0) // dlopen 错误
{
LOGD("dlopen error");
if (ptrace_call(pid, (long)dlerror_addr, parameters, 0, &CurrentRegs) == -1)
{
LOGD("Call Remote dlerror Func Failed");
ptrace_detach(pid);
return iRet;
}
char *Error = (void *)ptrace_getret(&CurrentRegs);
char LocalErrorInfo[1024] = {0};
ptrace_readdata(pid, Error, LocalErrorInfo, 1024);
LOGD("dlopen error:%s", LocalErrorInfo);
ptrace_detach(pid);
return iRet;
}
// 将so库中需要调用的函数名称写入到远程进程内存空间中
if (ptrace_writedata(pid, RemoteMapMemoryAddr + strlen(LibPath) + 2, FunctionName, strlen(FunctionName) + 1) == -1)
{
LOGD("Write FunctionName:%s to RemoteProcess error", FunctionName);
ptrace_detach(pid);
return iRet;
}
//GetProcAddress
// 设置dlsym的参数,返回值为远程进程内函数的地址
// void *dlsym(void *handle, const char *symbol);
parameters[0] = (long)RemoteModuleAddr;
parameters[1] = (long)(RemoteMapMemoryAddr + strlen(LibPath) + 2);
if (ptrace_call(pid, (long)dlsym_addr, parameters, 2, &CurrentRegs) == -1)
{
LOGD("Call Remote dlsym Func Failed");
ptrace_detach(pid);
return iRet;
}
// RemoteModuleFuncAddr为远程进程空间内获取的函数地址
RemoteModuleFuncAddr = (void *)ptrace_getret(&CurrentRegs);
LOGD("[+]Remote Process ModuleFunc Addr:0x%lx", (long)RemoteModuleFuncAddr);
// call
if (ptrace_call(pid, (long)RemoteModuleFuncAddr, FuncParameter, NumParameter, &CurrentRegs) == -1)
{
LOGD("Call Remote injected Func Failed");
ptrace_detach(pid);
return iRet;
}
if (ptrace_setregs(pid, &OriginalRegs) == -1)
{
LOGD("Recover reges failed");
ptrace_detach(pid);
return iRet;
}
LOGD("Recover Regs Success");
ptrace_getregs(pid, &CurrentRegs);
if (memcmp(&OriginalRegs, &CurrentRegs, sizeof(CurrentRegs)) != 0)
{
LOGD("Set Regs Error");
}
//Detach
if (ptrace_detach(pid) == -1)
{
LOGD("ptrace detach failed");
return iRet;
}
return 0;
}
/************************************************************
FileName: main.c
Description: ptrace注入
***********************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <asm/user.h>
#include <asm/ptrace.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <dlfcn.h>
#include <dirent.h>
#include <unistd.h>
#include <string.h>
#include <elf.h>
#include <inject.h>
#include <utils/PrintLog.h>
/*************************************************
Description: 通过进程名称定位到进程的PID
Input: process_name为要定位的进程名称
Output: 无
Return: 返回定位到的进程PID,若为-1,表示定位失败
Others: 无
*************************************************/
pid_t FindPidByProcessName(const char *process_name)
{
int ProcessDirID = 0;
pid_t pid = -1;
FILE *fp = NULL;
char filename[MAX_PATH] = {0};
char cmdline[MAX_PATH] = {0};
struct dirent * entry = NULL;
if ( process_name == NULL )
return -1;
DIR* dir = opendir( "/proc" );
if ( dir == NULL )
return -1;
while( (entry = readdir(dir)) != NULL )
{
ProcessDirID = atoi( entry->d_name );
if ( ProcessDirID != 0 )
{
snprintf(filename, MAX_PATH, "/proc/%d/cmdline", ProcessDirID);
fp = fopen( filename, "r" );
if ( fp )
{
fgets(cmdline, sizeof(cmdline), fp);
fclose(fp);
if (strncmp(process_name, cmdline, strlen(process_name)) == 0)
{
pid = ProcessDirID;
break;
}
}
}
}
closedir(dir);
return pid;
}
int main(int argc, char *argv[]) {
char InjectModuleName[MAX_PATH] = "/data/libInjectModule.so"; // 要注入模块全路径
char RemoteCallFunc[MAX_PATH] = "Inject_entry"; // 注入模块后调用模块函数名称
char InjectProcessName[MAX_PATH] = "com.example.yllen.myapplication"; // 注入进程名称
// 当前设备环境判断
#if defined(__i386__)
LOGD("Current Environment x86");
return -1;
#elif defined(__arm__)
LOGD("Current Environment ARM");
#else
LOGD("other Environment");
return -1;
#endif
pid_t pid = FindPidByProcessName(InjectProcessName);
if (pid == -1)
{
printf("Get Pid Failed");
return;
}
printf("begin inject process, RemoteProcess pid:%d, InjectModuleName:%s, RemoteCallFunc:%s\n", pid, InjectModuleName, RemoteCallFunc);
int iRet = inject_remote_process(pid, InjectModuleName, RemoteCallFunc, NULL, 0);
//int iRet = inject_remote_process_shellcode(pid, InjectModuleName, RemoteCallFunc, NULL, 0);
if (iRet == 0)
{
printf("Inject Success\n");
}
else
{
printf("Inject Failed\n");
}
printf("end inject,%d\n", pid);
return 0;
}

Android.mk

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := inject
LOCAL_SRC_FILES := inject.c main.c
LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog
include $(BUILD_EXECUTABLE)

参考Ref:

1. http://gslab.qq.com/portal.php?mod=view&aid=162