<span id="7ztzv"></span>
<sub id="7ztzv"></sub>

<span id="7ztzv"></span><form id="7ztzv"></form>

<span id="7ztzv"></span>

        <address id="7ztzv"></address>

            原文地址:http://drops.wooyun.org/mobile/4296

            0x01 Android簽名機制


            將APK重命名為zip文件,然后可以看到有個META-INF的文件夾,里面有三個文件,分別名為MANIFEST.MF、CERT.SF和CERT.RSA,這些就是使用signapk.jar生成的簽名文件。

            1、 MANIFEST.MF文件:

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

            #!java
            private static Manifest addDigestsToManifest(JarFile jar)
            

            關鍵代碼是

            #!java
            for (JarEntry entry: byName.values()) {
                 String name = entry.getName();
                 if (!entry.isDirectory() && !name.equals(JarFile.MANIFEST_NAME) &&
                     !name.equals(CERT_SF_NAME) && !name.equals(CERT_RSA_NAME) &&
                     (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", base64.encode(md.digest()));
                   output.getEntries().put(name, attr);
                }
            }
            

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

            #!java
            Manifest manifest = addDigestsToManifest(inputJar);
            je = new JarEntry(JarFile.MANIFEST_NAME);
            je.setTime(timestamp);
            outputJar.putNextEntry(je);
            manifest.write(outputJar);
            

            2、 生成CERT.SF文件:

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

            #!java
            Signature signature = Signature.getInstance("SHA1withRSA");
            signature.initSign(privateKey);
            je = new JarEntry(CERT_SF_NAME);
            je.setTime(timestamp);
            outputJar.putNextEntry(je);
            writeSignatureFile(manifest,
            new SignatureOutputStream(outputJar, signature));
            

            3、 生成CERT.RSA文件:

            生成MANIFEST.MF沒有使用密鑰信息,生成CERT.SF文件使用了私鑰文件。那么我們可以很容易猜測到,CERT.RSA文件的生成肯定和公鑰相關。 CERT.RSA文件中保存了公鑰、所采用的加密算法等信息。核心代碼如下:

            #!java
            je = new JarEntry(CERT_RSA_NAME);
            je.setTime(timestamp);
            outputJar.putNextEntry(je);
            writeSignatureBlock(signature, publicKey, outputJar);
            

            在程序中獲取APK的簽名時,通過signature方法進行獲取,如下:

            #!java
            packageInfo = manager.getPackageInfo(pkgname,PackageManager.GET_SIGNATURES);
            signatures = packageInfo.signatures;
            for (Signature signature : signatures) {
                builder.append(signature.toCharsString());
            }
            signature = builder.toString();
            

            所以一般的程序就是在代碼中通過判斷signature的值,來判斷APK是否被重新打包過。

            0x02 簽名繞過方式


            在講簽名繞過的方式前,需要先明確DEX校驗和簽名校驗:

            1.將apk以壓縮包的形式打開刪除原簽名后,再簽名,安裝能夠正常打開,但是用IDE(即apk改之理,會自動反編譯dex)工具二次打包,卻出現非正常情況的,如:閃退/彈出非正版提示框。可以確定是dex文件的校驗

            2、將apk以壓縮包的形式打開刪除原簽名再簽名,安裝之后打開異常的,則基本可以斷定是簽名檢驗。如果在斷網的情況下同樣是會出現異常,則是本地的簽名檢驗;如果首先出現的是提示網絡沒有連接,則是服務器端的簽名校驗.

            2.1.Java層校驗

            獲取簽名信息和驗證的方法都寫在android的java層。實例如下:

            1、使用APKIDE反編譯APK,不做任何操作,然后直接回編譯,安裝后運行,提示如下:

            enter image description here

            2、在APKIDE中搜索signatures(或者搜索錯誤提示),定位到簽名驗證的代碼處。

            enter image description here

            3、此處就是獲取簽名的,然后找程序判斷簽名的地方,進行修改,如下圖,if-nez是進行判斷的地方,將ne修改為eq。即if-eqz v2, :cond_0。則程序就可以繞過本地的簽名交易。

            enter image description here

            enter image description here

            2.2.NDK校驗

            將關鍵代碼放到so中,在底層獲取簽名信息并驗證。因為獲取和驗證的方法都封閉在更安全的so庫里面,能夠起到一定意義上的保護作用。實例如下:

            1、使用APKIDE反編譯APK,不做任何操作,然后直接回編譯,安裝后運行,程序直接退出,無任何提示。

            2、在APKIDE中搜索signatures(或者搜索錯誤提示),定位到簽名驗證的代碼處。

            enter image description here

            3、使?用JD-GUI打開AppActivity,可以看到,此處是獲取包名,然后進?行MD5計算。

            enter image description here

            4.在程序中搜索getSignature,發現并沒有調?用此函數的地?方,猜測在so?文件中,搜索loadLibrary。

            enter image description here

            5.在代碼中可以查找,可以找到調?用的是libcocos2dcpp.so

            6.使?用IDA打開libcocos2dcpp.so,然后搜索getSiganture,找到調?用此函數的地方。

            enter image description here

            從代碼中可以看到,此函數調?用了org.cocos2dx.cpp.AppActivity.getSignature

            enter image description here

            7、查看F5代碼,發現此函數是判斷簽名的函數,然后我們雙擊此函數的調?者,部分代碼如下。

            enter image description here

            8、從上圖可以看出,只需要修改BEQ loc_11F754,讓其不跳轉到jjni——>error,就可以繞過簽名校驗。 查看HEX,使?010editor跳到0011F73E,修改D0為D1。成功繞過簽名校驗。

            enter image description here

            2.3.服務器驗證

            在android的java層獲取簽名信息,上傳服務器在服務端進行簽名然后返回驗證結果。

            如下圖,網絡驗證時,如果網絡沒連接,一般都會提示錯誤。

            enter image description here

            既然是網絡驗證,肯定要把驗證信息發送到服務端,然后進行驗證,先看個簡單的實例,下次會有個難度大的。

            1、手機配置好抓包,然后抓包。第一種圖是正常的APK的時候的數據包,第二個圖是反編譯的APK的數據包,通過對比,發現cookie中的public_key不一樣,那么我們替換一下,發現可以正常使用APK的功能了。

            enter image description here

            enter image description here

            2、將正確的public_key添加到APK中。打開反編譯的代碼,搜索signatures,定位到簽名的代碼。

            enter image description here

            可以看到,代碼將signatures的值傳遞到V4中,然后傳遞到Utils->mPublicKey函數中,于是我們將正確的public_key傳給V4。

            enter image description here

            然后重新打包,重新安裝就可以了。

            0x03.總結


            java層的校驗很容易就可以破解掉,在so層實現校驗相對來說分析會更難點,而網絡驗證,如果僅僅是字符串的比較,那么也很容易破解掉。

            碼子碼的太累了。。

            后面還有幾篇正在寫的文章,包括so分析等等。

            摘抄: http://www.blogjava.net/zh-weir/archive/2011/07/19/354663.html

            <span id="7ztzv"></span>
            <sub id="7ztzv"></sub>

            <span id="7ztzv"></span><form id="7ztzv"></form>

            <span id="7ztzv"></span>

                  <address id="7ztzv"></address>

                      亚洲欧美在线