一例簡單的frida反調試繞過
前言最近在分析一款app時遇見了frida反調試,花了時間簡單學習了一下,有不少收獲,記錄下學習的過程。
拋出問題frida是一個很強大的hook框架,用的人多了,自然而然就出現了很多檢測方案,這次碰到的app就檢測了frida,可以正常打開,但是當你用frida -f啟動或者attach進程,不久后就會閃退。
常見frida檢測1.檢測frida-server文件名
2.檢測27042默認端口
3.檢測D-Bus
4.檢測/proc/pid/maps映射文件
5.檢測/proc/pid/tast/tid/stat或/proc/pid/tast/tid/status
6.雙進程保護
前兩種可以通過修改frida-server文件名,改默認端口繞過。雙進程可以通過-f spawn模式啟動繞過。其他的需要去hook修改。
定位先針對簡單的幾個可能檢測的方式,我修改了文件名,改了端口,也嘗試了spawn啟動,均會在啟動后不久閃退。
這時考慮到其他幾種檢測。
首先用frida去看看載入了哪些so,看看是哪里檢測了,看了個寂寞。
function fridaProcess(){ Java.perform(function () { var enumMoudle = Process.enumerateModules(); for (var i = 0; i < enumMoudle.length; i++){ console.log("", enumMoudle[i].name) } }); }
setImmediate(fridaProcess,0)

因為so載入的時候,底層最后open去打開的。
所以再用frida去hook應用中的open函數,看看讀取了哪些so或者文件,可以看到最后斷在了/proc/self/maps。
var pth = Module.findExportByName(null,"open"); Interceptor.attach(ptr(pth),{ onEnter:function(args){ this.filename = args[0]; console.log("",this.filename.readCString()) if (this.filename.readCString().indexOf(".so") != -1){ args[0] = ptr(0)
}
},onLeave:function(retval){ return retval; } })

稍稍深入這里當掛上frida后對應的maps文件中會出現re.frida.server之類的特征,這是在使用frida server的時候自動創建的,其中存放著frida的功能模塊,可以在載入so的hook腳本輸出中能看到最后也是斷在frida-agent.so。

這里要繞過這個檢測,我是通過備份一個正常啟動時的maps文件(這里前面也講到app不使用frida是能正常啟動不閃退的)。
function main() { 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 fakePath = "/data/data/com.app/maps"; var file = new File(fakePath, "w"); var buffer = Memory.alloc(512); Interceptor.replace(openPtr, new NativeCallback(function (pathnameptr, flag) { var pathname = Memory.readUtf8String(pathnameptr); var realFd = open(pathnameptr, flag); if (pathname.indexOf("maps") >= 0) { while (parseInt(read(realFd, buffer, 512)) !== 0) { var oneLine = Memory.readCString(buffer); if (oneLine.indexOf("tmp") === -1) { file.write(oneLine); } } var filename = Memory.allocUtf8String(fakePath); return open(filename, flag); } var fd = open(pathnameptr, flag); return fd; }, 'int', ['pointer', 'int']));}setImmediate(main)

然后就可以繼續調試了。
總結這只是一個簡單的例子,但是確實在這個bypass的過程中學到了東西,只要花時間是去分析,總能找到對應的突破口。