申请会员ID:FagerBeyond
1、申 请 I D:FagerBeyond
2、个人邮箱:3087035683@qq.com
3、原创技术文章:用DexClassLoader实现加壳_轻松免杀
JAVA 运行所需要依赖的API的是动态链接的,这个跟C/C++不一样,C/C++开发的程序可以是静态链接的也可以是动态链接的,其中静态链接是在编译时已经做好的,动态链接的运行时才链接的,也就是window 的DLL文件,linxu的SO文件都是动态链接库。java是动态链接,也就是说我们代码中 new一个对象,
static Class 调用,Class.forNmae(),Class.loderclass()这些动作,JVM先把这个class文件
加载到内存然后产生一个对象并吧这对象的地址返回给new,这样我们就可以调用对象的成员了。
其中JVM把class文件加载到内存就是用classloader了,关于classloader的详解可以参考这里http://blog.chinaunix.net/uid-21227800-id-65885.html
很高兴的是JAVA API中为我们提供了ClassLoader这个类,我们用这个类可以通过反射加载自己的class,正因为如初使得JAVA有很强的生命力,在防破解
加壳自定义插件方面发挥的很好,比如ecplise的思想就是“一切都是插件”,他的功能都是通过安装插件完成的,扩展性很强,是很多公司都为他开发插件作为IDE
,也很受开发者欢迎,其中ecplise就是靠ClassLoader加载插件了,这就看出了ClassLoader的强大。
在android中虽然android 的APK是用JAVA开发的,但是android 的虚拟机dalvik并不是java标准的JVM,android的可执行文件是DEX,而JVM的是.class他们并不兼容,
关于他们的区别可以参考这里http://www.w2bc.com/Article/14646。自然的用JAVA 标准的classloader 不能加载DEX,但是谷歌还是基本支持全部JAVA的特性,
因此classloder这个很好的JAVA特性谷歌不会放过,所以谷歌也提供给我们加载DEX的classloader,他的特性和用法跟JAVA标准的classloader差不多。
一个是DexClassLoader另一个是PathClassLoader,他们的区别可以参考这里http://www.apkbus.com/forum.php?mod=viewthread&tid=138499
这里只介绍DexClassLoader,那我们怎样用她来加壳免杀?http://img.blog.csdn.net/20150501130156243?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYmV5b25kMjk2MDg5NzI3/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center
先看看API文档的说明他有四个参数,dexpath表示所要加载DEX文件的路径,optimizedDirectory便是优化的DEX存放路径,libraryPath表示DEX中如果调用自己的SO文件的路径,parent表示为自己的DexClassLoader指定父classloader我们知道Classloader是双亲委派机制的,这是因为每个classloader只会在指定的文件了寻找和加载class,比如
上面如果在dexpath参数里指定了/sdcard/test.dex,那么这个dexclassloader只会在/sdcard/test.dex查找class,
如果我们的DEXclassloader通过反射加载了/sdcard/test.dex里的一个class com.my.test,而com.my.test如果
有 这样一句 String str="22555",我们知道JAVA是动态连接语言,这是如果 String类需要加载,那么他默认的classloader也是所属class的classloader,比如这里所属类是com.my.test,而com.my.test的classloader是我们的
DExclassloader,而如果我们的DExclassloader去自己的文件里test.dex找String类自然找不到,就抛出ClassNotFoundExcpiton,所以双亲委派机制就解决这个问题,当一个classloaer去加载一个class时他先调用他的parent Classloader去加载,如果parent Classloader没有在自己的文件里找到这个classs那么子classloader才去加载。
那么怎么加壳和免杀?
其实思路很简单,把我们所要加壳保护的代码导出成DEX,关于导出DEX看着里
http://www.cnblogs.com/over140/archive/2011/11/23/2259367.html
然后加密,放到服务器或者APK其他文件夹,
运行时通过再读取文件解密然后再用dexclassloader加载运行,这样就可以保护我们的代码的,
其实爱加密,360等加固都是这样的基本思路
比如爱加密的就这这样
http://img.blog.csdn.net/20150501133302942?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYmV5b25kMjk2MDg5NzI3/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center
箭头指向的就是原DEX,就是被加密保护的,至于加密解密其实很简单,我举个最简单的例子,把要保护的DEX文件的每个字节值+1,解密时-1,这样即使拿到DEX也没用。加密我们可以事先通过算法加密,然后才放到APK里,关键是解密,我们都知道APK的入口是application类,这时我们这样在applicatian类里运行加密程序完成DEx的解壳然后用dexclassloader加载并运行,当然了处于安全,解壳和加载DEx的算法应该放在SO,在application里通过JNI调用,其实爱加密也是这样做
http://img.blog.csdn.net/20150501134539731?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYmV5b25kMjk2MDg5NzI3/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center
图中的箭头指向就是他的解密SO
关于爱加密详细原理可以参考这里
http://blog.csdn.net/chengyingzhilian/article/details/38372601
所以用dexclassloader加壳就这么简单
那怎样免杀
通过上面的的分析我们已经很容易看到免杀思路,其实加密程序是一个很好的保护程序不被破解反编译和修改的一个好方案,在病毒里也是个很好的免杀方案,针对加密PC的杀毒杀毒软件时采用虚拟机的方案,也就是构建一个电脑虚拟环境让病毒在上面运行,诱骗他脱壳,这样代码就暴露了,杀毒软件就可以查杀了,但是运行虚拟机耗内存和CPU多使电脑卡,而且查杀慢,而且针对不同电脑构建虚拟机存在难题。总的来说针对加壳查杀杀毒软件很被动,没有理想的方案,这也看出加壳的厉害。在移动平台上基于上面的问题,现在很难实现没因为手机的内存和CPU都比PC的差很多,而且android本来就是基于虚拟机的,这样在嵌套个虚拟机跟难了,也就是说目前和以后很长时间里移动平台对加壳病毒无能为力。
那android 的杀毒软件主要查那些东西?
虽然我不太了解APP杀毒软件的实现,但是通过我观察他查的东西就几个1,特征马,2,包名,3,权限,4,classes.dex文件。对于程序文件值查默认的classes.dex,如果按上面的方法加壳,那么杀毒软件就找不到病毒代码了,自然就免杀了。权限才是难题,我们都知道android 要开发一些敏感的功能,比如发短信,打电话,读写短信,都需要在apk的androidmianfest.xml清单文件里声明对应权限才可以,虽然我们可以加密DEX,但是这样敏感文件不难加密,如果加密了就不能安装,也就是说这样文件必须是透明的,这是android系统的一个安全机制。这样真是杀毒软件查杀的重要依据,比如你申请了发短信权限,那么这个APP就有可能是木马,因为短信是木马最感兴趣的东西之一。这样问题来了,木马的DEx都隐藏的但是杀毒软件检查classes.dex并没有发现有相关的代码,所以速度软件容易判定为木马http://img.blog.csdn.net/20150501142345476?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYmV5b25kMjk2MDg5NzI3/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center
那句“使用与软件本身不符的风险权限”说的很明白,这样解决方案是在classes.dex里加入一些相关代码和一大堆无用的代码,这样360就认为APP是正常的APP,正常需要发短信了
在这就是签名,好多人喜欢用一些破解工具修改木马,比如APK 改之理这些工具都提供默认证书签名,这样人用多了自然引起杀毒专家的注意,他们也会把这些证书签名作为鉴别的依据之一,所以我们最好是用自己制作的证书签名
至于包名的跟不用说了,每个APK都有自己唯一的包名,没有源码情况下改包名麻烦,也就是说包名一般不该,所以给杀毒软件提供了很好的特征依据,也就是说这个包名的APK如果被检测为木马的,哪怕代码在修改包名不改很容易看出。
不过这里我不提倡大家用于实质非法活动,这是供大家学习研究,对杀毒安全的研究和理解
关于用dexclassloader动态加载DEx存在的问题,我们知道dexclassloader加载的类生命周期是虚拟机直接管理,但是对于组件类比如activity他们的声明周期不是由虚拟机直接管理,而是由各种对应的框架层manager管理,比如activity是有activitymanger
http://img.blog.csdn.net/20150501145316533?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYmV5b25kMjk2MDg5NzI3/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center
管理这就是为什么我们不能new activity的原因,只能通过startActivity()反射加载。但是最终activity也是用户classloader加载的。之所以这个组件类是用各框架层管理器管理是有原因的,因为这些类的声明周期是随机的,不可预知的,比如接受短信的BroadcastRecivier,当有短信来时系统收到了,交给广播管理器广播intent,如果我们的的androimainfest.xml定义了一个<recivier>,来接受短信,这是广播管理器会通知我们APP的主线程new 我们的BroadcastRecivier类并且调用onReciver()函数,这一切都是通过反射加载的。也就是new BroadcastRecivier是有短信来了才NEW,而 短信是随机的,所以我们不可能在代码中new ,你知道短信仕么时候来吗?!那么你NEW?!
这里就关键了,BroadcastRecivier组件类最终也是用classloader加载的,如果这个classloader是我们定义的Dexclassloader那么不管我们的组件类放在哪里都会被正常加载并且不存在生命周期问题,然而加载这些组件类的都是都APK的主线程ActivityThread来做,他用的是他自己的classloader加载,我们只把他的classloader替换成我们移动一的就得了关于实现方案我是参考jack_jia的来做http://blog.csdn.net/androidsecurity/article/details/8809542红色箭头是包含有activity等组件类的DEX,椭圆椭圆圈是替换classloaderderhttp://img.blog.csdn.net/20150501151748115?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYmV5b25kMjk2MDg5NzI3/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center
关键代码File dex=new File(Environment.getExternalStorageDirectory().toString()+File.separator+"proxy.dex");
try {
InputStream input=this.getAssets().open("proxy.dex");
dex.createNewFile();
FileOutputStream fo=new FileOutputStream(dex);
int a=0;
byte bf[]=new byte;
while ((a=input.read(bf))!=-1) {
fo.write(bf,0,a);
fo.flush();
}
fo.close();
input.close();
} catch (IOException e) {
e.printStackTrace();
}
File libs = this.getDir("payload_lib", MODE_PRIVATE);
String libPath = libs.getAbsolutePath();
File dex_in=new File(Environment.getExternalStorageDirectory().toString()+File.separator+"proxy.dex");
File optimizedDexOutputPath = getDir("temp", Context.MODE_PRIVATE);
ClassLoader apk_loader=getClassLoader();
loader=new DexClassLoader(dex_in.getAbsolutePath(),
optimizedDexOutputPath.getAbsolutePath(), null, apk_loader);
Object currentActivityThread = RefInvoke.invokeStaticMethod(
"android.app.ActivityThread", "currentActivityThread",
new Class[] {}, new Object[] {});
String packageName = this.getPackageName();
ArrayMap mPackages =(ArrayMap) RefInvoke.getFieldOjbect(
"android.app.ActivityThread", currentActivityThread,
"mPackages");
WeakReference wr = (WeakReference) mPackages.get(packageName);
/*DexClassLoader dLoader = new DexClassLoader(dex_in.getAbsolutePath(), optimizedDexOutputPath.getAbsolutePath(),
libPath, (ClassLoader) RefInvoke.getFieldOjbect(
"android.app.LoadedApk", wr.get(), "mClassLoader")); */
RefInvoke.setFieldOjbect("android.app.LoadedApk", "mClassLoader", wr.get(), loader);
android上做免杀的作用是什么?
页:
[1]