python反爬之反除錯檢測frida
前面有一兩篇博文介紹過frida,對於做安全和逆向的朋友來說,那簡直就是象棋裡“車”的存在,走哪殺哪,所以這也對做安全的人來說,肯定也會針對frida做一定的反制,以下就是轉載的檢測frida的方法,原貼連結:點我
Frida 在逆向工程獅中很受歡迎,你基本可以在執行時訪問到你能想到的任何東西,記憶體地址、native 函式、Java 例項物件等。
在 OWASP 的移動測試指南里就提到了 Frida。但是啊,每出來個好用的注入工具,都會有反注入、反反注入、反反反注入、反...注入。
這篇文章要介紹的是 Android APP 檢測 Frida 的方法。
檢查 Frida 的痕跡
一種簡易方法是檢測 Frida 的執行痕跡,也適用於同類工具的檢測,比如包檔案、二進位制檔案、庫檔案、程序、臨時檔案等等。
本例中針對的物件是 fridaserver,它通過 TCP 對外與 frida 通訊,此時可以用 Java 遍歷執行的程序列表從而檢查 fridaserver 是否在執行。
public boolean checkRunningProcesses() { boolean returnValue = false; // Get currently running application processes List<RunningServiceInfo> list = manager.getRunningServices(300); if(list != null){ String tempName; for(int i=0;i<list.size();++i){ tempName = list.get(i).process; if(tempName.contains("fridaserver")) { returnValue = true; } } } return returnValue; }
若 Frida 執行在預設配置時此法有效,若是遇到個笨拙的指令碼小子,在第一步就能絆倒他。繞過也是相當簡單,只需重新命名 fridaserver,我們得找個更好的方法。
fridaserver 預設的 TCP 埠是 27047,可以檢查這個埠是否開放。native 程式碼如下:
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… */ } }
同樣,這也得要求 fridaserver 是預設配置執行,命令列指定引數就可以改變它的監聽埠,繞過也太不麻煩了。
不過我們可以用nmap -sV
找到開放埠來改善這個方法,因為 fridaserver 使用 D-Bus 協議通訊,我們為每個開放的埠傳送 D-Bus 的認證訊息,哪個埠回覆了哪個就是 fridaserver。
/*
* 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);
}
我們現在好像有了個非常好用的方法了呢,但是還存在問題。
Frida 提供不需要 fridaserver 執行的模式!怎麼檢測?!
Frida 的各個模式都是用來注入的,我們可以利用的點就是 frida 執行時對映到記憶體的庫。最直接的是挨個檢查載入的庫。
char line[512];
FILE* fp;
fp = fopen("/proc/self/maps", "r");
if (fp) {
while (fgets(line, 512, fp)) {
if (strstr(line, "frida")) {
/* Evil library is loaded. Do something… */
}
}
fclose(fp);
} else {
/* Error opening /proc/self/maps. If this happens, something is off. */
}
}
這段程式碼檢測名字含有“frida”的庫,表明上有用,實際上:
-還記得為什麼檢測名字是“fridaserver”的方法為什麼不可靠吧?這裡也是一樣,稍微改一下 frida 就能重新命名代理庫名。
-這段程式碼依賴的是標準庫的fopen()
和strstr()
函式,可笑的是,我們竟想用能被 frida 輕而易舉就 hook 的函式來檢測 frida !
第一點可以用經典的病毒掃描法解決,在記憶體中掃描 frida 的庫特徵 “gadgets”。
我選擇字串 “LIBFRIDA”,它在所有 frida-gadget 和 frida-agent 的版本中都有出現。
下面的程式碼掃描了在/proc/sel/maps
裡找到的所有的可執行段,為了簡潔我放了部分程式碼,完整的在 https://github.com/b-mueller/frida-detection-demo/blob/master/AntiFrida/app/src/main/cpp/native-lib.cpp
static char keyword[] = "LIBFRIDA";
num_found = 0;
int scan_executable_segments(char * map) {
char buf[512];
unsigned long start, end;
sscanf(map, "%lx-%lx %s", &start, &end, buf);
if (buf[2] == 'x') {
return (find_mem_string(start, end, (char*)keyword, 8) == 1);
} else {
return 0;
}
}
void scan() {
if ((fd = my_openat(AT_FDCWD, "/proc/self/maps", O_RDONLY, 0)) >= 0) {
while ((read_one_line(fd, map, MAX_LINE)) > 0) {
if (scan_executable_segments(map) == 1) {
num_found++;
}
}
if (num_found > 1) {
/* Frida Detected */
}
}
注意my_openat()
等函式,它們並非平常的 libc 庫函式,是自定義實現的,但是功能和 libc 中的一樣,設定了系統呼叫的引數,執行了軟中斷。因為直接呼叫公共 API 並不可靠,這樣不容易被 hook。
完整的實現在 https://github.com/b-mueller/frida-detection-demo/blob/master/AntiFrida/app/src/main/cpp/syscall.S 。
下面是 my_openat 的程式碼:
#include "bionic_asm.h"
.text
.globl my_openat
.type my_openat,function
my_openat:
.cfi_startproc
mov ip, r7
.cfi_register r7, ip
ldr r7, =__NR_openat
swi #0
mov r7, ip
.cfi_restore r7
cmn r0, #(4095 + 1)
bxls lr
neg r0, r0
b __set_errno_internal
.cfi_endproc
.size my_openat, .-my_openat;
到這裡總算是有效的方法了,只用 frida 的話也不容易繞過,加了混淆更難。即使這樣,依然有很多辦法可以繞過,直接能想到的就是打補丁、hook 系統呼叫。但是記住,逆向工程永遠勝利!
想要試驗,可以在這裡 https://github.com/b-mueller/frida-detection-demo/ 下載 Android studio 工程。frida 注入時的執行結果如下:
以上為原文內容。
有了以上的方法,就可以一定程度的對frida進行反除錯,對了,注意我給的形容詞,【一定程度】,因為還是那句老話,爬蟲和反爬之間從來沒有絕對的壓制,只有使用者的技術高低決定最後的勝負