天天看點

Android 防止逆向

軟體逆向分析的出現必然會出現防止逆向分析的操作,這裡介紹五種防禦方式:

①代碼混淆技術

②針對不同的逆向工具的保護技術(如IDE、JD_GUI等)

③增加逆向難度(java代碼Native化)

④動态加載技術

⑤代碼驗證技術

代碼混淆

代碼混淆也稱花指令,是将計算機程式的代碼轉化為一種功能上的等價,但是難于閱讀和了解的形式的行為,代碼混淆可以用于程式編譯而成的中間代碼,執行代碼混淆的程式被稱作代碼混淆器,

将代碼中的各種元素,例如變量、函數、類的名字改成毫無意義的名字,比如改成單個字母,或是簡短的無意義的字母組合,甚至改成”_“這樣的符号,使得閱讀的人無法根據名字猜測其用途,重寫代碼中的部分邏輯,将其變成功能上的等價,但是更難以了解的形式,比如講for循環改成while循環,将循環改成遞歸,精簡中間變量,打亂代碼格式等。

ProGuard簡介

是一個壓縮、優化和混淆java位元組碼的免費工具,它可以删除無用的類、字段、方法和屬性,可以删除沒用的注釋,最大限度的優化位元組碼檔案,它還可以使得簡短的無意義的名稱來重命名已經存在的類、字段、方法和屬性:

①删除不可見的字元、注釋等無用代碼,建立緊湊的代碼文檔,為了更快的網絡傳輸,快速裝載和更小的記憶體占用。

②重命名,使得建立的程式和程式庫很難使得反向工程

③能删除來自原檔案的沒有調用的代碼

④充分利用java6的快速加載的優點來提前檢測和傳回java6中存在的類檔案

參數

-include{filename}   從給定的檔案中讀取配置參數

-basedirectory{basedirectory}   指定基礎目錄為以後相對應的檔案名稱

-injars{class_path}    指定要處理的應用程式jar、war、ear和目錄

-outjars{class_path} 指定處理完要輸出的jar、war、ear和目錄名稱

-libraryjars{class_path}  指定要處理的應用程式jar、war、ear和目錄所需要的程式庫檔案

-dontskipnibpubliclibraryclasses 指定不去忽略非公共的類庫

保留選項

-keep {Modifier} {類成員}    保護指定的類檔案和類成員

-keepclassmembers {類檔案}{類成員}    保護指定類的成員,如果此類收到保護,它們會保護的更好

-keepclasswithmembers{}   保護指定的類和類成員,但條件是所有指定的類和類成員要存在

-keepnames {類名稱}  保護指定的類和類成員的名稱

-keepclassmembername{類名稱}   保護指定的類的成員名稱

-keepclasswithmembernames{類名稱}   保護指定的類和類的成員的名稱,如果所有指定的類成員出席(在壓縮步驟之後)

-printseeds{檔案名稱}   列出類和類的成員-keep選項的清單,标準輸出給定的檔案

壓縮

-dontshrink  不壓縮輸入的類檔案

優化

-dontoptimize   不優化輸入的類檔案

-assumenosideeffects{類檔案} 優化時假設指定的方法,沒有任何副作用

-allowaccessmodification   優化時允許通路并修改有修飾符的類和類的成員

混淆

-dontobfuscate  不混淆輸入的類檔案

-printmapping{檔案名}

-applymapping{檔案名}    重用映射增加混淆

-obfuscationdictionary{檔案名}   使用給定檔案的關鍵字作為要混淆方法的名稱

-overloadaggressively 混淆時應用侵入式重載

-useuniqueclassmembernames  确定統一的混淆類的成員名稱來增加混淆

-flattenpackagehierarchy{檔案名} 重新包裝所有重命名的包并放在給定的單一包中

-dontusemixedcaseclassnames   混淆時不會産生形形色色的類名

-renamesourcefileattribute{string} 設定原檔案中給定的字元串常量

混淆帶來的問題

雖然混淆對我們的代碼反逆向起到比較良好的作用,但是過度的混淆也會帶來很多調試的困難,如

①混淆錯誤,用到第三方jar的時候,必須告訴ProGuard不要檢查,否則ProGuard會報錯

②運作錯誤,當code不能混淆的時候,我們必須要正确配置,否則程式會運作出錯,這種問題很多

③調試定位比較痛苦,列印的錯誤資訊中錯誤堆棧是混淆後的代碼,開發者自己也看不懂,這個時候需要自己存一份map,來記錄對應的混淆映射關系。

DEX保護

DEX檔案是Android 應用程式的邏輯所在處,是以DEX檔案的安全至關重要,我們可以對ProGuard進行代碼混淆,代碼混淆隻是增加了逆向的閱讀難度,卻不能真正的解決防止逆向的問題,黑客還是可以通過動态注入的方式,将一些自定義的邏輯注入到我們的DEX檔案中進行重編譯。

DEX優化與混淆處理

DEX優化與混淆處理的目的就是為了對抗一些常見的逆向工具,使得在逆向DEX檔案的時候産生崩潰與無法了解的資訊,當然,也有些處理會讓應用程式更加緊湊,使得程式運作更快的效果。

什麼是殼

加殼,其實是一個形象的稱呼,即給應用程式加一層保護,如同堅韌的外殼一樣,加殼的全稱應該是可執行程式資源壓縮,是保護檔案的一種常用的手段,加殼過後的程式可以直接運作,但是不能檢視源代碼,去殼的過程,我們一般又稱為脫殼。

so檔案保護

上面提到的Dex檔案的加殼,雖然能夠簡單的實作我們的目的,但是這種加殼方式是用java方式實作的,被反編譯的風險仍然很大,為了克服這個缺點,很容易就會想到我們是否能夠将核心業務邏輯代碼放到加密定的.jar檔案或.apk中,在需要調用時用Native C/C++代碼進行解密,同時完成對解密後的檔案的完整性的校驗,

這不能夠完全滿足我們的需求,因為使用C/C++來完成也會存在反彙編的風險,故此,對so檔案進行加殼也就勢在必行了,對so檔案加殼主要解決兩個問題:對ELF檔案加殼,對Android系統中的so檔案分加載,調用機制做處理。

防止二次打包

二次打包,又稱為重打包,一般是在使用逆向工具APKTool等工具逆向修改後,進行APK檔案重新生成的過程,被重新打包的apk應用檔案,因為與之前的應用程式高度相似,市面上稱為山寨貨盜版APP。

在android系統作業系統中apk的唯一識别碼是靠包名和簽名來做鑒别的,包名和簽名是綁定在一起的,一旦apk被反編譯後簽名自動消失,apk簽名需要簽名檔案,簽名檔案是md5值基本上是無法僞造成一緻的,Android要求安裝到手機上的apk檔案必須有簽名,而理論上開發者的簽名他人是無法得到的(有密碼),是以比較容易想到的就是執行簽名校驗,驗證本程式的簽名是否為合法程式。

目前市面上的很多應用商店也是通過開發者提供的包名與簽名做正版判斷,是以我們需要對自己的程式apk防止二次打包,也就是在自己的應用程式内部加入代碼驗證自我的簽名與包名是否被篡改,如果被篡改了,那麼肯定是被二次打包了。

private static final String SIGNATRUE_MD5 = "";//定義正版的簽名md5值           
String getMd5 = getSignatrueMd5(this);
//和apk目前的簽名檔案相比較,判斷是否是原始的檔案
if(!SIGNATRUE_MD5.equals(getMd5)){
    System.exit(0);//簽名不正确,強行推退出
}           
//擷取目前apk的md5
 public static String getSignatrueMd5(Context context){
        String backString = "";

        try {
            PackageInfo mPackageinfo = context.getPackageManager().getPackageInfo(context.getPackageName(),PackageManager.GET_SIGNATURES);
            byte[] arrayOfByte = mPackageinfo.signatures[0].toByteArray();
            backString = DigestUtil.md5(arrayOfByte);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return backString;
    }           

這種保護的方式雖然可行,但是如果面對的是專業打包黨的話,這種方式意義不大,因為在逆向後,我們在Smali代碼中搜尋簽名方法中使用到的相關方法關鍵字,就能夠快速定位到簽名檔案判斷的相關操作處。修改檔案後,再次重新打包,就會避開我們的驗證方法。

ndk技術底層擷取簽名和驗證

在java代碼中做驗證很容易被逆向者修改,是以很多人想到,将判斷邏輯放置入C/C++中去實作,通過Context、Activity、PackageManager、PackageInfo四個對象中的一個作為參數參入底層,在底層擷取簽名資訊并驗證,因為擷取和驗證的方法都封閉在更安全的so庫裡面,是以能夠在一定意義上起到保護的作用,

但是C/C++編譯出來的so檔案在逆向中确實比較困難,但是卻不是不可攻破的難題,通過java層的hook技術護着IDA PRO等反編譯工具修改一樣可以把這種保護完美破解,相對于前兩種,此種保護的意義和價值就更大了。

繼續閱讀