参考:https://bbs.pediy.com/thread-217482.html

ptrace占坑

ptrace(0,0,0,0)开启一个子进程附加主进程,这个其实不算检测,主要是为了限制frida和IDA进行附加进程,因为app只能被一个进程attach,自己attach了自己,其他的进程就无法attach了。绕过也比较简单,使用-f参数指定包名,加上--no-pause参数,使js代码优先attach上,而且frida的attach是用完就释放,不影响app代码里的ptrace

同一个app有多个进程的情况,守护进程(主进程崩掉了之后由守护进程把主进程再跑起来)、子进程附加主进程(不让别人再附加上去)、普通多进程。用ps -A里看到的PPID就是父进程ID

双进程也可以尝试使用PID的方式去注入,不使用包名(使用包名也没用,因为两个进程包名一样),这种针对的是普通双进程,对于既是双进程又是子进程附加主进程的一般没用

进程名检测

遍历运行的进程列表,检测frida-server是否运行

端口检测

检测frida-server默认端口27042是否开发

D-Bus协议通信

Frida使用D-Bus协议通信,可以遍历/proc/<PID>/net/tcp文件,或者对每个端口挨个发送消息

向每个开放的端口发送D-Bus认证消息,哪个端口回复了Reject,就是frida server

检测demo,绕过的话就去hook strcmp函数就可以了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
* Mini-portscan to detect frida-server on any local port.
*/
for(i = 0 ; i <= 65535 ; i++) {
sock = socket(AF_INET , SOCK_STREAM , 0);
sa.sin_port = htons(i);
if (connect(sock , (struct sockaddr*)&sa , sizeof sa) != -1) {
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "FRIDA DETECTION [1]: Open Port: %d", i);
memset(res, 0 , 7);
// send a D-Bus AUTH message. Expected answer is “REJECT"
send(sock, "\x00", 1, NULL);
send(sock, "AUTH\r\n", 6, NULL);
usleep(100);
if (ret = recv(sock, res, 6, MSG_DONTWAIT) != -1) {
if (strcmp(res, "REJECT") == 0) {
/* Frida server detected. Do something… */
}
}
}
close(sock);
}

扫描maps文件

maps文件用于显示当前app中加载的依赖库,maps文件位于/proc/<PID>/maps

frida在运行时会先确定路径下是否有re.frida.server文件夹

若没有则创建该文件夹并往文件夹里存放frida-agent.so等文件,该so文件会出现在maps文件中

扫描task目录

扫描目录下所有/proc/<PID>/task/<线程ID>/status中的Name字段,其实就是线程名,寻找是否存在frida注入的特征

具体线程名为gmaingdbusgum-js-looppool-frida

检测文件及内存特征字符串

通过readlink查看/proc/self/fd/proc/self/task/<pid>/fd下所有打开的文件,检测是否有frida相关文件

常见用于检测的系统函数

1
2
3
strstr、strcmp、open、read、fread、readlink
因为要检测文件内容,所以会有open和read
readlink是打开的同时去读取

扫描内存中是否有frida库特征出现,例如字符串LIBFRIDA

hluwa的去掉字符串特征的frida-server https://github.com/hluwa/strongR-frida-android

补充

通常会被检测的文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
riru的特征文件
/system/lib/libmemtrack.so
/system/lib/libmemtrack_real.so

cmdline 检测进程名,防止重打包 cat /proc/<PID>/cmdline

status 检测进程是否被附加 cat /proc/<PID>/status
status文件里的State字段代表当前进程的状态,被调试的时候这个字段会变
还有TracePid字段,如果被调试的话这个字段不为0

stat 检测进程是否被附加 cat /proc/<PID>/stat 和status文件类似
stat和status是检测调试的

task/xxx/stat 位于/proc/<PID>/task/<线程ID>/stat
task/xxx/status 位于/proc/<PID>/task/<线程ID>/status 检测线程的name字段是否包含frida关键字
上面两个task都是检测线程的,frida会在进程中开启线程
fd/xxx 位于/proc/<PID>/fd 记录了app所打开的文件,检测app是否打开了frida的相关文件

maps 检测app加载的依赖库里是否有frida
net/tcp 检测app打开的端口

hluwa-server 处理了re.frida.server文件夹以及该文件夹下的文件的名字

使用这个server,不放在/data/local/tmp目录下的话,基本可以不用关心fd和maps的检测,但是线程关键字里还是可能有的,但是也不多,有时候可以用

frida-gadget https://bbs.pediy.com/thread-269866.html