王國珍,楊紅麗
(北京工業(yè)大學 信息學部,北京 100124)
隨著移動互聯(lián)網的高速發(fā)展,智能手機已經成為每個人生活中必不可少的工具,手機操作系統(tǒng)也正在高速發(fā)展.截止到2017年,Android智能手機在全球市場中占有超過85%的市場份額[1],占據(jù)著市場的主導地位.Android應用市場為用戶提供了功能各異的應用程序,截止2017年2月,Google Play已經發(fā)布了2700 000個應用[2].Android應用的種類變得更加多樣,提供的功能也更加專業(yè),應用之間可以分享信息并且相互協(xié)作完成一些復雜的任務.例如,一個電子支付應用可以被多個第三方的電子商務應用調用來完成支付功能.Android系統(tǒng)提供了開放活動(Exported Activity,EA)機制,可以將應用內特定的Activity分享給其他的應用.
EA往往包含開發(fā)者想要推廣的關鍵功能,可以被其他的應用重復執(zhí)行.因此,它們的質量是關鍵功能得到有效推廣的關鍵因素.另一方面,因為EA可以被任意的應用執(zhí)行,因此包含EA但是開發(fā)不是很完備的應用很容易被惡意應用濫用[3].綜上,開放活動的質量驗證是一個非常值得關注的課題.
在Android應用質量驗證方面,測試是一個很熱門的課題.大部分現(xiàn)有的工作主要集中在分析和測試單個應用的圖形交互界面(Graphical User Interface,GUI)上,被測應用與外部應用之間的交互往往被忽略.我們的實驗結果表明,在現(xiàn)有工作中EA很難被覆蓋到.因此,在對Android應用的測試過程中應該使用針對性的技術對這類Activity進行測試.
本文討論了如何系統(tǒng)的測試Android應用中的EA.首先,自動的生成一系列的應用作為測試驅動應用,然后利用這些測試驅動應用啟動目標應用中的EA,發(fā)現(xiàn)其中的漏洞.本文使用數(shù)據(jù)流分析技術得到啟動EA所需的信息,結合預先定義的模板生成測試驅動應用.選取了10個現(xiàn)實生活中使用非常廣泛的安卓應用進行了測試并且有效的檢測到了一些問題.通過分析測試結果,將檢測到的問題分為兩類:應用崩潰和界面異常.實驗結果表明本文提出的方法可以有效的對EA進行系統(tǒng)化測試,間接提高了存在EA應用的質量.
這部分內容將介紹在一些相關的背景知識,主要包括EA和Android系統(tǒng)提供的Intent機制.
Activity是使用率最高的Android組件,它提供了與用戶交互的GUI窗口.Activity可以分成兩類:內部活動(Internal Activity,IA)和開放活動(Exported Activity,EA).前者只能被同一應用中的其他組件啟動,后者允許被外部應用調用.EA是一種應用間有效的交互、協(xié)作方式.默認情況下除了應用的Main Activity之外所有的Activity都是IA類型,開發(fā)者可以在Manifest文件中將Activity的屬性(android:exported)設置為TRUE,使得該Activity變?yōu)镋A類型.如果不設置android:exported屬性,也可以在Manifest配置文件中EA對應的 外部應用通過Intent機制調用其他應用中的EA.Intent是消息傳遞的載體,其中包含目標組件的標識符和目標組件初始化所需的數(shù)據(jù). 發(fā)送方組件通過一系列重載的API(Application Programming Interface)以鍵值對(key-value)的形式將不同類型的數(shù)據(jù)附加到Intent中,例如,putExtra(String,int)可以添加整形數(shù)據(jù),putExtra(String,String)可以附加字符串型數(shù)據(jù).該方法的第一個參數(shù)是用于識別不同數(shù)據(jù)的鍵值(key),第二個參數(shù)是表明該數(shù)據(jù)的值(value).Android系統(tǒng)還提供了接收方組件獲取特定鍵值所對應數(shù)據(jù)的API.例如,getIntExtra(String key)可以根據(jù)指定的key值來獲取其對應的整形數(shù)值. 第三方開發(fā)商開發(fā)的應用通常會通過該機制為EA傳遞數(shù)據(jù)來完成一些任務,所以數(shù)據(jù)的有效性檢驗和EA的容錯性是非常重要并且需要特別關注的方向. 本小節(jié)將通過一個簡單的例子介紹本文研究的動機.圖1是樣例應用中一個EA(Foo)的代碼片段,該EA不會被應用中的其他組件調用.在onCreate方法中包含一條字符串類型數(shù)據(jù)和一條整形數(shù)據(jù),它們的鍵值分別為:“key1”、“key2”.由于該 Activity 不會被應用自身調用,所以現(xiàn)有的技術和工具[4,5]不會覆蓋到它. 圖1 EA的代碼片段 圖2是一個調用EA的測試驅動應用的示例代碼.它創(chuàng)建了一個Intent實例,設置它的目標Activity組件為Foo,并且設置了Foo初始化數(shù)據(jù),最后通過startActivity(Intent intent)方法執(zhí)行該Intent.通過這個例子可以發(fā)現(xiàn),對EA系統(tǒng)化測試的關鍵問題是如何為Intent中各種各樣的數(shù)據(jù)賦值. 圖2 Foo的測試驅動應用 本文提出了一種系統(tǒng)化測試Android應用中EA的方法.該小節(jié)中,首先對方法進行了簡單的概述,然后詳細介紹幾個關鍵模塊. 為了測試待測樣本中所有的EA,本文所提方法的主要思想是自動化的生成一批測試驅動應用,每個測試驅動應用會執(zhí)行攜帶不同數(shù)據(jù)(包括無效數(shù)據(jù))的Intent,啟動被測EA以檢測它處理不同數(shù)據(jù)時是否會出現(xiàn)漏洞.圖3是方法的概述.它包含四個模塊:Android安裝包(Android Package,APK)解析、Intent分析、測試驅動生成、測試執(zhí)行.第一個模塊提取待測樣本中所有的EA信息,包括:EA的包名和類名等;第二個模塊獲取每個EA啟動所需的數(shù)據(jù)信息;測試驅動生成模塊生成一批可調用EA的測試驅動應用;最后一個模塊在一臺真實的設備上執(zhí)行生成的測試驅動應用并記錄執(zhí)行結果. Android應用大多數(shù)都采用Java語言實現(xiàn)并被編譯為Dalvik字節(jié)碼.應用中的字節(jié)碼文件、資源文件和配置文件最后被打包成一個二進制形式的APK文件.為了進行后面的分析,本文首先利用Apktool[6]對APK文件進行反編譯,反匯編二進制代碼和配置文件.Apktool是Google官方提供的一款對Android應用逆向工程的工具.基于Android官方文檔中對Manifest配置文件的介紹,解析Manifest文件提取所有Activity信息,根據(jù)EA的android:exported屬性以及 圖3 方法概述 為了構建測試驅動應用,需要獲取每個EA所需的數(shù)據(jù)信息.根據(jù)上文所述,Activity主要利用若干特定的系統(tǒng)API(參見1.2)將鍵值(或者數(shù)據(jù)名稱)指定為API的參數(shù)來獲取數(shù)據(jù)內容.因此,該模塊的目標就是提取每個EA中數(shù)據(jù)的鍵值,并通過判定API的類型確定數(shù)據(jù)的類型. 以圖1中的源碼為例,需要分析該EA代碼中所有的方法并且確定getStringExtra和getIntExtra的第一個參數(shù)的值,即Intent中附加數(shù)據(jù)的鍵值.實際上,該問題可以被看作是一個到達定值問題,它是數(shù)據(jù)流分析中最普遍和最有用的模型.到達定值模型可以靜態(tài)的確定那些預定義的變量在到達代碼指定位置時的值.本文中使用Soot[7,8]提供的數(shù)據(jù)流分析模型ForwardDataFlowAnalysis實現(xiàn)了該算法. 該模塊生成測試EA的測試驅動應用,預先設計了一個測試驅動應用的模板,只包含一個Activity.在入口函數(shù)onCreate中創(chuàng)建了一個Intent實例,它的目標Activity是被測EA,這樣就可以在測試驅動程序啟動后可以自動的啟動目標EA.之后我們隨機生成之前模塊中提取到的鍵值所對應數(shù)據(jù)類型的值,并且使用putExtra APIs將生成的數(shù)據(jù)添加到Intent實例中.在onCreate的最后將Intent作為startActivity API的參數(shù)啟動EA. 除了這些代碼,Manifest文件也是應用執(zhí)行的重要部分,所以創(chuàng)建了一個Manifest文件并且在其中聲明Activity列表.最后,將源碼和Manifest文件一起打包成一個APK文件. 測試驅動應用生成之后,將它們部署到設備中并執(zhí)行它們去啟動EA,為了檢測EA中存在的問題,需要記錄執(zhí)行過程中設備中出現(xiàn)的信息.使用Adb工具將上述過程自動化,Adb是Android 軟件程序工具包(Software Development Kit,SDK)提供的一款用于連接Android設備的工具.Adb可以批量的將測試驅動應用安裝到設備中并執(zhí)行這些應用,測試驅動應用被Adb啟動后會自動化的啟動測試目標應用中的EA,并且保存設備的屏幕截圖供之后的分析用. 為了評估方法的有效性,本文根據(jù)上文提到技術實現(xiàn)了一個工具EASTER(Exported Activity:Specific TestER),使用若干真實應用在一臺Google Nexus 5上進行了實驗. 從Google Play和其他的Android市場上下載了10個應用作為實驗應用.表1展示了這些應用的詳細信息,包括應用大小、Activity的數(shù)量和EA數(shù)量.從表中可以發(fā)現(xiàn)EA在現(xiàn)實應用中被廣泛使用,系統(tǒng)的測試它們是一個非常重要的研究課題.本文使用了很流行的Android應用黑盒測試工具Monkey[9]對處理過的應用進行測試,用以評估Monkey對應用中EA的覆蓋情況,本次試驗中對應用中EA的字節(jié)碼進行了插樁處理.實驗中設置Monkey對每個應用進行測試時生成的事件數(shù)量為10 000.覆蓋率如表1中最后一列所示,實驗表明應用中大約有17%的EA可以被Monkey生成的事件序列所覆蓋. 實驗中首先使用EASTER為應用中每個EA生成一個測試驅動應用,然后讓它們在設備中有序的運行.試驗中,如果一個測試驅動應用可以成功的啟動該EA,就認為該測試驅動應用可以覆蓋該EA.表2展示詳細的實驗結果,其中第三列給出了被覆蓋的EA數(shù)量,最后一列表明了覆蓋率.從表中可以發(fā)現(xiàn),生成的測試驅動應用可以覆蓋實驗應用中大多數(shù)的EA(平均73.7%),覆蓋率遠遠大于Monkey對EA的覆蓋率.有幾個特殊的樣本的覆蓋率較低,例如:Snapchat和騰訊新聞.這些應用中對一些EA設置了某些系統(tǒng)或者自定義的權限,拒絕來自于未授權應用的調用請求.這個問題將在之后的工作中解決. 表1 實驗應用 表2 EASTER的覆蓋率 實驗中使用EASTER結合不同的Intent數(shù)據(jù)為應用中每個EA生成了5個測試驅動應用,并深入研究了它們執(zhí)行過程中出現(xiàn)的問題.可以將實驗過程中出現(xiàn)的問題分成兩類:應用奔潰和顯示異常,其中前者表示該EA在測試中會崩潰,后者代表EA顯示不正常,例如顯示沒有友好用戶提示的空白窗口.表3展示了詳細的實驗結果,其中第二和第三列是生成測試驅動應用的數(shù)量和報告出有漏洞EA的數(shù)量.最后兩列分別列出了在EA測試過程中出現(xiàn)應用崩潰和顯示異常兩類問題的測試驅動程序的數(shù)量. 表3 EASTER檢測到漏洞數(shù)量 本小節(jié)中進一步的分析了存在漏洞應用的代碼,準確的定位漏洞的位置.首先利用反編譯工具jdgui[10]將有漏洞的應用的字節(jié)碼轉換成Java程序,之后人工的檢查檢測報告中EA的代碼.下面分別對兩個應用中的兩種漏洞進行分析. 圖4顯示愛奇藝應用中一個類名為 FalconActivity的EA的代碼片段.推測第三行中開發(fā)者忽視了對“argument”鍵值所對應數(shù)據(jù)使用前的有效性校驗.在實驗中發(fā)現(xiàn),隨機生成一個字符串賦值給該變量,應用總會出現(xiàn)崩潰. 圖4 愛奇藝應用的代碼片段 圖5給出了優(yōu)酷應用中類名為 GameDetailsActivity的EA中onCreate方法的代碼片段.我們可以發(fā)現(xiàn)如果Intent不為空并且appid為空時loaddata方法不會被執(zhí)行并且該Activity會顯示了一個空白窗口,這樣會迷惑用戶. 圖5 優(yōu)酷的代碼片段 這部分將簡要介紹了幾種Android應用自動測試生成方法的相關工作. Fuzzing是一個被普遍使用,對Android應用進行黑盒測試的方法.Machir等人[4]開發(fā)了一款隨機生成系統(tǒng)事件的工具——Dynodroid,該工具生成的事件與用戶事件相同. 基于模型的測試也是測試GUI程序典型的技術,也可以用來測試Android應用.Wang等人[5]將GUI行為構建成一個FSM模型,他們利用靜態(tài)分析技術提取與控件相關的事件,使用動態(tài)探測技術捕獲Activity的遷移.Azim和Neamtiu[11]也提出了一個測試生成工具——A3E,它使用靜態(tài)分析技術構建GUI模型,基于深度優(yōu)先搜索和目標搜索策略并結合GUI模型生成事件序列. 以上研究值關注為應用生成事件序列.Mirzaei等人[4]將Android應用中的事件輸入和數(shù)據(jù)輸入區(qū)分開,利用符號執(zhí)行引擎Symbolic PathFinder(SPF)生成數(shù)據(jù)輸入.Jensen等人[12]使用符號執(zhí)行技術生成事件和數(shù)據(jù)覆蓋指定代碼. 現(xiàn)有的工作主要是通過動態(tài)執(zhí)行應用或者靜態(tài)分析代碼來提取和遍歷程序行為.這些方法有一個共同的缺點就是它們不能有效的覆蓋應用的特殊部分——EA,因為EA往往在應用內部不會被調用,大部分EA是提供給外部應用進行訪問的. 本文介紹了一個自動化測試Android應用中EA的方法,現(xiàn)有的工作中很少有相關的討論.實驗結果表明EA被廣泛的應用在現(xiàn)實的應用中,但是很多時候開發(fā)者對它的開發(fā)不是非常完備.由于EA通常包含開發(fā)者渴望推廣的功能,對EA進行系統(tǒng)化的測試在保證Android應用質量的研究中是非常值得關注的問題.相信本文的工作是對現(xiàn)有工作的一個非常有用的補充,之后的研究也是很有意義的. 本文只是對Android應用中EA進行了初步的研究,并沒有全面考慮EA和Intent機制的所有特性,例如Intent Filter和Permission等.之后的工作將解決這些問題以加強EASTER的性能.除此之外,Intent的數(shù)據(jù)也是通過自己開發(fā)的工具隨機生成的,之后的工作中也可以使用模糊測試或者混合測試技術加強EASTER的功能.1.2 Intent
1.3 示例說明
2 測試方法
2.1 方法概述
2.2 APK解析
2.3 Intent分析
2.4 測試驅動生成
2.5 測試執(zhí)行
3 試驗結果與分析
3.1 實驗設計
3.2 EA的測試覆蓋率
3.3 實驗結果分析
3.4 案例分析
4 相關工作
5 結語