日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android签名与风险分析

發布時間:2024/8/1 Android 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android签名与风险分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Android簽名概括:

在Android 系統中,所有安裝到系統的應用程序都必有一個數字證書,這個數字證書就是這個應用的簽名。此數字證書用于標識應用程序的作者和在應用程序之間建立信任關系,如果一個 permission的protectionLevel為signature,那么就只有那些跟該permission所在的程序擁有同一個數字證書的應 用程序才能取得該權限。這個數字證書并不需要權威的數字證書簽名機構認證,它只是用來讓應用程序包自我認證的。

Android簽名作用:

為了保證每個應用程序開發商合法ID,防止部分開放商可能通過使用相同的Package Name來混淆替換已經安裝的程序,冒充原來的應喲功能。我們需要對我們發布的APK文件進行唯一簽名,保證我們每次發布的版本的一致性(如自動更新不會因為版本不一致而無法安裝)。

概括起來有以下幾點:

(1 ) ?發送者的身份認證

(2)保證輸入信息的完整性

(3)防止交易中的抵賴發生

Android簽名方法:

方法一: 使用keytool和jarsigner命令

創建key,需要用到 keytool,使用產生的key對apk簽名用到的是jarsigner。

keytool -genkey -alias demo.keystore -keyalg RSA -validity 40000 -keystore demo.keystore

/*說明:-genkey 產生密鑰

-alias demo.keystore 別名 demo.keystore

-keyalg RSA 使用RSA算法對簽名加密

-validity 40000 有效期限4000天

-keystore demo.keystore */

jarsigner -verbose -keystore demo.keystore -signedjar demo_signed.apk demo.apk demo.keystore

說明:-verbose 輸出簽名的詳細信息

-keystore ?demo.keystore 密鑰庫位置

-signedjar demor_signed.apk demo.apk demo.keystore 正式簽名,三個參數中依次為簽名后產生的文件demo_signed,要簽名的文件demo.apk和密鑰庫demo.keystore.

查看密鑰信息

keytool -printcert -v -file miyao.cer?
keytool -list -keystore debug.keystore

方法二: 使用signapk 工具

java -jar signapk.jar platform.x509.pem platform.pk8 MyDemo.apk MyDemo_signed.apk?

signapk的參數分別為公鑰,私鑰,需要簽名的apk,簽名后的apk

使用源碼內置的簽名可以獲取系統的不同權限。

簽名之后,可以用zipalign(壓縮對齊)優化APK文件

zipalign -v 4 demo_signed.apk final.apk

Android源碼打包apk分析

使用andorid源碼打包apk是使用signapk簽名的,我們分析一下這個過程

1、生成MANIFEST.MF文件:

程序遍歷app包中的所有文件(entry),對非文件夾非簽名文件的文件,逐個生成SHA1的數字簽名信息,再用Base64進行編碼。具體代碼見這個方法:

private static Manifest addDigestsToManifest(JarFile jar)

/** Add the SHA1 of every file to the manifest, creating it if necessary. */private static Manifest addDigestsToManifest(JarFile jar)throws IOException, GeneralSecurityException {Manifest input = jar.getManifest();Manifest output = new Manifest();Attributes main = output.getMainAttributes();if (input != null) {main.putAll(input.getMainAttributes());} else {main.putValue("Manifest-Version", "1.0");main.putValue("Created-By", "1.0 (Android SignApk)");}MessageDigest md = MessageDigest.getInstance("SHA1");byte[] buffer = new byte[4096];int num;// We sort the input entries by name, and add them to the// output manifest in sorted order. We expect that the output// map will be deterministic.TreeMap<String, JarEntry> byName = new TreeMap<String, JarEntry>();for (Enumeration<JarEntry> e = jar.entries(); e.hasMoreElements(); ) {JarEntry entry = e.nextElement();byName.put(entry.getName(), entry);}for (JarEntry entry: byName.values()) {String name = entry.getName();if (!entry.isDirectory() &&(stripPattern == null || !stripPattern.matcher(name).matches())) {InputStream data = jar.getInputStream(entry);while ((num = data.read(buffer)) > 0) {md.update(buffer, 0, num);}Attributes attr = null;if (input != null) attr = input.getAttributes(name);attr = attr != null ? new Attributes(attr) : new Attributes();attr.putValue("SHA1-Digest",new String(Base64.encode(md.digest()), "ASCII"));output.getEntries().put(name, attr);}}return output;}

之后將生成的簽名寫入MANIFEST.MF文件。關鍵代碼如下:

private static void signFile(Manifest manifest, JarFile inputJar,X509Certificate[] publicKey, PrivateKey[] privateKey,JarOutputStream outputJar)throws Exception {// Assume the certificate is valid for at least an hour.long timestamp = publicKey[0].getNotBefore().getTime() + 3600L * 1000;JarEntry je;// Everything elsecopyFiles(manifest, inputJar, outputJar, timestamp);// MANIFEST.MFje = new JarEntry(JarFile.MANIFEST_NAME);je.setTime(timestamp);outputJar.putNextEntry(je);manifest.write(outputJar);int numKeys = publicKey.length;for (int k = 0; k < numKeys; ++k) {// CERT.SF / CERT#.SFje = new JarEntry(numKeys == 1 ? CERT_SF_NAME :(String.format(CERT_SF_MULTI_NAME, k)));je.setTime(timestamp);outputJar.putNextEntry(je);ByteArrayOutputStream baos = new ByteArrayOutputStream();writeSignatureFile(manifest, baos);byte[] signedData = baos.toByteArray();outputJar.write(signedData);// CERT.RSA / CERT#.RSAje = new JarEntry(numKeys == 1 ? CERT_RSA_NAME :(String.format(CERT_RSA_MULTI_NAME, k)));je.setTime(timestamp);outputJar.putNextEntry(je);writeSignatureBlock(new CMSProcessableByteArray(signedData),publicKey[k], privateKey[k], outputJar);}}

SHA1數字簽名。簡 單地說,它就是一種安全哈希算法,類似于MD5算法。它把任意長度的輸入,通過散列算法變成固定長度的輸出(這里我們稱作“摘要信息”)。你不能僅通過這 個摘要信息復原原來的信息。另外,它保證不同信息的摘要信息彼此不同。因此,如果你改變了apk包中的文件,那么在apk安裝校驗時,改變后的文件摘要信息與MANIFEST.MF的檢驗信息不同,于是程序就不能成功安裝。

2、生成CERT.SF文件:

對前一步生成的Manifest,使用SHA1-RSA算法,用私鑰進行簽名。關鍵代碼如下:

private static void writeSignatureFile(Manifest manifest, OutputStream out)throws IOException, GeneralSecurityException {Manifest sf = new Manifest();Attributes main = sf.getMainAttributes();main.putValue("Signature-Version", "1.0");main.putValue("Created-By", "1.0 (Android SignApk)");MessageDigest md = MessageDigest.getInstance("SHA1");PrintStream print = new PrintStream(new DigestOutputStream(new ByteArrayOutputStream(), md),true, "UTF-8");// Digest of the entire manifestmanifest.write(print);print.flush();main.putValue("SHA1-Digest-Manifest",new String(Base64.encode(md.digest()), "ASCII"));Map<String, Attributes> entries = manifest.getEntries();for (Map.Entry<String, Attributes> entry : entries.entrySet()) {// Digest of the manifest stanza for this entry.print.print("Name: " + entry.getKey() + "\r\n");for (Map.Entry<Object, Object> att : entry.getValue().entrySet()) {print.print(att.getKey() + ": " + att.getValue() + "\r\n");}print.print("\r\n");print.flush();Attributes sfAttr = new Attributes();sfAttr.putValue("SHA1-Digest",new String(Base64.encode(md.digest()), "ASCII"));sf.getEntries().put(entry.getKey(), sfAttr);}CountOutputStream cout = new CountOutputStream(out);sf.write(cout);// A bug in the java.util.jar implementation of Android platforms// up to version 1.6 will cause a spurious IOException to be thrown// if the length of the signature file is a multiple of 1024 bytes.// As a workaround, add an extra CRLF in this case.if ((cout.size() % 1024) == 0) {cout.write('\r');cout.write('\n');}}

RSA是一種非對稱加密算法。用私鑰通過RSA算法對摘要信息進行加密。在安裝時只能使用公鑰才能解密它。解密之后,將它與未加密的摘要信息進行對比,如果相符,則表明內容沒有被異常修改。

3、生成CERT.RSA文件:

生成MANIFEST.MF沒有使用密鑰信息,生成CERT.SF文件使用了私鑰文件。那么我們可以很容易猜測到,CERT.RSA文件的生成肯定和公鑰相關。

CERT.RSA文件中保存了公鑰、所采用的加密算法等信息。

生成CERT.RSA文件:核心代碼如下:

// CERT.RSA / CERT#.RSAje = new JarEntry(numKeys == 1 ? CERT_RSA_NAME :(String.format(CERT_RSA_MULTI_NAME, k)));je.setTime(timestamp);outputJar.putNextEntry(je);writeSignatureBlock(new CMSProcessableByteArray(signedData),publicKey[k], privateKey[k], outputJar);


總結分析:

分根據APK包的簽名流程,我們可以意識到:

1、 Android簽名機制其實是對APK包完整性和發布機構唯一性的一種校驗機制。

2、 Android簽名機制不能阻止APK包被修改,但修改后的再簽名無法與原先的簽名保持一致。(擁有私鑰的情況除外)。

3、 APK包加密的公鑰就打包在APK包內,且不同的私鑰對應不同的公鑰。換句話言之,不同的私鑰簽名的APK公鑰也必不相同。所以我們可以根據公鑰的對比,來判斷私鑰是否一致。

4、簽名是不對META-INF的文件校驗的,可以利用這個漏洞做一些事情。比如快速動態做渠道標記


簽名對App的影響

1) App升級。 使用相同簽名的升級軟件可以正常覆蓋老版本的軟件,否則系統比較發現新版本的簽名證書和老版本的簽名證書不一致,不會允許新版本安裝成功的。

2) App模塊化。android系統允許多個安裝包的App運行在同一個進程中,如果運行在同一個進程中,則他們相當于同一個App,但是你可以單獨對他們升級更新,這是一種App級別的模塊化思路。

3) 允許代碼和數據共享。android中提供了一個基于簽名的Permission標簽。通過允許的設置,我們可以實現對不同App之間的訪問和共享


簽名安全性問題:

在app的AndroidManifest.xml中加上 android:sharedUserId="android.uid.system"然后使用目標系統的platform密鑰來重新給apk文件簽名。這首先找到密鑰文件,在Android源碼目錄中的位置 是“build\target\product\security”,下面的platform.pk8和platform.x509.pem兩個文件。然 后用Android提供的Signapk工具來簽名,signapk的源代碼是在“build\tools\signapk”下,用法為“signapk platform.x509.pem platform.pk8 input.apk output.apk”,文件名最好使用絕對路徑防止找不到,也可以修改源代碼直接使用。這樣修改后的應用就會獲取系統權限。


簽名的驗證過程

?安裝apk時,通過CERT.RSA查找公鑰和算法,并對CERT.SF進行解密和簽名驗證,確認MANIFEST.MF,最終對每個文件簽名校驗。

升級時,android也會進行簽名驗證。如果遇到以下情況,都不能完成升級:

1) ? ? 兩個應用,名字相同,簽名不同

2) ? ? 升級時前一版本簽名,后一版本沒簽名。

3) ? ? 升級時前一版本為DEBUG簽名,后一個為自定義簽名。

4) ? ? 升級時前一版本為Android源碼中的簽名,后一個為DEBUG簽名或自定義簽名。

5) ? ? 安裝未簽名的程序。

6) ? ? 安裝升級已過有效期的程序。


歡迎掃描二維碼,相互學習。

總結

以上是生活随笔為你收集整理的Android签名与风险分析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。