詳解Android 安全機(jī)制
public void enforceCallingOrSelfUriPermission(Uri uri, int modeFlags, String message)
public void enforceUriPermission(Uri uri, String readPermission, String writePermission,int pid, int uid, int modeFlags, String message)
2.2.2 實(shí)現(xiàn)分析
ContextImpl.java 中提供的 API ,其實(shí)都是由 ActivityManagerService 中的如下幾個接口進(jìn)行的封裝。
public int checkPermission(String permission, int pid, int uid) throws RemoteException; // 主要用于一般的 permission 檢查
public int checkUriPermission(Uri uri, int pid, int uid, int mode) throws RemoteException; // 主要用于 Content Uri 的 permission 檢查
n checkPermission 的實(shí)現(xiàn)分析
1. 如果傳入的 permission 名稱為 null ,那么返回 PackageManager.PERMISSION_DENIED 。
2. 判斷調(diào)用者 uid 是否符合要求 。
1 ) 如果 uid 為 0 ,說明是 root 權(quán)限的進(jìn)程,對權(quán)限不作控制。
2 ) 如果 uid 為 system server 進(jìn)程的 uid ,說明是 system server ,對權(quán)限不作控制。
3 ) 如果是 ActivityManager 進(jìn)程本身,對權(quán)限不作控制。
4 )如果調(diào)用者 uid 與參數(shù)傳入的 req uid 不一致,那么返回 PackageManager.PERMISSION_DENIED 。
3. 如果通過 2 的檢查后,再 調(diào)用 PackageManagerService.checkUidPermission ,判斷 這個 uid 是否擁有相應(yīng)的權(quán)限,分析如下 。
1 ) 首先它通過調(diào)用 getUserIdLP ,去 PackageManagerService.Setting.mUserIds 數(shù)組中,根據(jù) uid 查找 uid (也就是 package )的權(quán)限列表。一旦找到,就表示有相應(yīng)的權(quán)限。
2 ) 如果沒有找到,那么再去 PackageManagerService.mSystemPermissions 中找。這些信息是啟動時,從/system/etc/permissions/platform.xml 中讀取的。這里記錄了一些系統(tǒng)級的應(yīng)用的 uid 對應(yīng)的 permission 。
3 )返回結(jié)果 。
n 同樣 checkUriPermission 的實(shí)現(xiàn) 主要在 ActivityManagerService 中,分析如下:
1. 如果 uid 為 0 ,說明是 root 用戶,那么不控制權(quán)限。
2. 否則,在 ActivityManagerService 維護(hù)的 mGrantedUriPermissions 這個表中查找這個 uid 是否含有這個權(quán)限,如果有再檢查其請求的是讀還是寫權(quán)限。
關(guān)于簽名機(jī)制,其實(shí)分兩個階段。
包掃描階段需要進(jìn)行完整性和證書的驗(yàn)證。普通 package 的簽名和證書是必須要先經(jīng)過驗(yàn)證的。具體做法是對 manifest 下面的幾個文件進(jìn)行完整性檢查。完整性檢查包括這個 jar 包中的所有文件。如果是系統(tǒng) package 的話,只需要使用 AndroidMenifest.xml 這個文件去提取簽名和驗(yàn)證信息就可以了。
在權(quán)限創(chuàng)建階段。如果該 package 來自 system img (系統(tǒng) app ),那么 trust it ,而且使用新的簽名信息去替換就的信息。前提是如果這個 package 與其它 package 共享一個 uid ,那么這個共享 uid 對應(yīng)的 sharedUser 中保存的簽名與之不一致,那么簽名驗(yàn)證失敗。有些時候系卸載一個 app ,但是不刪除數(shù)據(jù),那么其 PackageSettings 信息會保留,其中會保存簽名信息。這樣再安裝是就會出現(xiàn)不一致。
3.1 Android Package 簽名原理
android 中系統(tǒng)和 app 都是需要簽名的??梢宰约和ㄟ^ development/tools/make_key 來生成公鑰和私鑰。
android 源代碼中提供了工具 。/out/host/linux-x86/framework/signapk.jar 來進(jìn)行手動簽名。簽名的主要作用在于限制對于程序的修改僅限于同一來源。系統(tǒng)中主要有兩個地方會檢查。如果是程序升級的安裝,則要檢查新舊程序的簽名證書是否一致,如果不一致則會安裝失??;對于申請權(quán)限的 protectedlevel 為 signature 或者 signatureorsystem 的,會檢查權(quán)限申請者和權(quán)限聲明者的證書是否是一致的。簽名相關(guān)文件可以從 apk 包中的 META-INF 目錄下找到。
signapk.jar 的源代碼在 build/tools/signapk ,簽名主要有以下幾步:
l 將除去 CERT.RSA , CERT.SF , MANIFEST.MF 的所有文件生成 SHA1 簽名
首先將除了 CERT.RSA , CERT.SF , MANIFEST.MF 之外的所有非目錄文件分別用 SHA-1 計(jì)算摘要信息,然后使用 base64 進(jìn)行編碼,存入MANIFEST.MF 中。 如果 MANIFEST.MF 不存在,則需要創(chuàng)建。存放格式是 entry name 以及對應(yīng)的摘要
l 根據(jù) 之前計(jì)算的 SHA1 摘要信息,以及 私鑰生成 一系列的 signature 并寫入 CERT.SF
對 整個 MANIFEST.MF 進(jìn)行 SHA1 計(jì)算,并將摘要信息存入 CERT.SF 中 。然后對之前計(jì)算的所有摘要信息使用 SHA1 再次計(jì)算數(shù)字簽名,并寫入 CERT.SF 中。
l 把公鑰和簽名信息寫入 CERT.RST
把之前整個的簽名輸出文件 使用私有密鑰計(jì)算簽名。同時將簽名結(jié)果,以及之前聲稱的公鑰信息寫入 CERT.RSA 中保存。
3.2 Package 的簽名驗(yàn)證
安裝時對一個 package 的簽名驗(yàn)證的主要邏輯在 JarVerifier.java 文件的 verifyCertificate 函數(shù)中實(shí)現(xiàn)。 其主要的思路是通過提取 cert.rsa 中的證書和簽名信息,獲取簽名算法等信息,然后按照之前對 apk 簽名的方法進(jìn)行計(jì)算,比較得到的簽名和摘要信息與 apk 中保存的匹配。
第一步。提取證書信息,并對 cert.sf 進(jìn)行完整性驗(yàn)證。
1. 先找到是否有 DSA 和 RSA 文件 ,如果找到則對其進(jìn)行 decode ,然后讀取其中的所有的證書列表(這些證書會被保存在 Package 信息中,供后續(xù)使用)。
2. 讀取這個文件中的簽名數(shù)據(jù)信息塊列表,只取第一個簽名數(shù)據(jù)塊。讀取其中的發(fā)布者和證書序列號。
3. 根據(jù)證書序列號,去匹配之前得到的所有證書,找到與之匹配的證書。
4. 從之前得到的簽名數(shù)據(jù)塊中讀取簽名算法和編碼方式等信息
5. 讀取 cert.sf 文件,并計(jì)算整個的簽名,與數(shù)據(jù)塊中的簽名(編碼格式的)進(jìn)行比較,如果相同則完整性校驗(yàn)成功。
第二步。使用 cert.sf 中的摘要信息,驗(yàn)證 MANIFEST.MF 的完整性。
在 cert.sf 中提取 SHA1-Digest-Manifest 或者 SHA1-Digest 開頭的簽名 數(shù)據(jù)塊 ( -Digest-Manifest 這個是整個 MANIFEST.MF 的摘要 信息,其它的是 jar 包中其它文件的摘要信息 ), 并逐個對這些數(shù)據(jù)塊 進(jìn)行驗(yàn)證。驗(yàn)證的方法是,現(xiàn)將 cert.sf 看做是很多的 entries ,每個entries 包含了一些基本信息,如這個 entry 中使用的摘要算法( SHA1 等),對 jar 包中的哪個文件計(jì)算了摘要,摘要結(jié)果是什么。 處理時先找到每個摘要數(shù)據(jù)開中的文件信息,然后從 jar 包中讀取,然后使用 -Digest 之前的摘要算法進(jìn)行計(jì)算,如果計(jì)算結(jié)果與摘要數(shù)據(jù)塊中保存的信息的相匹配,那么就完成驗(yàn)證。
pid控制相關(guān)文章:pid控制原理
評論