基于ASM修复Jar包的Bug(修改class文件)

前言

同事发现了一个crash是来源于公司内某个闭源jar的,而负责此Jar开发的同事已经离职,难以找人修复,于是就想找我帮忙弄下。
想修改class文件,方式很多,如Javassist、ASM等

照片相似识别技术研究

前言

15年7月时,那时刚去完团建,想到一个很有用的需求:照片按人脸自动分类。不过之前没怎么研究过图像处理方面的知识,就想着先从简单的照片处理相关的功能入手。之后在研究市面上是否已经有相应的产品时,发现手管、360、猎豹等都已经有做相似照片清理的功能,于是人为地通过大量数据进行测试对比。结果发现它们的运行速度都很不错,但要么误判率较高,要么覆盖率过低,这估计是速度与结果之间以速度优先。那时就想,这结果看起来不错,但图片一多,需要人工参与得就越多,那能不能尽量更自动化一些,同时速度上也不至于难以接受呢?

目前市面上的实现主要是基于phash算法的(感知哈希算法),phash算法的特点是速度快,准确性较高。除此以外,常见的hash算法还有ahash算法,dhash算法,参见:
相似图片搜索的三种哈希算法

不过ahash算法与dhash算法虽然速度较phash算法要快些,但测试发现效果并不理想。之后从一位以前曾在百度工作过的大牛了解到,百度的图片相似搜索是基于phash进行改进的,这也显现出phash算法在照片相似识别上的独特优势。

查看全文

Android通过代码伪造短信

声明:本文只作技术探讨,禁止用于非法用途。

前言

伪造短信浅谈一文中,简单地分析了伪造短信的各种方案。今天,就谈一谈如何在Android中通过代码伪造短信。

前面说过,这个方案有个比较大的限制——需要非常高的系统权限,如root、system。如果手机已经root,那当然非常好办,找个合理的理由告诉用户需要root权限即可。但对于大部分小白用户来说,他们的手机一般没进行root。为了拿到高的系统权限,并且兼容性高,覆盖范围广,我们可以选择利用一些通用的漏洞。

最早在2012年时,就已经爆出Android4.0原生短信app的漏洞:对Android最新fakesms漏洞的分析。这漏洞影响的平台在1.64.1,但直至2015年9月,根据Google最新的版本分布统计,4.15.1才是现今的主流。也就是说,我们还需要找各种漏洞进行各版本的适配,才能兼容大部分设备,这也是伪造短信木马的难点之一。

查看全文

伪造短信浅谈

这大半年来,手机总是时不时会收到10086发过来的“积分兑换”短信,真是烦不胜烦。出于好奇心,前段时间我曾研究过关于伪造短信的手段,今天本文就来谈一谈就我所知的一些伪造短信的方案。

短信其实也是一份数据,想要伪造短信,就需要从数据进行切入。我们先想一下,对于用户来说,一条短信的到来一般是怎么样的——短信app提醒你有一条新的信息!而至于怎么提醒,这是短信app应该关心的,而不是我们关心的。

那么,如果我们要伪造短信,就意味着要让短信app去提醒用户,不然用户不知道的话,就没意义了。这里可切入的点就很多了:

查看全文

5、总结

回顾

本系列文章到这里就已经到尾声了,在第二章时,我给大家介绍了很多相关的知识,这些知识是学习本系列文章的基础。接着在第三章中,我介绍了目前流行的相似度识别方案,并针对网上没开源的方案进行简单模拟实现。之后在第四章中,我介绍了一些代码混淆的方案,这些方案只是给大家个引子,希望大家能够举一反三,想出更多更好的方案。

分析

现在我们已经能够把代码混淆得面目全非了,但是怎么才能知道它的混淆效果了呢?一般做法有两种,一是人工分析,二是通过工具自动化分析。

人工分析很难有个衡量标准,所以这里我打算使用工具自动化分析。在第三章中,我介绍了一些相似度分析工具,这里我就用那三个相似度分析工具进行分析,并比较。

接下来使用的混淆工具,都进行了随机混淆处理,也就是说两次分别处理的应用,混淆效果是不一样的,而后面的分析结果,除重打包是基于处理前后的应用外,其它都是基于两次分别处理的应用。

下面是开源中国的测试结果:

查看全文

4.5、重构为本地方法

前言

JNI(Java Native Interface)意为Java本地接口,我们可以通过JNI来实现Java与C/C++之间互调。

前面我们介绍了重构方法的方案,不过重构后的方法仍然是Java方法,因此分析起来相对也比较容易。

这一章我将介绍的是重构到本地方法中,即需要把字节码转换为本地代码。

方案选择

实现方案 优势 劣势
方案一 把字节码直接转换为相应的汇编代码 字节码是基于栈的,而汇编中直接支持栈的操作,因此实现比较容易且运行效率非常高。 汇编代码不跨平台,因而需要针对每个平台来编写对应的汇编代码。
方案二 把字节码转换为相应的C/C++代码 跨平台,实现起来比较简单。 运行效率相对较低。

如果是为了做优化,建议选择方案一,但如果只是为了混淆,那么方案二是个好选择,毕竟编程起来更容易,也更好维护。这里选择的是方案二。

另外,这里选择使用C,因为C编译出来的体积更少。

查看全文

4.4、合并方法

前言

合并方法指的是把多个方法合并成一个方法,从而达到减少方法数量,增加分析难度的目的。

前面提到过,Android中Dex有65536个方法数量的限制,因而进行方法合并有利于缓解此限制。另外上一章提到的重构方法方案会大量的增加方法,如果把增加的方法进行合并,那么可缓解增加方法的数量。

一些问题

合并方法时,需要修改合并后的方法签名,而有些方法是对外提供的接口,是不能合并的。如Android中的Activity等四大组件中继承的一些特定方法,插件化框架中对外提供的接口等等。

被合并方法选择

1、只要被Proguard混淆过的方法,大部分都可以进行合并,而未混淆的代码,则由于可能有各种各样的潜规则(如JNI或其它地方反射调用该方法、作为插件化框架所提供的接口等),而需要通过配置Keep住。

2、没继承关系的方法,皆可进行处理。

3、有继承关系的方法,虽有部分能处理,但经测试量较少,且处理成本非常大,因而不建议处理。

4、重构产生的方法,均可以进行合并处理

查看全文

4.2、指令替换与花指令

前言

在Java开发的过程中,一般是通过javac工具把Java代码编译成字节码。在编译的过程中,每一种语法都会有一一对应的指令组合起来。只要熟悉这一对应关系,就完全能够通过字节码猜出它对应的Java代码。这时,我们可以通过指令等价替换或者增加无意义的花指令的方式,把正常的写法改成javac不会产生的写法,从而加大破解分析的难度。

指令替换

指令替换意为指令的等价替换,即把一条或多条指令替换为等价的一条或多条指令。

指令替换的方式多种多样,它有可能会增加指令的数量,也有可能会减少指令的数量。有可能会增大或减少方法代码的字节数,有可能会加快或减低代码的执行速度。

下面我讲解几种指令替换方案:

查看全文

4.3、重构方法

前言

在各种IDE中,都会有重构代码到一个新方法的选项(以下简称为重构方法),如下面是eclipse的重构功能:

重构方法可重复利用代码,优化软件设计,提高代码的可读性,使得功能扩展更容易等等。当然,过度地重构会使得代码变得难以阅读,难以定位出错的原因。

可重构分析

在进行重构之前,我们需要先分析方法中哪些代码是可以重构。可重构的代码有几个特点:

1)不应该包含返回指令(因为此时还未知该代码重构后的返回值是什么)。

2)重构代码外的跳转指令不能跳转到重构代码中,重构代码中的跳转指令只能跳转到重构代码中。

3)代码前后堆栈平衡。

4)最多只能有一个返回值,但可有多个参数。

查看全文

4.1、反射调用与字符串加密

前言

说起混淆,不得不提的是开源工具proguard了。proguard最大的优势在于它会优化你的代码,并删掉无用的类、方法、属性及代码。其次,proguard还会更改你的类名、方法名、属性名,使得反编译后变得难以看懂。但对于有经验的反编译人员或者一些静态分析工具,就变得无能为力了。

而另一款收费软件dexguard则提供了更为强大的功能,dexguard是proguard的作者针对android推出的加强版,其包含了proguard的全部功能,而且还提供了加密的功能,如常量字符串加密、入口类加密、本地库加密、资源文件加密等。此外,它还提供了隐藏敏感API的功能,这功能的实现就是通过反射调用并加密字符串来实现的。它还针对Android做了很多优化,如整合了编译流程,编译起来比proguard更快、自动去掉android的Log日志、自动分Dex等。

反射调用属性

Java的反射调用包括很多方面,如类、属性、方法、注解等,这里我介绍的是针对属性调用与方法调用的反射,下面先介绍反调调用属性。

在bytecode中,获取属性的值使用getstatic和getfield这两条指令,而设置属性的值对应为putstatic和putfield。

查看全文