
1.了解常见frida检测
1.教程Demo(更新)
2.jadx-gui
3.VS Code
4.jeb
1.检测/data/local/tmp路径下的是否有frida特征文件,server端改名,例如:fr
2.指定端口转发
3.spawn启动过双进程保护
PS:学会看注入报错的日志,比如说当app主动附加自身进程时,这时候再注入就会提示run frida as root
(以spawn的方式启动进程即可)
4.借助脚本定位检测frida的so
5.随着firda的版本迭代,以前诸多检测点以失效
(1.)例如检测D-Bus
D-Bus是一种进程间通信(IPC)和远程过程调用(RPC)机制,最初是为Linux开发的,目的是用一个统一的协议替代现有的和竞争的IPC解决方案。
(2)检测fd
/proc/pid/fd 目录的作用在于提供了一种方便的方式来查看进程的文件描述符信息,这对于调试和监控进程非常有用。通过查看文件描述符信息,可以了解进程打开了哪些文件、网络连接等,帮助开发者和系统管理员进行问题排查和分析工作。
(3)检测文件
众所周知frida我们一般都会放在data/local/tmp目录下,旧版fridaserver端运行时都会释放到re.frida.server,所以这里在旧版也会被当做一个检测点,而新版已不再释放

/proc/self/maps
是一个特殊的文件,它包含了当前进程的内存映射信息。当你打开这个文件时,它会显示一个列表,其中包含了进程中每个内存区域的详细信息。这些信息通常包括:
anti脚本
重定向maps
用eBPF来hook系统调用并修改参数实现目的,使用bpf_probe_write_user向用户态函数地址写内容直接修改参数
anti脚本
通过Frida查看一个函数hook之前和之后的机器码,以此来判断是否被Frida的inlinehook注入。

下面的方案以内存中字节和本地对应的字节进行比较,如果不一致,那么可以认为内存中的字节被修改了,即被inlinehook了
获取hook前字节码的脚本
anti脚本
注意版本!!!
strongR-frida-android
待更新
百度云
阿里云
哔哩哔哩
教程开源地址
PS:解压密码都是52pj,阿里云由于不能分享压缩包,所以下载exe文件,双击自解压
frida常用检测点及其原理--一把梭方案
frida 检测
从inlinehook角度检测frida
Frida检测手段探究
Lsposed 技术原理探讨 && 基本安装使用
strongR-frida-android
[原创]绕过bilibili frida反调试
基础反检测 frida-server
关于frida检测的一个新思路
读取本地so文件的符号的偏移
.
/
fs1
-
l
0.0
.
0.0
:
6666
adb forward tcp:
6666
tcp:
6666
frida
-
H
127.0
.
0.1
:
6666
wuaipojie
-
l hook.js
.
/
fs1
-
l
0.0
.
0.0
:
6666
adb forward tcp:
6666
tcp:
6666
frida
-
H
127.0
.
0.1
:
6666
wuaipojie
-
l hook.js
frida
-
U
-
f 进程名
-
l hook.js
frida
-
U
-
f 进程名
-
l hook.js
function
hook_dlopen() {
Interceptor.attach(Module.findExportByName(
null
,
"android_dlopen_ext"
),
{
onEnter:
function
(args) {
var
pathptr = args[0];
if
(pathptr !== undefined && pathptr !=
null
) {
var
path = ptr(pathptr).readCString();
console.log(
"load "
+ path);
}
}
}
);
}
function
hook_dlopen() {
Interceptor.attach(Module.findExportByName(
null
,
"android_dlopen_ext"
),
{
onEnter:
function
(args) {
var
pathptr = args[0];
if
(pathptr !== undefined && pathptr !=
null
) {
var
path = ptr(pathptr).readCString();
console.log(
"load "
+ path);
}
}
}
);
}
bool
check_dbus() {
struct
sockaddr_in sa;
int
sock;
char
res[7];
for
(
int
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,
"ZJ595"
,
"FRIDA DETECTION [1]: Open Port: %d"
, i);
memset
(res, 0, 7);
send(sock,
"\x00"
, 1, 0);
send(sock,
"AUTH\r\n"
, 6, 0);
usleep(100);
if
(recv(sock, res, 6, MSG_DONTWAIT) != -1) {
if
(
strcmp
(res,
"REJECT"
) == 0) {
close(sock);
return
true
;
}
}
}
close(sock);
}
return
false
;
}
bool
check_dbus() {
struct
sockaddr_in sa;
int
sock;
char
res[7];
for
(
int
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,
"ZJ595"
,
"FRIDA DETECTION [1]: Open Port: %d"
, i);
memset
(res, 0, 7);
send(sock,
"\x00"
, 1, 0);
send(sock,
"AUTH\r\n"
, 6, 0);
usleep(100);
if
(recv(sock, res, 6, MSG_DONTWAIT) != -1) {
if
(
strcmp
(res,
"REJECT"
) == 0) {
close(sock);
return
true
;
}
}
}
close(sock);
}
return
false
;
}
bool
check_fd() {
DIR *dir = NULL;
struct
dirent *entry;
char
link_name[100];
char
buf[100];
bool
ret =
false
;
if
((dir = opendir(
"/proc/self/fd/"
)) == NULL) {
LOGI(
" %s - %d error:%s"
, __FILE__, __LINE__,
strerror
(
errno
));
}
else
{
entry = readdir(dir);
while
(entry) {
switch
(entry->d_type) {
case
DT_LNK:
sprintf
(link_name,
"%s/%s"
,
"/proc/self/fd/"
, entry->d_name);
readlink(link_name, buf,
sizeof
(buf));
if
(
strstr
(buf,
"frida"
) ||
strstr
(buf,
"gum-js-loop"
) ||
strstr
(buf,
"gmain"
) ||
strstr
(buf,
"-gadget"
) ||
strstr
(buf,
"linjector"
)) {
LOGI(
"check_fd -> find frida:%s"
, buf);
ret =
true
;
}
break
;
default
:
break
;
}
entry = readdir(dir);
}
}
closedir(dir);
return
ret;
}
bool
check_fd() {
DIR *dir = NULL;
struct
dirent *entry;
char
link_name[100];
char
buf[100];
bool
ret =
false
;
if
((dir = opendir(
"/proc/self/fd/"
)) == NULL) {
LOGI(
" %s - %d error:%s"
, __FILE__, __LINE__,
strerror
(
errno
));
}
else
{
entry = readdir(dir);
while
(entry) {
switch
(entry->d_type) {
case
DT_LNK:
sprintf
(link_name,
"%s/%s"
,
"/proc/self/fd/"
, entry->d_name);
readlink(link_name, buf,
sizeof
(buf));
if
(
strstr
(buf,
"frida"
) ||
strstr
(buf,
"gum-js-loop"
) ||
strstr
(buf,
"gmain"
) ||
strstr
(buf,
"-gadget"
) ||
strstr
(buf,
"linjector"
)) {
LOGI(
"check_fd -> find frida:%s"
, buf);
ret =
true
;
}
break
;
default
:
break
;
}
entry = readdir(dir);
}
}
closedir(dir);
return
ret;
}
adb shell ps | findstr com.zj.wuaipojie
cat
/
proc
/
12186
/
maps|grep frida
adb shell ps | findstr com.zj.wuaipojie
cat
/
proc
/
12186
/
maps|grep frida
字段 |
描述 |
u0_a504 |
用户ID和应用ID:在Android系统中,u0 代表系统用户(user 0),而a504 是该应用在用户0下的唯一标识符。 |
28082 |
PID(进程ID):该进程在操作系统中的标识符。 |
1935 |
PPID(父进程ID):该进程的父进程的PID。 |
6511212 |
虚拟内存:进程使用的虚拟内存大小,通常以字节为单位。 |
125728 |
共享内存:进程使用的共享内存大小,同样以字节为单位。 |
0 |
CPU时间/线程数:这通常表示进程的CPU时间或者是线程数,具体含义取决于ps 命令的输出格式。 |
S |
状态:其中S 代表睡眠状态(Sleeping),即进程没有在执行,而是在等待某些事件或资源。 |
bool
check_maps() {
char
line[512];
FILE
* fp =
fopen
(
"/proc/self/maps"
,
"r"
);
if
(fp) {
while
(
fgets
(line,
sizeof
(line), fp)) {
if
(
strstr
(line,
"frida"
) ||
strstr
(line,
"gadget"
)) {
fclose
(fp);
return
true
;
}
}
fclose
(fp);
}
else
{
}
return
false
;
}
bool
check_maps() {
char
line[512];
FILE
* fp =
fopen
(
"/proc/self/maps"
,
"r"
);
if
(fp) {
while
(
fgets
(line,
sizeof
(line), fp)) {
if
(
strstr
(line,
"frida"
) ||
strstr
(line,
"gadget"
)) {
fclose
(fp);
return
true
;
}
}
fclose
(fp);
}
else
{
}
return
false
;
}
function
anti_maps() {
var
pt_strstr = Module.findExportByName(
"libc.so"
,
'strstr'
);
var
pt_strcmp = Module.findExportByName(
"libc.so"
,
'strcmp'
);
Interceptor.attach(pt_strstr, {
onEnter:
function
(args) {
var
str1 = args[0].readCString();
var
str2 = args[1].readCString();
if
(str2.indexOf(
"REJECT"
) !== -1 || str2.indexOf(
"frida"
) !== -1) {
this
.hook =
true
;
}
},
onLeave:
function
(retval) {
if
(
this
.hook) {
retval.replace(0);
}
}
});
Interceptor.attach(pt_strcmp, {
onEnter:
function
(args) {
var
str1 = args[0].readCString();
var
str2 = args[1].readCString();
if
(str2.indexOf(
"REJECT"
) !== -1 || str2.indexOf(
"frida"
) !== -1) {
this
.hook =
true
;
}
},
onLeave:
function
(retval) {
if
(
this
.hook) {
retval.replace(0);
}
}
});
}
function
anti_maps() {
var
pt_strstr = Module.findExportByName(
"libc.so"
,
'strstr'
);
var
pt_strcmp = Module.findExportByName(
"libc.so"
,
'strcmp'
);
Interceptor.attach(pt_strstr, {
onEnter:
function
(args) {
var
str1 = args[0].readCString();
var
str2 = args[1].readCString();
if
(str2.indexOf(
"REJECT"
) !== -1 || str2.indexOf(
"frida"
) !== -1) {
this
.hook =
true
;
}
},
onLeave:
function
(retval) {
if
(
this
.hook) {
retval.replace(0);
}
}
});
Interceptor.attach(pt_strcmp, {
onEnter:
function
(args) {
var
str1 = args[0].readCString();
var
str2 = args[1].readCString();
if
(str2.indexOf(
"REJECT"
) !== -1 || str2.indexOf(
"frida"
) !== -1) {
this
.hook =
true
;
}
},
onLeave:
function
(retval) {
if
(
this
.hook) {
retval.replace(0);
}
}
});
}
function
mapsRedirect() {
var
FakeMaps =
"/data/data/com.zj.wuaipojie/maps"
;
const openPtr = Module.getExportByName(
'libc.so'
,
'open'
);
const open =
new
NativeFunction(openPtr,
'int'
, [
'pointer'
,
'int'
]);
var
readPtr = Module.findExportByName(
"libc.so"
,
"read"
);
var
read =
new
NativeFunction(readPtr,
'int'
, [
'int'
,
'pointer'
,
"int"
]);
var
MapsBuffer = Memory.alloc(512);
var
MapsFile =
new
File(FakeMaps,
"w"
);
Interceptor.replace(openPtr,
new
NativeCallback(
function
(pathname, flag) {
var
FD = open(pathname, flag);
var
ch = pathname.readCString();
if
(ch.indexOf(
"/proc/"
) >= 0 && ch.indexOf(
"maps"
) >= 0) {
console.log(
"open : "
, pathname.readCString());
while
(parseInt(read(FD, MapsBuffer, 512)) !== 0) {
var
MBuffer = MapsBuffer.readCString();
MBuffer = MBuffer.replaceAll(
"/data/local/tmp/re.frida.server/frida-agent-64.so"
,
"FakingMaps"
);
MBuffer = MBuffer.replaceAll(
"re.frida.server"
,
"FakingMaps"
);
MBuffer = MBuffer.replaceAll(
"frida-agent-64.so"
,
"FakingMaps"
);
MBuffer = MBuffer.replaceAll(
"frida-agent-32.so"
,
"FakingMaps"
);
MBuffer = MBuffer.replaceAll(
"frida"
,
"FakingMaps"
);
MBuffer = MBuffer.replaceAll(
"/data/local/tmp"
,
"/data"
);
MapsFile.write(MBuffer);
}
var
filename = Memory.allocUtf8String(FakeMaps);
return
open(filename, flag);
}
return
FD;
},
'int'
, [
'pointer'
,
'int'
]));
}
function
mapsRedirect() {
var
FakeMaps =
"/data/data/com.zj.wuaipojie/maps"
;
const openPtr = Module.getExportByName(
'libc.so'
,
'open'
);
const open =
new
NativeFunction(openPtr,
'int'
, [
'pointer'
,
'int'
]);
var
readPtr = Module.findExportByName(
"libc.so"
,
"read"
);
var
read =
new
NativeFunction(readPtr,
'int'
, [
'int'
,
'pointer'
,
"int"
]);
var
MapsBuffer = Memory.alloc(512);
var
MapsFile =
new
File(FakeMaps,
"w"
);
Interceptor.replace(openPtr,
new
NativeCallback(
function
(pathname, flag) {
var
FD = open(pathname, flag);
var
ch = pathname.readCString();
if
(ch.indexOf(
"/proc/"
) >= 0 && ch.indexOf(
"maps"
) >= 0) {
console.log(
"open : "
, pathname.readCString());
while
(parseInt(read(FD, MapsBuffer, 512)) !== 0) {
var
MBuffer = MapsBuffer.readCString();
MBuffer = MBuffer.replaceAll(
"/data/local/tmp/re.frida.server/frida-agent-64.so"
,
"FakingMaps"
);
MBuffer = MBuffer.replaceAll(
"re.frida.server"
,
"FakingMaps"
);
MBuffer = MBuffer.replaceAll(
"frida-agent-64.so"
,
"FakingMaps"
);
MBuffer = MBuffer.replaceAll(
"frida-agent-32.so"
,
"FakingMaps"
);
MBuffer = MBuffer.replaceAll(
"frida"
,
"FakingMaps"
);
MBuffer = MBuffer.replaceAll(
"/data/local/tmp"
,
"/data"
);
MapsFile.write(MBuffer);
}
var
filename = Memory.allocUtf8String(FakeMaps);
return
open(filename, flag);
}
return
FD;
},
'int'
, [
'pointer'
,
'int'
]));
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课