再战开放式注册算法:手机通话短信定位大师注册算法还原
本帖最后由 taintitly 于 2014-8-8 08:44 编辑http://www.52pojie.cn/thread-255540-1-1.html这个帖子的软件,最近失业在家,闲来无事,拿来练手。大家如果有兴趣,可以自己拿来练练手,编译,还原算法,写注册机。这个软件集合了反编译,dex2jar,算法还原等几个很值得研究的地方。如果你只是想简单的用爆破解决问题,可以跳过这篇文章了。爆破就像抢劫,没有一点技术含量。本篇文章也是给大家一个写注册算法的启发。
本篇只限于探讨算法还原,不涉及第三方反编译和dex转jar的讨论,谢谢
老规矩,反编译进入smali,找到判别注册与否的函数isreg()
.method public staticisReg(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z .locals 27 .param p0, "arg0" #Ljava/lang/String; //邮箱(大写) .param p1, "arg1" #Ljava/lang/String; //手机imei最后8位 .param p2, "arg2" #Ljava/lang/String; //输入的注册码注册码
.prologue .line 451 const-string v23, ""
move-object/from16 v0, v23
move-object/from16 v1, p0
invoke-virtual {v0, v1},Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v23
if-nez v23, :cond_0
if-nez p0, :cond_1
.line452 :cond_0 const/16 v23, 0x0
.line 492 :goto_0return v23 //判别邮箱是否为空,如果是则返回false 还原为java代码:if(("".equals(paramString1)) || (paramString1 == null)) return false
.line 454 :cond_1 const-string v23, ""
move-object/from16 v0, v23
move-object/from16 v1, p1
invoke-virtual {v0, v1},Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v23
if-nez v23, :cond_2
if-nez p1, :cond_3
.line 455 :cond_2 const/16 v23, 0x0
goto :goto_0//判别机器码是否为空,如果是则返回false 还原为java代码:if(("".equals(paramString2)) || (paramString2 == null)) return false
.line 457 :cond_3 const-string v23, ""
move-object/from16 v0, v23
move-object/from16 v1, p2
invoke-virtual {v0, v1},Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v23
if-nez v23, :cond_4
if-nez p2, :cond_5
.line 458 :cond_4 const/16 v23, 0x0
goto :goto_0 //判别输入的注册码是否为空,是则返回false 还原为java代码:if(("".equals(paramString3)) || (paramString3 == null)) return false
.line 461 :cond_5 :try_start_0 invoke-virtual/range {p2 .. p2}, Ljava/lang/String;->length()I
move-result v10//计算输入的注册码的字符长度,推入i还原为java代码:int i =paramString3.length()
.line 462 .local v10, "l":I const/16 v23, 0x0
const/16 v24, 0x1
move-object/from16 v0, p2
move/from16 v1, v23
move/from16 v2, v24
invoke-virtual {v0, v1, v2},Ljava/lang/String;->substring(II)Ljava/lang/String;
move-result-object v23
invoke-static/range {v23 .. v23},Ljava/lang/Integer;->parseInt(Ljava/lang/String;)I
move-result v8//将注册码的第一位数值推入j 还原为java代码:int j =Integer.parseInt(paramString3.substring(0, 1))
.line 463 .local v8, "i":I add-int/lit8 v23, v10, -0x1
move-object/from16 v0, p2
move/from16 v1, v23
invoke-virtual {v0, v1},Ljava/lang/String;->substring(I)Ljava/lang/String;
move-result-object v23
invoke-static/range {v23 .. v23},Ljava/lang/Integer;->parseInt(Ljava/lang/String;)I
move-result v9 //将注册码最后一位数值推入k 还原为java代码:int k =Integer.parseInt(paramString3.substring(i - 1))
.line 465 .local v9, "j":I const/16 v23, 0x0
add-int/lit8 v24, v8, 0x1
move-object/from16 v0, p2
move/from16 v1, v23
move/from16 v2, v24
invoke-virtual {v0, v1, v2},Ljava/lang/String;->substring(II)Ljava/lang/String;
move-result-objectv13//
还原为java代码:String str1 =paramString3.substring(0, j + 1)
.line 466 .local v13, "q":Ljava/lang/String; add-int/lit8 v23, v8, 0x1
add-int/lit8 v24, v10, -0x1
move-object/from16 v0, p2
move/from16 v1, v23
move/from16 v2, v24
invoke-virtual {v0, v1, v2},Ljava/lang/String;->substring(II)Ljava/lang/String;
move-result-objectv14
还原为java代码:String str2 = paramString3.substring(j + 1,i - 1)
.line 468 .local v14, "r":Ljava/lang/String; new-instance v23, Ljava/lang/StringBuilder;
const/16 v24, 0x0
move/from16 v0, v24
invoke-virtual {v14, v0, v9},Ljava/lang/String;->substring(II)Ljava/lang/String;
move-result-object v24
invoke-static/range {v24 .. v24},Ljava/lang/String;->valueOf(Ljava/lang/Object;)Ljava/lang/String;
move-result-object v24
invoke-direct/range {v23 .. v24},Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)V
add-int/lit8 v24, v9, 0x1
move/from16 v0, v24
invoke-virtual {v14, v0},Ljava/lang/String;->substring(I)Ljava/lang/String;
move-result-object v24
invoke-virtual/range {v23 .. v24},Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v23
invoke-virtual/range {v23 .. v23},Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v15
.line 469 .local v15, "s":Ljava/lang/String; const/16 v23, 0x10
move/from16 v0, v23
invoke-static {v15, v0},Ljava/lang/Long;->parseLong(Ljava/lang/String;I)J
move-result-widev21
还原为java代码:long l1 =Long.parseLong(str2.substring(0, k) + str2.substring(k + 1), 16)
.line 470 .local v21, "y":J add-int/lit8 v23, v9, 0x1
move/from16 v0, v23
invoke-virtual {v14, v9, v0},Ljava/lang/String;->substring(II)Ljava/lang/String;
move-result-object v23
invoke-static/range {v23 .. v23},Ljava/lang/Integer;->parseInt(Ljava/lang/String;)I
move-result v20
还原为java代码:int m =Integer.parseInt(str2.substring(k, k + 1))
.line 472 .local v20, "x":I invoke-static {}, Ljava/lang/System;->currentTimeMillis()J
move-result-widev3
还原为java代码:long l2 =System.currentTimeMillis()
.line 474 .local v3, "c":J new-instance v23, Ljava/lang/StringBuilder;
invoke-static/range {p0 .. p0},Ljava/lang/String;->valueOf(Ljava/lang/Object;)Ljava/lang/String;
move-result-object v24
invoke-direct/range {v23 .. v24},Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)V
const-string v24, "0o"
invoke-virtual/range {v23 .. v24},Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v23
move-object/from16 v0, v23
move/from16 v1, v20
invoke-virtual {v0, v1},Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;
move-result-object v23
invoke-virtual/range {v23 .. v23},Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v23
invoke-static/range {v23 .. v23},Lcn/malasi/service/OtherOperatorService;->MD5(Ljava/lang/String;)Ljava/lang/String;
move-result-objectv6 还原为java代码:String str3 =MD5(paramString1 + "0o" + m)
.local v6, "g":Ljava/lang/String; new-instance v23, Ljava/lang/StringBuilder;
invoke-static/range {p1 .. p1},Ljava/lang/String;->valueOf(Ljava/lang/Object;)Ljava/lang/String;
move-result-object v24
invoke-direct/range {v23 .. v24},Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)V
const-string v24, "0o"
invoke-virtual/range {v23 .. v24},Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v23
move-object/from16 v0, v23
move/from16 v1, v20
invoke-virtual {v0, v1},Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;
move-result-object v23
invoke-virtual/range {v23 .. v23},Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v23
invoke-static/range {v23 .. v23},Lcn/malasi/service/OtherOperatorService;->MD5(Ljava/lang/String;)Ljava/lang/String;
move-result-objectv7
还原为java代码:String str4 =MD5(paramString2 + "0o" + m)
.line 475 .local v7, "h":Ljava/lang/String; new-instance v23, Ljava/lang/StringBuilder;
invoke-static {v8}, Ljava/lang/String;->valueOf(I)Ljava/lang/String;
move-result-object v24
invoke-direct/range {v23 .. v24},Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)V
add-int v24, v8, v9
move/from16 v0, v24
invoke-virtual {v6, v9, v0},Ljava/lang/String;->substring(II)Ljava/lang/String;
move-result-object v24
invoke-virtual/range {v23 .. v24},Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v23
invoke-virtual/range {v23 .. v23},Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-objectv11
还原为java代码:String str5 = j+ str3.substring(k, j + k)
.local v11, "m":Ljava/lang/String; new-instance v23, Ljava/lang/StringBuilder;
invoke-static {v8}, Ljava/lang/String;->valueOf(I)Ljava/lang/String;
move-result-object v24
invoke-direct/range {v23 .. v24},Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)V
add-int v24, v8, v9
move/from16 v0, v24
invoke-virtual {v7, v9, v0}, Ljava/lang/String;->substring(II)Ljava/lang/String;
move-result-object v24
invoke-virtual/range {v23 .. v24},Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v23
invoke-virtual/range {v23 .. v23},Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-objectv12
还原为java代码:String str6 = j+ str4.substring(k, j + k)
.line 477 .local v12, "n":Ljava/lang/String; invoke-virtual {v11, v13},Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v23
if-nez v23, :cond_6
invoke-virtual {v12, v13},Ljava/lang/String;->equals(Ljava/lang/Object;)Z:try_end_0
.catch Ljava/lang/Exception; {:try_start_0 .. :try_end_0} :catch_0
move-result v23
if-eqz v23,:cond_9
还原为java代码:!str5.equals(str1)) { boolean bool = str6.equals(str1); if (!bool); }
.line 479 :cond_6 const/16 v23, 0x9
move/from16 v0, v20
move/from16 v1, v23
if-ne v0, v1, :cond_7
.line 480 const/16 v23, 0x1
goto/16 :goto_0
.line 482 :cond_7 if-nez v20, :cond_8
const/16 v20, 0xc
.line 483 :cond_8 sub-long v16, v3, v21
.local v16, "te":J const-wide v23, 0x9a7ec800L
move/from16 v0, v20
int-to-long v0, v0
move-wide/from16 v25, v0
mul-long v18, v23, v25
.line 484 .local v18, "tt":J const-wide/16 v23, 0x0
cmp-long v23, v16, v23
if-lez v23, :cond_9
cmp-long v23, v16, v18
if-gez v23, :cond_9
.line 485 const/16 v23, 0x1
goto/16 :goto_0
还原为java代码: { if (m == 9) return true; if (m == 0) m = 12; long l3 = l2 - l1; long l4 = 2592000000L * m; if ((l3 > 0L) && (l3 <l4)) return true; }
.line 489 .end local v3 # "c":J .end local v6 #"g":Ljava/lang/String; .end local v7 #"h":Ljava/lang/String; .end local v8 # "i":I .end local v9 # "j":I .end local v10 #"l":I .end local v11 #"m":Ljava/lang/String; .end local v12 # "n":Ljava/lang/String; .end local v13 #"q":Ljava/lang/String; .end local v14 #"r":Ljava/lang/String; .end local v15 #"s":Ljava/lang/String; .end local v16 #"te":J .end local v18 #"tt":J .end local v20 #"x":I .end local v21 #"y":J :catch_0 move-exception v5
.line 490 .local v5, "e":Ljava/lang/Exception; invoke-virtual {v5}, Ljava/lang/Exception;->printStackTrace()V
.line 492 .end local v5 #"e":Ljava/lang/Exception; :cond_9 const/16 v23, 0x0
goto/16 :goto_0 还原为java代码: catch (Exception localException) { localException.printStackTrace(); } return false;
.end method
看了头晕吧?肯定头晕,现在把片段再整理下,整理的好一些:
Java代码整段还原如下:
public static boolean isReg(String paramString1, String paramString2,String paramString3){ if (("".equals(paramString1)) || (paramString1 == null)) return false; //判别邮箱是否为空 if (("".equals(paramString2)) || (paramString2 == null)) return false; //判别机器码是否为空 if (("".equals(paramString3)) || (paramString3 == null)) return false; //判别注册码是否为空 try { int i = paramString3.length(); //i=注册码长度 int j = Integer.parseInt(paramString3.substring(0, 1));//j=注册码首位 int k = Integer.parseInt(paramString3.substring(i - 1));//k=注册码末位 String str1 = paramString3.substring(0, j + 1);//str1=注册码第一位到第j+1位 String str2 = paramString3.substring(j + 1, i - 1);//str2=注册码第j+2位到第i-1位 long l1 = Long.parseLong(str2.substring(0, k)+ str2.substring(k + 1), 16); int m = Integer.parseInt(str2.substring(k, k + 1));//m=str2第k+1位 long l2 = System.currentTimeMillis(); String str3 = MD5(paramString1 + "0o" + m);//str3=邮箱地址+0o+m字符串MD5加密 String str4 = MD5(paramString2 + "0o" + m); //str4=机器码+0o+m字符串MD5加密 String str5 = j + str3.substring(k, j + k);//str5=注册码首位字符+str3第K+1位到j+k位 String str6 = j + str4.substring(k, j + k); //str6=注册码首位字符+str3第K+1位到j+k位 if (!str5.equals(str1)) //判别:如果str1=str5 注册成功(邮箱) { boolean bool = str6.equals(str1); //判别:如果str1=str6 注册成功(机器码) if (!bool); } else { if (m == 9) return true; if (m == 0) m = 12; long l3 = l2 - l1; long l4 = 2592000000L * m; if ((l3 > 0L) && (l3 < l4)) return true; } } catch (Exception localException) { localException.printStackTrace(); } return false;}
看完上面的内容你是不是万念聚灰了?注册码本身居然也作为一个运算参数参与了注册码的计算,而且是MD5运算。再简化一下吧:注册码=注册码第一位+MD5(邮箱/机器码+”0o”+(注册码第j+2位到第i-1位字符的第k+1位))的第K+1位到j+k位 所以说,这是一个开放性的注册码,一个邮箱或者机器码能有很多个注册码。但是,如果我们限定住一个或者两个条件。因为j和k这两个最主要的参数是注册码的第一位和最后一位。那么,注册码的判别就没有那么复杂了。为了让注册码看起来不那么容易被拆解分析,我先将j和k设定成一个固定的数值。写出来的注册机有时候运算一个注册码也是需要1-3分钟时间。囧。不过好歹还是可以用了。
PS:我用vb完全按JAVA还原出来的算法写的注册机,跑了8小时没跑出一个能用的注册码来。更囧。我已经把算法的源码给还原出来了,至于大家用什么方式自己去写注册机啥的,就看大家自己了,我只会用vb6.0此软件有后门,会泄露信息,莫用!!用这个软件发布这篇文章,探讨开放性注册算法罢了。如果你有需要软件,留下机器码,我送10枚。
liye1320 发表于 2014-8-21 15:08
smali文件 不用转换成java吗?好难看清楚
不用 我看smali文件更习惯 楼猪,不错,写得可以 楼主辛苦了! 楼主辛苦了,谢谢分享,学习了。 期待更多更精彩的内容! smali文件 不用转换成java吗?好难看清楚 太专业,有点看不懂 楼主辛苦来。 大侠牛逼啊