本帖最后由 世事繁华皆成空 于 2015-12-17 16:33 编辑
由于网络原因暂时不上传软件图片
0x0 软件简介
GiS Pro 包括西安80、北京54等坐标系的时时转换显示,
支持3参数的设置,支持显示当前坡度、坡向、海拔、中央经线、带号、一万图幅号、
五万图幅号等信息,支持手持GPS的记录航点航迹和计算面积周长功能,
支持数据交流和shapefile等格式加载功能。
0x1 开刀
0x2 修复apk
常规的app脱壳后都需要手动去删除一些文件,修复下Application入口,这是最简单的,
复杂点的还需要去修复一些方法,那这个App只需要在Manifest文件中
删除梆梆加固的meta元素即可,不需要修复入口,回编译,能够正常运行,证明无签名校验
0x3 分析
自2.x之后,作者就换了一套加密算法,我们来看看
打开软件后,会给我们一个弹窗,让我们输入注册码,这个弹窗无法取消焦点,除非点击退出键,
那如果只是单纯的靠一个无法取消的弹窗来限制非注册用户的话确实比较容易搞定,只需要不让他弹窗就行了
那我们直接搜索弹窗上的关键字,“请输入序列号”,搜索结果
[Java] 纯文本查看 复制代码 <string name="register_account_hint">请输入序列号</string>
搜索到字符串后继续通过name id搜索,发现其位于main_sign_dialog.xml文件下,那就知道此处是一个自定义的dialog view了,
直接搜索这个xml文件名即可,在public.xml文件下得到索引值,通过索引来到smali文件下,来到SignDialog.smali下发现其是一个单独类
继承自DialogFragment,那既然是单独的就有调用的地方,这里先不管他,我们先找找注册算法,有多种方法可以追踪到注册判断,搜索
字符串或者根据按钮的调用,这里既然来到这个类下了,直接就从这里分析
[Java] 纯文本查看 复制代码 ((TextView)v2).setOnClickListener(new eb(this));
((TextView)v0).setOnClickListener(new eb(this));
this.c.setOnLongClickListener(new ea(this));
((Button)v3).setOnClickListener(new eb(this));
((Button)v4).setOnClickListener(new eb(this));
发现这里所有按钮都指向了eb这个类,来到eb下,这里就是判断了
[Java] 纯文本查看 复制代码 case 2131296328: {
if(DecodeHelper.Decrypt(SignDialog.b(this.a).getText().toString().trim(), SignDataHelper
.Cipher("MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAISJXsEkRv6q7r0GAUuES2DRe0ww",
"/L8g46SkGM17kkVDE7PLnY9L2xv+jM0avr35+DMaLADZnxWQc3fslmtRbWXGNUUUCTbotLMGwGu7\n9jSeVLTbhDtDwKlwSrCwmjV4L//LOoI3tFRQMEjPa8JcMhPVvxOG8f3jeym4hfWtUwCNAgMBAAEC\ngYBEuXKf1i7WGU6IR5feT7BCeP1lSbWVafmAwvJ1gpEbRyftQDToPB5Wysy6AhdMLVVNMlIE8tNx\n/CBT3CM3bNa7gtRsOTlypISIuVqeVK5NQ18gYxhB3d9bowSKKh/P9dH9NSF7SqOKHEU+M+PvTs+Q\nOAYpSHmAzUChrwLm/KuVxQJBAMaeMna4iP+Y7RzjzONvoNJlKaMhnPDvyDZuQ9yK8CuBJGud08gg\niPUHyt22LXZJpex/bdglz8n1a/mV2hJMhucCQQCq08orrA7LiCqK5V5vU982tzCf5M6gESYm2n7I\nTt165FWyQsjoEmBRjujU2UHcnOqiL2742a9bFoOpAw+y5rJrAkEAo23sjC/P2rFU+h6fqs1hgX3o\nQukXoFFNZyxX/pL8iG+dLkgRyWysBSNCVCjhQ6HaO72m/uIuFjoxfI9HfyMlJQJAaE4JE8FrBzuN\nPmHu12sO0Anq1raOs43FDdQ7tXLyKSdibAX7RjhyN1pbMBu360ykt4Le73N7btLAcWI9I69ZIQJA\nGNIcYuNMDnotJjsy+1kIBmzt4RZmWSfzQjqBBPI9AEOPYMqyOwFtOywCFpNtYuEAjPpn67LyqmOC",
"D2EzFHeamw==")).indexOf(SignDialog.c(this.a).getText().toString()) != -1) {
if(SignDialog.a(this.a) != null) {
SignDialog.a(this.a).Register(SignDialog.b(this.a).getText().toString().trim());
}
this.a.dismiss();
return;
}
new MessageDialogFragment(2130837687, this.a.getString(2131361948), this.a.getString(
2131361946), DialogType.OkButton).show(this.a.getFragmentManager(), "errBox");
break;
}
case 2131296455: {
this.a.dismiss();
break;
}
case 2131296457: {
if(SignDialog.a(this.a) == null) {
return;
}
SignDialog.a(this.a).Dispose();
break;
}
case 2131296460: {
new MessageDialogFragment("\t\t购买方式", "加QQ群:xxxxxxxxxxxx,联系群主购买,感谢支持!", DialogType.OkButton)
.show(this.a.getFragmentManager(), "buyBox");
break;
如果注册码不对,就会弹窗提示购买,那签名的算法我们也看到了,判断DecodeHelper.Decrypt解密后是否包含SignDialog.c(this.a).getText().toString(),
如果不包含则会返回-1,注册失败,跟踪下Decrypt,
[Java] 纯文本查看 复制代码 public static String Decrypt(String arg1, String arg2) {
String v0_1;
try {
v0_1 = RSAUtils.decryptByPrivateKey(arg1, RSAHelper.getPrivateKey(arg2));
}
catch(Exception v0) {
v0_1 = "";
}
return v0_1;
}
在跟踪RSAUtils.decryptByPrivateKey,
[Java] 纯文本查看 复制代码 public static String decryptByPrivateKey(String arg7, RSAPrivateKey arg8) {
Cipher v2 = Cipher.getInstance("RSA");
v2.init(2, ((Key)arg8));
int v0 = arg8.getModulus().bitLength() / 8;
byte[] v1 = arg7.getBytes();
byte[] v3 = RSAUtils.ASCII_To_BCD(v1, v1.length);
String v1_1 = "";
byte[][] v3_1 = RSAUtils.splitArray(v3, v0);
int v4 = v3_1.length;
for(v0 = 0; v0 < v4; ++v0) {
v1_1 = String.valueOf(v1_1) + new String(v2.doFinal(v3_1[v0]));
}
return v1_1;
}
RSA算法,那这里就是将注册码传进来,通过私钥进行解密,如果解密后包含SignDialog.c(this.a).getText().toString(),则注册成功
大家可以自行分析下SignDialog.c(this.a).getText().toString(),这个其实就是弹窗时提示的硬件码,硬件码由设备号加密生成,
程序中也有判断,如果加密后的数据不是15位则程序会自动退出,再获取不到设备号的情况下,默认返回pksqsGPSpro871006,之前的
[Java] 纯文本查看 复制代码 SignDataHelper
.Cipher("MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAISJXsEkRv6q7r0GAUuES2DRe0ww",
"/L8g46SkGM17kkVDE7PLnY9L2xv+jM0avr35+DMaLADZnxWQc3fslmtRbWXGNUUUCTbotLMGwGu7\n9jSeVLTbhDtDwKlwSrCwmjV4L//LOoI3tFRQMEjPa8JcMhPVvxOG8f3jeym4hfWtUwCNAgMBAAEC\ngYBEuXKf1i7WGU6IR5feT7BCeP1lSbWVafmAwvJ1gpEbRyftQDToPB5Wysy6AhdMLVVNMlIE8tNx\n/CBT3CM3bNa7gtRsOTlypISIuVqeVK5NQ18gYxhB3d9bowSKKh/P9dH9NSF7SqOKHEU+M+PvTs+Q\nOAYpSHmAzUChrwLm/KuVxQJBAMaeMna4iP+Y7RzjzONvoNJlKaMhnPDvyDZuQ9yK8CuBJGud08gg\niPUHyt22LXZJpex/bdglz8n1a/mV2hJMhucCQQCq08orrA7LiCqK5V5vU982tzCf5M6gESYm2n7I\nTt165FWyQsjoEmBRjujU2UHcnOqiL2742a9bFoOpAw+y5rJrAkEAo23sjC/P2rFU+h6fqs1hgX3o\nQukXoFFNZyxX/pL8iG+dLkgRyWysBSNCVCjhQ6HaO72m/uIuFjoxfI9HfyMlJQJAaE4JE8FrBzuN\nPmHu12sO0Anq1raOs43FDdQ7tXLyKSdibAX7RjhyN1pbMBu360ykt4Le73N7btLAcWI9I69ZIQJA\nGNIcYuNMDnotJjsy+1kIBmzt4RZmWSfzQjqBBPI9AEOPYMqyOwFtOywCFpNtYuEAjPpn67LyqmOC",
"D2EzFHeamw==")
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAISJXsEkRv6q7r0GAUuES2DRe0ww
/L8g46SkGM17kkVDE7PLnY9L2xv+jM0avr35+DMaLADZnxWQc3fslmtRbWXGNUUUCTbotLMGwGu7
9jSeVLTbhDtDwKlwSrCwmjV4L//LOoI3tFRQMEjPa8JcMhPVvxOG8f3jeym4hfWtUwCNAgMBAAEC
gYBEuXKf1i7WGU6IR5feT7BCeP1lSbWVafmAwvJ1gpEbRyftQDToPB5Wysy6AhdMLVVNMlIE8tNx
/CBT3CM3bNa7gtRsOTlypISIuVqeVK5NQ18gYxhB3d9bowSKKh/P9dH9NSF7SqOKHEU+M+PvTs+Q
OAYpSHmAzUChrwLm/KuVxQJBAMaeMna4iP+Y7RzjzONvoNJlKaMhnPDvyDZuQ9yK8CuBJGud08gg
iPUHyt22LXZJpex/bdglz8n1a/mV2hJMhucCQQCq08orrA7LiCqK5V5vU982tzCf5M6gESYm2n7I
Tt165FWyQsjoEmBRjujU2UHcnOqiL2742a9bFoOpAw+y5rJrAkEAo23sjC/P2rFU+h6fqs1hgX3o
QukXoFFNZyxX/pL8iG+dLkgRyWysBSNCVCjhQ6HaO72m/uIuFjoxfI9HfyMlJQJAaE4JE8FrBzuN
PmHu12sO0Anq1raOs43FDdQ7tXLyKSdibAX7RjhyN1pbMBu360ykt4Le73N7btLAcWI9I69ZIQJA
GNIcYuNMDnotJjsy+1kIBmzt4RZmWSfzQjqBBPI9AEOPYMqyOwFtOywCFpNtYuEAjPpn67LyqmOC
/L8g46SkGM17kkVDE7PLnY9L2xv+jM0avr35+DMaLADZnxWQc3fslmtRbWXGNUUUCTbotLMGwGu7
9jSeVLTbhDtDwKlwSrCwmjV4L//LOoI3tFRQMEjPa8JcMhPVvxOG8f3jeym4hfWtUwCNAgMBAAEC
gYBEuXKf1i7WGU6IR5feT7BCeP1lSbWVafmAwvJ1gpEbRyftQDToPB5Wysy6AhdMLVVNMlIE8tNx
/CBT3CM3bNa7gtRsOTlypISIuVqeVK5NQ18gYxhB3d9bowSKKh/P9dH9NSF7SqOKHEU+M+PvTs+Q
OAYpSHmAzUChrwLm/KuVxQJBAMaeMna4iP+Y7RzjzONvoNJlKaMhnPDvyDZuQ9yK8CuBJGud08gg
iPUHyt22LXZJpex/bdglz8n1a/mV2hJMhucCQQCq08orrA7LiCqK5V5vU982tzCf5M6gESYm2n7I
Tt165FWyQsjoEmBRjujU2UHcnOqiL2742a9bFoOpAw+y5rJrAkEAo23sjC/P2rFU+h6fqs1hgX3o
QukXoFFNZyxX/pL8iG+dLkgRyWysBSNCVCjhQ6HaO72m/uIuFjoxfI9HfyMlJQJAaE4JE8FrBzuN
PmHu12sO0Anq1raOs43FDdQ7tXLyKSdibAX7RjhyN1pbMBu360ykt4Le73N7btLAcWI9I69ZIQJA
GNIcYuNMDnotJjsy+1kIBmzt4RZmWSfzQjqBBPI9AEOPYMqyOwFtOywCFpNtYuEAjPpn67LyqmOC好吧,RSA的密钥向来都很长,到这里先打住,我们来到初始启动的类,即com/pksqs/activity/DisplayActivity
我们观察下其内容,发现这个类中有非常多的对注册码进行验证的地方,我们需要的就是下面这个判断
[Java] 纯文本查看 复制代码 DecodeHelper.Decrypt(SignDataHelper
.getCursor(v0, "key"), SignDataHelper.Cipher("MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAISJXsEkRv6q7r0GAUuES2DRe0ww",
"/L8g46SkGM17kkVDE7PLnY9L2xv+jM0avr35+DMaLADZnxWQc3fslmtRbWXGNUUUCTbotLMGwGu7\n9jSeVLTbhDtDwKlwSrCwmjV4L//LOoI3tFRQMEjPa8JcMhPVvxOG8f3jeym4hfWtUwCNAgMBAAEC\ngYBEuXKf1i7WGU6IR5feT7BCeP1lSbWVafmAwvJ1gpEbRyftQDToPB5Wysy6AhdMLVVNMlIE8tNx\n/CBT3CM3bNa7gtRsOTlypISIuVqeVK5NQ18gYxhB3d9bowSKKh/P9dH9NSF7SqOKHEU+M+PvTs+Q\nOAYpSHmAzUChrwLm/KuVxQJBAMaeMna4iP+Y7RzjzONvoNJlKaMhnPDvyDZuQ9yK8CuBJGud08gg\niPUHyt22LXZJpex/bdglz8n1a/mV2hJMhucCQQCq08orrA7LiCqK5V5vU982tzCf5M6gESYm2n7I\nTt165FWyQsjoEmBRjujU2UHcnOqiL2742a9bFoOpAw+y5rJrAkEAo23sjC/P2rFU+h6fqs1hgX3o\nQukXoFFNZyxX/pL8iG+dLkgRyWysBSNCVCjhQ6HaO72m/uIuFjoxfI9HfyMlJQJAaE4JE8FrBzuN\nPmHu12sO0Anq1raOs43FDdQ7tXLyKSdibAX7RjhyN1pbMBu360ykt4Le73N7btLAcWI9I69ZIQJA\nGNIcYuNMDnotJjsy+1kIBmzt4RZmWSfzQjqBBPI9AEOPYMqyOwFtOywCFpNtYuEAjPpn67LyqmOC",
"D2EzFHeamw==")).equals(Algorithm.check(new DataInfo().getSerial(((Context)this)))
0x4 破解
(1)得到公钥,只要得到公钥,一切问题迎刃而解,然而这并没有什么卵用,因难度过大,不会,放弃
(2)偷梁换柱法,既然是纯本地注册验证的,我们只需要替换其公钥私钥,用自己的代替,那整套注册流程可以完全被我们掌控(可行)
(3)爆破法,之前提到了,因为这个软件是靠不可取消的弹窗来限制非注册用户的,那只需要删除这个弹窗即可,跟踪到主类下发现其调用
情况整个方法后完成爆破,之后的测试除了点击关于之后会闪退,其余一切正常,闪退这里自行处理下即可
|