Android下实现ptrace注入&hook

思路

  1. 通过目标进程名找到进程PID
  2. 将so注入到进程空间
  3. 如果hook Native层函数,则有IAT hook,调试hook,inline hook,hotfix hook等多种手段;如果是Java层hook,可以使用反射机制

使用ndk编译linux原生应用程序

建立工程文件夹,工程文件夹内建立jni文件夹

进入jni文件夹

创建源文件,Android.mk,Application.mk

Android.mk

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 一个Android.mk file首先必须定义好LOCAL_PATH变量。
# 它用于在开发树中查找源文件。在这个例子中,宏函数’my-dir’,
# 由编译系统提供,用于返回当前路径(即包含Android.mk file文件的目录)。
LOCAL_PATH := $(call my-dir)
# CLEAR_VARS由编译系统提供,
# 指定让GNU MAKEFILE为你清除许多LOCAL_XXX变量(例如 LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES, 等等...),除LOCAL_PATH 。这是必要的,
# 因为所有的编译控制文件都在同一个GNU MAKE执行环境中,所有的变量都是全局的。
include $(CLEAR_VARS)
# LOCAL_MODULE变量必须定义,以标识你在Android.mk文件中描述的每个模块。名称必须是唯一的,而且不包含任何空格。
# 注意编译系统会自动产生合适的前缀和后缀,换句话说,一个被命名为'foo'的共享库模块,将会生成'libfoo.so'文件。
LOCAL_MODULE := hello-jni
# LOCAL_SRC_FILES变量必须包含将要编译打包进模块中的C或C++源代码文件。注意,你不用在这里列出头文件和包含文件,
# 因为编译系统将会自动为你找出依赖型的文件;仅仅列出直接传递给编译器的源代码文件就好。
LOCAL_SRC_FILES := hello-jni.c
# BUILD_EXECUTABLE 表示以一个可执行程序的方式进行编译
# BUILD_SHARED_LIBRARY 表示动态链接库的方式进行编译
include $(BUILD_EXECUTABLE)

fpid是你的目标文件名,1.c是源文件名

Application.mk

1
2
3
4
#### APP_ABI := arm64-v8a 后面接的是需要生成的.so平台文件,
#### 正常手机使用arm64处理器的即可。 all是全平台
#### APP_PLATFORM :=后面接的是使用SDK的最低等级
APP_ABI := all

然后进入工程目录执行

1
ndk-build

在libs目录下可以找到编译好的文件,使用adb push命令可以送到手机

查找PID

主要是利用了linux的文件系统,/proc存储着进程有关信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <stdio.h>
#include <sys/ptrace.h>
#include <dirent.h>
#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>
#define MAX_PATH 256

pid_t findPIdByName(const char *name){
pid_t pid = -1;
int pDirId = 0; // process dir id
FILE *f;
char filename[MAX_PATH];
char cmdline[MAX_PATH];
struct dirent *entry=NULL;
int cnt;
if(name==NULL){
return -1;
}
DIR *dir = opendir("/proc");
if(dir==NULL){
return -1;
}
while((entry=readdir(dir))!=NULL){
pDirId=atoi(entry->d_name);
if(pDirId!=0){
snprintf(filename,MAX_PATH,"/proc/%d/cmdline",pDirId);
f = fopen(filename,"r");
if(f){
fgets(cmdline,sizeof(cmdline),f);
cnt = (int)strlen(cmdline);
while(cnt>=0&&cmdline[cnt]!='/')cnt--; // cmdline是完整路径,这里只找最后一个/之后的,就是可执行文件的文件名
cnt++;
if(!strncmp(name,&cmdline[cnt],strlen(name))){
pid=pDirId;
break;
}
}
fclose(f);
}
}
closedir(dir);
return pid;
}
int main(int argc,char**argv){
if(argc!=2){
printf("usage: fpid processname\n");
return -1;
}
pid_t pid = findPIdByName(argv[1]);
printf("%d\n",pid);
return 0;

}

注入so

步骤

  1. attach到目标进程
  2. 保存寄存器上下文
  3. 调用mmap函数分配内存空间-这里主要为了传递一些字符串参数
  4. 向内存空间写入加载模块名和调用函数
  5. 调用dlopen打开注入模块
  6. 调用dlsym获取调用函数的地址
  7. 调用被注入模块的函数
  8. 恢复寄存器环境
  9. 从远程进程detach

64位注入器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
#include <stdio.h>
#include <stdlib.h>
#include <sys/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 <sys/uio.h>

#define pt_regs user_pt_regs

#define uregs regs
#define ARM_pc pc
#define ARM_sp sp
#define ARM_cpsr pstate
#define ARM_lr regs[30]
#define ARM_r0 regs[0]
#ifndef PTRACE_GETREGS
#define PTRACE_GETREGS PTRACE_GETREGSET
#endif
#ifndef PTRACE_SETREGS
#define PTRACE_SETREGS PTRACE_SETREGSET
#endif
#define CPSR_T_MASK (1u<<5)

#define MAX_PATH 512
char libcPath[]="/system/lib64/libc.so";

void ptraceWriteData(pid_t pid,void*addr,const char*data,size_t len){
size_t i=0;
for(;i<len;i+=sizeof(long)){
ptrace(PTRACE_POKETEXT,pid,(long)addr+i,(void*)*(long*)&data[i]);
}
// 每次写sizeof(long)字节,直接对齐
}
void ptraceReadData(pid_t pid,void*addr,char*data,size_t len){
size_t i=0;
long rdata;
for(;i<len;i+=sizeof(long)){
rdata=ptrace(PTRACE_PEEKTEXT,pid,(long)addr+i,NULL);
*(long*)&data[i]=rdata;
}
}
void ptraceAttach(pid_t pid){
if(ptrace(PTRACE_ATTACH,pid,NULL,NULL)==-1){
printf("[INJECT F]Failed to attach:%d\n",pid);
}
int stat=0;
waitpid(pid,&stat,WUNTRACED);
}
void ptraceGetRegs(pid_t pid,struct pt_regs*regs_addr){
struct iovec io;
io.iov_base=regs_addr;
io.iov_len=sizeof(struct pt_regs);
if(ptrace(PTRACE_GETREGS,pid,NT_PRSTATUS,&io)==-1){
printf("Get regs error\n");
}
}
void ptraceSetRegs(pid_t pid,struct pt_regs*regs_addr){
struct iovec io;
io.iov_base = regs_addr;
io.iov_len = sizeof(struct pt_regs);
if(ptrace(PTRACE_SETREGS,pid,NT_PRSTATUS,&io)==-1){
printf("Set regs error\n");
}
}
void ptraceDetach(pid_t pid){
ptrace(PTRACE_DETACH,pid,NULL,NULL);
}
void ptraceContinue(pid_t pid){
if(ptrace(PTRACE_CONT,pid,NULL,NULL)==-1){
printf("ptrace continue error\n");
}
}
void *getModuleBaseAddr(pid_t pid,const char*moduleName){
if(pid==-1)pid=getpid();
// 通过解析/proc/pid/maps 获得基址
char filepath[MAX_PATH];
void*moduleBaseAddr=NULL;
snprintf(filepath,MAX_PATH,"/proc/%d/maps",pid);
FILE *f = fopen(filepath,"r");
char line[MAX_PATH];
char base[MAX_PATH],name[MAX_PATH];
size_t cnt,start;
while(!feof(f)){
memset(line,0,MAX_PATH);
memset(name,0,MAX_PATH);
fgets(line,MAX_PATH,f);
cnt=0;
while(line[cnt]!='/')cnt++;
start=cnt;
while(line[cnt]){
name[cnt-start]=line[cnt];
cnt++;
}
name[cnt-start-1]=0;

if(strncmp(name,moduleName,MAX_PATH))continue;
memset(base,0,MAX_PATH);
cnt=0;
while(line[cnt]!='-'){
base[cnt]=line[cnt];
cnt++;
}
base[cnt]=0;
sscanf(base,"%llx",(long long*)(&moduleBaseAddr));
printf("[INJECT] GotBaseAddr %p of %s\n",moduleBaseAddr,moduleName);
break;
}
fclose(f);
return moduleBaseAddr;
}
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);
printf("[INJECT] GotFuncAddr:%p\n",remoteFuncAddr);
return remoteFuncAddr;
}
int ptraceCall(pid_t pid,void* funcAddr,long*paras,long paraLen,struct pt_regs *regs){

// 多于8个参数通过栈传递

if(paraLen>8){

regs->ARM_sp-=(paraLen-8)*sizeof(long);
ptraceWriteData(pid,(void*)regs->ARM_sp,(char*)&paras[6],sizeof(long)*(paraLen-6));
}
// 前6个参数通过寄存器传递
for(size_t i=0;i<8;i++){
regs->uregs[i]=paras[i];
}
// 调用函数
regs->ARM_pc=(unsigned long long)funcAddr;
// 判断arm模式还是thumb模式
if(regs->ARM_pc&1){
regs->ARM_pc&=~1;
regs->ARM_cpsr|=CPSR_T_MASK;
}else{
regs->ARM_cpsr&=~CPSR_T_MASK;
}
regs->ARM_lr=0;
ptraceSetRegs(pid,regs);
int stat=0;
while(stat!=0xb7f){
ptraceContinue(pid);
waitpid(pid,&stat,WUNTRACED);
printf("[INJECT] substatus: %x\n",stat);
}

ptraceGetRegs(pid,regs);
return 0;
}
void inject(pid_t pid,const char*libname,const char*funcName){
struct pt_regs oldRegs;
struct pt_regs regs;
long paras[6];
char realLibPath[PATH_MAX];
realpath(libname,realLibPath);
printf("[INJECT]Real path of lib found:%s\n",realLibPath);

ptraceAttach(pid);
// 保存寄存器环境
ptraceGetRegs(pid,&oldRegs);
memcpy(&regs,&oldRegs,sizeof(struct pt_regs));
// 获取mmap地址
void *mmapAddr = getRemoteFuncAddr(pid,libcPath,(void*)mmap);
// 调用mmap
paras[0]=0;
paras[1]=0x1000;
paras[2]=PROT_READ|PROT_WRITE|PROT_EXEC;
paras[3]=MAP_ANONYMOUS|MAP_PRIVATE;
paras[4]=0;
paras[5]=0;
ptraceCall(pid,mmapAddr,paras,6,&regs);
void *remoteMemAddr=(void*)regs.ARM_r0;
printf("[INJECT] remote mmaped addr:%p\n",remoteMemAddr);
// 调用dlopen
void *dlopenAddr=getRemoteFuncAddr(pid,libcPath,(void*)dlopen);
void *dlcloseAddr=getRemoteFuncAddr(pid,libcPath,(void*)dlclose);
void *dlErrorAddr=getRemoteFuncAddr(pid,libcPath,(void*)dlerror);
ptraceWriteData(pid,remoteMemAddr,realLibPath,strlen(realLibPath)+1); // 作为dlopen的参数
//debug start
char buf[MAX_PATH];
memset(buf,0,MAX_PATH);
ptraceReadData(pid,remoteMemAddr,buf,strlen(realLibPath)+3);
printf("%s\n",buf);
//debug end
paras[0]=(long)remoteMemAddr;
paras[1]=RTLD_NOW|RTLD_GLOBAL;
ptraceCall(pid,dlopenAddr,paras,2,&regs);
void*libBaseAddr=(void*)regs.ARM_r0;
printf("[INJECT]remote lib base:0x%llx of %s\n",(long long)libBaseAddr,realLibPath);
// 调用dlsym
void*dlsymAddr=getRemoteFuncAddr(pid,libcPath,(void*)dlsym);
ptraceWriteData(pid,remoteMemAddr,funcName,strlen(funcName)+1);
//debug start
memset(buf,0,MAX_PATH);
ptraceReadData(pid,remoteMemAddr,buf,strlen(funcName)+3);
printf("%s\n",buf);
//debug end
paras[0]=(long)libBaseAddr;
paras[1]=(long)remoteMemAddr;
ptraceCall(pid,dlsymAddr,paras,2,&regs);
void*remoteFuncAddr = (void*)regs.ARM_r0;
printf("[INJECT]addr:0x%llx of func %s\n",(long long)remoteFuncAddr,funcName);
// 调用目标函数
ptraceCall(pid,remoteFuncAddr,paras,0,&regs);
// 恢复寄存器环境
ptraceSetRegs(pid,&oldRegs);
ptraceDetach(pid);
}
pid_t findPIdByName(const char *name){
pid_t pid = -1;
int pDirId = 0; // process dir id
FILE *f;
char filename[MAX_PATH];
char cmdline[MAX_PATH];
struct dirent *entry=NULL;
int cnt;
if(name==NULL){
return -1;
}
DIR *dir = opendir("/proc");
if(dir==NULL){
return -1;
}
while((entry=readdir(dir))!=NULL){
pDirId=atoi(entry->d_name);
if(pDirId!=0){
snprintf(filename,MAX_PATH,"/proc/%d/cmdline",pDirId);
f = fopen(filename,"r");
if(f){
fgets(cmdline,sizeof(cmdline),f);
cnt = (int)strlen(cmdline);
while(cnt>=0&&cmdline[cnt]!='/')cnt--; // cmdline是完整路径,这里只找最后一个/之后的,就是可执行文件的文件名
cnt++;
if(!strncmp(name,&cmdline[cnt],strlen(name))){
pid=pDirId;
break;
}
}
fclose(f);
}
}
closedir(dir);
return pid;
}

int main(int argc,char **argv){
if(argc!=4){
printf("usage: inject processname libexample.so funcname\n");
return 0;
}
pid_t pid = findPIdByName(argv[1]);
printf("[INJECT]found pid:%d of %s\n",pid,argv[1]);
inject(pid,argv[2],argv[3]);
return 0;
}

32位注入器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
#include <stdio.h>
#include <stdlib.h>
#include <sys/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 <sys/uio.h>

#define CPSR_T_MASK (1u<<5)

#define MAX_PATH 512
char libcPath[]="/system/lib/libc.so";
char linkerPath[] = "/system/bin/linker";

void ptraceWriteData(pid_t pid,void*addr,const char*data,size_t len){
size_t i=0;
for(;i<len;i+=sizeof(long)){
ptrace(PTRACE_POKETEXT,pid,(long)addr+i,(void*)*(long*)&data[i]);
}
// 每次写sizeof(long)字节,直接对齐
}
void ptraceReadData(pid_t pid,void*addr,char*data,size_t len){
size_t i=0;
long rdata;
for(;i<len;i+=sizeof(long)){
rdata=ptrace(PTRACE_PEEKTEXT,pid,(long)addr+i,NULL);
*(long*)&data[i]=rdata;
}
}
void ptraceAttach(pid_t pid){
if(ptrace(PTRACE_ATTACH,pid,NULL,NULL)==-1){
printf("[INJECT F]Failed to attach:%d\n",pid);
}
int stat=0;
waitpid(pid,&stat,WUNTRACED);
}
void ptraceGetRegs(pid_t pid,struct pt_regs*regs_addr){
// struct iovec io;
// io.iov_base=regs_addr;
// io.iov_len=sizeof(struct pt_regs);
if(ptrace(PTRACE_GETREGS,pid,NULL,regs_addr)==-1){
printf("Get regs error\n");
}
}
void ptraceSetRegs(pid_t pid,struct pt_regs*regs_addr){
// struct iovec io;
// io.iov_base = regs_addr;
// io.iov_len = sizeof(struct pt_regs);
if(ptrace(PTRACE_SETREGS,pid,NULL,regs_addr)==-1){
printf("Set regs error\n");
}
}
void ptraceDetach(pid_t pid){
ptrace(PTRACE_DETACH,pid,NULL,NULL);
}
void ptraceContinue(pid_t pid){
if(ptrace(PTRACE_CONT,pid,NULL,NULL)==-1){
printf("ptrace continue error\n");
}
}
void *getModuleBaseAddr(pid_t pid,const char*moduleName){
if(pid==-1)pid=getpid();
// 通过解析/proc/pid/maps 获得基址
char filepath[MAX_PATH];
void*moduleBaseAddr=NULL;
snprintf(filepath,MAX_PATH,"/proc/%d/maps",pid);
FILE *f = fopen(filepath,"r");
char line[MAX_PATH];
char base[MAX_PATH],name[MAX_PATH];
size_t cnt,start;
while(!feof(f)){
memset(line,0,MAX_PATH);
memset(name,0,MAX_PATH);
fgets(line,MAX_PATH,f);
cnt=0;
while(line[cnt]!='/')cnt++;
start=cnt;
while(line[cnt]){
name[cnt-start]=line[cnt];
cnt++;
}
name[cnt-start-1]=0;

if(strncmp(name,moduleName,MAX_PATH))continue;
memset(base,0,MAX_PATH);
cnt=0;
while(line[cnt]!='-'){
base[cnt]=line[cnt];
cnt++;
}
base[cnt]=0;
sscanf(base,"%x",(unsigned int*)(&moduleBaseAddr));
printf("[INJECT] GotBaseAddr %p of %s\n",moduleBaseAddr,moduleName);
break;
}
fclose(f);
return moduleBaseAddr;
}
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);
printf("[INJECT] GotFuncAddr:%p\n",remoteFuncAddr);
return remoteFuncAddr;
}
int ptraceCall(pid_t pid,void* funcAddr,long*paras,long paraLen,struct pt_regs *regs){

// 多于4个参数通过栈传递

if(paraLen>4){

regs->ARM_sp-=(paraLen-4)*sizeof(long);
ptraceWriteData(pid,(void*)regs->ARM_sp,(char*)&paras[6],sizeof(long)*(paraLen-6));
}
// 前6个参数通过寄存器传递
for(size_t i=0;i<4;i++){
regs->uregs[i]=paras[i];
}
// 调用函数
regs->ARM_pc=(unsigned long long)funcAddr;
// 判断arm模式还是thumb模式
if(regs->ARM_pc&1){
regs->ARM_pc&=~1;
regs->ARM_cpsr|=CPSR_T_MASK;
}else{
regs->ARM_cpsr&=~CPSR_T_MASK;
}
regs->ARM_lr=0;
ptraceSetRegs(pid,regs);
int stat=0;
while(stat!=0xb7f){
ptraceContinue(pid);
waitpid(pid,&stat,WUNTRACED);
printf("[INJECT] substatus: %x\n",stat);
}

ptraceGetRegs(pid,regs);
return 0;
}
void inject(pid_t pid,const char*libname,const char*funcName){
struct pt_regs oldRegs;
struct pt_regs regs;
long paras[6];
char realLibPath[PATH_MAX];
realpath(libname,realLibPath);
printf("[INJECT]Real path of lib found:%s\n",realLibPath);

ptraceAttach(pid);
// 保存寄存器环境
ptraceGetRegs(pid,&oldRegs);
memcpy(&regs,&oldRegs,sizeof(struct pt_regs));
// 获取mmap地址
void *mmapAddr = getRemoteFuncAddr(pid,libcPath,(void*)mmap);
// 调用mmap
paras[0]=0;
paras[1]=0x1000;
paras[2]=PROT_READ|PROT_WRITE|PROT_EXEC;
paras[3]=MAP_ANONYMOUS|MAP_PRIVATE;
paras[4]=0;
paras[5]=0;
ptraceCall(pid,mmapAddr,paras,6,&regs);
void *remoteMemAddr=(void*)regs.ARM_r0;
if(remoteMemAddr==(void*)-1){
printf("[INJECT ERR]mmapFailed\n");
}
printf("[INJECT] remote mmaped addr:%p\n",remoteMemAddr);
// 调用dlopen
void *dlopenAddr=getRemoteFuncAddr(pid,linkerPath,(void*)dlopen);
void *dlcloseAddr=getRemoteFuncAddr(pid,linkerPath,(void*)dlclose);
void *dlErrorAddr=getRemoteFuncAddr(pid,linkerPath,(void*)dlerror);
ptraceWriteData(pid,remoteMemAddr,realLibPath,strlen(realLibPath)+1); // 作为dlopen的参数
//debug start
char buf[MAX_PATH];
memset(buf,0,MAX_PATH);
ptraceReadData(pid,remoteMemAddr,buf,strlen(realLibPath)+3);
printf("%s\n",buf);
//debug end
paras[0]=(long)remoteMemAddr;
paras[1]=RTLD_NOW|RTLD_GLOBAL;
ptraceCall(pid,dlopenAddr,paras,2,&regs);
void*libBaseAddr=(void*)regs.ARM_r0;
printf("[INJECT]remote lib base:0x%llx of %s\n",(long long)libBaseAddr,realLibPath);
// 调用dlsym
void*dlsymAddr=getRemoteFuncAddr(pid,libcPath,(void*)dlsym);
ptraceWriteData(pid,remoteMemAddr,funcName,strlen(funcName)+1);
//debug start
memset(buf,0,MAX_PATH);
ptraceReadData(pid,remoteMemAddr,buf,strlen(funcName)+3);
printf("%s\n",buf);
//debug end
paras[0]=(long)libBaseAddr;
paras[1]=(long)remoteMemAddr;
ptraceCall(pid,dlsymAddr,paras,2,&regs);
void*remoteFuncAddr = (void*)regs.ARM_r0;
printf("[INJECT]addr:0x%llx of func %s\n",(long long)remoteFuncAddr,funcName);
// 调用目标函数
ptraceCall(pid,remoteFuncAddr,paras,0,&regs);
// 恢复寄存器环境
ptraceSetRegs(pid,&oldRegs);
ptraceDetach(pid);
}
pid_t findPIdByName(const char *name){
pid_t pid = -1;
int pDirId = 0; // process dir id
FILE *f;
char filename[MAX_PATH];
char cmdline[MAX_PATH];
struct dirent *entry=NULL;
int cnt;
if(name==NULL){
return -1;
}
DIR *dir = opendir("/proc");
if(dir==NULL){
return -1;
}
while((entry=readdir(dir))!=NULL){
pDirId=atoi(entry->d_name);
if(pDirId!=0){
snprintf(filename,MAX_PATH,"/proc/%d/cmdline",pDirId);
f = fopen(filename,"r");
if(f){
fgets(cmdline,sizeof(cmdline),f);
cnt = (int)strlen(cmdline);
while(cnt>=0&&cmdline[cnt]!='/')cnt--; // cmdline是完整路径,这里只找最后一个/之后的,就是可执行文件的文件名
cnt++;
if(!strncmp(name,&cmdline[cnt],strlen(name))){
pid=pDirId;
break;
}
}
fclose(f);
}
}
closedir(dir);
return pid;
}

int main(int argc,char **argv){
if(argc!=4){
printf("usage: inject processname libexample.so funcname\n");
return 0;
}
pid_t pid = findPIdByName(argv[1]);
printf("[INJECT]found pid:%d of %s\n",pid,argv[1]);
inject(pid,argv[2],argv[3]);
return 0;
}

要注入的so文件编译

Android.mk

1
2
3
4
5
6
7
8
LOCAL_PATH:=$(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE := hook
LOCAL_SRC_FILES := hook.c
LOCAL_LDLIBS += -llog

include $(BUILD_SHARED_LIBRARY)

Application.mk指定架构即可

hook.c

1
2
3
4
5
6
7
8
9
10
11
12
#include <android/log.h>

#define LOG_TAG "INJECT"
#define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG , LOG_TAG, __VA_ARGS__))

void _init(void){
LOGD("Injected!\n");

}
void hookEntry(){
LOGD("Hook Entry called\n");
}

这里init可以作为Android的.init段,在so加载时执行

参考

[1] https://www.jianshu.com/p/c546783ad284

[2] https://xz.aliyun.com/t/5361?spm=5176.12901015.0.i12901015.583e525cW8q5ne

[3] https://gslab.qq.com/portal.php?mod=view&aid=162