Androidapk如何加固防止被破解(防止逆向編譯)
現在主要工具是接觸SDK,為了防止遊戲包被破解編譯,以及發現加密串,我來分享下以下幾點:
防破解技術主要有四種實現方式:
1.程式碼混淆(ProGuard)技術
2.簽名比對技術
3.NDK .so 動態庫技術
4.動態載入技術
5.第三方平臺加密以及檢測漏洞
這個在 Android 安全之如何反編譯與加密apk包 這篇文章中也提及到了相關的知識點。
- 第一種: 程式碼混淆技術(ProGuard) 該技術主要是進行程式碼混淆,降低程式碼逆向編譯後的可讀性,但該技術無法防止加殼技術進行加殼(加入吸費、廣告、病毒等程式碼),而且只要是細心的人,依然可以對程式碼依然可以對程式碼進行逆向分析,所以該技術並沒有從根本解決破解問題,只是增加了破解難度。
- 第二種: 簽名比對技術 該技術主要防止加殼技術進行加殼,但程式碼逆向分析風險依然存在。而且該技術並不能根本解決被加殼問題,如果破解者將簽名比對程式碼註釋掉,再編譯回來,該技術就被破解了。
- 第三種: NDK .so動態庫技術,該技術實現是將重要核心程式碼全部放在C檔案中,利用NDK技術,將核心程式碼編譯成.so動態庫,再用JNI進行呼叫。該技術雖然能將核心程式碼保護起來,但被加殼風險依然存在。
- 第四種: 動態載入技術,該技術在Java中是一個比較成熟的技術,而Android中該技術還沒有被大家充分利用起來。
-
第五種: 第三方平臺使用
主要講解第四種方法,該技術可以有效的防止逆向分析、被破解、被加殼等問題,動態載入技術分為以下幾步:
-
將核心程式碼編譯成dex檔案的Jar包
- 對jar包進行加密處理
- 在程式主入口利用NDK進行解密
- 再利用ClassLoader將jar包進行動態載入
- 利用反射技術將ClassLoader 設定成系統的ClassLoader。
主要優點有:
1.核心程式碼在被加密的jar中,所以破解者無法解壓出class檔案,如果加密祕鑰被破解者拿到,那將是另外一層面的安全問題了。
2.該技術也可以有效防止加殼技術,程式碼是動態載入上來的,破解者的殼程式無法加入到已加密的jar包中,及時破解者注入殼程式入口,殼程式因為不在ClassLoader 的jar包中,所以也無法被執行起來,除非破解者替換ClassLoader的jar包,關掉NDK解密程式碼.但這種安裝到手機上,已經不在是我們的應用,使用者一定會將其解除安裝掉。
所以綜合起來比較,第四種動態載入技術是最安全的,但效率問題,本人並沒做嚴格測試,粗略實驗了一下,效率並沒有明顯降低。
// 1.Jar包加密加密解密檔案//
public static boolean enOrDecryptFile(byte[] paramArrayOfByte,
String sourceFilePath, String destFilePath,int mode){
File sourceFile = new File(sourceFilePath);
File destFile = new File(destFilePath);
CipherOutputStream cout = null;
FileInputStream in = null;
FileOutputStream out = null;
if (sourceFile.exists() && sourceFile.isFile()) {
if (!destFile.getParentFile().exists()) {
destFile.getParentFile().mkdirs();
}
try {
destFile.createNewFile();
in = new FileInputStream(sourceFile);
out = new FileOutputStream(destFile);
// 獲取金鑰//
init();
SecretKeySpec secretKeySpec = new SecretKeySpec(defPassword, "AES");
Cipher cipher;
cipher = Cipher.getInstance("AES");
cipher.init(mode, secretKeySpec);
cout = new CipherOutputStream(out, cipher);
byte[] cache = new byte[CACHE_SIZE];
int nRead = 0;
while ((nRead = in.read(cache)) != -1) {
cout.write(cache, 0, nRead);
cout.flush();
}
}catch (IOException e) {
e.printStackTrace();
return false;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return false ;
} catch (NoSuchPaddingException e) {
e.printStackTrace();
return false ;
}catch (InvalidKeyException e) {
e.printStackTrace();
return false;
}finally{
if(cout != null){
try {
cout.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(out != null){
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(in != null){
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return true;
}
return false;
}
jar用SDKplatform-tools下的dx命令進行dex格式轉化
dx --dex --output=生成的目標檔案的地址(絕對路徑) 需要轉化的jar檔案(絕對路徑)
例如:dx --dex --output=H:classdex.jar H:dujinyang-KARL.jar
然後再用加密工具將生成jar檔案進行加密處理
最後通過程式碼動態載入:
File file = new File("/data/data/" + base.getPackageName() + "/.cache/");
if (!file.exists()) {
file.mkdirs();
}
try {
Runtime.getRuntime().exec("chmod 755 " + file.getAbsolutePath()).waitFor();
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
Util.copyJarFile(this);
Object currentActivityThread = RefInvoke.invokeStaticMethod(
"android.app.ActivityThread", "currentActivityThread",
new Class[] {}, new Object[] {});
String packageName = getPackageName();
HashMap mPackages = (HashMap) RefInvoke.getFieldOjbect(
"android.app.ActivityThread", currentActivityThread,
"mPackages");
WeakReference wr = (WeakReference) mPackages.get(packageName);
MyClassLoader dLoader = new MyClassLoader("/data/data/"
+ base.getPackageName() + "/.cache/classdex.jar", "/data/data/"
+ base.getPackageName() + "/.cache", "/data/data/"
+ base.getPackageName() + "/.cache/", base.getClassLoader());
try {
Class<?> class1 = dLoader.loadClass("com.example.test.TestActivity");
Log.i("b364","----------->class1: "+class1);
} catch (ClassNotFoundException e){
Log.i("b364","----------->class not found Exception!");
e.printStackTrace();
}
Log.i("b364","------>PackageInfo: "+wr.get());
// DexClassLoader dLoader = new DexClassLoader(apkFileName, odexPath,
// libPath, (ClassLoader) RefInvoke.getFieldOjbect(
// "android.app.LoadedApk", wr.get(), "mClassLoader"));
RefInvoke.setFieldOjbect("android.app.LoadedApk", "mClassLoader",
wr.get(), dLoader);
處理完成,如果在Application中做特別處理也是可行的。之前就有人分析了愛加密的加密方式,不過這裡不做闡述,有興趣可以一起討論。
下篇文章中我們來講講如何 逆向apk的動態庫
相關文章
- .NET應用如何防止被反編譯編譯
- c#寫的軟體如何防止被反編譯C#編譯
- 如何防止網站被侵入,如何防止網站被掛馬,如何防止網站被入侵?網站
- 程式碼混淆防止APP被反編譯指南APP編譯
- 如何保護Java程式 防止Java反編譯Java編譯
- 一些防止java程式碼被反編譯的方法Java編譯
- 如何防止在網路上被“人肉”?
- 如何防止網路爬蟲被限制?爬蟲
- 如何防止高匿名代理被識別
- 如何防止Google Voice號碼被回收Go
- android 防止反編譯的若干方法Android編譯
- 如何防止在網路上被“人肉”出來?
- 扭曲變換加密 【目前防止軟體被破解最好的方法】加密
- 如何防止網站資料庫被攻擊 被篡改網站資料庫
- 防止API被惡意呼叫API
- 如何防止抓取資料時被列入黑名單?
- 從刪庫到跑路,DBA 如何防止被淘汰?
- Linux防止SSH暴力破解Linux
- Cython加密python程式碼防止反編譯加密Python編譯
- 防止用DeDe軟體反編譯delphi程式 (轉)編譯
- 怎樣防止網站被攻擊 DEDECMS程式碼的加固安全解決方案網站
- 如何防止DNS汙染?DNS
- 如何防止sql注入SQL
- win10系統下如何防止被PingWin10
- 如何有效防止網站資料被竊取、篡改?網站
- CRM管理系統如何防止客戶被帶走?
- 如何徹底擦除資料 防止資料被恢復?
- 如何防止伺服器被惡意網路攻擊?伺服器
- 如何防止window.open彈窗被瀏覽器遮蔽瀏覽器
- 防止密碼被非法獲取 (轉)密碼
- 如何有效防止sql注入SQL
- 如何防止 goroutine 洩露Go
- fail2ban 防止ssh暴力破解AI
- 再談powerbuilder程式防止破解的辦法UI
- 如何用iptables來防止web伺服器被CC攻擊Web伺服器
- java加密保護jar包及class檔案,防止反編譯Java加密JAR編譯
- android開發--防止介面被抓包Android
- 防止代理IP被限制的五種方法