每当我安装并启动 frida-server 时,我的银行应用程序都会表现得很奇怪。经过一番研究,我发现某些应用程序可能能够在 NDK 级别运行 frida-server 的设备上进行端口扫描。我尝试将
frida-server
的默认端口更改为其他端口,但我仍在重现应用程序的确切行为。
根据 mullerberndt,我编写了一个脚本来检查 frida-server 的默认端口和整个端口范围,并发送 D-Bus 协议探测
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
struct sockaddr_in sa;
int detect_frida_server(void);
bool check_protocol(int);
bool check_all_ports(int);
int main() {
int res = detect_frida_server();
printf("Detection result return value: %d\n", res);
return 0;
}
int detect_frida_server() {
const int fs_port = 27047;
memset(&sa, 0 , sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = htons(fs_port);
inet_aton("127.0.0.1", &(sa.sin_addr));
int sock = socket(AF_INET, SOCK_STREAM, 0);
if(connect(sock, (struct sockaddr *) &sa, sizeof sa) != -1) {
printf("FRIDA DETECTION[1]: Open port: %d\n", fs_port);
if(check_protocol(sock)) {
printf("Frida server detected!");
return 1;
}
printf("Suspicious.\n");
return 2;
}
else if(check_all_ports(fs_port)) {
printf("Frida server detected!");
return 1;
}
if(check_all_ports(fs_port)) {
printf("Frida server detected!");
return 1;
}
return 0;
}
bool check_all_ports(int port) {
int i, sock;
for (i = 0; i <=65535; i++) {
if(i == port) continue;
sock = socket(AF_INET, SOCK_STREAM, 0);
sa.sin_port = htons(i);
if(connect(sock, (struct sockaddr *) &sa, sizeof sa) != -1)
{
printf("FRIDA DETECTION[1]: Open port: %d\n", i);
if(check_protocol(sock)) return true;
}
}
return false;
}
bool check_protocol(int s) {
char res[7];
bool rres = false;
memset((void*) res, 0, sizeof(res));
send(s, "\x00", 1, NULL);
send(s, "AUTH\r\n", 6, NULL);
usleep(100);
if(recv(s, res, sizeof(res) - 1, MSG_DONTWAIT) != -1)
if(strcmp(res, "REJECT") == 0)
rres = true;
return rres;
}
编译它
\Android\Sdk\ndk\21.4.7075529\toolchains\llvm\prebuilt\windows-x86_64\bin\aarch64-linux-android21-clang detect-fs.c -o detect_frida
并用
推动adb push detect_frida /data/local/tmp/detect-fs-v2
运行代码时,我能够检测到开放端口,并且
connect
但 D-Bus 协议似乎不起作用,因此陷入了循环(如果已连接,则会打印 FridaDetected”):
因此我将代码精简为仅连接到端口并返回真/假值:
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
int port_scan(void);
int main() {
int open = port_scan();
if(open) printf("Port is open at: %d\n", open);
else printf("No ports were found to be open. System secure.\n");
return 0;
}
int port_scan() {
struct sockaddr_in sa;
memset(&sa, 0 , sizeof(sa));
sa.sin_family = AF_INET;
for(int i = 0; i < 65535; i++) {
int sock = socket(AF_INET, SOCK_STREAM, 0);
sa.sin_port = htons(i);
if(connect(sock, (struct sockaddr *) &sa, sizeof sa) != -1) {
close(sock);
return i;
}
}
return 0;
}
无需连接协议。我怀疑这就是我感兴趣的应用程序正在做的事情。公平地说,我授予了二进制根访问权限,并对二进制文件执行了
chmod 775
操作。但我确实想知道 Play 商店应用程序是否能够在 NDK 级别的非 root 环境中检测到这一点,而无需经历尝试构建 apk 来测试自己的麻烦。
在非 root 的 Android 环境中,不允许任何端口在本地主机上侦听是否合理? (甚至没有端口 80 上的 Web 服务器)?好吧,由于该应用程序没有彻底抱怨根,我知道它能够应对最彻底的情况,因此可以合理地假设它给了我一个怀疑的好处,但暗示我的环境不安全。
因此,除了 mullerberndt 的 frida-server 端口扫描方法之外,另一种方法是检查我们没有使用的 frida-gadget,我们如何编写一个 frida 脚本来挂钩 connect 方法以返回 false(即所有端口都是关闭)。请记住,我们必须允许合法的连接方法,因为这是具有自己的后端的应用程序通信方法的基础
此外,扫描 Android 设备上的所有端口需要多长时间才能作为 root/篡改检查的一种实用方法?
在进一步研究中,我实际上发现正在运行 2 个
frida-server
实例,一个在默认端口上,另一个在自定义端口上。我必须在我的设备上在 Termux 上运行端口扫描器 5-10 分钟才能真正为我提供 2 个开放端口。
我刚刚得出结论,我的目标应用程序实际上是在检查 frida 是否正在使用此代码监听默认端口 27047
boolean is_frida_server_listening() {
struct sockaddr_in sa;
memset(&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = htons(27047);
inet_aton("127.0.0.1", &(sa.sin_addr));
int sock = socket(AF_INET , SOCK_STREAM , 0);
if (connect(sock , (struct sockaddr*)&sa , sizeof sa) != -1) {
/* Frida server detected. Do something… */
}
}
这回答了我的问题,即在所有 65535 端口上运行完整端口扫描需要多长时间。在 arm-64 Android 设备上基本上需要 5 - 10 分钟。对于根检测器来说不是一个好的选择。