dx.jar部分类的用法——以检测https劫持漏洞为例
2014-10-19 15:12
302 查看
本文原载,欢迎转载,转载请注明出处(好像大家都喜欢这么写)。
在ADT的build-tools的目录下,有一个叫做dx.jar的包,这个包可以解析dex文件(目前用到的就是这么多),但是在网上一搜都没看到什么相关接口的资料,只能自己慢慢看(老大给了我很多帮助),算是稍微会了一些相应的接口调用,总结总结,也给需要的朋友一些帮助。
1.为什么要用dx.jar
因为它能解析dex文件,所以用它来获取dalvik指令,而这样就可以对整个dex文件进行扫描,发现一些应用程序的漏洞神马的。由于自己也是初学者,所以就挑了一个简单的https劫持漏洞,漏洞原理可以看下面几篇文章:
http://security.tencent.com/index.php/blog/msg/41
http://www.programmer.com.cn/15036/
简单来说就是使用自己的类覆盖了google官方默认证书检查的类,以免自己的证书会报异常,而在检测服务器是否可信的函数中却没有进行安全处理,比如某银行网银安卓客户端:
还有一种情况就是直接信任来自所有服务器的证书,来自同一个客户端:
2.制定检测方案
了解了漏洞的形成原理,就可以有针对性的进行检测。思路如下:
(1).由dx.jar包中的函数获得dex文件中的所有类
(2).由于有两种原因导致的漏洞,所以分两部分检测,首先检测是否信任所有服务器的证书,也就是有没有setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER)这行代码。这个只要检测每个函数中的代码是不是有SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER字符串就可以了。
(3).第二部分则是通过检测checkServerTrusted函数是不是有throw这条语句,因为无论如何,只要验证服务器端不可信,便会抛出,只要没有throw抛出异常的代码,那便可以判断肯定存在问题。
3.调用dx.jar解析dex
3.1获得dex对象
首先是利用dex类解析dex文件,而dex又有多个构造函数,如下所示:
我这里是先用zipfile进行解压获得class.dex的File对象,然后作为参数传入,其实直接传入apk文件的路径也是可以的,因为它会帮你进行解压缩,代码如下:
3.2获取dex基本信息
由于检测方案基于静态扫描,所以解析了dex文件之后就要获得文件中所有类的定义、所有类型名称以及所有的字符串信息,代码如下:
3.3调用检测漏洞的函数
获得X509TrustManager和SSLSocketFactory类的类名,然后判断是否有这两个类的子类,如果是就将这个类传入相应的处理函数进行进一步的处理,返回值则是有漏洞的类路径:
3.3验证是否信任所有服务器——sslHostnameVerifier函数
首先是获取类的所有函数,同时还有ALLOW_ALL_HOSTNAME_VERIFIER字符串的索引用于后面进行比对:
然后从每个函数中获取全部代码并由decodeAll解码成一个指令数组,这个数组的每一项就是一句smali代码,分别对应这不同的指令格式:
这样就找到了有漏洞的函数了。
3.4验证checkServerTrusted是否有thow语句
主要流程是差不多的,有所不同的是这里添加了对于函数是否为checkServerTrusted的判断:
如果是,则获得函数中所有代码并检查是否有throw语句,而这条语句的指令可以在这里找到,可以看到其指令数值为39:
最后就是判断部分了:
4.总结与不足
这次接触到的dx.jar里面的函数还只是一小部分,以后用到了会再多总结总结。上面提到的检测http的例子,其实还是有一些特殊情况检测不到的,比如不一定只有继承了X509TrustManager才能覆盖里面的checkServerTrusted函数,在实例化的时候可以通过将checkServerTrusted函数作为参数传递进去,还有一种情况就是并没有直接使用ALLOW_ALL_HOSTNAME_VERIFIER,而是传入一个继承自HostnameVerifier的类,而这个类里面的verify函数并没有验证,而是直接返回空:
可能也还有更多的情况没有考虑进去,因为刚接触这方面,所以大家看了有什么宝贵意见还望批评指正。
在ADT的build-tools的目录下,有一个叫做dx.jar的包,这个包可以解析dex文件(目前用到的就是这么多),但是在网上一搜都没看到什么相关接口的资料,只能自己慢慢看(老大给了我很多帮助),算是稍微会了一些相应的接口调用,总结总结,也给需要的朋友一些帮助。
1.为什么要用dx.jar
因为它能解析dex文件,所以用它来获取dalvik指令,而这样就可以对整个dex文件进行扫描,发现一些应用程序的漏洞神马的。由于自己也是初学者,所以就挑了一个简单的https劫持漏洞,漏洞原理可以看下面几篇文章:
http://security.tencent.com/index.php/blog/msg/41
http://www.programmer.com.cn/15036/
简单来说就是使用自己的类覆盖了google官方默认证书检查的类,以免自己的证书会报异常,而在检测服务器是否可信的函数中却没有进行安全处理,比如某银行网银安卓客户端:
还有一种情况就是直接信任来自所有服务器的证书,来自同一个客户端:
2.制定检测方案
了解了漏洞的形成原理,就可以有针对性的进行检测。思路如下:
(1).由dx.jar包中的函数获得dex文件中的所有类
(2).由于有两种原因导致的漏洞,所以分两部分检测,首先检测是否信任所有服务器的证书,也就是有没有setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER)这行代码。这个只要检测每个函数中的代码是不是有SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER字符串就可以了。
(3).第二部分则是通过检测checkServerTrusted函数是不是有throw这条语句,因为无论如何,只要验证服务器端不可信,便会抛出,只要没有throw抛出异常的代码,那便可以判断肯定存在问题。
3.调用dx.jar解析dex
3.1获得dex对象
首先是利用dex类解析dex文件,而dex又有多个构造函数,如下所示:
我这里是先用zipfile进行解压获得class.dex的File对象,然后作为参数传入,其实直接传入apk文件的路径也是可以的,因为它会帮你进行解压缩,代码如下:
/* */ public Dex(File file) /* */ throws IOException /* */ { /* 103 */ if (FileUtils.hasArchiveSuffix(file.getName())) { /* 104 */ ZipFile zipFile = new ZipFile(file); /* 105 */ ZipEntry entry = zipFile.getEntry("classes.dex"); /* 106 */ if (entry != null) { /* 107 */ loadFrom(zipFile.getInputStream(entry)); /* 108 */ zipFile.close(); /* */ } else { /* 110 */ throw new DexException("Expected classes.dex in " + file); /* */ } /* 112 */ } else if (file.getName().endsWith( ".dex")) { /* 113 */ loadFrom(new FileInputStream(file)); /* */ } else { /* 115 */ throw new DexException( "unknown output extension: " + file); /* */ } /* */ } |
由于检测方案基于静态扫描,所以解析了dex文件之后就要获得文件中所有类的定义、所有类型名称以及所有的字符串信息,代码如下:
Dex dex = new Dex(zipFile.getInputStream(entry)); zipFile.close(); //获取所有类 Iterable<ClassDef> all_class = dex.classDefs(); //获取dex文件中所有类型名 List<String> type_names = dex.typeNames(); //获取dex文件中所有字符串 List<String> dex_strings = dex.strings(); |
获得X509TrustManager和SSLSocketFactory类的类名,然后判断是否有这两个类的子类,如果是就将这个类传入相应的处理函数进行进一步的处理,返回值则是有漏洞的类路径:
//获取X509TrustManager和SSLSocketFactory类所在的索引,以便后面进行对比 int x509_idx = type_names.indexOf("Ljavax/net/ssl/X509TrustManager;" ); int sslsocket_idx = type_names.indexOf("Lorg/apache/http/conn/ssl/SSLSocketFactory;" ); for(ClassDef one_class : all_class) { int super_type_idx = one_class.getSupertypeIndex(); //对所有的类进行检查 if(super_type_idx == sslsocket_idx) vulnerable_method.addAll( sslHostnameVerifier(one_class, dex, type_names, dex_strings)); if(super_type_idx == x509_idx) vulnerable_method.addAll( x509TrustVerifier(one_class, dex, type_names, dex_strings)); } |
首先是获取类的所有函数,同时还有ALLOW_ALL_HOSTNAME_VERIFIER字符串的索引用于后面进行比对:
HashSet<String> vulnerable_method = new HashSet<String>(); //获取类数据 ClassData data = dex.readClassData(one_class); //获取所有方法 Method[] all_method = data.allMethods(); int verifier_idx = dex_strings.indexOf( "ALLOW_ALL_HOSTNAME_VERIFIER" ); |
for(Method method : all_method) { //获取方法的所有代码并转化成instructions Code code = dex.readCode(method); DecodedInstruction[] instructions = DecodedInstruction.decodeAll(code.getInstructions()); for(DecodedInstruction instruction : instructions) { if(instruction == null) continue; //获取指令在dex文件中的索引 int field_idx = instruction.getIndex(); try { //根据field_idx获得nameIndex并和之前的verifier_idx进行比较 int field_string_idx = dex.nameIndexFromFieldIndex(field_idx); if(field_string_idx == verifier_idx) { int method_string_idx = dex.nameIndexFromMethodIndex(method.getMethodIndex()); //将出现漏洞的类添加到返回值中 vulnerable_method.add( type_names.get(one_class .getTypeIndex()) + "->" + dex_strings.get(method_string_idx)); } } catch(Exception e) { continue; } } } |
3.4验证checkServerTrusted是否有thow语句
主要流程是差不多的,有所不同的是这里添加了对于函数是否为checkServerTrusted的判断:
int method_string_idx = dex.nameIndexFromMethodIndex( method.getMethodIndex()); String method_name = dex_strings.get(method_string_idx); //判断函数是否是checkServerTrusted if(method_name.indexOf("checkServerTrusted" ) == -1) continue; |
最后就是判断部分了:
for(DecodedInstruction instruction : instructions) { if(instruction == null) continue; if(instruction.getOpcode() == 39) { is_throw = true; break; } } //如果checkServerTrusted函数中没有throw代码,则肯定存在漏洞 if(!is_throw) vulnerable_method.add(type_names.get(one_class.getTypeIndex()) + "->" + method_name); |
这次接触到的dx.jar里面的函数还只是一小部分,以后用到了会再多总结总结。上面提到的检测http的例子,其实还是有一些特殊情况检测不到的,比如不一定只有继承了X509TrustManager才能覆盖里面的checkServerTrusted函数,在实例化的时候可以通过将checkServerTrusted函数作为参数传递进去,还有一种情况就是并没有直接使用ALLOW_ALL_HOSTNAME_VERIFIER,而是传入一个继承自HostnameVerifier的类,而这个类里面的verify函数并没有验证,而是直接返回空:
可能也还有更多的情况没有考虑进去,因为刚接触这方面,所以大家看了有什么宝贵意见还望批评指正。
相关文章推荐
- Android静态安全检测 -> HTTPS敏感数据劫持漏洞
- Android HTTPS中间人劫持漏洞浅析
- Android平台https嗅探劫持漏洞
- 窃听风暴:Android平台https嗅探劫持漏洞
- Android HTTPS中间人劫持漏洞浅析
- Android HTTPS中间人劫持漏洞浅析
- linux和unix下SAR命令的用法,对机器性能检测很有帮助
- [转载]SDL 用法,第 2 部分:"Pirates Ho!" 编码
- 映象劫持使部分程序不可运行的解决方法
- 百度空间存在js破坏漏洞,部分用户被威胁删除数据
- TamperIE - 一个小巧的XSS漏洞检测辅助工具
- 《JAVA性能瓶颈和漏洞检测7.0》(JProbe Suite 7.0)
- 如何使用Nikto漏洞扫描工具检测网站安全 推荐
- VI的用法和部分指令
- php代码不开源下的一种漏洞检测思路
- Extjs的Tree的部分用法
- JAR的基本用法
- Hough检测直线,圆,椭圆的部分代码
- 使用 Rational Application Developer 构建 HTTPS Web 服务,第 1 部分:Web 服务与 Web 服务客户机
- WebSphere 配置 Web 服务安全性,第 1 部分: HTTPS、.NET