java异或加解密及其改善
2016-07-20 18:05
429 查看
最近在做Android的逆向分析,我主要是负责网络请求的逆向分析,在分析的过程中必然会碰到数据加解密的过程。其中最常见的加解密就是异或。
异或加密是数据加密中比较简单的一种,也是比较常用的一种方法。
所谓异或就是一种位运算,比如1^1=0;1^0=1,也就是两个运算位为同为“1”或“0”则返回“0”,若两个运算位不同为“1”或“0”则返回“1”。
算了,说多无用,直接代码:
运行结果:
这里的key长度可以自己设置,内容也是自己设定,这里只是简单地定为“TheKey”。
然而,像这种异或加密只能是防君子,不可防小人,为什么呢?我们知道0和任何key异或都等于key本身,我们可以把一个足够长的byte[]的元素都置0作为参数,再去调用xorEnCode函数,返回的是key的信息。。。
我们现在增加几行代码:
public class Xor {
public static void main(String[] args) {
// TODO Auto-generated method stub
String data="hello world";
System.out.println("------------原文--------------");
System.out.println(data);
String after=new String(xorEncode(data.getBytes()));
System.out.println("------------加密--------------");
System.out.println(after);
String before=new String(xorEncode(after.getBytes()));
System.out.println("------------解密---------------");
System.out.println(before);
String key=new String(xorEncode(new byte[50]));
System.out.println("------------秘钥---------------");
System.out.println(key);
}
public static byte[] xorEncode(byte[] data){
//key,用于异或
String key="TheKey";
byte[] keyBytes=key.getBytes();
byte[] encryptBytes=new byte[data.length];
for(int i=0; i<data.length; i++){
encryptBytes[i]=(byte) (data[i]^keyBytes[i%keyBytes.length]);
}
return encryptBytes;
}
}
运行结果:
可以看到,从重复的字符串可以看到,秘钥就是TheKey。
下面再看看两张图,这两张图是我分析某地图时所遇到的情况,它在给数据加密的地方是用C写的,也就是本地调用,通过一般的反编译软件是看不到其源代码的,这也是为什么一些敏感的代码用C来写,用jni来调用的原因。但是,我们可以通过hook技术,修改参数,传进都为0的byte[],从而验证是否是个异或算法,很幸运,恰恰是~这得看脸。
图一,本地方法:
图二,hook后日志暴露出key:
我们可以从循环的一组byte[]获取到其key。
那么既然存在那么傻瓜的方法就能破解了,那异或算法也没什么价值了呀~不过,我们可以通过一些技巧使这些傻瓜式的方法破解不了,也就是稍微增强一些,不被那么容易就被破解了。
要怎么做呢?从一些其他的APP逆向分析过程中,我学习到了一些技巧,下面就讲一个吧,是在和数据异或前对key进行处理的。
废话不多说,直接修改函数xorEncode,贴出来,仔细看一下key的处理:
public class Xor {
public static void main(String[] args) {
// TODO Auto-generated method stub
String data="hello world";
System.out.println("------------原文--------------");
System.out.println(data);
String after=new String(xorEncode(data.getBytes()));
System.out.println("------------加密--------------");
System.out.println(after);
String before=new String(xorEncode(after.getBytes()));
System.out.println("------------解密---------------");
System.out.println(before);
String key=new String(xorEncode(new byte[50]));
System.out.println("------------秘钥---------------");
System.out.println(key);
}
public static byte[] xorEncode(byte[] data){
String key="abc";
//将任意长的key转变成长度为256的新key
byte[] keyBytes=new byte[256];
for(int i=0; i<key.getBytes().length; i++){
keyBytes[i]=key.getBytes()[i%key.getBytes().length];
}
//该byte[]为输出密文
byte[] encodeBytes=new byte[data.length];
//在每一轮循环中对key下功夫,比如置换
int j=0;
int k=0;
for(int i=0; i<encodeBytes.length; i++){
k=0xff & k+1;
j=0xff & j+keyBytes[k];
int m=keyBytes[k];
keyBytes[k]=keyBytes[j];
keyBytes[j]=(byte) m;
int n=0xff & keyBytes[j]+keyBytes[k];
encodeBytes[i]=(byte) (data[i]^keyBytes
);
}
return encodeBytes;
}
}
运行结果:
我们可以看到,即使传0进去,也暴露不出key。
异或加密是数据加密中比较简单的一种,也是比较常用的一种方法。
所谓异或就是一种位运算,比如1^1=0;1^0=1,也就是两个运算位为同为“1”或“0”则返回“0”,若两个运算位不同为“1”或“0”则返回“1”。
算了,说多无用,直接代码:
public class Xor { public static void main(String[] args) { // TODO Auto-generated method stub String data="hello world"; System.out.println("------------原文--------------"); System.out.println(data); String after=new String(xorEncode(data.getBytes())); System.out.println("------------加密--------------"); System.out.println(after); String before=new String(xorEncode(after.getBytes())); System.out.println("------------解密---------------"); System.out.println(before); } public static byte[] xorEncode(byte[] data){ //key,用于异或 String key="TheKey"; byte[] keyBytes=key.getBytes(); byte[] encryptBytes=new byte[data.length]; for(int i=0; i<data.length; i++){ encryptBytes[i]=(byte) (data[i]^keyBytes[i%keyBytes.length]); } return encryptBytes; } }
运行结果:
这里的key长度可以自己设置,内容也是自己设定,这里只是简单地定为“TheKey”。
然而,像这种异或加密只能是防君子,不可防小人,为什么呢?我们知道0和任何key异或都等于key本身,我们可以把一个足够长的byte[]的元素都置0作为参数,再去调用xorEnCode函数,返回的是key的信息。。。
我们现在增加几行代码:
public class Xor {
public static void main(String[] args) {
// TODO Auto-generated method stub
String data="hello world";
System.out.println("------------原文--------------");
System.out.println(data);
String after=new String(xorEncode(data.getBytes()));
System.out.println("------------加密--------------");
System.out.println(after);
String before=new String(xorEncode(after.getBytes()));
System.out.println("------------解密---------------");
System.out.println(before);
String key=new String(xorEncode(new byte[50]));
System.out.println("------------秘钥---------------");
System.out.println(key);
}
public static byte[] xorEncode(byte[] data){
//key,用于异或
String key="TheKey";
byte[] keyBytes=key.getBytes();
byte[] encryptBytes=new byte[data.length];
for(int i=0; i<data.length; i++){
encryptBytes[i]=(byte) (data[i]^keyBytes[i%keyBytes.length]);
}
return encryptBytes;
}
}
运行结果:
可以看到,从重复的字符串可以看到,秘钥就是TheKey。
下面再看看两张图,这两张图是我分析某地图时所遇到的情况,它在给数据加密的地方是用C写的,也就是本地调用,通过一般的反编译软件是看不到其源代码的,这也是为什么一些敏感的代码用C来写,用jni来调用的原因。但是,我们可以通过hook技术,修改参数,传进都为0的byte[],从而验证是否是个异或算法,很幸运,恰恰是~这得看脸。
图一,本地方法:
图二,hook后日志暴露出key:
我们可以从循环的一组byte[]获取到其key。
那么既然存在那么傻瓜的方法就能破解了,那异或算法也没什么价值了呀~不过,我们可以通过一些技巧使这些傻瓜式的方法破解不了,也就是稍微增强一些,不被那么容易就被破解了。
要怎么做呢?从一些其他的APP逆向分析过程中,我学习到了一些技巧,下面就讲一个吧,是在和数据异或前对key进行处理的。
废话不多说,直接修改函数xorEncode,贴出来,仔细看一下key的处理:
public class Xor {
public static void main(String[] args) {
// TODO Auto-generated method stub
String data="hello world";
System.out.println("------------原文--------------");
System.out.println(data);
String after=new String(xorEncode(data.getBytes()));
System.out.println("------------加密--------------");
System.out.println(after);
String before=new String(xorEncode(after.getBytes()));
System.out.println("------------解密---------------");
System.out.println(before);
String key=new String(xorEncode(new byte[50]));
System.out.println("------------秘钥---------------");
System.out.println(key);
}
public static byte[] xorEncode(byte[] data){
String key="abc";
//将任意长的key转变成长度为256的新key
byte[] keyBytes=new byte[256];
for(int i=0; i<key.getBytes().length; i++){
keyBytes[i]=key.getBytes()[i%key.getBytes().length];
}
//该byte[]为输出密文
byte[] encodeBytes=new byte[data.length];
//在每一轮循环中对key下功夫,比如置换
int j=0;
int k=0;
for(int i=0; i<encodeBytes.length; i++){
k=0xff & k+1;
j=0xff & j+keyBytes[k];
int m=keyBytes[k];
keyBytes[k]=keyBytes[j];
keyBytes[j]=(byte) m;
int n=0xff & keyBytes[j]+keyBytes[k];
encodeBytes[i]=(byte) (data[i]^keyBytes
);
}
return encodeBytes;
}
}
运行结果:
我们可以看到,即使传0进去,也暴露不出key。
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树