Android程序防破解是發布app時一個很需要考慮的問題,通常的做法是對代碼加入混淆干擾以增加破解難度。但即便如此,混淆操作之後的java代碼仍然可以被通過各種方法進行破解。在基於NDK的Android中含有相應的main.cpp來作為應用程序的入口,因而在這裡進行一些防破解較驗,相應的破解難度就會增大不少(相對於java代碼)。
在Android整個導出過程中,生成.dex階段是整個打包發布操作的基礎,包括相應的java源代碼、外部庫文件均會被編譯鏈接到.dex文件中,而其中關於代碼的任何改動後重新生成.dex,其均會與原始文件均會有所不同,因而就可通過對.dex文件進行MD5較驗而做為app是否被破解的依據。
基本流程:
階段1: 計算.dex文件的MD5串並將其寫入到對應的main.cpp中,相應的ant操作大體如下(並不完整以)。
生成dex對應的MD5,並將其存儲到一個文件中:
<target name="predexmd5"depends="dex">
<exe cexecutable="${dexmd5tool}" failonerror="true">
<argvalue="${dexmd5tempfile}" />
<arg value="${dex-ospath}"/>
</exec>
</target>
從外部文件中讀入相應的MD5串,並存儲到一個ANT的變量:
<target name="dexmd5" depends="predexmd5">
<loadfile srcfile="${dexmd5tempfile}"property="dexmd5sign"/>
</target>
將.dex文件的MD5串寫入到main.cpp中:
<targetname="setmaincpp" depends="dexmd5">
<replace file="${maincppfile}"token="Ant_DexMD5Sign" value="${dexmd5sign}"/>
</target>
其中使用的dexmd5tool是一個自實現的外部exe,主要實現對任意文件計算其相應的MD5並將串值保存到一個指定的文件。這裡需要MD5串以文件形式進行保存主要是以便在ant中打該文件並讀入其中的字符串到ant變量中(並沒有找到其它方法直接將相應的MD5碼寫入到ant變量中去,因而做這樣的婉轉實現)。將MD5串向main.cpp中寫入主要就是利用ant的字符串替換機制來實現即可。
更新完main.cpp之後需要利用NDK對工程進行重新編譯(主要是重編譯這裡有改動的C++代碼,該步必須進行)
調用NDKbuikd來完成相應的重編譯工作:
<targetname="ndkbuild" depends="setmaincpp">
<exec executable="${basedir}/ndkbuild.bat" failonerror="true">
</exec>
</target>
Ndkbuild.bat中的相關內容即如同Eclipse中配置的編譯參數一樣:
X:/cygwin/bin/bash.exe --login -c "cd/cygdrive/XXX/XXX/Android/jni && $NDK/ndk-build"
階段2: 對dex計算相應的MD5並在main.cpp中進行啟動時較驗。
這裡需要在app每次啟動運行中動態得到當前apk包中的.dex文件並進行MD5的計算與較驗。這裡直接實現並不太容易,因而借助於了一個第三方包libzip(https://github.com/julienr/libzip-android),它可以以.so的形式鏈入到NDK工程中,並將指定的zip包(apk包)解壓縮,將其中的所有文件以二進制的方式返回。如此一來就可以運行時得到當前apk包的dex的二進制流;將計算binary的MD5代碼也一並加入到該工程中即可以完成在main.cpp中啟動時動態較驗.dex的MD5值。
若當前apk包中的.dex文件MD5碼與main.cpp中存儲的MD5碼(階段1得到)匹配,程序合法運行;否則,較驗不通過認為已經被修改過,直接退出。
更多Android相關信息見Android 專題頁面 http://www.linuxidc.com/topicnews.aspx?tid=11