1. 程式人生 > >[日更-2019.5.8、9] Android 系統的安全性分析(二)--Dalvik/ART層面上的安全措施

[日更-2019.5.8、9] Android 系統的安全性分析(二)--Dalvik/ART層面上的安全措施

宣告

  1. 最近工作上涉及到對Android系統安全性的改造,在改造之前先分析整理下目前Android系統自身的安全性;
  2. 參考了一些文章及書籍,在這裡大部分是對別人描述的提煉,我挑出一些對我有用的內容整理;

1 Dalvik/ART層上的許可權(應用許可權)

1.1 對Dalvik/ART上Java程式碼的監視和對原生Native層上C/C++程式碼的監視

    因為Android的Java程式碼需要執行在Dalvik/ART虛擬機器上,使得Dalvik/ART虛擬機器能夠在監視操作強制安全檢查方面有很大操作空間。而對於原生Native程式碼,雖然也能靠監視系統呼叫的方式來獲知程式對資源的訪問情況,但監視系統呼叫的問題是: 它們所能提供的監視粒度不夠精確。比如:

  • 檔案訪問,也就只有“open/read/write/close”這幾個操作;
  • 完成一次DNS查詢,由於需要呼叫多個系統呼叫,監視起來就很費力;

    此時,虛擬機器的優勢就顯現出來了,因為大多數的操作都是由預先提供的包或類來實現的,而這些包或類中己經自帶了許可權檢查功能。

1.2 繞過Dalvik/ART上Java程式碼的監視?

    Android系統做得很絕,作為惡意程式設計者來說即便你有虛擬機器層面的監事操作和強制安全檢查,但是我依然可以在一個正常的Java類中顯式地匯入其他類,並在這些被匯入的其他類中實現一些惡意的功能程式碼,甚至我直接在類裡新增Native方法使用JNI來逃避虛擬機器的監控範圍,從而避開Dalvik/ART虛擬機器許可權檢查。這樣做可不可以呢?

    但是這一做法在Android早就考慮到了,因為我在《[日更-2019.5.6、7] Android 系統的安全性分析(一)--移動裝置上的安全威脅》中提到使用者APP安裝後只有有限的許可權可用,它在Linux層上沒有任何許可權或權能,它對任何超越許可權的系統底層資源的訪問都會被直接拒絕。因為使用者APP想要做任何影響會超出應用自身範圍的操作時,都必須呼叫getSystemService()函式,通過system_server 中的服務完成相關操作

1.3 Android留的後手:system_server及應用許可權系統

    任何應用都能任意發起呼叫system_server中相關係統服務的請求,但是請求是不是會被允許,就不是應用說了算的,因為system_server會對請求是否符合許可權規定進行稽核

。這一稽核是在應用自身程序之外進行的,所以除了事先就已經被分配到了的許可權之外,應用是沒有任何途徑能獲取相關服務的訪問許可權的。

    而許可權的分配則是在安裝或載入應用或時執行的(不過在Android 6.0以後Android也開始採用iOS那種執行時檢查許可權的模式,在相關操作發生的時候,才使用應用自身程序以外的另一個程序來提示使用者),這也就意味著使用者會看到系統自動彈出一個對話方塊,提示該應用需要什麼許可權,再由使用者同意授予應用這些的許可權。如果應用執行時所請求的操作因沒有相關許可權而被拒絕,那麼就會丟擲一個安全異常(正常情況下,這會導致應用崩潰一一除非開發者專門為這類異常編寫了異常處理程式碼,這種情況下,應用將會自己來處理這個異常,通常會彈出一個對話方塊解釋應用需要什麼許可權,有時也會靜靜地做好收尾工作,並結束程式)。

    接下來要說的是:許可權本身是不需要任何特殊的資料結構或複雜的元資料來表示的。在Dalvik虛擬機器中的許可權只不過是一個簡單的常量值一一這個值是根據應用在它的(AndroidManifest.xml檔案中的) < user-permission>元素中宣告的許可權,分配在它的mainifest 中的。應用也可以在Manifest 中的<permission>標籤裡,定義它自己的常量。當包管理器安裝一個應用時,它會把應用自己宣告的許可權,新增到“許可權資料庫”中去。這個所謂的“許可權資料庫”實際上只是包資料庫(/data/system/packages.xml)的一部分。這個資料庫中除了許可權之外,還含有大量(包括各個應用的公鑰在內的)極具價值的資訊。

2 Android 如何將APP在Dalvik/ART虛擬機器層上的許可權對映至Linux UID上

    Dalvik/ART虛擬機器層上的許可權最終還是會落在它的支撐者Linux的UID/GID上,因為它的許可權機制實現的Linux基礎就是Linux自身的使用者機制,不同的許可權對應的就是Linux上的不同UID/GID。

    Dalvik層面上的許可權到Linux層面上的許可權之間的“橋樑”是/system/etc/permissions/platform.xml檔案。這是個包含在AOSP原始碼中的檔案,有良好的文件支援,以便廠商能夠(謹慎地〉往其中新增特定的許可權或AID 。對映可以以兩種方式進行:

  • 可以用<permission>標籤,把Dalvik上Java語言使用的許可權與記錄在<group> 標籤中的GID關聯起來;
  • 也可以用<assign-permission>Dalvik上Java語言使用的許可權賦予某個UID。

    如果檢視你自己的移動裝置上的/system/etc/permissions/目錄,或許會看到目錄中有另外幾個XML檔案(android.hardware.和android.software.),這些檔案都是在build系統的過程中,從AOSP原始碼檔案中複製過來的,其中有些也可能是廠商加進來的檔案。

3 程式碼簽名

    在第1節提到了應用許可權問題,但是存在一個操作上的問題,因為所有的應用都能在它的AndroidManifest.xml中宣告它需要使用哪些許可權,而一些不靠譜的使用者也可能在提示框彈出後,看也不看就直接去點“確定”按鈕。

    所以為了保證安全性,Google規定所有上傳到Google Play商店中的應用都必須經過數字簽名,這樣就能驗證應用開發者的身份,並在必要時能夠追究相關的責任。

    因此,所有的Android應用都必須經過簽名。Google出於同蘋果競爭的考慮,開放了Google Play商店,希望通過簡化釋出驗證流程的形式,吸引開發者。相對於蘋果公司冗長的釋出驗證流程(所有的應用都必須通過蘋果公司的審查,並對它們做數字簽名),Google則讓任何人都能對應用進行數字簽名,只要建立一對(公,私)金鑰,公開他們的公鑰,井用私鑰對他們的APK檔案做數字簽名就行了。

    Google這樣做的理由是:在仍然保證可以有效驗證APK的作者的前提下,極大的簡化將應用提交到商店中的流程。這一做法使得Google Play商店裡惡意軟體的數量爆炸式增長。Google處理這一問題卻採取了亡羊補牢的對策:一旦發現或有人舉報惡意軟體,就直接把它從商店裡刪掉,同時把對應的公鑰加