android加固系列—6.仿愛加密等第三方加固平臺之動態加載dex防止apk被反編譯

【版權全部,轉載請註明出處。出處:http://www.cnblogs.com/joey-hua/p/5402599.html 】html

此方案的目的是隱藏源碼防止直接性的反編譯查看源碼,原理是加密編譯好的最終源碼文件(dex),而後在一個新項目中用新項目的application啓動來解密原項目代碼並加載到內存中,而後再把當前進程替換爲解密後的代碼,art模式下也沒問題。好了,廢話很少說,來看代碼,下面是最終想運行的項目,也稱爲原項目:java

這是原項目的目錄,項目名叫Hello,就兩個activity,第一個activity的佈局以下:android

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
    
<TextView 
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="我是Hello項目的FirstActivity"
    android:textSize="20sp"
    />
<Button
    android:id="@+id/btn"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="跳轉"
    />
</LinearLayout>

很是簡單,沒什麼好說的,運行效果以下:git

接下來介紹dex加密工具,名字叫DexJiami,關鍵代碼以下:github

	private static final String root = "C:";
	private static final String path = root + "/Users/lenovo/Documents/mygithub/android-protection/LoadDex/dexFileTmp";
	private static final String path_encrypt_source = path + "/mycode.jar";
	private static final String path_encrypt = path+"/mycode.dat";
	private static String cmd_dex2jar = "cmd /c "+root+" && cd "+path+ " && jar cvf " 
			+ path_encrypt_source + " classes.dex";
	
	
	private static String key="GiEhjghmZIO7RTWyycQ9PQ==";
	/*
	 * 須要生成新的祕鑰時使用
	 */
//	static {
//		try {
//			key = AESUtils.getSecretKey();
//		} catch (Exception e) {
//			e.printStackTrace();
//		}
//	}

這個path就是你準備把dex放置的一個臨時文件夾,生成加密文件用;key的值就是加密和解密用的祕鑰,我們用的AES對稱加解密,這裏的key值是經過這個靜態塊來生成的,生成一次就好了,直接copy到引號,若是想生成新的祕鑰就去掉註釋行。算法

public static void main(String[] args) throws Exception {
		dex2Jar();	//給dex打成jar包
		encrypt();	//對jar加密並生成爲.dat文件
	}

如上,這是從我公司項目的自動化打包工具上裁剪了的,如今整個工具就兩個方法,第一個是把原項目的源碼dex文件打成jar包,而後再對jar包用key值加密並生成dat文件。安全

加密工具使用方法,先從原項目的/bin目錄下找到classes.dex,這個文件就是原項目全部的java源碼生成的最終的字節碼文件,android系統運行你寫的程序就是加載這個dex文件。把它拷貝到你自定義的dexFileTmp文件夾,而後run這個加密工具,最終生成的文件以下:app

最終要用的就是mycode.dat這個文件,怎麼用待會再說,得先介紹第二個android項目DexLoader,這裏稱爲啓動項目,先介紹java版的,後面再介紹jni版,先看下java版的目錄結構:ide

這裏注意,除了上面的這幾個java文件不同以外,全部的資源文件和AndroidManifest都是直接從原項目拷貝過來的,還有就是把上面的mycode.dat文件拷貝至啓動項目的assets目錄下,下面的關鍵代碼爲首先在進程的系統文件夾下面建立一個自定義的app_cache文件夾,做爲加密文件的中轉文件夾,而後解密dat文件並變成jar,變成jar包後系統才能識別並把classes.dex抽取出來。函數

File odex = this.getDir("cache", MODE_PRIVATE);
		String odexPath = odex.getAbsolutePath();
		System.out.println("odexPath--->" + odexPath);
		try {
			Util.decryptFile(this, odexPath+"/mycode.jar");
		} catch (Exception e2) {
			// TODO Auto-generated catch block
			e2.printStackTrace();
		}

接下來的關鍵代碼以下,把解密後的jar包,也就是原項目的代碼加載至內存:

DexClassLoader dLoader = new DexClassLoader(odexPath+"/mycode.jar", odexPath, 
				"/data/data/" + base.getPackageName() + "/lib/",
		 base.getClassLoader().getParent());

接下來程序就會走onCreate方法,大量用到了RefInvoke類,這是一個專門調用反射的類,目的是獲取系統的private變量和執行private方法,就很少介紹了,最終替換當前進程的代碼爲剛纔加載至內存的代碼,最終程序運行以下:

並且還能夠跳轉至第二個activity。大功告成!

 

 下面介紹一下Jni版,先看下目錄結構

 

對比java版能夠看出,解密的代碼不見了,實際上是被封裝到了jni層,下面是java層的關鍵代碼:

static{
		System.loadLibrary("load");
	}

	@Override
	protected void attachBaseContext(Context base) {
		super.attachBaseContext(base);
		Object currentActivityThread = RefInvoke.invokeStaticMethod(
				"android.app.ActivityThread", "currentActivityThread",
				new Class[] {}, new Object[] {});
		String packageName = getPackageName();
		Map mPackages = (Map) RefInvoke.getFieldOjbect(
				"android.app.ActivityThread", currentActivityThread,
				"mPackages");
		WeakReference wr = (WeakReference) mPackages.get(packageName);

		run(this, base, "/data/data/"+ base.getPackageName() + "/lib/", base.getClassLoader().getParent(),wr.get());
	}
	
	private native String run(Application wrapper, Context context, String libPath,ClassLoader classLoader, Object obj);

能夠對比java版的代碼,attachBaseContext裏的部分關鍵代碼都封裝在run函數裏,目的就是隱藏解密算法。jni層的代碼就很少介紹了,代碼原理自己和java版是同樣的,只不過多了在jni層獲取java層的對象和方法的過程。後續工做還須要對so文件加殼及反調試,本版本中並無,固然本版本也有必定的安全做用,畢竟能夠防止反編譯apk直接查看源碼。運行結果和上面一致,也能夠跳轉到第二個activity。

最後咱們再來看下愛加密處理後的源碼,將愛加密處理後的apk解壓,對classes.dex執行反編譯查看源碼,以及assets目錄下的ijiami.dat,以下圖:

分析而知愛加密也是運用了動態解密加載dex文件並替換當前進程的方式實現了隱藏原項目源碼的行爲。

 

一個碼農的平常 

加密工具

原項目

java版啓動項目

jni版啓動項目

相關文章
相關標籤/搜索