天天看點

Android APK 加強--開發者角度(零)Android APK 加強–開發者角度(零)

Android APK 加強–開發者角度(零)

1.APK加強介紹

Android應用程式使用的開發語言是Java語言,由于蠶蛹的是這種解釋性語言,是以代碼可以被反編譯。如果沒有經過混淆或是加密,會非常讓人容易讀懂,換言之就是容易被破解。為了能夠使我們的apk更好的保護起來,Android的開發以及安全人員對APK進行了一系列的加強措施。對APK加強從開發者的角度來看,以下是常用的手段和方式:

1.使用proguard對apk中的源碼進行混淆

2.對apk反編譯之後的smali進行混淆

3.對apk中的字元串進行加密

4.對apk中的檔案進行校驗

2.使用proguard對apk中的源碼進行混淆

AndroidStudio預設已經有proguard的支援,在小牧目錄安排app下的build.gradle中有配置資訊,隻需要将false變為true即可。

預設隻有release的配置,而工程預設是debug的,是以想要為debug上添加混淆要在release後面添加debug模式。

Android APK 加強--開發者角度(零)Android APK 加強–開發者角度(零)

Proguard的混淆結果會處處到/build/outputs/mapping/release/目錄或是/build/outputs/mapping/debug/,一共有四個輸出檔案:

1.dump.txt:描述APK中所有類檔案的内部結構

2.mapping.txt:提供混淆前後類名,方法名和成員變量的對應關系。

3.seeds.txt:列出沒有被混淆的類和成員

4.usage.txt:列出從apk中移除的代碼

混淆之後可能出錯,出錯異常的分析:

http://simplyadvanced.net/blog/android-how-to-decode-proguards-obfuscated-code-from-stack-trace/

Proguard 包括四個功能,shrinker(壓縮),optimizer(優化),obfuscator(混淆),preverifier(預校驗)

3.對反編譯之後的smali進行混淆

源碼經過混淆之後,在一個産品級的apk中對apk的保護是有一定幫助的,而對于一些有一定經驗的破解者,他們還是會找到比較關鍵的地方,一般這種方式都是經過反編譯之後進行分析的,那麼如果我們效仿windows下的保護軟體,對smali代碼進行混淆,那麼某種程度上加大了破解者的分析難度。比較友善的混淆方式就是代碼亂序。

1.代碼亂序

原理:

我們在分析smali代碼時,一般會借助于反編譯工具反編譯成java代碼,代碼亂序的主要目的就是想要将smali代碼亂序之後,使反編譯的效果大打折扣,這樣就會擋住很短菜鳥,至少可以減慢分析速度。

2.對apk中的字元串進行加密

在開發過程中字元串的使用不可避免,但是這些字元串極可能是破解的關鍵點,比如伺服器的位址和錯誤提示這些敏感的字元串資訊。如果這些字元串采用寫死的方式,很容易通過靜态分析擷取。

1.采用StringBuilder拼接的方式。

2.編碼混淆:在寫死的時候将字元串先轉換成16進制的數組或者Unicode編碼,在使用的時候在回轉字元串,這種方式比StringBuider方式更難直接識别。

3.加密處理:先将字元串在本地進行加密處理,後将密文寫死進去,運作時再進行解密。可以将解密方法通過JNI實作。

4.對apk中的檔案進行校驗

在apk中包括代碼和資源以及簽名檔案,一般我們會對可執行檔案進行校驗,還有證書的簽名進行校驗,以及apk本身的校驗。

1. 對apk中的dex檔案進行校驗

classes.dex是android虛拟機的可執行檔案,我們所寫的java代碼騎士都在這裡面,所有很多賭赢程式的篡改都是針對classes.dex檔案的。

1.編寫代碼

代碼比較簡單,這裡是通過計算好的crc儲存在string.xml檔案裡,當然我們可以随便那一個值代替,等開發完成後替換掉。

private void verifyDex(){
	Long dexCrc = Long.parseLong(this.getString(R.string.crc_value));
	String apkPath = this.getPackageCodePath();
	try{
		ZipFile zipFile = new ZipFile(apkPath);
		ZipEntry dexEntry = zipFile.getEntry("classes.dex");
		//計算classex.dex的crc
		long dexEntryCrc = dexEntry.getCrc();
		Log.d("DEX",dexEntryCrc+" ");
		//對比
		if(dexCrc == dexEntryCrc){
			Log.d("DEX","dex hasn't been modified");
		}else{
			Log.d("DEX","dex has ben modified");
		}
	}catch (IOException e){
		e.printStackTrace();
	}
}
           

2.對apk中的apk進行校驗

與DEX校驗不同apk校驗必須把計算好的Hash值放在網絡服務端,因為對APK的任何改動都會印象到最後的Hash值。

校驗代碼:

private void verifyApk(){
//擷取data/app/**/base.apk 路徑
	String apkPath = getPackageResourcePath();
	MessageDigest msgDigest;
	try{
		//擷取apk并計算MD5
		msgDigest = MessageDigest.getInstance("MD5");
		byte[] bytes = new byte[4096];
		int count;
		FileInputStream fis;
		fis = new FileInputStream(new File(apkPath));
		while((count = fis.read(bytes))>0){
			msgDigest.update(bytes,0,count);
			}
			//計算出MD5值
			BigInteger bInt = new BigInteger(1,msgDigest.digest);
			String md5 = bInt.toString(16;
			fis.close();
			Log.d("apk",md5);
			//擷取服務端的md5對比
			}catch(){
			}
           

3.對apk中的簽名進行校驗

每個APK都會經過開發者獨有的整數進行簽名,如果破解者對APK進行二次打包一般會用自己的簽名證書 打包。這時候我們就可以通過校驗簽名證書的MD5值進行校驗。

校驗代碼:

public void verifySignature(){
	String packageName = this.getPackageName();
	PackageManager pm = this.getPackageManager();
	PackageInfo pi;
	String md5 = "";
	try{
		pi = pm.getPackageInfo(packageName,PackageManager.GET_SIGNATURES);
		Signature[] s=pi.signatures;
		//計算md5值
		//擷取服務端簽名證書,對比
           

繼續閱讀