田 坤 劉興偉 馬宏亮
1(西華大學計算機與軟件工程學院 成都 610039)
2(北京娜迦信息科技發展有限公司 北京 100094)
(1935896048@qq.com)
車聯網在國外起步較早,在20世紀60年代,日本就開始研究車間通信.2000年前后,歐洲和美國也相繼啟動多個車聯網項目,旨在推動車間網聯系統的發展.與國外車聯網產業發展相比,我國的車聯網技術直至2009年才剛剛起步,最初只能實現基本的導航、救援等功能.此后至2017年底,國家頒布了多項方案,將發展車聯網提到了國家創新戰略層面.在此期間,人工智能和大數據分析等技術的發展使得車載互聯網更加實用,如企業管理和智能物流.未來,依托于人工智能、語音識別和大數據等技術的發展,車聯網將與移動互聯網結合,為用戶提供更具個性化的定制服務[1-3].
車聯網業務系統的不斷發展,與之帶來的是安全問題日益突出,車企發布的車控APP實現的功能也越來越多,除了車輛輔助功能外,有些車企的車控APP已經可以開始控制車輛的啟動、停止、車窗、車傳感器等相關的車輛安全功能.現今車載IVI日益趨向于Android系統,那么在車載IVI之上的Android車控APP也即將變得越來越普及.Android系統的開放性使得它的推廣性極強,同時也帶來了日益突顯的安全性問題.那么,車控APP安全性研究,對整體提高車聯網的安全就變得非常迫切.
車載IVI采用Android系統,而Dalvik虛擬機(Dalvik VM)是Google專門為Android系統設計的一套虛擬機[4-5].不同于標準Java虛擬機JVM的class文件格式,Dalvik VM擁有專屬的 DEX可執行文件格式和指令集代碼.Smali和baksmali則是針對DEX執行文件格式的匯編器和反匯編器,反匯編后DEX文件會產生.Smali后綴的代碼文件,Smali代碼擁有特定的格式與語法.Smali語言是對Dalvik VM字節碼的一種解釋,雖然不是官方標準語言,但所有語句都遵循一套語法規范[6-8].
本研究旨在通過“車聯網+安全防御[9-10]”行動計劃的建設思想,以網絡安全法、等級保護、國家十三五規劃等要求為基礎,憑借在車聯網應用安全的前瞻性研究,充分利用先進技術資源,對車控APP的匯編代碼結構進行分析.
本研究主要從以下3個方面進行:
1) 車控APP的匯編代碼結構;
2) 虛擬機引擎對車控APP的Smali匯編進行轉碼操作,把Smali匯編代碼轉碼為Native C/C++代碼,對車控APP核心邏輯進行保護;
3) 轉碼完成的數據,對Native C/C++進行編譯組裝,形成受保護后的車控APP.
通過對車控APP進行細致到類函數的分析,把整個流程分為29個階段,總體設計流程如圖1所示.
1) 車控APK進行Smali反匯編處理,期望得到APK中詳細的類函數分布;
2) 對Smali匯編后的文件進行BasicBlock(BB)切分,把匯編代碼切分成獨立的指令塊;
3) 構建IrBuilder,針對的是要轉碼的Method,包含Method中所有的BasicBlock塊迭代器、Method開始BasicBlock塊、類名、方法名、輸入參數列表、Graph初始化、方法的屬性、輸入參數的類型、Method的Exception列表;
4) 啟動IrBuilder中的process,調用bfs(廣度優先搜索),構建Method中塊的圖關系;
5) 構造Graph對象,初始化入口、結束出口、landing_pads、Method中node集合、rpo、edges字典、catch_edges字典、reverse_edges字典、reverse_catch_edges字典、offset_to_node字典、node_to_landing_pad字典;
6) 使用bfs算法計算Method中BasicBlock之間的相互關系,得出生成器集合,開始填充Graph;
7) 循環生成器(DVMBasicBlock)集合,把每一個DVMBasicBlack初始為IrBasicBlock,IrBasicBlock中包含dvm_basicblock、指令集合、變量列表、類(使用)列表、字段(使用)列表、方法(調用)列表、是否是異常塊、異常塊的類型、是否對該對象進行過填充、初始化PHI集合、初始化catch_successors集合、得到dvm_basicblock的start_offset;
8) 建立dvm_basicblock與IrBasciBlock關系字典;
9) 如果遇到Method中的dvm_basicblock會觸發異常塊,則進行LandingPad對象轉化;
10) 建立ExceptionAnalysis(dvm_basicblock塊的exception_analysis屬性)與LandingPad關系字典;
11) 根據dvm_basicblock.exception_analysis.exceptions,得到catch塊的異常類型、異常塊offset、異常塊(dvm_basicblock)對象;
12) 建立try(IrBasicBlock)/catch(IrBasicBlock)關系;
13) 建立Graph中catch_edges關系、reverse_catch_edges關系;
14) 建立node(try-IrBasicBlock)與landing_pad(catch塊轉換為LandingPad對象)關系;
15) 查找此dvm_basicblock正常跳轉的字塊,建立相互關系;
16) 填充Graph存放以下關鍵信息,包括:各個dvm_basicblock轉換為IrBasicBlock的信息(包括dvm_basicblock、類定義、方法定義、是否包含try/catch塊、字段定義、PHI節點集合、dvm_basicblock起始偏移)、IrBasicBlock的路徑關系采用圖的廣度優先搜索算法進行定義、BasicBlock中try/catch路徑關系(包含嵌套try/catch)、方法入口塊、塊轉換為node的節點集合、landing_pads集合、edges字典、reverse_edges字典;
17) 從Method中的start dvm_basicblaock開始通過edges和catch_edges這2個字典,遞歸找到此Method最后一個dvm_basicblock塊,并進行編號,形成從調用的子node到父node的調用路徑序號;
18) 通過所有node的len減去17)中的編號,得出從父node到子node的最終調用路徑;
19) 建立offset與node(IrBasicBlock)的字典關系;
20) 完善Graph中node與LandingPad的字典關系;
21) 完善Graph中offset與node(IrBasicBlock)的字典關系;
22) 通過reverse_catch_edges{catch:try}進行搜索,如果父節點中in_catch屬性為true,那么子節點中in_catch屬性也應修訂為true;
23) 初始化構建IRmethod結構體,用于Smali匯編指令翻譯為C/C++語言;
24) 對Smali函數參數進行解析,用于翻譯后C/C++語言函數的輸入參數;
25) 通過生成好的Graph解析BasicBlock塊中指令,用于填充IRMethod結構體;
26) 對IRMethod結構體進行指令轉碼;
27) 形成Native C/C++語言的源代碼;
28) 調用NDK編譯工具鏈對27)中的源碼進行編譯;
29) 形成轉碼編譯完成后的可執行文件.

圖1 應用轉碼保護總體設計流程
車載IVI應用轉碼保護的實現[11-13]主要包含以下5個方面:
1) BasicBlock(BB)切分方式.BasicBlock中包含相關code指令,是組成程序結構的基本單元,BB塊切分的原則是:①判斷指令切分;②返回指令切分;③try/catch指令切分;④goto指令切分.
對整個應用程序的Smali匯編逐行進行讀取,遇到上述的指令就把此指令之前的代碼進行提取,并對提取的代碼進行BB塊編號,同時對編號后的BB塊中的指令計算offset,指出每個BB塊對應的跳轉關系,最后每個BB塊初始化為BasicBlock對象,放入Method的有序列表中.
2) 構建Graph并解析指令填充.Graph中包含了用于Smali匯編轉碼C/C++語言代碼的重要信息,通過迭代器BB塊的方式,分析每一個BB塊中的指令、獲取第1個BB塊的offset、本地變量、輸入參數、異常發生器、異常捕獲的目標,同時分析出每個BB塊的相互調用關系.
Graph首先會對Method列表中的BB塊集合進行輪訓分析,主要分析每個BB塊中的指令是否含有異常指令,找出異常指令的catch捕獲模塊,建立1對1或1對多的處理關系,比如try{}catch{},try{}catch{}finally{};第二,會根據對Method列表中的BB塊集合,按后置順序返回圖的節點,即我們訪問所有訪問節點本身之前的子節點,然后按前置的順序對其排序,用于后續Native代碼的轉換,因為代碼的轉換是從入口點開始,逐步按照節點的邏輯關系進行;第三,根據Method方法的輸入參數形成Native變量的標號,根據本地寄存器個數減去輸入參數個數后自增的方式,得出Method方法的輸入參數的寄存器編號;第四,根據Method方法的Smali返回類型,確定Native方法的返回類型.Graph中各BB塊的關系如圖2所示:

圖2 Graph中各BB塊關系
3) 構建IRMethod結構體.IRMethod結構體中存放的是Smali匯編語言轉碼為IR中間語言的載體,包含了EncodeMethod、IR對象、方法的開始BB塊、方法的類名、方法名、方法輸入參數、本地變量寄存器下標序號、方法BB塊的offset表、Graph對象、方法的簽名.
通過對Graph對象的填充以及對BB塊的分析,接下來完成IR指令的轉碼,對各個BB塊中的指令逐條分析,根據各指令opcode封裝不同指令的轉換方法,opcode包括:空指令、數據操作指令、返回指令、數據定義指令、鎖指令、實例操作指令、數組操作指令、異常指令、跳轉指令、比較指令、字段操作指令、方法調用指令、數據轉換指令、數據運算指令.具體的指令轉換列表如圖3所示:

# 0x00nop, # nopmove, # movemovefrom16, # move∕from16move16, # move∕16movewide, # move-wide?returnvoid, # return-voidreturn_reg, # return# 0x10returnwide, # return-widereturnobject, # return-objectconst4, # const∕4const16, # const∕16const, # const?monitorexit, # monitor-exitcheckcast, # check-cast# 0x20instanceof, # instance-ofarraylength, # array-lengthnewinstance, # new-instancenewarray, # new-arrayfillednewarray, # filled-new-array?cmpgfloat, # cmpg-floatcmpldouble, # cmpl-double?# 0xd0addintlit16, # add-int∕lit16?# 0xe0shlintlit8, #shl-int∕lit8?

圖3 指令轉換
4) 形成Native代碼.獲取到IRMethod結構體后,逐一取出IRMethod中的數據,通過變量類型構建規則、運算構建規則以及內部函數調用規則,構建C/C++語言代碼,構建規則如表1和表2所示.
函數轉換構建規則:①將原有的方法改成Native屬性的方法;②刪除原有方法中的方法實現.
5) 編譯Native形成受保護可執行文件.通過以上步驟形成C/C++源代碼文件,調用編譯器編譯生成本地二進制文件.

表1 運算構建規則

表2 內部函數調用規則

圖4 二進制源程序
使用對比工具,對受保護前后車控APP中classes.dex文件進行對比,說明其保護效果.
1) 二進制工具對比:通過Beyond Compare工具,對車控APP中受保護前后DEX文件進行對比.其中圖4為二進制源程序,圖5為經過轉碼保護的二進制程序.
通過兩者的對比可以確定進行轉碼保護后,原始文件和轉碼保護后的文件相似度為零,達到了保護的效果.
2) 反匯編后對比:采用JEB工具:對車控APP受保護前后的DEX進行反匯編后對比.其中圖6是保護前程序代碼,圖7是保護后程序代碼.

圖5 保護后二進制程序
通過兩者的對比可以得出結論,經過反匯編轉碼后保護了前后代碼,應用程序的核心邏輯進行了轉碼,在應用程序原始文件中已經無法獲取,有效地解決了車載IVI應用程序容易被篡改以及2次打包的問題,達到了保護效果.

圖6 保護前程序代碼

圖7 保護后程序代碼
本文針對車聯網在車載IVI程序保護方面存在的問題,設計并實現了車載IVI應用程序進行轉碼保護,通過對車載IVI應用程序的特點進行研究,對應用程序的Smali匯編進行Native轉碼,有效地把相關業務邏輯的實現轉移到了Native層,增加了破解分析的難度,使車載IVI應用程序具備了防逆向、防篡改的安全功能.最后通過安全測試驗證了本文提出的車載IVI應用程序進行轉碼保護的有效性.