018 Android加固之实现dex加载器
文章目錄
- Android APK加固-安全人員角度
- 關(guān)于類(lèi)加載器
- 類(lèi)加載器
- 類(lèi)加載器的種類(lèi)和個(gè)數(shù)
- 創(chuàng)建類(lèi)加載實(shí)例
- 類(lèi)加載器DexClassLoader和PathClassLoader
- 使用類(lèi)加載器動(dòng)態(tài)加載dex文件
- 制作dex文件
- 動(dòng)態(tài)加載dex文件
- 完整步驟回顧
Android APK加固-安全人員角度
Android安全人員對(duì)APK加固采取的角度大概分為以下幾個(gè)方面:
那如果繼續(xù)再細(xì)分一下,實(shí)現(xiàn)一個(gè)初級(jí)的APK加固:
接下來(lái)就是從類(lèi)加載器開(kāi)始一步步完成APK加固
關(guān)于類(lèi)加載器
類(lèi)加載器
在JAVA開(kāi)發(fā)中動(dòng)態(tài)加載的技術(shù)主要用于加載jar包,使軟件具備動(dòng)態(tài)添加插件的功能,Java代碼都是寫(xiě)在Class里的,程序運(yùn)行在虛擬機(jī)上時(shí),虛擬機(jī)需要把需要的Class加載進(jìn)來(lái)才能創(chuàng)建實(shí)例對(duì)象并工作,而完成這一加載工作的角色就是ClassLoader。
Android的Dalvik/ART虛擬機(jī)如同標(biāo)準(zhǔn)JAVA的JVM虛擬機(jī)一樣,在運(yùn)行程序時(shí)首先需要將對(duì)應(yīng)的類(lèi)加載到內(nèi)存中。因此我們可以利用這一點(diǎn),在程序運(yùn)行時(shí)手動(dòng)加載Class,從而達(dá)到代碼動(dòng)態(tài)加載可執(zhí)行文件的目的。
Android的Dalvik/ART虛擬機(jī)雖然與標(biāo)準(zhǔn)Java的JVM虛擬機(jī)不一樣,ClassLoader具體的加載細(xì)節(jié)不一樣,但是工作機(jī)制是類(lèi)似的,也就是說(shuō)在Android中同樣可以采取類(lèi)似的動(dòng)態(tài)加載jar或者dex的功能,只是在Android應(yīng)用中動(dòng)態(tài)加載一個(gè)jar或者dex的工作要比Eclipse加載一個(gè)插件復(fù)雜許多
類(lèi)加載器的種類(lèi)和個(gè)數(shù)
動(dòng)態(tài)加載的基礎(chǔ)是ClassLoader,從名字可以看出ClassLoader就是專(zhuān)門(mén)用來(lái)處理類(lèi)加載工作的,所以這個(gè)類(lèi)也叫類(lèi)加載器,而且一個(gè)運(yùn)行中的APP不僅有一個(gè)類(lèi)加載器。
其實(shí)在Android系統(tǒng)啟動(dòng)的時(shí)候會(huì)創(chuàng)建一個(gè)Boot類(lèi)型的ClassLoader實(shí)例,用于加載一些系統(tǒng)Framework層級(jí)需要的類(lèi),我們的Android應(yīng)用里也需要用到一些系統(tǒng)的類(lèi),所以APP啟動(dòng)的時(shí)候也會(huì)把Boot類(lèi)型的ClassLoader傳進(jìn)來(lái)。此外,APP也有自己的類(lèi)。
這些類(lèi)保存在APK的dex文件里面,所以APP啟動(dòng)的時(shí)候,也會(huì)創(chuàng)建一個(gè)自己的ClassLoader實(shí)例,用于加載自己dex文件中的類(lèi)。下面我們?cè)陧?xiàng)目里驗(yàn)證看看。
public void enmuClassLoader(){int count=0;//獲取當(dāng)前包的ClassLoaderClassLoader classLoader=getClassLoader();if (classLoader!=null){Log.d("GuiShou","[onCreate] classLoader"+count++ +":"+classLoader.toString());}while (classLoader.getParent()!=null){classLoader=classLoader.getParent();Log.d("GuiShou","[onCreate] classLoader"+count++ +":"+classLoader.toString());}}可以看見(jiàn)有兩個(gè)ClassLoader實(shí)例,一個(gè)是BootClassLoader,系統(tǒng)啟動(dòng)時(shí)候創(chuàng)建的,一個(gè)是PathClassLoader,應(yīng)用啟動(dòng)時(shí)創(chuàng)建的。由此也可以看出,一個(gè)運(yùn)行的Android應(yīng)用至少有兩個(gè)ClassLoader。
創(chuàng)建類(lèi)加載實(shí)例
動(dòng)態(tài)加載外部Dex文件的時(shí)候,我們也可以使用自己創(chuàng)建的ClassLoader實(shí)例來(lái)加載dex里面的class,不過(guò)ClassLoader的創(chuàng)建方式有點(diǎn)特殊,我們先來(lái)看看它的構(gòu)造方法
private ClassLoader(Void unused,ClassLoader parent){this.parent=parent; }創(chuàng)建一個(gè)ClassLoader的時(shí)候,需要使用一個(gè)現(xiàn)有的ClassLoader的實(shí)例作為新創(chuàng)建的實(shí)例的Parent。這樣一來(lái),一個(gè)Android應(yīng)用,甚至整個(gè)Android系統(tǒng)里所有的ClassLoader實(shí)例都會(huì)被一棵樹(shù)關(guān)聯(lián)起來(lái),這也是ClassLoader的雙親代理模型(Parent-Delegation Model)的特點(diǎn)
類(lèi)加載器DexClassLoader和PathClassLoader
在Android中,ClassLoader是一個(gè)抽象類(lèi),在實(shí)際開(kāi)發(fā)過(guò)程中,我們一般是使用其子類(lèi)DexClassLoader和PathClassLoader來(lái)加載類(lèi)的。
它們的不同之處是:
- DexClassLoader可以加載jar/dex/apk,可以從SD卡中加載未安裝的APK
- PathClassLoader只能加載系統(tǒng)中已經(jīng)安裝過(guò)的APK
根據(jù)功能,我們更加傾向于使用DexClassLoader,所以接下來(lái)先使用DexClassLoader來(lái)加載一個(gè)簡(jiǎn)單的dex文件
使用類(lèi)加載器動(dòng)態(tài)加載dex文件
制作dex文件
為了能與Android的類(lèi)有互動(dòng),先寫(xiě)這樣一段代碼
public class TestActivity {public void CreateVew(Activity ac){//創(chuàng)建一個(gè)TextViewTextView tv=new TextView(ac);//創(chuàng)建布局 設(shè)置參數(shù)FrameLayout.LayoutParams params=new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT,FrameLayout.LayoutParams.WRAP_CONTENT);//設(shè)置控件到頂端的距離params.topMargin=0;//設(shè)置控件的位置params.gravity= Gravity.TOP|Gravity.CENTER_HORIZONTAL;tv.setText("TestActivity View");//添加TextView到Avtivity中ac.addContentView(tv,params);} }這段代碼的效果就是顯示一段TextView到Activity中
這次代碼直接在Android項(xiàng)目中編譯,然后在app的目錄中查找class文件復(fù)制到自己的目錄中即可。類(lèi)所在的目錄是app/build/intermediates/classes/debug/包名
接下來(lái)把當(dāng)前的這個(gè)Activity進(jìn)行反編譯得到的smali文件轉(zhuǎn)成一個(gè)dex文件放到這個(gè)工程的資源文件里
將apk用AndroidKiller打開(kāi),分析完成后打開(kāi)smali文件路徑,復(fù)制出一份副本
刪除其余的smali文件,只保留我們自己寫(xiě)的TestActivity類(lèi)的smali,然后通過(guò)smali.jar將其轉(zhuǎn)成dex文件
然后在main文件夾下新建一個(gè)assets文件夾,將dex文件復(fù)制到里面,并且刪除TestActivity類(lèi)
動(dòng)態(tài)加載dex文件
現(xiàn)在我們已經(jīng)有了一個(gè)制作好的dex文件,接著就需要將這個(gè)dex文件動(dòng)態(tài)加載進(jìn)來(lái)。想要?jiǎng)討B(tài)加載dex,需要下面幾個(gè)步驟。
首先拷貝dex文件
public String CopyDex(String dexName){//獲取Asserts目錄管理器AssetManager as=getAssets();//合成路徑 data/data/包名/files/dex名稱(chēng)String path=getFilesDir()+ File.separator+dexName;Log.d("GuiShou",path);//創(chuàng)建文件流try {FileOutputStream out=new FileOutputStream(path);//打開(kāi)文件InputStream is=as.open(dexName);//循環(huán)讀取文件,拷貝到目標(biāo)路徑byte[] buffer=new byte[1024];int len=0;while ((len=is.read(buffer))!=-1){out.write(buffer,0,len);}//關(guān)閉文件out.close();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return path;}接著創(chuàng)建DexClassLoader
public DexClassLoader GetLoader(String path){//創(chuàng)建dex的類(lèi)加載器,返回DexClassLoader對(duì)象DexClassLoader dexClassLoader=new DexClassLoader(path, //dex文件路徑getCacheDir().toString(), //優(yōu)化后的dex文件路徑null, //原生庫(kù)路徑getClassLoader() //父類(lèi)加載器);return dexClassLoader;}最后調(diào)用加載的dex中的class方法
public void execClassMethod(DexClassLoader dex,String ClassName, String MethodName){try {//獲取加載的類(lèi)信息Class TestDex=dex.loadClass(ClassName);//獲取構(gòu)造方法 無(wú)參構(gòu)造Constructor localConstructor=TestDex.getConstructor(new Class[]{});//調(diào)用構(gòu)造方法 創(chuàng)建對(duì)象Object instance=localConstructor.newInstance(new Object[]{});//獲取成員方法Method methodTest=TestDex.getDeclaredMethod(MethodName,new Class[]{Activity.class});//取消java訪問(wèn)檢查,提高反射速度methodTest.setAccessible(true);//調(diào)用方法 this指針傳進(jìn)去methodTest.invoke(instance,new Object[]{this});} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}}最后調(diào)用以上三個(gè)函數(shù)
//加載dexpublic void loadDex(){//拷貝自定義資源中的dex到程序目錄下String dexPath=CopyDex("test.dex");//創(chuàng)建一個(gè)DexClassLoader,加載dexDexClassLoader dexClassLoader=GetLoader(dexPath);//調(diào)用加載dex中的class方法execClassMethod(dexClassLoader,"com.example.classloaderdemo.TestActivity","CreateVew");}到這里,代碼就已經(jīng)全部完成了。
接著運(yùn)行程序,
效果和之前寫(xiě)的dex文件代碼一致,那么就說(shuō)明我們已經(jīng)完成了動(dòng)態(tài)加載dex文件的過(guò)程。
完整步驟回顧
總結(jié)
以上是生活随笔為你收集整理的018 Android加固之实现dex加载器的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 017 Android加固之APK混淆和
- 下一篇: 020 Android之so文件动态调试