正是因為反編譯這么簡單,如果不加保護,我們的勞動成果就會被輕易盜取。
市面上比較常用的反編譯工具有:dex2jar,jd-gui,apktool,IDA等等。
這里我簡單的說一下dex2jar這個常用反編譯工具的使用。
在下載到了dex2jar和jd-gui這兩個工具之后。
1.將要反編譯的APK后綴名改為.rar或 .zip,並解壓
-------------------------------------------------------------
2.得到其中的classes.dex文件(它就是java文件編譯再通過dx工具打包而成的),將獲取到的classes.dex放到之前解壓出來的工具dex2jar-0.0.9.15 文件夾內
-------------------------------------------------------------
3.在命令行下定位到dex2jar.bat所在目錄,輸入dex2jar.bat classes.dex。
效果如下:
在該目錄下會生成一個classes_dex2jar.jar的文件,然后打開工具jd-gui文件夾里的jd-gui.exe,之后用該工具打開之前生成的classes_dex2jar.jar文件,便可以看到源碼了,效果如下:
被混淆過的效果圖(類文件名稱以及里面的方法名稱都會以a,b,c....之類的樣式命名):
沒有經過處理或者只是簡單的混淆過的APP其代碼的反編譯的比較容易的。你的代碼經過上面那三步已經暴露出來了。
在下面提供的更多的途徑來給各位學習反編譯。
更多反編譯的教程:
-------------------------------------------------------------
[size=21.3333339691162px]
apktool反編譯工具使用教程:
http://www.apkbus.com/forum.php?mod=viewthread&tid=60541&highlight=反編譯
-------------------------------------------------------------
反編譯與防止反編譯:
http://www.apkbus.com/forum.php?mod=viewthread&tid=183482&highlight=%E5%8F%8D%E7%BC%96%E8%AF%91
-------------------------------------------------------------
黑馬Android視頻教程——119_應用程序的反編譯:
http://www.apkbus.com/forum.php?mod=viewthread&tid=130649&highlight=%E5%8F%8D%E7%BC%96%E8%AF%91
怎樣防止應用被破解?
在知道了這么容易就可以破解我苦心經營的APP時,我的心是崩潰的。這個時候我要聽專家的,我還認真的記錄了下來,看看專家怎么說。
從上圖我們可以看到,現在的防止反編譯的手段已經發展到了資本主義了。
下面一一列舉了各種對抗反編譯的手段,希望對大家有所幫助。
(一)基礎手段--混淆代碼
代碼混淆技術基本原理是使反編譯工具反編譯出來的代碼人難以閱讀,從而達到防止被逆向破解的目的。簡單的理解就是把原來的類名、方法名、字段名、參數名、變量名等,用無意義的字符序列來替換。變成類似abc這樣的無命名規則的字符,增加閱讀難度。
步驟:
-------------------------------------------------------------
1.找到或者創建一個proguard-project.txt文件
-------------------------------------------------------------
2.在proguard-project.txt添加混淆的申明
a) 申明外包jar包(申明的外面jar不會被混淆)
例如:-libraryjars libs/abc.jar
b) 將你不需要混淆的部分申明進來(因為有些類經過混淆會導致程序編譯不通過)
如系統組件和API的類:
-keep public class * extends android.app.Fragment
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class * extends android.support.v4.**
c) -dontwarn 缺省proguard 會檢查每一個引用是否正確,但是第三方庫里面往往有些不會用到的類,沒有正確引用。如果不配置的話,系統就會報錯。
例如:-dontwarn android.support.**
d) -keepclassmembers 指定的類成員被保留。
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
e) -keepclasseswithmembers 指定的類和類成員被保留,假如指定的類成員存在的話。
例如:
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
-------------------------------------------------------------
3.以上工作完成,混淆工作就完成了一大半了,最后需要做的就是在project.properties文件中加上你的混淆文件申明了,如下:
proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
-------------------------------------------------------------
4.最后一步,打簽名包測試
(二)簽名自校驗
簡單的理解,簽名就是標明一個APP是不是官方正版發行的標記。發現一個APP跟你的一樣卻無法覆蓋安裝,就是簽名不一致的緣故。也可以理解為你的APP已經被破解並重新打包了。
那么如何獲取到APK文件的公鑰信息呢?因為Android系統安裝程序肯定會獲取APK信息進行比對,所以我們可以通過Android源碼獲得一些思路和幫助。
源碼中有一個隱藏的類用於APK包的解析。這個類叫PackageParser,路徑為frameworks\base\core\java\android\content\pm\PackageParser.java。當我們需要獲取APK包的相關信息時,可以直接使用這個類,下面代碼就是一個例子函數:
代碼:
private PackageInfo parsePackage(String archiveFilePath, int flags){ PackageParser packageParser = new PackageParser(archiveFilePath); DisplayMetrics metrics = new DisplayMetrics(); metrics.setToDefaults(); final File sourceFile = new File(archiveFilePath); PackageParser.Package pkg = packageParser.parsePackage( sourceFile, archiveFilePath, metrics, 0); if (pkg == null) { return null; } packageParser.collectCertificates(pkg, 0); return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0); }
其中參數archiveFilePath指定APK文件路徑;flags需設置PackageManager.GET_SIGNATURES位,以保證返回證書簽名信息。
具體如何通過PackageParser獲取簽名信息在此處不做詳述,具體代碼請參考PackageParser中的public boolean collectCertificates(Package pkg, int flags)和private Certificate[] loadCertificates(JarFile jarFile, JarEntry je, byte[] readBuffer)方法。至於如何在Android應用開發中使用隱藏的類及方法,可以參看我的這篇文章: 《Android應用開發中如何使用隱藏API》 。
緊接着,我們就可以通過packageInfo.signatures來訪問到APK的簽名信息。還需要說明的是 Android中Signature和Java中Certificate的對應關系。它們的關系如下面代碼所示:
代碼:
pkg.mSignatures = new Signature[certs.length]; for (int i=0; i<N; i++) { pkg.mSignatures = new Signature( certs.getEncoded()); }
也就是說signature = new Signature(certificate.getEncoded()); certificate證書中包含了公鑰和證書的其他基本信息。公鑰不同,證書肯定互不相同。我們可以通過certificate的getPublicKey方法獲取公鑰信息。所以比對簽名證書本質上就是比對公鑰信息。
OK,獲取到APK簽名證書之后,就剩下比對了。這個簡單,功能函數如下所示:
代碼:
private boolean IsSignaturesSame(Signature[] s1, Signature[] s2) { if (s1 == null) { return false; } if (s2 == null) { return false; } HashSet<Signature> set1 = new HashSet<Signature>(); for (Signature sig : s1) { set1.add(sig); } HashSet<Signature> set2 = new HashSet<Signature>(); for (Signature sig : s2) { set2.add(sig); } // Make sure s2 contains all signatures in s1. if (set1.equals(set2)) { return true; } return false; }
在程序運行時,自我進行簽名比對。比對樣本可以存放在APK包內,也可存放於雲端。缺點是程序被破解時,自檢測功能同樣可能遭到破壞,使其失效。
(三)源程序使用C層編寫
將核心代碼使用C/C++編寫然后編譯成為.so文件,這種方式的代碼保護性是比Java代碼提升了不少。使用工具反編譯之后的是匯編語言,不過對於熟悉匯編語言的高手來說破解也是很可能的。
對於如何編譯成so文件大家可以參考下面的文檔:
http://www.apkbus.com/forum.php?mod=viewthread&tid=240211&highlight=NDK%E7%BC%96%E8%AF%91
在了解了比較常用的技術之后我們來看看專家推薦的比較高新的對抗技術有哪些
(四)DEX文件隱藏(加殼技術)
加殼技術原理:
所謂apk的加殼技術和pc exe的加殼原理一樣,就是在程序的外面再包裹上另外一段代碼,保護里面的代碼不被非法修改或反編譯,在程序運行的時候優先取得程序的控制權做一些我們自己想做的工作。
加殼作用:
加殼的程序可以有效阻止對程序的反匯編分析,以達到它不可告人的目的。這種技術也常用來保護軟件版權,防止被軟件破解。
大家可以參考下面的文章:
http://www.apkbus.com/forum.php?mod=viewthread&tid=240207&extra=
http://www.apkbus.com/forum.php?mod=viewthread&tid=240662&highlight=so
(五)利用反編譯工具漏洞
一、對抗JD-GUI原理
通常在對apk進行反編譯的時候用到的最多的兩個工具就是apk-tool和dex2jar。利用這兩個工具將apk首先反編譯成classes.dex然后再將classes.dex反編譯成jar文件或者將apk直接反編譯成jar文件;得到jar文件以后就可以利用JD-GUI將得到的jar文件打開就可以直接查看apk的java源碼了。我們花了那么大心思寫的程序就這么容易被別人拿到源碼是不是很不甘心,現在我就告訴你對抗JD-GUI查看源碼的方法。我們在用JD-GUI查看源碼時有時有些函數的根本看不到直接提示error錯誤,我們就利用這點來保護我們的apk。原來JD-GUI在將經過混淆處理的jar里面的class字節碼文件轉成java文件時,遇到函數中根本走不到的分支的特殊實現時就會提示函數error。這時我們只要查看這些提示error的文件或者函數對應的源碼是有什么語句引起的,將這些語句加到我們的源碼中就可以防止利用JD-GUI去查看我們的apk源碼了。
二、原理實現
(1)假如我們的apk onCreate的函數實現如下:
<font style=
"color:rgb(51, 51, 51)"
><font face=
"微軟雅黑"
><font style=
"font-size:16px"
>[url=home.php?mod=space&uid=
389554
]
@Override
[/url]
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); }</font></font></font>
(2)將我們的apk經過混淆處理后經過簽名導出我們的apk,我們用dex2jar工具將我們的apk轉換成jar文件
(3)用JD-GUI打開我們的jar文件就可以看到我們的apk onCreate函數的源碼了。如下:
(4)這時我們在apk onCreate函數里面加上不可能的特殊分支語句,代碼如下:
<font style="color:rgb(51, 51, 51)"><font face="微軟雅黑"><font style="font-size:16px">@Override protected void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); switch ( ) { case : JSONObject jsoObj; String date= null ; String second= null ; try { jsoObj= new JSONObject(); date=jsoObj.getString( "date" ); second=jsoObj.getString( "second" ); } catch (JSONException e) { e.printStackTrace(); } test.settime(date,second); break ; }
class
test
{
public
static
void
settime(String a,String b){}
}
(5)我們用(2)中同樣的方法將apk轉成jar文件,然后用JD-GUI打開會看到提示error錯誤。如下:
根據上面的講述相信大家對對抗JD-GUI的方法有了一定的了解,我只是舉了其中的一個方法,之所以說是特殊的分支語句是因為不是所有的分支語句都可以讓JD-GUI提示error。
(六)運行時修改Dalvik指令
我們知道apk生成后所有的java生成的class文件都被dx命令整合成了一個classes.dex文件,當apk運行時dalvik虛擬機加載classes.dex文件並且用dexopt命令進行進一步的優化成odex文件。我們的方法就是在這個過程中修改dalvik指令來達到我們的目的。
大家可以參考下面的文章:
http://www.apkbus.com/forum.php?mod=viewthread&tid=240208&extra=
快捷的APK反逆向解決方案
在了解上面這么多的反逆向方法之后,我們要保護自己的APP要付出的時間和技術成本看起來還是很高的,這時候如果有一些產品或者工具可以幫我們完成這些工作。那么這方面的成本就低很多了,而目前市面上的確有不少這樣的服務。
360加固寶
http://jiagu.360.cn/protect/welcome/
阿里聚安全
愛加密
網址百度收
梆梆加固
百度雲加固
騰訊雲加固