【双码锁机】对"卡Iphone7 plus永久在线"的逆向分析+加密源码
本帖最后由 1595901624 于 2016-11-7 19:47 编辑昨天,一位坛友,给我发消息,说有款锁机,让我看看,我看了一下,现在把分析过程与大家分享一下
I首先认识一下这款软件
知彼知己,才能百战百胜,现在我们看看软件长啥样,如图(左为图标,右为锁屏界面):
随便输入密码,显示“输入不正确”
static/image/hrline/1.gif
II反编译
这反编译工具,我在这里有必要说明一下,许多坛友好像使用的是Android改之理或者AndroidKiller,但是我建议大家使用JEB,关于好处,
大家可以自己对比一下,我在这儿就不多说了。
我们看目录得知,锁屏界面对应的是MainActivity,定位到关键位置(因为这里有密码不正确)
从图中,可以看到,v3是获取编辑框的值,然后判断,v3和jb * 6如果不相等,就会显示密码错误,那么我们的密码就是jb*6;那么这jb是什么呢,我们网上找(如图)
发现是个随机数,那么,他就是锁屏界面的随机码,得知 随机码 * 6就是密码,输入看看,对不对(我这里是39442 * 6 = 236652)
http://www.52pojie.cn/static/image/hrline/1.gif
重点来了->锁机确实解开了,但是锁机软件还设置了pin码(如图),这锁机是双码锁机
我们再看目录,还有一个pin(也可以看一下manifest,入口Activiy是pin),那么这个就是pin码的锁机了
这个szmm()就是关键函数,划圈的就是设置密码的语句,所以我们现在就是吧pass这个变量作为重中之重,pass有个初始值6088,输入试试,
提示不对,但是,现在有些人可能输入6088会成功解锁,原因我后面再说【疑问一】
我们看看这个szmm()是从哪调用来的,找到OnCreate()函数,这个函数相当于我们学各种语言的main()函数,当程序进入Activity时,会执行它
看这个OnCreate()函数:
红圈就是调用的地方,看上面
看蓝圈,特殊字符,乍一看是base64加密的,网页上找工具,解出是乱码,暂时先不管;
看青色的圈,decoder解密俩字符,一个赋值到pinm,一个赋值到url;
(这个解密函数在enorde类里面,这个类我稍后分析,暂时跳过)【疑问二】
看绿圈,启动了一个线程,我们定位到这里,看看
线程里,又有个get(url),又把url传到get函数里面,再看get()函数
发现是联网获取数据,现在的锁机真实可怕啊,获取的什么数据(但是我们需要知道url)
【疑问一解答】这里是获取了网络上的锁机密码,但是如果当前APP没有联网,则会直接设置密码为6088,
这也就是为什么,有些人刚才输入6088,会解锁的原因
接着分析,这里调用了正则表达式,获取了网络上的密码,最后赋值给pass
因此,我们的重中之重是加解密函数
【疑问二解答】
加解密类是enorde,我就不上图了,作者采用的是Zlib+Base64回合加密,但是又在原来的基础上修改了,
加入了加密密钥,这款软件的加密密钥是“password”(加解密都需要用到它)
我试着还原了作者这个加解密函数,文章最后奉上源码的下载链接
解码之后的url是 http://www.wencaojun.top/in.html,网站截图如下
因为网页是gbk编码,要用utf8编码,否则会显示乱码,经过zhengze()函数之后,留下的就只有7593
因此7593就是当手机在网络良好状况下的锁机pin码
static/image/hrline/1.gif
III总结
软件双码加密,普通锁机密码是 随机码*6 ;在断网和网络不好的情况下,pin码是6088;
在网络良好的状况下,pin码【暂时是】7593——(作者可以更改网页内容,来修改锁机密码)
源码里面有加解密例子,在这里就不写例子了
IV 源码
最后公开【锁机中的Zlib + Base64】加解密源码
import java.io.ByteArrayOutputStream;
import java.util.zip.Deflater;
import java.util.zip.Inflater;
/**
* 被修改的Zlib + Base64加解密算法
*
* @author lhy 2016-11-03
* @version 1.1.0.5
*
*/
public class Enorde {
private static char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".toCharArray();
private String key = ""; // 自定义加密的密钥
/**
* 初始化base64字符集表
*/
private static byte[] codes = new byte;
static {
for (int i = 0; i < 256; i++)
codes = -1;
for (int i = 'A'; i <= 'Z'; i++)
codes = (byte) (i - 'A');
for (int i = 'a'; i <= 'z'; i++)
codes = (byte) (26 + i - 'a');
for (int i = '0'; i <= '9'; i++)
codes = (byte) (52 + i - '0');
codes['+'] = 62;
codes['/'] = 63;
}
public Enorde(String key) {
this.key = key;
}
/**
* 被修改的 Zlib 压缩算法
*
* @author lhy
* @param str
* : 需要压缩的String数组
* @Return 压缩之后的String数组
* @throws Exception
* : 数据为空,则报出“数据错误”异常
*/
public String encoder(String str) throws Exception {
return new String(encoder(str.getBytes()));
}
/**
* 被修改的 Zlib 解压缩算法
*
* @author lhy
* @param str
* : 需要解压缩的String数组
* @return 解压缩之后的String数组
* @throws Exception
* : 数据为空,则报出“数据错误”异常
*/
public String decoder(String str) throws Exception {
return new String(decoder(str.getBytes()));
}
/**
* @author lhy
* @param str
* : 需要编码成Base64的String数组
* @return : 编码后的String数组
*/
public String encodeToBase64(String str) {
return new String(encodeToBase64(str.getBytes()));
}
/**
* @author lhy
* @param str
* : 需要解码Base64的String数组
* @return : 解码后的String数组
*/
public String decodeFromBase64(String str) {
return new String(decodeFromBase64(str.getBytes()));
}
/**
* @author lhy
* @param byteArray
* : 需要编码成Base64的Byte数组
* @return : 编码后的Byte数组
*/
public byte[] encodeToBase64(byte[] byteArray) {
byte[] b = new byte[(byteArray.length + 2) / 3 * 4];
for (int i = 0, index = 0; i < byteArray.length; i += 3, index += 4) {
boolean quad = false;
boolean trip = false;
int val = (0xFF & (int) byteArray);
val <<= 8;
if ((i + 1) < byteArray.length) {
val |= (0xFF & (int) byteArray);
trip = true;
}
val <<= 8;
if ((i + 2) < byteArray.length) {
val |= (0xFF & (int) byteArray);
quad = true;
}
b = (byte) alphabet[(quad ? (val & 0x3F) : 64)];
val >>= 6;
b = (byte) alphabet[(trip ? (val & 0x3F) : 64)];
val >>= 6;
b = (byte) alphabet;
val >>= 6;
b = (byte) alphabet;
}
return b;
}
/**
* Base64解码
*
* @author lhy
*
* @param byteArray
* : 需要解码的Base64的Byte数组
* @return : 解码后的Byte数组
*/
public byte[] decodeFromBase64(byte[] byteArray) {
int length = (byteArray.length + 3) / 4 * 3;
if (byteArray.length > 0 && byteArray == '=') {
--length;
}
if (byteArray.length > 1 && byteArray == '=') {
--length;
}
byte[] b = new byte;
int shift = 0;
int accum = 0;
int index = 0;
for (int ix = 0; ix < byteArray.length; ix++) {
int value = codes & 0xFF];
if (value >= 0) {
accum <<= 6;
shift += 6;
accum |= value;
if (shift >= 8) {
shift -= 8;
b = (byte) ((accum >> shift) & 0xff);
}
}
}
try {
if (index == b.length) {
return b;
}
} catch (Exception e) {
System.err.println("miscalculated data length!");
}
return b;
}
/**
* 被修改的 Zlib 解压缩算法
*
* @author lhy
* @param byteArray
* : 需要解压缩的byte数组
* @return 解压缩之后的数组
* @throws Exception
* : 数据为空,则报出“数据错误”异常
*/
public byte[] decoder(byte[] byteArray) throws Exception {
Enorde e = new Enorde(key);
if (byteArray == null) {
throw new Exception("Data error!");
}
byteArray = e.decodeFromBase64(byteArray);
if (!key.equals("")) {
for (int i = 0; i < byteArray.length; ++i) {
byte[] keyByte = key.getBytes();
byteArray = ((byte) (((char) (byteArray ^ keyByte))));
}
}
Inflater in = new Inflater();
in.reset();
in.setInput(byteArray);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] b = new byte;
while (!in.finished()) {
bos.write(b, 0, in.inflate(b));
}
return bos.toByteArray();
}
/**
* 被修改的 Zlib 压缩算法
*
* @author lhy
* @param byteArray
* : 需要压缩的byte数组
* @return 压缩之后的数组
* @throws Exception
* : 数据为空,则报出“数据错误”异常
*/
public byte[] encoder(byte[] byteArray) throws Exception {
Enorde e = new Enorde(key);
if (byteArray == null) {
throw new Exception("Data error");
}
Deflater df = new Deflater();
df.reset();
df.setInput(byteArray);
df.finish();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] b = new byte;
while (!df.finished()) {
bos.write(b, 0, df.deflate(b));
}
byte[] bosArray = bos.toByteArray();
if (!key.equals("")) {
for (int i = 0; i < bosArray.length; ++i) {
byte[] keyByte = key.getBytes();
bosArray = ((byte) (((char) (bosArray ^ keyByte))));
}
}
return e.encodeToBase64(bosArray);
}
}
锁机APK+加解密源码
土豪下载通道:解压密码:52pojie
屌丝下载通道:链接:https://eyun.baidu.com/s/3pLo5y8j 密码:6666
http://pan.baidu.com/s/1slfcxsT 大神求破这个锁机软件 作者说很牛逼模拟器都不能开了 我QQ邮箱1343450392@qq.com 求大神破解 Hmily 发表于 2016-11-7 19:16
@1595901624 附件样本压缩包上传时必须使用压缩密码保护,压缩密码:52pojie,防止下载样本的时候被杀软拦截 ...
知道了,H大,现在马上改{:1_918:} 这是什么语言? 我其实可想直接把第一张图里的
v0.tv1.setText("密码不正确"); 改成 v0.finish(); 厉害啊就是!{:1_921:} 505547425 发表于 2016-11-4 16:29
这是什么语言?
Java.{:301_1008:} 楼主好厉害呀 楼主这不是广告吗? 这个锁机app比较厉害貌似 NB大神.... 威武霸气,谢谢楼主