最近刚接触android逆向,因此,分析的比较简单,请多多包涵。
apk来源于本论坛,当时帖子的作者,通过修改积分数值,对软件进行了破解,但并未找出注册机制等等,因此下面将对注册机制进行分析。
原帖:http://www.52pojie.cn/forum.php? ... 6orderby%3Ddateline
刚拿到该APK,先安装看看效果,但是安装后会闪退,并给出提示如下:
因此,猜测该APK应该会检查更新,如果有更新,就退出,并提示安装新版本。
载入JEB,进行分析,发现代码进行了混淆。虽然如此,但可以找到activity_register,An_QimenActivity。activity_register用处不是特别大,找到An_QimenActivity中的onCreate方法,发现如下代码:
[Java] 纯文本查看 复制代码 this.getWindow().setSoftInputMode(3);
if(this.b()) {
Toast.makeText(this.getApplicationContext(), "本程序已有升级版,可在南方周易程序网站升级更新:www.nfbazi.com", 1)
.show();
this.finish();
}
else {。。。}
可以看到,我们的猜测是对的,因此首先去掉该限制,利用apktool反编译,找到An_QimenActivity.smali中的onCreate方法,找到如下代码:
[Java] 纯文本查看 复制代码 if-eqz v0, :cond_0
invoke-virtual {p0}, Lcom/nfbazi/qimen/An_QimenActivity;->getApplicationContext()Landroid/content/Context;
move-result-object v0
const-string v1, "\u672c\u7a0b\u5e8f\u5df2\u6709\u5347\u7ea7\u7248\uff0c\u53ef\u5728\u5357\u65b9\u5468\u6613\u7a0b\u5e8f\u7f51\u7ad9\u5347\u7ea7\u66f4\u65b0\uff1awww.nfbazi.com"
invoke-static {v0, v1, v7}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
move-result-object v0
invoke-virtual {v0}, Landroid/widget/Toast;->show()V
invoke-virtual {p0}, Lcom/nfbazi/qimen/An_QimenActivity;->finish()V
:goto_0
将if-eqz v0修改为if-nez v0,重新打包,签名,即可运行。
分析发现,该软件有10次的限制,10后积分会减为0,当然针对积分的限制,原帖作者已经给出了破解方法。而本文重点介绍该软件的注册机制
点击菜单可以发现注册窗口,因此需要分析该软件的注册机制,找到注册码。
在JEB中找到bp类,并找到onClick方法,代码如下:
[Java] 纯文本查看 复制代码 public void onClick(View arg6) {
int v3 = -16776961;
if(a.q) {
this.a.finish();
}
else {
View v0 = this.a.findViewById(2131165230);
View v1 = this.a.findViewById(2131165231);
String v0_1 = ((EditText)v0).getText().toString().trim();
if(v0_1.length() == 0) {
((TextView)v1).setTextColor(v3);
((TextView)v1).setText("您还没有输入注册码。");
}
else if(!d.a(a.o, v0_1)) {
((TextView)v1).setTextColor(v3);
((TextView)v1).setText("您输入的注册码不对。");
}
else {
((TextView)v1).setTextColor(-65536);
((TextView)v1).setText("注册成功,点击“退出”。");
activity_register.a(this.a, this.a.getSharedPreferences("pcr", 0));
activity_register.a(this.a).edit().putString("acc", this.a.a.a(v0_1)).commit();
activity_register.a(this.a).edit().putString("bcc", this.a.a.a(a.o)).commit();
a.c("pcr");
}
a.p = "a@^*(^*ga$(&%io";
}
}
看到注册部分的代码了吧,主要是提取我们输入的注册码,与该软件的真正的注册码进行比较判断。
跟入a.o 发现是一个string,
[Java] 纯文本查看 复制代码 public class a {
....
public static String o;
....
static {
.....
a.o = "";
}
}
然后查看什么时候对a.o进行的赋值,如下:
[Java] 纯文本查看 复制代码 public boolean b() {
int v6 = 8;
int v5 = 7;
Object v0 = this.G.getSystemService("phone");
String v1 = ((TelephonyManager)v0).getDeviceId();
String v2 = ((TelephonyManager)v0).getSubscriberId();
String v0_1 = ((TelephonyManager)v0).getSimSerialNumber();
if(v1 == null) {
v1 = "";
}
if(v2 == null) {
v2 = "";
}
if(v0_1 == null) {
v0_1 = "";
}
if(a.l == null) {
a.l = "";
}
if(!v1.equals("")) {
v1 = v1.toUpperCase();
}
if(!v2.equals("")) {
v2 = v2.toUpperCase();
}
if(!v0_1.equals("")) {
v0_1 = v0_1.toUpperCase();
}
if(!a.l.equals("")) {
a.l = a.l.toUpperCase();
}
if(v1.length() >= v6) {
v1 = v1.substring(v1.length() - 7);
}
if(v2.length() >= v6) {
v2 = v2.substring(v2.length() - 7);
}
if(v0_1.length() >= v6) {
v0_1 = v0_1.substring(v0_1.length() - 7);
}
if(a.l.length() >= v6) {
a.l = a.l.substring(a.l.length() - 7);
}
if(v1.length() != v5 || (this.d(v1))) {
if(v2.length() == v5 && !this.d(v2)) {
v0_1 = String.valueOf(v2) + "B";
goto label_71;
}
if(v0_1.length() == v5 && !this.d(v0_1)) {
v0_1 = String.valueOf(v0_1) + "C";
goto label_71;
}
if(a.l.length() == v5 && !this.d(a.l)) {
v0_1 = String.valueOf(a.l) + "E";
goto label_71;
}
v0_1 = this.c();
}
else {
v0_1 = String.valueOf(v1) + "A";
}
label_71:
a.o = String.valueOf(v0_1) + "-2414";
boolean v0_2 = v0_1.length() > 0 ? true : false;
return v0_2;
}
上面便是注册码的产生计算的过程。继续查看class d 类。
[Java] 纯文本查看 复制代码 public static boolean a(String arg3, String arg4) {
boolean v0 = true;
a.p = d.a(d.a.a(arg3));
if(a.p.equals(arg4)) {
a.q = true;
}
else {
a.q = false;
v0 = false;
}
return v0;
}
其中a.p中保存了真正的注册码,其中深入分析可知a.p实际上也是一个string。
注册机制的分析就到此结束了。
知道了注册机制,下面就让程序把自己的注册码吐出来
打开反编译的文件d.smali,找到如下代码:
[Java] 纯文本查看 复制代码 .method public static a(Ljava/lang/String;Ljava/lang/String;)Z
.locals 3
const/4 v0, 0x1
const/4 v1, 0x0
sget-object v2, Lcom/nfbazi/qimen/a/d;->a:Lcom/nfbazi/qimen/a/b;
invoke-virtual {v2, p0}, Lcom/nfbazi/qimen/a/b;->a(Ljava/lang/String;)Ljava/lang/String;
move-result-object v2
invoke-static {v2}, Lcom/nfbazi/qimen/a/d;->a(Ljava/lang/String;)Ljava/lang/String;
move-result-object v2
sput-object v2, Lcom/nfbazi/qimen/a/a;->p:Ljava/lang/String;
sget-object v2, Lcom/nfbazi/qimen/a/a;->p:Ljava/lang/String;
invoke-virtual {v2, p1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v2
这个便是上面的 public static boolean a(String arg3, String arg4)方法,修改如下:
然后打包,签名,允许程序,并注册,其中注册码随便写。
然后在cmd中输入adb logcat -s SN:V
可以得到注册码如下所示:
然后用程序自己吐出来的注册码进行注册,提示注册成功,并可以升级该apk
|