確保軟件產品的安全性和可靠性是現代企業面臨的最大挑戰之一。隨著產品的發展,每個新功能都會為潛在的安全漏洞和性能瓶頸打開大門。
動態分析和逆向工程是允許開發人員在應用程序運行時探索其內部工作原理的兩種方法。借助這些見解,開發人員可以識別漏洞並發現潛在的安全問題。
在本文中,您將學習如何使用Frida 動態分析您的應用程序並發現漏洞。我們將根據我們自己的項目經驗向您展示Frida 工具的實際應用示例。本文對於想要確保其產品受到保護的安全研究人員、CTO 和CSO 非常有用。
什麼是動態分析以及為什麼它很重要?動態分析和逆向工程是企業增強產品安全性的兩種重要網絡安全方法。
動態分析允許網絡安全專家評估軟件運行時的行為。這對於:
漏洞檢測——發現潛在漏洞併計劃網絡安全增強,以保護您的產品免受數據洩露
真實世界模擬— 了解您的產品在現實條件下的表現,使您能夠從用戶的角度檢查您的產品,並了解它如何處理敏感數據和關鍵操作
性能優化——除了安全性之外,動態分析還有助於優化應用程序性能,從而幫助您改善產品的用戶體驗並優化基礎設施成本
合規保證——在潛在的違規行為導致合規違規和處罰之前識別它們
動態分析用於逆向工程,即使沒有源代碼或文檔,開發人員也可以剖析軟件並了解其內部工作原理。
在Apriorit,我們專注於逆向工程,並利用它來幫助企業評估和提高其軟件的安全性。這包括保護其免受可能導致重大聲譽和金錢損失的違規、惡意軟件攻擊和數據洩露。
有許多工具可以讓企業進行動態分析和逆向工程。在我們的逆向項目中,我們經常使用Frida。
Frida是什麼? Frida是一個動態開源檢測工具包,允許開發人員和逆向工程師將JavaScript 代碼注入正在運行的應用程序中。注入使開發人員能夠實時跟踪函數調用、修改函數行為和攔截數據,使其成為動態分析的寶貴工具。
Frida 提供了一套全面的API,可用於與正在運行的應用程序進行交互。
Frida 的體系結構基於客戶端-服務器模型。 Frida 服務器在目標設備或計算機上運行,而客戶端用於與服務器交互並將JavaScript 代碼注入正在運行的應用程序中。
讓我們看幾個示例,了解您可以使用Frida 執行哪些動態應用程序分析任務。我們將從桌面應用程序開始。
使用Frida 對桌面應用程序進行動態分析Frida 支持Windows、macOS 和Linux,使其成為分析桌面應用程序的可靠選擇,無論它們運行在何種操作系統上。讓我們看看您可以使用Frida 執行的一些任務。
在執行任何動態分析或操作操作之前,我們需要將Frida 注入到我們的桌面應用程序中。這是一個相對簡單的過程:
在目標系統上安裝Frida。
使用命令frida-server -l 0.0.0.0.這將啟動Frida 服務器並使其可供網絡上的其他設備訪問。
將Frida 客戶端附加到目標進程並註入Frida 腳本。
在Windows 桌面應用程序中掛鉤MessageBox為了演示如何使用Frida 掛鉤函數,讓我們考慮在Windows 桌面應用程序中掛鉤MessageBox函數的示例。該函數用於向用戶顯示消息框,使其成為動態分析的絕佳目標。
要使用Frida 掛鉤MessageBox函數,我們首先需要編寫一個Frida 腳本。該腳本將附加到目標進程,找到MessageBox 函數的地址,並使用攔截器掛鉤該函數。這是我們的一個項目中的自定義腳本:
在此腳本中,我們使用Module.findBaseAddress查找user32.dll 庫的基地址,其中包含MessageBox函數。然後,我們使用findExportByName方法獲取MessageBox函數的地址(對於私有方法,我們可以使用帶有偏移量的add)。最後,我們使用Interceptor.attach來掛鉤MessageBox函數,在調用該函數時將消息記錄到控制台。
要運行此腳本,請將其保存到文件(例如hook_messagebox.js)並使用以下命令運行Frida 客戶端:
這會將Frida 連接到目標進程並註入腳本。當目標進程調用MessageBox函數時,Frida將攔截該函數並將消息記錄到控制台。
在macOS 桌面應用程序中修改NSURLRequestFrida 在桌面應用程序中的另一個強大功能是實時修改數據。例如,讓我們考慮使用NSURLRequest發出HTTP 請求的macOS 桌面應用程序的情況。我們可以使用Frida 在發送HTTP 請求之前對其進行修改,從而使我們能夠繞過安全措施或修改應用程序的行為。
要使用Frida 修改macOS 桌面應用程序中的NSURLRequest,我們首先需要編寫一個Frida 腳本。該腳本將附加到目標進程,查找NSURLRequest對象的地址,並使用JavaScript 修改其屬性。這是一個例子:
functionmodify_nsurlrequest(){
//FindtheaddressoftheNSURLRequestobject
varrequestPtr=null;
varobjc_msgSend=newNativeFunction(Module.findExportByName('libobjc.A.dylib','objc_msgSend'),'pointer',['pointer','pointer']);
Interceptor.attach(objc_msgSend,{
onEnter:function(args){
varsel=ObjC.selectorAsString(args[1]);
if(sel==='initWithURL:cachePolicy:timeoutInterval:'){
requestPtr=args[0];
}
},
onLeave:function(retval){
if(requestPtr!==null){
varrequest=newObjC.Object(requestPtr);
request.setValue_forHTTPHeaderField_('my-custom-header','X-Custom-Header');
requestPtr=null;
}
}
});
}
//Attachtothetargetprocessandwaitforittostart
Process.enumerateApplications({
onMatch:function(info){
if(info.name==='TargetApp'){
console.log('Attachingto'+info.name+'('+info.pid+')');
//Attachtotheprocessandwaitforitsmainmoduletobeloaded
Process.attach(info.pid,{
onModuleLoaded:function(module){
if(module.name==='TargetApp'){
//Waitforthescriptruntimetobeready
setTimeout(modify_nsurlrequest,0);
}
}
});
}
},
onComplete:function(){
console.log('Failedtofindtargetprocess');
}
});該腳本使用objc_msgSend函數攔截對NSURLRequest類的initWithURL:cachePolicy:timeoutInterval:方法的調用。當調用這個方法時,我們保存初始化的NSURLRequest對象的地址。當該方法返回時,我們創建一個代表NSURLRequest對象的ObjC.Object實例,並根據需要修改其屬性。
接下來,我們使用Process.enumerateApplications按名稱查找目標進程。找到進程後,我們使用Process.attach附加到它並等待其主模塊加載。當主模塊加載時,我們調用setTimeout函數來安排在下一次事件循環迭代期間對修改_nsurlrequest函數的調用,從而為腳本運行時提供完全初始化的機會。
一旦調用了modify_nsurlrequest函數,它將攔截對NSURLRequest初始化方法的調用,並根據需要修改任何初始化的NSURLRequest對象的屬性。
這些只是您可以在桌面應用程序中使用Frida 執行的動態分析任務的幾個示例。現在讓我們看一下Frida 在移動應用程序中的用途。
使用Frida 對移動應用程序進行動態分析動態分析是識別移動應用程序中漏洞的有效方法,因為它使我們能夠實時監控應用程序行為。
Frida 可用於對Android 和iOS 應用程序執行動態分析。借助Frida,我們可以連接正在運行的應用程序並監視其行為,包括函數調用、網絡流量和內存使用。
要使用Frida對應用程序進行動態分析,我們首先需要將應用程序安裝在物理或虛擬設備上。然後,我們可以將Frida 附加到正在運行的進程並開始監視應用程序的行為。
Frida 可用於未root、已root 和越獄的設備。 Frida 官方文檔中詳細描述了安裝。通常,它涉及在目標設備上運行run frida-server 命令並在調試模式下使用USB 連接到目標設備。
讓我們看一些示例,了解如何使用Frida 在移動應用程序上運行動態分析。
繞過根檢測許多開發人員實施root 檢測以防止用戶在root 設備上運行其應用程序。然而,使用Frida 的動態分析可以繞過這個問題。
讓我們看一個使用Frida 繞過Android 應用程序中的root 檢測的示例。在這種情況下,我們假設應用程序正在使用SafetyNet API 來檢查設備是否已獲得root 權限。
為了繞過root 檢測,我們將使用Frida 攔截對SafetyNet API 的調用並修改返回值以指示設備未獲得root 權限。下面是實現此目的的JavaScript 代碼:
然而,現代移動應用程序和系統通常採用多層安全措施來檢測和防止各種形式的篡改和未經授權的訪問。因此,繞過當代應用程序和系統中的根檢測可能需要更廣泛和復雜的掛鉤技術。
您可以在CodeShare上找到這些技術和實施示例。
篡改API 調用移動應用程序通常使用API 與後端服務器進行通信。通過篡改API 調用,攻擊者可以修改應用程序行為或竊取敏感數據。
我們將在Frida 動態儀器中合乎道德地使用這項技術。篡改API 調用可以幫助您評估應用程序的整體安全性、檢查流量和監控行為。
Frida 允許篡改iOS 應用程序中的API 調用。在本例中,我們假設應用程序正在使用URLSession API 向後端服務器發出請求。
為了篡改API 調用,我們將使用Frida 攔截對URLSession API 的調用並在請求發送到服務器之前修改請求。這是實現此目的的代碼:
通過篡改API調用,您可以評估應用程序的安全漏洞。在Apriorit,我們使用這種方法來模擬各種攻擊場景,並識別應用程序處理數據、與服務器通信或響應意外輸入的方式中的潛在弱點。
與Frida 進行逆向工程您可以使用Frida 進行逆向工程。它提供了一個動態分析環境,可幫助您檢查應用程序在運行時的行為方式。 Frida 允許我們掛鉤應用程序的執行流程,監視和操作函數調用和參數,並攔截應用程序發送或接收的數據。
在Apriorit,我們使用Frida 執行各種逆向工程任務,例如:
提取加密密鑰
分析網絡流量
跟踪系統調用
識別惡意軟件行為
研究專有協議
分析二進制代碼
還有其他活動,例如使用Frida 進行惡意軟件檢測,允許網絡安全專家對惡意軟件進行逆向工程。
在本指南中,我們使用Android 應用程序作為示例演示前三個任務。 Frida 特別適合Android 平台,而其他工具可能更適合桌面和iOS 平台上的逆向工程任務。
提取加密密鑰Apriorit 安全專家團隊使用Frida 提取應用程序使用的加密密鑰來保護敏感數據。通過連接應用程序的加密函數,我們可以攔截應用程序生成或使用的密鑰並記錄它們以供進一步分析。
以下是使用Frida 從應用程序中提取加密密鑰的腳本示例:
該腳本掛鉤javax.crypto.KeyGenerator和javax.crypto.Cipher類並攔截它們的函數調用。當KeyGenerator初始化新密鑰時,腳本會記錄密鑰大小並生成密鑰。當使用密鑰初始化Cipher時,腳本會記錄有關密鑰的信息。
分析網絡流量Frida 可用於通過連接網絡功能並攔截應用程序發送或接收的數據來分析應用程序的網絡流量。這對於識別通過網絡傳輸的敏感數據以及了解應用程序如何與外部服務進行通信非常有用。
下面是一個使用Frida 攔截網絡流量的示例腳本:
Java.perform(function(){
varURL=Java.use('java.net.URL');
varHttpURLConnection=Java.use('java.net.HttpURLConnection');
varOutputStreamWriter=Java.use('java.io.OutputStreamWriter');
varBufferedReader=Java.use('java.io.BufferedReader');
//Intercepttherequest
HttpURLConnection.getOutputStream.implementation=function(){
varoutputStream=this.getOutputStream();
varrequestMethod=this.getRequestMethod();
varurl=this.getURL().toString();
//PrintouttherequestmethodandURL
console.log('[+]Intercepted'+requestMethod+'requestto'+url);
//Readtherequestbody
varrequest='';
//GettheInputStreamobject
varinputStream=this.getInputStream();
//CreateanewInputStreamReaderobject
varinputStreamReader=InputStreamReader.$new.overload('java.io.InputStream','java.lang.String')(inputStream,'UTF-8');
//CreateanewBufferedReaderobject
varBufferedReader_instance=BufferedReader.$new.overload('java.io.Reader')(inputStreamReader);
varline='';
while((line=BufferedReader_instance.readLine())!=null){
request+=line;
}
//Printouttherequestbody
console.log('[+]Requestbody:'+request);
//Modifytherequest
if(requestMethod=='POST'){
varmodifiedRequest='param1=value1param2=value2';
console.log('[+]Modifyingrequestbodyto:'+modifiedRequest);
//GettheOutputStreamWriterconstructor
varOutputStreamWriter=Java.use('java.io.OutputStreamWriter');
//GettheCharsetandStandardCharsetsclasses
varCharset=Java.use('java.nio.charset.Charset');
varStandardCharsets=Java.use('java.nio.charset.StandardCharsets');
//GettheOutputStreamobject
varoutputStream=this.getOutputStream();
//GettheUTF-8Charsetobject
varutf8Charset=StandardCharsets.UTF_8;
//CreateanewOutputStreamWriterobject
varoutputStreamWriter=OutputStreamWriter.$new.overload('java.io.OutputStream','java.nio.charset.Charset')(outputStream,utf8Charset);
outputStreamWriter.write(modifiedRequest);
outputStreamWriter.flush();
outputStreamWriter.close();
}
returnoutputStream;
};
//Intercepttheresponse
HttpURLConnection.getInputStream.implementation=function(){
varinputStream=this.getInputStream();
//Readtheresponsebody
varresponse='';
//GettheInputStreamobject
varinputStream=this.getInputStream();
//CreateanewInputStreamReaderobject
varinputStreamReader=InputStreamReader.$new.overload('java.io.InputStream','java.lang.String')(inputStream,'UTF-8');
//CreateanewBufferedReaderobject
varBufferedReader_instance=BufferedReader.$new.overload('java.io.Reader')(inputStreamReader);
varline='';
while((line=BufferedReader_instance.readLine())!=null){
response+=line;
}
//Printouttheresponsebody
console.log('[+]Responsebody:'+response);
returninputStream;
};
});該腳本攔截HTTP 請求和應用程序響應並顯示有關它們的信息,包括:
請求方式
網址
請求正文
響應體
它還演示瞭如何使用
Recommended Comments