APK的安全性(一)--如何攻擊

APK的安全性

可以通過修改客戶端文件篡改客戶端行爲。攻擊者可以讓客戶端顯示自己製作的釣魚網站,偷取用戶信息

以下攻擊部分摘自知乎:

https://www.zhihu.com/question/41368839/answer/112182560

防禦部分摘自如下博文:

http://blog.csdn.net/jiangwei0910410003/article/details/48415225

http://www.cnblogs.com/ijiami/archive/2013/08/27/3284209.html

如何攻擊

工具

工欲善其事,必先利其器。首先準備好工具:

反編譯工具

1, apktool反編譯利器

2, dex2jar將dex文件反編譯成jar文件(java代碼)工具,用於解讀代碼

3, gui 打開jar文件工具

簽名工具

1, apksign給java程序簽名的工具

2, testkey.pk8 teskkey.x509.pem用於簽名的文件

首先下載好apk

一,用ApkTool反編譯android程序

用apktool反編譯,命令如下:

apktool.bat d test.apk
...

成功後會在同級目錄生成一個test文件夾

https://pic4.zhimg.com/7d2a8a7eaf2df76816507bc53749721b_b.png

這就是反編譯之後的android程序了,可以看出,這個目錄結構跟我們編寫android代碼時的目錄結構非常相似,除了java代碼是以smali的格式呈現之外,其他都基本是原來的代碼。其實有很多人抄界面,到這一步就可以抄出完整的界面了。如manifest文件,裏面的Activity定義都可以看的很清楚了。然後layout文件,各種res都可以看見了。

其實寫到這,我就有個問題了,這一步怎麼防?我不知道,願請教一二。
如果我們要參考(chao)一個程序的界面,到這一步已經夠了,以爲所有的res和layout文件已經能看到了。
改代碼重新編譯也是要在這個文件夾中改smali文件的,所以smali的語法還是要熟悉一點。但是看代碼邏輯我們不用去看晦澀難懂的smali語言,這就是下一步要做的工作。反編譯出java代碼。

二、用dex2jar反編譯出java源代碼

第一步做的工作先放在這,我們需要重新操作apk文件,其實apk文件就是一種壓縮包,所以我們把後綴名改成rar,用解壓縮工具打開。

看到這裏,有人會問,爲什麼不直接解壓縮,跟我們剛纔用apktool反編譯出來的不一樣嗎,你可以試一下。

這裏其他文件在apktool那一步已經反編譯出來了,我們需要的僅僅是class文件,這是java代碼編譯後生成的文件,用dex2jar這個工具就可以反編譯出原代碼(java格式)了。把這個class文件解壓出來,放在dex2jar的同級目錄下。

d2j-dex2jar.bat test.dex

命令如上,成功之後就會在同級目錄下生成jar文件了。

三、用gui查看代碼

還記得一開始我們說過的工具gui,通過gui打開jar文件,就能看到java代碼了

這裏所有的引入的包代碼都會有,那麼怎麼尋找我們要的主程序代碼呢,這就要依賴在第一步我們反編譯出的manifest文件,熟悉android的朋友知道,在manifest文件中有兩個信息比較重要。
一是包名,也就是主程序的路徑,在manifest的最開始一行。

第二個信息是入口activity,這個很簡單,只要找到有launcher標識的activity就是入口activity。

現在你就可以去gui裏面找到這個入口類了

代碼有混淆,但是混淆只是替換了一些變量名或者類名而已,增加了代碼閱讀的困難性,並不會修改程序邏輯本身,所以只要靜下心來慢慢看,還是看到懂得。

至此,反編譯的過程就結束了,你想看到一個程序的邏輯或者一個程序的界面邏輯都可以看的到的。

四、重新打包,簽名,運行

下面,開始進行最重要的工作,修改代碼,二次打包。其實這裏你可以什麼代碼先都別改,只重新打包一次,看看程序是否能夠正常運行,如果不能,看看程序是哪一步阻止了運行,這也方便你後期定位簽名驗證的位置。目前我見過的簽名驗證有以下幾種:

  • 直接拋出異常,禁止運行
  • 彈出提示框提示用戶,提示框消失後,退出程序
  • 跟服務器交互傳遞簽名信息,如果不正確則服務器不返回數據

重新打包是這樣的,還要用到apktool,記得在第一步反編譯出的那個文件夾嗎,就是用這些文件再重新打包。打包命令如下:

apktool b test -o test1.apk

成功後,在同級目錄下會看到test1.apk文件,這裏只是打包成功了,程序還沒有簽名,沒有簽名的程序是無法安裝到手機上的。簽名用的的是apksign這個工具,這是java提供給開發者用於程序簽名的工具,android的各類IDE也是用這個工具在簽名。使用方法如下,將signapk.jar,testkey.pk8,testkey.x509.pem放在一個目錄下,寫一個signapk.bat文件,如下

java -jar signapk.jar testkey.x509.pem testkey.pk8 %1 %2

然後運行命令

成功後會在同級目錄下生成一個簽過名的apk文件,這個文件我們需要的最終文件,只要你改過代碼並且簽完名後這個apk可以正常安裝運行,那麼本次的任務就算完成了。現在安裝一下,看看會發生什麼。

程序啓動,然後彈出提示框

程序彈出提示,點擊確認後退出程序,看來這個app的簽名驗證是用了我說的上面第二種方法,下面來進行一些嘗試來繞過這個簽名驗證。

五、繞過程序防二次打包機制

首先,我建議大家先全局搜一下signatures這個字符串,因爲程序要獲取app的簽名就要通過packageInfo.signatures這種方式,如果在這裏我們不讓程序獲取到真正的簽名,而是直接返回給它那個“正確”的簽名,豈不是瞞天過海,一步搞定。當然了,你必須要有原來那個程序的“正確”簽名,不過這個簡單,android系統並不阻止你去獲取其他程序的簽名,所以我們可以寫個小的test程序,然後安裝原來的apk,去獲取一次正確的簽名,記錄下來。

獲取其他程序簽名代碼如下

private static String getSignture(Application paramApplication) {
    try {
        String packageName = "packageName";
        List<PackageInfo> packages = paramApplication.getPackageManager().getInstalledPackages(PackageManager.GET_SIGNATURES);
        for (PackageInfo packageInfo : packages) {
            Signature[] signs = packageInfo.signatures;
            Signature sign = signs[0];
            String signString = sign.toCharsString();
            System.out.println(signString);
            return signString;
        }
    } catch (Exception e) {
        return "";
    }
    return "";
}

先裝上原來從正常渠道下載的程序,然後改一下包名,運行這個程序,就能得到正確程序的正確簽名了,記錄一下簽名,然後去我們反編譯的代碼裏面找signatures相關的代碼,看在哪裏獲取了簽名並驗證。

是不是跟我寫的那個方法完全一樣,這個方法其實是獲取程序的本來的簽名的,這就好說了,我們直接返回剛纔記錄的“正確”簽名就可以瞞過程序了。img

好,第一次嘗試,去apktool反編譯出的文件中的smali文件夾下找到這個類MainActivity,如下

這是smali的語法,挺複雜的,感興趣的朋友可以自己再翻閱一下資料。這裏我們把這個方法全部注掉,直接返回“正確”的簽名。如下

按照前面說的簽名的方法,重新打包,簽名,安裝。

我們會發現,程序第一次進入是不行的,還是會提示,簽名驗證失敗,第二次之後就可以正常進入了,這不是我們要的完美效果,思考一下,爲什麼會有這個情況,我想到以下幾種原因:

  • 第一次的時候signinfo還沒有獲取,爲空,所以認爲是非法的
  • 除了這裏,程序在另外的地方做了二次驗證,而且這個二次驗證並不一定每次都能執行成功,這個很像是一個網絡請求方法,跟服務器做驗證,所以根據網絡情況,並不一定每次都成功。

如果是第一種情況,爲什麼正常的程序沒有問題,我們就只是讓返回值變了一下,其他並沒有改變邏輯。我推測是時間差,因爲原來的方法執行獲取簽名需要較長的時間,而直接返回正確簽名很快,難道是這個時間差的影響?我決定把原來那個方法改回來,只修改返回值。如下:

只修改返回值,原來的邏輯不變,時間差應該也排除了,重新打包簽名運行。好吧,很明顯不是,而且情況更嚴重了,前面這些只是我的經驗之談,你在完全不瞭解邏輯的情況下,可以這樣先試一下,我想能繞過30%的app吧。如果是上面說的第二種情況,我們還是來看一下代碼邏輯吧。

全局搜一下應用簽名驗證失敗這句話,看看什麼情況下會觸發。

一共有兩處,我們先看第一處

其實混淆後的代碼挺噁心的,你看這個邏輯好像是如果LoginActivity的c方法爲null就執行,但是你去看c方法就會發現根本就沒有返回值,穩穩的null。這裏代碼其實是這樣看的,要跳出前面那個while,所以我們去loginActivity找what值是19的情況。

往前看,可以發現他調用了一個方法

看來驗證應該是在這裏了,而且是一個網絡請求驗證,所以這個app的防二次打包的機制已經做的比較好的。研究下這個方法,混淆代碼不是很容易看,我先用抓包工具抓了一下包。

發現程序在啓動的時候發了兩個用來驗證的請求,第一個請求沒有參數,服務器返回如下字段


第二次請求帶有如下參數

正常的包服務器返回的是status=1,而我重新打包後服務器返回的是status=0

這是一種典型的challenge-response的方法,服務器發來challenge,然後程序用自身特性的一個字符串加密後再返回response,如果正確,則通過驗證,反之則阻止運行。

這裏我想的是,我找的加密challenge的那一段算法,看他是用什麼方式加密的,用的是程序的哪一段特徵值,然後像前面改簽名一樣,用“正確”的特徵值替換下。

但是,恕我愚鈍,看不懂代碼,這裏我貼一下邏輯,有大神對混淆比較瞭解的可以跟我交流下。

首先loginActivity調了這個Post請求,第一次調用參數爲空,服務器會返回challenge 四個字符串

程序會把這四個字符串交給一個handler處理

抱歉我追到這就追不下去了,因爲中間這幾個不管a還是b都因爲混淆無法直接找到,我也沒想出什麼能間接找到的方法。

是不是到這就束手無策了呢,其實也不是,前面的分析是希望在最上游解決問題,如果我們能在最上游把問題解決了,下面不管什麼邏輯都不用擔心了,但是現在最上游無解了,那麼我們就往下找一找,前面說過, 簽名驗證失敗彈框是在服務器返回後根據服務器返回信息來判斷的,那麼我們可以把判斷的邏輯改掉。

將這個代碼改成永true

我們去smali找到LoginActivity裏的f類,smali編譯時會把所有的內部類編成一個單獨的文件,所有我們去找LoginActivity$f這個文件

這段代碼是比較status和1,如果爲0則跳到cond_2,cond_2就是會給message19的那部分代碼,這裏我們不讓他跳轉,所以刪掉這一句即可。另外MainActivity裏也有一個同樣的校驗,一起改掉就行了。

現在打包,簽名,運行

程序正常啓動,沒有彈出任何異常提醒,試試其他功能,都正常。既然簽名驗證我們搞定,現在往裏面加一句彈toast的代碼,輕而易舉,我準備加在MainActivity的onCreate的時候,找到這部分代碼。

注意要加在super.onCreate之後。彈框代碼如下

加完代碼之後如下

打包,簽名,運行

效果如上,至此,這篇文章就結束了,我們繞過了這個app的防二次打包機制,併成功的修改了代碼。

總結一下

​ 1, 混淆確實是有用處的,雖然混淆後的邏輯仍然可以看懂,但是如果你想去追蹤一些細節邏輯,很難,當然,我混淆代碼研究的太少,經驗太少也是一個方面。

​ 2, App層面上的簽名驗證基本是無效的的,比如一開始我們說的getSignature這裏。

​ 3, 採用challenge-response的方式跟服務器驗證,如果使用不恰當,基本也是完全無效的,比如該應用,成功與否只判斷服務器返回的一個字符串,而且判斷語句是在本地,這個完全是可以繞過的。

至於更好的方法,我查資料的時候,網上看到這樣一個方法,同樣是跟服務器驗證,但是服務器不是返回一個字段,而是返回一段核心代碼,然後程序動態執行這段核心代碼。我覺得采用這種方法,難度會上升一個層級。但還是無法有效避免二次打包。

【原創】Android程序的簽名保護及繞過方法**

幾個問題:

​ 1, 跟服務器驗證的時候,驗證的是什麼東西,前面講了因爲那段代碼沒跟出來,所以不知道實現邏輯。以我的經驗,二次打包唯一變動的應該就是簽名了,但是簽名我們已經繞過去了,不知道還有什麼可以拿來驗證的東西。

​ 2, Android資源層面的東西有沒有防反編譯的方法,我是說res,layout這些。

ok,洋洋灑灑的終於寫完了,我是覺得自己寫得已經很詳細了,已經到了讀者完全可以複製過程的程度。但難免有一些地方我覺得可以省略,但是讀者不懂,可以在評論區提問,我會回答的。

另外,再次強調一下,繞過程序的防二次打包機制畢竟不是一件好事,搞不好做這個程序的程序員要背鍋,所以文章中代碼都是以圖片形式給出,關鍵識別位置都打了馬賽克,但是我想一些有心人還是可以看出這是什麼程序,你看出來就看出來吧,就不要說出來了,好嗎。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章