上次在研究Ptrace for Android的时候漏了一个东西,如何hook并修改除了Syscall 以外的函数,今天顺便实现一下。
平台:Android 2.3.3
目标:利用Ptrace拦截进程的自定义函数并修改逻辑。
先看目标进程,代码相当简单:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
#include <stdio.h>
int
flag = 1;
int
count = 0;
int
sub()
{
printf
(
"Sub call.\n"
);
return
1;
}
int
main()
{
while
(flag)
{
printf
(
"Sub return:%d\n"
, sub());
count++;
sleep(3);
}
return
0;
}
|
我们要做的是拦截自定义函数sub(),修改函数,跳过printf语句并把返回值改成2.
基本思路是利用Ptrace attach 以后找到函数代码段的入口点,修改相应的代码即可。如何找到函数入口点?静态看或者动态调都可以。我们代码简单,静态看就好了。
静态看的过程并不如想象的顺利,原因是IDA这货真心坑爹,解析Thumb和ARM的混合代码竟然会出错:
只好手动修改一下便于查看:
一目了然,0x84D0处开始返回指针压栈,我们只需要从0x84D2开始把代码改成如下就可以了:
1
2
|
MOVS R0, #2
POP {R3, PC}
|
因而得出trace的代码如下:
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
|
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <sys/syscall.h>
int
long_size =
sizeof
(
long
);
void
putdata(pid_t pid,
long
addr,
char
*str,
int
len)
{
char
*laddr;
int
i, j;
union
u {
long
val;
char
chars[long_size];
}data;
i = 0;
j = len / long_size;
laddr = str;
while
(i < j) {
memcpy
(data.chars, laddr, long_size);
ptrace(PTRACE_POKEDATA, pid,
addr + i * 4, data.val);
++i;
laddr += long_size;
}
j = len % long_size;
if
(j != 0) {
memcpy
(data.chars, laddr, j);
ptrace(PTRACE_POKEDATA, pid,
addr + i * 4, data.val);
}
}
void
tracePro(
int
pid)
{
int
len = 4;
char
insertcode[] =
"\x02\x20\x08\xBD"
;
putdata(pid, 0x84d2, insertcode, len);
}
int
main(
int
argc,
char
*argv[])
{
if
(argc != 2) {
printf
(
"Usage: %s <pid to be traced>\n"
, argv[0], argv[1]);
return
1;
}
pid_t traced_process;
int
status;
traced_process =
atoi
(argv[1]);
if
(0 != ptrace(PTRACE_ATTACH, traced_process, NULL, NULL))
{
printf
(
"Trace process failed:%d.\n"
,
errno
);
return
1;
}
tracePro(traced_process);
ptrace(PTRACE_DETACH, traced_process, NULL, NULL);
return
0;
}
|
上传至模拟器调试,一次成功: