好友
阅读权限20
听众
最后登录1970-1-1
|
最近正在学习android逆向分析,于是打算找个apk练练手,在咱论坛上看到 http://www.52pojie.cn/thread-191522-1-1.html 分析,但是元亨利之贞大大只是分析了修改程序流程来实现破解,我一咬牙一跺脚,打算来分析一下注册算法,于是就有了这篇混积分的帖子。
首先是安装软件测试测试,发现提示有更新,不更新还不让运行,找到代码如下,修改后重新编译运行,找到软件注册入口如下:
分析代码找到判断注册是否成功的地方
[AppleScript] 纯文本查看 复制代码 00000084 sget-object v2, a->o:String #获取机器码
00000088 invoke-static d->a(String, String)Z, v2, v0 #注册和比较算法
0000008E move-result v2
00000090 if-nez v2, :A6
:94
00000094 invoke-virtual TextView->setTextColor(I)V, v1, v3
0000009A const-string v0, "您输入的注册码不对。"
0000009E invoke-virtual TextView->setText(CharSequence)V, v1, v0
000000A4 goto :7A
:A6
000000A6 const/high16 v2, 0xFFFFFFFFFFFF0000
000000AA invoke-virtual TextView->setTextColor(I)V, v1, v2
000000B0 const-string v2, "注册成功,点击“退出”。"
000000B4 invoke-virtual TextView->setText(CharSequence)V, v1, v2
可以发现重点在 d->a(String, String)Z, v2, v0 这个函数中,进去看看,代码如下:
[AppleScript] 纯文本查看 复制代码 .method public static a(String, String)Z
.registers 5
00000000 const/4 v0, 0x1
00000002 const/4 v1, 0x0
00000004 sget-object v2, d->a:b
00000008 invoke-virtual b->a(String)String, v2, p0
0000000E move-result-object v2
00000010 invoke-static d->a(String)String, v2
00000016 move-result-object v2
00000018 sput-object v2, a->p:String
0000001C sget-object v2, a->p:String
00000020 invoke-virtual String->equals(Object)Z, v2, p1 #将计算结果和用户输入的注册码进行比较
00000026 move-result v2
00000028 if-eqz v2, :32
:2C
0000002C sput-boolean v0, a->q:Z
:30
00000030 return v0
:32
00000032 sput-boolean v1, a->q:Z
00000036 move v0, v1
00000038 goto :30
.end method
这个函数的功能是将机器码经过一系列计算,然后将计算结果和用户输入的代码进行比较,由此可以判断注册算法肯定在如下两个函数中: [AppleScript] 纯文本查看 复制代码 invoke-virtual b->a(String)String, v2, p0 和 [AppleScript] 纯文本查看 复制代码 00000010 invoke-static d->a(String)String, v2
首先看第一个函数:
[AppleScript] 纯文本查看 复制代码 .method public a(String)String
.registers 5
00000000 invoke-direct b->a()V, p0 #这个函数是初始化变量,0x67452301,0xEFCDAB89, 0x98BADCFE, 0x10325476 初步判断函数为MD5
00000006 invoke-virtual String->getBytes()[B, p1
0000000C move-result-object v0
0000000E invoke-virtual String->length()I, p1
00000014 move-result v1
00000016 invoke-direct b->a([B, I)V, p0, v0, v1 # 将机器码和其长度传递给函数, 这个函数内部函数更加确定了这个函数是MD5算法函数
0000001C invoke-direct b->b()V, p0
00000022 const-string v0, ""
00000026 iput-object v0, p0, b->c:String
0000002A const/4 v0, 0x0
:2C
0000002C const/16 v1, 0x10
00000030 if-lt v0, v1, :3A
:34
00000034 iget-object v0, p0, b->c:String
00000038 return-object v0
:3A
0000003A iget-object v1, p0, b->c:String
0000003E new-instance v2, StringBuilder
00000042 invoke-static String->valueOf(Object)String, v1
00000048 move-result-object v1
0000004A invoke-direct StringBuilder-><init>(String)V, v2, v1
00000050 iget-object v1, p0, b->g:[B
00000054 aget-byte v1, v1, v0
00000058 invoke-static b->b(B)String, v1
0000005E move-result-object v1
00000060 invoke-virtual StringBuilder->append(String)StringBuilder, v2, v1
00000066 move-result-object v1
00000068 invoke-virtual StringBuilder->toString()String, v1
0000006E move-result-object v1
00000070 iput-object v1, p0, b->c:String
00000074 add-int/lit8 v0, v0, 0x1
00000078 goto :2C
.end method
因此知道这个函数是MD5算法函数,返回值为MD5的Hash结果,接着看下一个函数,函数参数是机器码的MD5值:
[AppleScript] 纯文本查看 复制代码 .method public static a(String)String
.registers 10
00000000 const/4 v8, 0x3
00000002 const/16 v7, 0xC
00000006 const/4 v6, 0x7
00000008 const/4 v2, 0x0
0000000A const-string v0, ""
0000000E const-string v3, ""
00000012 invoke-virtual String->length()I, p0 #获取Hash值的长度
00000018 move-result v1
0000001A if-lez v1, :2C #如果长度小于等于0 跳转
:1E
0000001E move v1, v2
:20
00000020 invoke-virtual String->length()I, p0
00000026 move-result v4
00000028 if-lt v1, v4, :EA #判断是否读取到了最后一个字符(去除字母功能循环)
:2C
0000002C invoke-virtual String->length()I, v0
00000032 move-result v1
00000034 if-lt v1, v7, :6A #如果长度小于12则跳转到6A
:38 #下面这段函数是将字符串的前六位和后六位交换位置
00000038 new-instance v1, StringBuilder
0000003C invoke-virtual String->substring(I, I)String, v0, v6, v7 #取出字符串的7-12位
00000042 move-result-object v4
00000044 invoke-static String->valueOf(Object)String, v4
0000004A move-result-object v4
0000004C invoke-direct StringBuilder-><init>(String)V, v1, v4
00000052 invoke-virtual String->substring(I, I)String, v0, v2, v6 #取出字符串的1-6位
00000058 move-result-object v0
0000005A invoke-virtual StringBuilder->append(String)StringBuilder, v1, v0
00000060 move-result-object v0
00000062 invoke-virtual StringBuilder->toString()String, v0
00000068 move-result-object v0
:6A
0000006A move-object v1, v3
0000006C move v3, v2
:6E
0000006E invoke-virtual String->length()I, v0
00000074 move-result v4
00000076 if-lt v3, v4, :128
:7A
0000007A invoke-virtual String->length()I, v1
00000080 move-result v0
00000082 const/16 v3, 0xB
00000086 if-gt v0, v3, :A6 #如果字符串长度大于12则跳转到A6
:8A
0000008A invoke-static Long->parseLong(String)J, v1 #当字符串长度小于等于12时,将其转换成长整型
00000090 move-result-wide v0
00000092 const-wide v3, 0x1CBE991A14
0000009C add-long/2addr v0, v3 #将其与数字123456789012 相加
0000009E invoke-static String->valueOf(J)String, v0, v1
000000A4 move-result-object v1 #将结果转换成字符串
:A6
000000A6 new-instance v0, StringBuilder
000000AA invoke-virtual String->substring(I, I)String, v1, v6, v7 #取出字符串的7-12位
000000B0 move-result-object v3
000000B2 invoke-static String->valueOf(Object)String, v3
000000B8 move-result-object v3
000000BA invoke-direct StringBuilder-><init>(String)V, v0, v3
000000C0 invoke-virtual String->substring(I, I)String, v1, v2, v8 #取出字符串的1-3位
000000C6 move-result-object v2
000000C8 invoke-virtual StringBuilder->append(String)StringBuilder, v0, v2
000000CE move-result-object v0
000000D0 invoke-virtual String->substring(I, I)String, v1, v8, v6 #取出字符串的4-6位
000000D6 move-result-object v1
000000D8 invoke-virtual StringBuilder->append(String)StringBuilder, v0, v1
000000DE move-result-object v0
000000E0 invoke-virtual StringBuilder->toString()String, v0
000000E6 move-result-object v0
000000E8 return-object v0 #将转换后的结果返回,成真正的验证码
:EA
000000EA invoke-virtual String->charAt(I)C, p0, v1 #取出字符
000000F0 move-result v4
000000F2 invoke-static Character->isDigit(C)Z, v4 #判断该字符是否是数字
000000F8 move-result v5
000000FA if-eqz v5, :120 # 如果取出的是字符就跳转到120
:FE
000000FE new-instance v5, StringBuilder #取出的是数字这将其添加到字符串V5的的末尾
00000102 invoke-static String->valueOf(Object)String, v0
00000108 move-result-object v0
0000010A invoke-direct StringBuilder-><init>(String)V, v5, v0
00000110 invoke-virtual StringBuilder->append(C)StringBuilder, v5, v4
00000116 move-result-object v0
00000118 invoke-virtual StringBuilder->toString()String, v0
0000011E move-result-object v0
:120
00000120 add-int/lit8 v1, v1, 0x1
00000124 goto/16 :20
:128
00000128 add-int/lit8 v4, v3, 0x1 # v4=v3+1
0000012C invoke-virtual String->substring(I, I)String, v0, v3, v4 #依次取出字符
00000132 move-result-object v4
00000134 invoke-static Integer->parseInt(String)I, v4 #将字符转换成数字
0000013A move-result v4
0000013C xor-int/lit8 v4, v4, 0x5 # 将数字进行5次方
00000140 new-instance v5, StringBuilder
00000144 invoke-static String->valueOf(Object)String, v1
0000014A move-result-object v1
0000014C invoke-direct StringBuilder-><init>(String)V, v5, v1
00000152 invoke-static String->valueOf(I)String, v4 #将数字转换成字符串
00000158 move-result-object v1
0000015A invoke-virtual StringBuilder->append(String)StringBuilder, v5, v1 #将字符串添加到字符串V1的末尾
00000160 move-result-object v1
00000162 invoke-virtual StringBuilder->toString()String, v1
00000168 move-result-object v1
0000016A add-int/lit8 v3, v3, 0x1 #V3 = V3+1
0000016E goto :6E
.end method
从方法中分析出注册算法的流程如下:
[AppleScript] 纯文本查看 复制代码 Step0: 初始化字符串R1,2,3,4,5为空 (其中R1,2,3,4为中间变量保存值,R5为计算结果)。
Step1: 计算机器码的MD5值 结果为R1;
Step2: 去掉R1中的所有字母结果为R2;
Step3: 如果R2的长度不大于12则将R2的值赋给R3,然后跳转到Step5;
Step4: 去除R2的前12位并将前六位和后六位交换位置,结果赋值给R3;
Step5: 依次将R3中的每一位转换成数值,并进行5次方,然后转换成字符串,粘贴在字符串R4的末尾;
Step6: 如果R4的长度大于11位则跳转到Step8;
Step7: 将R4转换成长整型然后和123456789012相加,结果保存在R4中;
Step8: 依次取出R4的7到12位,1-3位,4-6位粘贴到R5的末尾,R5即为真正注册码。
到此算法分析完成。接下来是编写注册机,python代码如下:
[Python] 纯文本查看 复制代码 #!/usr/bin/env python
#coding=utf-8
import hashlib, getopt, sys, os
def usage(self):
print("[+] usage: python registcode.py -c DA44015E-2414")
def registCode(hashcode):
len1 = 3;
len2 = 12;
len3 = 7;
tempcode = ""
result = ""
if len(hashcode) > 0:
for temp in hashcode:
if temp.isdigit():
tempcode += temp
if len(tempcode) > len2:
tempcode = tempcode[len3:len2] + tempcode[:len3]
for temp in tempcode:
result += str(int(temp)^5)
if len(result) <12:
result = str(int(result) +123456789012)
return result[len3:len2] + result[:len1] + result[len1:len3]
if __name__ == '__main__':
opts, args = getopt.getopt(sys.argv[1:], "hc:");
machinecode = ""
for op,value in opts:
if op == "-c":
machinecode = value
elif op == "-h":
usage()
sys.exit()
if len(machinecode) == 0:
print("[-] No Machine Code")
sys.exit()
print("[+] machine code: %s"%machinecode)
md = hashlib.md5();
md.update(machinecode.encode(encoding='gb2312'))
print(md.hexdigest())
print(registCode(md.hexdigest()))
运行结果如下:
[Asm] 纯文本查看 复制代码 [+] machine code: DA44015E-2414
[+] MD5 code: 227c1bab3334277b3e8c06ca227b4a20
[+] regist code: 246661722677
打完收工,附上JAVA和Python实现的简单注册代码,菜鸟一枚,大牛勿喷。 |
-
-
-
注册.zip
1.8 KB, 下载次数: 10, 下载积分: 吾爱币 -1 CB
注册算法实现文件
免费评分
-
查看全部评分
|