主要內(nèi)容:
frida-inject腳本持久化的方案
App開(kāi)關(guān)文件目錄以及腳本存儲(chǔ)文件目錄selinux配置
封裝和超級(jí)Root權(quán)限后臺(tái)進(jìn)程通信的java Api接口以及封裝訪問(wèn)腳本相關(guān)目錄文件的Java接口
系統(tǒng)源碼中添加App啟動(dòng)的時(shí)候執(zhí)行frida-inject命令的邏輯代碼
開(kāi)發(fā)控制App實(shí)現(xiàn)對(duì)第三方App 持久化的配置
1.frida-inject腳本持久化方案原理
方案原理:
在系統(tǒng)源碼App啟動(dòng)入口的地方,找一個(gè)合適的時(shí)機(jī)。將frida-inject組裝執(zhí)行附加的命令通過(guò)Socket連接發(fā)送到超級(jí)Root權(quán)限后臺(tái)進(jìn)程中執(zhí)行,達(dá)到實(shí)現(xiàn)App啟動(dòng)就加載js腳本的功能。App啟動(dòng)入口加載時(shí)機(jī)我們選擇ActivityThread.java中的handleBindApplication方法。以下是該方案的一個(gè)圖示:
2.持久化相關(guān)目錄文件創(chuàng)建及selinux配置
2.1 文件及目錄設(shè)計(jì)
在該方案中,設(shè)計(jì)以下的文件目錄用來(lái)判斷App是否需要開(kāi)啟frida inject持久化以及加載的js文件路徑。設(shè)計(jì)如下:
#配置某一個(gè)App是否開(kāi)啟持久化功能,$PKG_NAME表示App的包名 #比如一個(gè)參考:/data/system/xsettings/frdinject/persist/com.android.jnidemo01/persist_fridainject /data/system/xsettings/frdinject/persist/$PKG_NAME/persist_fridainject #配置某一個(gè)App加載的js文件路徑,$PKG_NAME表示App的包名 #/data/system/xsettings/frdinject/jscfg/com.android.jnidemo01/config.js /data/system/xsettings/frdinject/jscfg/$PKG_NAME/config.js
在涉及以上的文件或者目錄中,管控端App具有system權(quán)限,需要配置系統(tǒng)權(quán)限的App對(duì)以上文件或者目錄讀寫(xiě)的selinux權(quán)限。普通App需要對(duì)以上文件有讀的權(quán)限,所以需要配置第三方App具有讀以上文件的selinux權(quán)限。
2.2 配置selinux操作
(1).創(chuàng)建文件類型selinux標(biāo)簽
在如下文件中創(chuàng)建文件標(biāo)簽frdinject_data_file,文件列表:
systemsepolicypublicfile.te systemsepolicyprebuiltsapi29.0publicfile.te
在以上文件中添加如下內(nèi)容,需要保證兩個(gè)文件添加的內(nèi)容一致。不然要編譯錯(cuò)誤。
#/data/system/xsettings/ typefrdinject_data_file,file_type,data_file_type,core_data_file_type,mlstrustedobject;
(2).為文件目錄關(guān)聯(lián)frdinject_data_file標(biāo)簽
在如下文件中添加關(guān)聯(lián)/data/system/xsettings目錄selinux標(biāo)簽,文件列表:
systemsepolicyprebuiltsapi29.0privatefile_contexts systemsepolicyprivatefile_contexts
在以上文件中添加如下內(nèi)容,需要保證兩個(gè)文件添加的內(nèi)容一致。不然要編譯錯(cuò)誤。
/data/system/xsettings(/.*)?ufrdinject_data_file:s0
(3).配置App訪問(wèn)frdinject_data_file標(biāo)簽的權(quán)限
這個(gè)地方主要配置兩種App。一種是system權(quán)限的配置端App。第二種是第三方App。
具有系統(tǒng)權(quán)限的配置端App selinux配置如下:
在如下文件中:
systemsepolicyprivatesystem_app.te systemsepolicyprebuiltsapi29.0privatesystem_app.te
添加如下訪問(wèn)權(quán)限,添加之后請(qǐng)保持兩個(gè)文件內(nèi)容一致:
#addforaccessingfrdinject_data_file allowsystem_appfrdinject_data_file:dir{getattrsetattropenreadwriteremove_namecreateadd_namesearchrmdir}; allowsystem_appfrdinject_data_file:file{getattrsetattropenreadwritecreateunlink};
第三方App配置selinux如下:
在以下文件中添加app訪問(wèn)文件夾的selinux策略。確保相對(duì)應(yīng)的文件內(nèi)容一致。
在以下untrusted_app_all.te文件:
systemsepolicyprivateuntrusted_app_all.te systemsepolicyprebuiltsapi29.0privateuntrusted_app_all.te
添加內(nèi)容如下:
#addforaccessingfrdinject_data_file allowuntrusted_app_allfrdinject_data_file:dir{getattropenreadsearch}; allowuntrusted_app_allfrdinject_data_file:file{getattropenread};
在以下untrusted_app_27.te文件:
systemsepolicyprivateuntrusted_app_27.te systemsepolicyprebuiltsapi29.0privateuntrusted_app_27.te
在以下文件:
#addforaccessingfrdinject_data_file allowuntrusted_app_27frdinject_data_file:dir{getattropenreadsearch}; allowuntrusted_app_27frdinject_data_file:file{getattropenread};
在以下untrusted_app_25.te文件:
systemsepolicyprivateuntrusted_app_25.te systemsepolicyprebuiltsapi29.0privateuntrusted_app_25.te
#addforaccessingfrdinject_data_file allowuntrusted_app_25frdinject_data_file:dir{getattropenreadsearch}; allowuntrusted_app_25frdinject_data_file:file{getattropenread};
在以下untrusted_app.te文件:
systemsepolicyprivateuntrusted_app.te systemsepolicyprebuiltsapi29.0privateuntrusted_app.te
#addforaccessingfrdinject_data_file allowuntrusted_appfrdinject_data_file:dir{getattropenreadsearch}; allowuntrusted_appfrdinject_data_file:file{getattropenread};
2.3 init.rc中配置開(kāi)機(jī)的時(shí)候就創(chuàng)建對(duì)應(yīng)的目錄
該持久化實(shí)現(xiàn)中,使用了如下目錄。
/data/system/xsettings/frdinject/persist /data/system/xsettings/frdinject/jscfg
所以可以將該目錄放在init進(jìn)程啟動(dòng)的時(shí)候進(jìn)行創(chuàng)建。由于init進(jìn)程會(huì)解析init.rc文件執(zhí)行配置的命令,所以可以根據(jù)init.rc創(chuàng)建文件夾的規(guī)則加入創(chuàng)建以上兩個(gè)目錄的操作。在systemcore ootdirinit.rc文件中添加內(nèi)容如下:
#/data/system/xsettings/frdinject/persist mkdir/data/system/xsettings0775systemsystem mkdir/data/system/xsettings/frdinject0775systemsystem mkdir/data/system/xsettings/frdinject/persist0775systemsystem mkdir/data/system/xsettings/frdinject/jscfg0775systemsystem
3.系統(tǒng)源碼中相關(guān)Java接口封裝
3.1 封裝和超級(jí)Root權(quán)限通信的MgskSu模塊
在源碼根目錄中創(chuàng)建如下對(duì)應(yīng)的目錄:
frameworksasecorejavaandroidxfrd
在目錄xfrd中將存放MgskSu模塊的接口實(shí)現(xiàn)。具體實(shí)現(xiàn)如下:
packageandroid.xfrd; importjava.io.BufferedReader; importjava.io.BufferedWriter; importjava.io.InputStreamReader; importjava.io.OutputStreamWriter; importjava.net.InetSocketAddress; importjava.net.Socket; publicclassMgskSu{ publicstaticStringmagiskSu(Stringcmd) { StringretString=""; try{ //創(chuàng)建socket StringmyCmd="do_cmd|"+cmd; SocketmSocket=newSocket(); InetSocketAddressinetSocketAddress=newInetSocketAddress("127.0.0.1",11111); mSocket.connect(inetSocketAddress); BufferedWriterbufferedWriter=newBufferedWriter(newOutputStreamWriter(mSocket.getOutputStream())); BufferedReaderbufferedReader=newBufferedReader(newInputStreamReader(mSocket.getInputStream())); bufferedWriter.write(myCmd+" "); bufferedWriter.flush(); retString=bufferedReader.readLine(); bufferedReader.close(); bufferedWriter.close(); }catch(Exceptioneeeee) { eeeee.printStackTrace(); } returnretString; } }
3.2 封裝針對(duì)App需要持久化判斷和獲取對(duì)應(yīng)js文件路徑的接口
在該方案中通過(guò)對(duì)應(yīng)App的包名組裝文件路徑來(lái)識(shí)別是否存在來(lái)判斷App是否需要啟動(dòng)就加載js文件。在MagiskSu.java同目錄中創(chuàng)建FrdSettings.java模塊文件。核心代碼如下:
packageandroid.xfrd; importandroid.system.Os; importjava.io.File; publicclassFrdSettings{ staticfinalStringTAG=FrdSettings.class.getSimpleName(); privatestaticfinalStringSETTINGS_DIR="/data/system/xsettings/frdinject/persist"; privatestaticfinalStringCONFIG_JS_DIR="/data/system/xsettings/frdinject/jscfg"; publicstaticfinalStringPERSIST_FRIDA_INJECT="persist_fridainject"; publicstaticfinalStringPERSIST_FRIDA_GADGET="persist_fridagadget"; publicstaticfinalStringPERSIST_FRIDA_GUMJS="persist_fridagumjs"; // publicstaticbooleanisAppJsPathExists(StringpkgName){ Filefile=newFile(CONFIG_JS_DIR+"/"+pkgName+"/config.js"); returnfile.exists(); } publicstaticStringgetAppJsPath(StringpkgName) { Filefile=newFile(CONFIG_JS_DIR+"/"+pkgName+"/config.js"); returnfile.getAbsolutePath(); } /**********************判斷是否開(kāi)啟持久化***************************/ //設(shè)置對(duì)應(yīng)的App是否開(kāi)啟持久化 publicstaticvoidsetEnablePersistFridaInject(StringpkgName,StringmethodType,booleanisEnable){ Filefile=newFile(SETTINGS_DIR); if(!file.exists()){ file.mkdirs(); try{ Os.chmod(file.getAbsolutePath(),0775); }catch(Exceptioneeee){ } } FilepkgFile=newFile(file,pkgName); if(!pkgFile.exists()){ pkgFile.mkdirs(); try{ Os.chmod(pkgFile.getAbsolutePath(),0775); }catch(Exceptioneeee){ eeee.printStackTrace(); } } FileenableFile=newFile(pkgFile,methodType); if(isEnable){ if(!enableFile.exists()){ try{ enableFile.createNewFile(); //MyLog.d(TAG,"createfilesuccess"); Os.chmod(enableFile.getAbsolutePath(),0775); }catch(Exceptioneeee){ //MyLog.d(TAG,"filecreateerrror:"+enableFile.getAbsolutePath()); eeee.printStackTrace(); } }else{ //MyLog.d(TAG,"fileexists:"+enableFile.getAbsolutePath()); } }else{ if(enableFile.exists()){ enableFile.delete(); } } } //判斷app是否打開(kāi)自動(dòng)注入腳本功能 publicstaticbooleanisEnablePersistFrida(StringpkgName,StringmethodType){ FileenableFile=newFile(SETTINGS_DIR,pkgName+"/"+methodType); returnenableFile.exists(); } }
4.源碼中在App啟動(dòng)入口ActivityThread.java中添加加載js邏輯
在之前方案分析中已經(jīng)找到了在frameworksasecorejavaandroidappActivityThread.java中的handleBindApplication方法中加入加載js的邏輯是一個(gè)比較不錯(cuò)的選擇。在handleBindApplication中加入如下關(guān)鍵調(diào)用代碼,實(shí)現(xiàn)App啟動(dòng)的時(shí)候就去加載執(zhí)行js。核心關(guān)鍵代碼如下:
StringcurPkgName=data.appInfo.packageName; intmypid=Process.myPid(); intmytempUid=Process.myUid(); if(mytempUid>10000) { BooleanisB=FrdSettings.isEnablePersistFrida(curPkgName,FrdSettings.PERSIST_FRIDA_INJECT); Log.d("FridaInject","curPkgNameisEnableFridaInject:"+isB); if(isB) { StringjsPath=FrdSettings.getAppJsPath(curPkgName); if(jsPath!=null) { //這個(gè)地方比較重要,不然App運(yùn)行會(huì)奔潰。 //App中主線程中調(diào)用網(wǎng)絡(luò)socket操作配置 android.os.StrictMode.ThreadPolicypolicy=newandroid.os.StrictMode.ThreadPolicy.Builder().permitAll().build(); android.os.StrictMode.setThreadPolicy(policy); StringcmdString="myfridainjectarm64-p"+mypid+"-s"+jsPath+"-e"; StringretString=MgskSu.magiskSu(cmdString); try{ Thread.sleep(50); }catch(Exceptioneee) { } Log.d("FridaInject","retStringis"+retString); }else{ Log.d("FridaInject","jsPathisnull"); } }else{ } }
5.控制端App開(kāi)發(fā)實(shí)現(xiàn)對(duì)第三方App持久化配置
控制端App中對(duì)App是否持久化開(kāi)關(guān)配置以及js路徑配置使用的封裝接口和以上系統(tǒng)源碼中封裝的FrdSettings.java是一樣的封裝。這個(gè)地方就不講接口的封裝了。只說(shuō)一下幾個(gè)關(guān)鍵的地方使用。
配置界面參考:
主要涉及的幾個(gè)接口調(diào)用如下:
(1).打開(kāi)/關(guān)閉第三方App加載js功能
調(diào)用了封裝的接口:setEnablePersistFridaInject
(2).將選擇的js文件復(fù)制到對(duì)應(yīng)App的配置js目錄
調(diào)用了封裝的接口:copyJsFileToAppJsPath
(3).判斷App當(dāng)前是否配置了加載js功能
調(diào)用了封裝的接口:isEnablePersistFrida
(4).獲取App配置的js文件路徑
置以及js路徑配置使用的封裝接口和以上系統(tǒng)源碼中封裝的FrdSettings.java是一樣的封裝。這個(gè)地方就不講接口的封裝了。只說(shuō)一下幾個(gè)關(guān)鍵的地方使用。
配置界面參考:
[外鏈圖片轉(zhuǎn)存中…(img-L6IhssD7-1667868558625)]
主要涉及的幾個(gè)接口調(diào)用如下:
(1).打開(kāi)/關(guān)閉第三方App加載js功能
調(diào)用了封裝的接口:setEnablePersistFridaInject
(2).將選擇的js文件復(fù)制到對(duì)應(yīng)App的配置js目錄
調(diào)用了封裝的接口:copyJsFileToAppJsPath
(3).判斷App當(dāng)前是否配置了加載js功能
調(diào)用了封裝的接口:isEnablePersistFrida
(4).獲取App配置的js文件路徑
調(diào)用了封裝接口:getAppJsPath
審核編輯:劉清
-
JAVA
+關(guān)注
關(guān)注
19文章
2966瀏覽量
104707 -
API接口
+關(guān)注
關(guān)注
1文章
84瀏覽量
10437
原文標(biāo)題:基于frida-inject腳本持久化開(kāi)發(fā)實(shí)戰(zhàn)
文章出處:【微信號(hào):哆啦安全,微信公眾號(hào):哆啦安全】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論