首页
论坛
课程
招聘
雪    币: 3704
活跃值: 活跃值 (1248)
能力值: ( LV12,RANK:210 )
在线值:
发帖
回帖
粉丝

[原创] FastStone Capture 软件注册算法破解及注册机编写

2020-6-29 23:31 1603

[原创] FastStone Capture 软件注册算法破解及注册机编写

2020-6-29 23:31
1603

FastStone Capture 注册算法分析

前言

前几日准备找一个可以将录屏转成gif图的软件,无意间发现了FastStone Capture。安装之后还需要注册码,碰巧还要申请一个大学的暑假实习,就花了四五天来分析一下注册算法,并写一下注册机。温馨提示:想要注册码的可以直接到文章结尾去下代码,跑一跑就出来了。

注册算法总流程图

用户名: 可以输入任意长度的内容。
注册码: 输入20个字节的字母,其中不能有数字。每五个字符之间用横线分割,如: ZYXWV-UTSRQ-PONML-KJIHG。
注册算法主要分为两部分的验证,将注册码分为三部分: rcode_one(前8字节),rcode_two(中间8字节),rcode_three(后4字节).

 

outline_graph

验证算法一

关键函数0x6D4FEC --> 0x6D472C

 

0x6D472C

 

交叉过程

# 交叉函数涉及的数据只有username和rcode_one
def character_intersect(uname, rcode):
    uname_length = len(uname)
    rcode_length = len(rcode)
    s = ''
    i = j = num = 0
    while i < uname_length and j < rcode_length:
        if num % 2 == 0:
            s += uname[i]
            i += 1
        else:
            s += rcode[j]
            j += 1
        num += 1
    if j != rcode_length:
        s += rcode[j:8]
    if i != uname_length:
        s += uname[i:]
    return s.upper()

intersect_function

 

加密函数

加密函数涉及IDEA和BlowFish,Hash函数涉及Sha1和Sha512函数.
加密的内容: username和rcode_one交叉的部分.

 

注意事项: 加密的方法有些不同,下面用代码讲解

# 由于字符串编码为byte时, 会出现一个字节变成两个字节的情况, 所以使用latin1编码。
plain_text = t_third # username和registeration code的交叉部分
first_cipher = str()
# blowfish_encrypt_result 作为初始化的
blowfish_encrypt_result = bf.main_transform(0, 0)
for i in range(len(plain_text)):
    tmp = bf.main_transform(blowfish_encrypt_result[0], blowfish_encrypt_result[1])
    # 明文部分与得到结果的一个字节异或
    first_cipher += chr(((tmp[0] >> 24) & 0xff) ^ ord(plain_text[i]))
    # blowfish_encrypt_result 在内存中循环左移一个字节
    blowfish_encrypt_result[0] = ((blowfish_encrypt_result[0] << 8) & 0xffffffff) | blowfish_encrypt_result[1] >> 24
    blowfish_encrypt_result[1] = ((blowfish_encrypt_result[1] << 8) & 0xffffff00) | ((tmp[0] >> 24) & 0xff) ^ ord(plain_text[i])

first_cipher_base64 = base64.b64encode(first_cipher.encode('latin1'))

plain_text = first_cipher_base64 # IDEA 加密的部分是blowfish得到的base64结果
two_cipher = str()
IDEA_zero_byte = b'\x00\x00\x00\x00\x00\x00\x00\x00'
IDEA_encrypt_result = idea.encrypt(IDEA_zero_byte)

for i in range(len(plain_text)):
    tmp = idea.encrypt(IDEA_encrypt_result)
    # 明文部分与得到结果的一个字节异或
    two_cipher += chr(tmp[0] & 0xff ^ plain_text[i])
    IDEA_encrypt_result = IDEA_encrypt_result[1:] + chr(tmp[0] & 0xff ^ plain_text[i]).encode('latin1')

two_cipher_base64 = base64.b64encode(two_cipher.encode('latin1'))

encryption_one_function

 

函数0x6C4D78

(Sha1, blowfish)和(sha512, IDEA)都在此函数中完成,但传入的参数不同,应该是使用面向对象中的某些性质. 此函数主要完成hash函数和子密钥的生成.

 

0x6C4D78

 

校验部分

提取密文中的大写字符,与rcode_two进行比较.

 

verfiy_first

验证算法二

函数0x6D50C0 --> 0x6D4BB8, 交叉函数和验证算法一一样.

 

encryption_two

 

加密函数

加密函数涉及IDEA和BlowFish,Hash函数涉及Sha1和Sha512函数。
加密的内容: username和rcode_one交叉的部分。

# IDEA encrypt
plain_text = (s_third).encode('utf-8')
plain_length = len(plain_text)
first_cipher = bytearray(plain_length)
IDEA_zero_byte = b'\x00\x00\x00\x00\x00\x00\x00\x00'
IDEA_encrypt_result = idea.encrypt(IDEA_zero_byte)
times = ord(register_code[0]) - 0x31
# 多次使用idea加密
for i in range(plain_length * times):
    tmp = idea.encrypt(IDEA_encrypt_result)
    # 
    first_cipher[i % plain_length] = tmp[0] & 0xff ^ plain_text[i % plain_length]
    IDEA_encrypt_result = IDEA_encrypt_result[1:] + chr(tmp[0] & 0xff ^ plain_text[i % plain_length]).encode('latin1')

first_cipher_base64 = base64.b64encode(first_cipher)
print("the middle 8 character, IDEA base64 cipher" + str(first_cipher_base64))


# blowfish encrypt,明文部分为上一步加密之后的base64编码
plain_text = first_cipher_base64
two_cipher = bytearray(len(plain_text))
blowfish_zero_byte = b'\x00\x00\x00\x00\x00\x00\x00\x00'
blowfish_encrypt_result = bf.main_transform(0, 0)
for i in range(len(plain_text)):
    tmp = bf.main_transform(blowfish_encrypt_result[0], blowfish_encrypt_result[1])
    # 明文与8字节结果的一个字节异或
    two_cipher[i] = (tmp[0] >> 24) & 0xff ^ plain_text[i]
    blowfish_encrypt_result[0] = ((blowfish_encrypt_result[0] << 8) & 0xffffffff) | blowfish_encrypt_result[1] >> 24
    blowfish_encrypt_result[1] = ((blowfish_encrypt_result[1] << 8) & 0xffffff00) | ((tmp[0] >> 24) & 0xff) ^ plain_text[i]

two_cipher_base64 = base64.b64encode(two_cipher)

encryption_two_function

 

函数0x6C4D78

与验证算法一中的一样.

 

校验部分

提取加密结果中的大写字符,与rcode_three相比较。

 

check_two

破解思路

整个验证思路:

    1. username和rcode_one进行组合,结果为intersection_string。
    1. 验证算法一对intersection_string进行运算,提取前8个大写字符,与rcode_two比较。
    1. 验证算法二对intersection_string进行运算,提取前8个大写字符,与rcode_three比较。
    1. 两个比较结果都为真,即可验证成功。

破解方法:

    1. 输入用户名username和随机生成8字节字符串s1,组合后结果为s。
    1. 验证算法一对s进行运算,提取前8个大写字符,作为s2。
    1. 验证算法二对s进行运算,提取前4个大写字符,作为s2。
    1. 最终的注册码为strcat(s1, s2, s3).

其他部分

以上内容介绍的是主要的验证算法,还有其他的一些函数,顺便介绍一些。

 

other_function

如何生成对应类型(Family、Educational、Corporate)的注册码? 下面用代码来进行说明:

# 下面是生成对应类型的注册码,校验方法也很简单
# 提取rcode_one中的3、7、5、1四个位置的字符,分别与'M'、'D'、'I'、'O'四个字符相减
# 得到的四个数字依次拼接,与下面数字进行比较
# 1111 --> Family License that covers up to 5 computers
# 4997 --> Educational Site License
# 4998 --> Educational Worldwide License
# 4999 --> Corporate Site License
# > 5000 --> Corporate Worldwide License
# FVLQORJM -->  Educational Site License
def generate_8_upper_case():
    # Family License that covers up to 5 computers 1111
    family_registeration_code = "{0}{1}{2}{3}{4}{5}{6}{7}".format(randomString(1), 'P', randomString(1), 'N', randomString(1), 'K', randomString(1), 'E')
    # Educational Site License 4997
    education_site_registeration_code = "{0}{1}{2}{3}{4}{5}{6}{7}".format(randomString(1), 'V', randomString(1), 'Q', randomString(1), 'R', randomString(1), 'M')
    # Educational Worldwide License 4998
    education_worldwide_registeration_code = "{0}{1}{2}{3}{4}{5}{6}{7}".format(randomString(1), 'W', randomString(1), 'Q', randomString(10), 'R', randomString(1), 'M')
    # Corporate Site License 4999
    Corporate_site_registeration_code = "{0}{1}{2}{3}{4}{5}{6}{7}".format(randomString(1), 'X', randomString(1), 'Q', randomString(1), 'R', randomString(1), 'M')
    # Corporate Worldwide License  5000
    corporate_worldwide_registeration_code = "{0}{1}{2}{3}{4}{5}{6}{7}".format(randomString(1), 'T', randomString(1), 'R', randomString(1), 'K', randomString(1), 'E')

    return [family_registeration_code, education_site_registeration_code, education_worldwide_registeration_code, Corporate_site_registeration_code, corporate_worldwide_registeration_code]

总结

虽然看雪上面也有一篇关于破解FastStone Viewer,但破解这个软件还是花了四五天的时间。其实两者验证算法极其相识,但注册码还是不能通用,原因就是其中一个字符串不同,FastStone Viewer96332, FastStone Capture96338. 将FastStone Viewer这篇文章中提到的注册机中的字符串96332修改为96338,生成的注册码也是可以用的.

心得

这是第一次真正的破解一个软件,虽然看了别人破解内容,但自己实地操作还是遇到许多坑,尤其是面向对象的一些性质。另外,就是一些加密算法要非常熟悉,这样才能整个数据的变化非常清楚,例如:FastStone Capture的BlowFish加密的内容不是用户名和注册码交叉的部分。

注册机

Github



[赠书活动] 《云计算安全》和《云存储安全实践》上线!老师留下通讯地址,即可获得赠书一套!送100套,送完为止!

最后于 2020-6-30 08:53 被baolongshou编辑 ,原因:
最新回复 (9)
雪    币: 3704
活跃值: 活跃值 (1248)
能力值: ( LV12,RANK:210 )
在线值:
发帖
回帖
粉丝
baolongshou 活跃值 2 2020-6-29 23:37
2
0
对应的idb文件,有需要的留一下邮箱。
雪    币: 115
活跃值: 活跃值 (99)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
真难取 活跃值 2020-6-30 07:34
3
0

pypy.exe keygen.py:
Traceback (most recent call last):
  File "keygen.py", line 6, in <module>
    from blowfish import BlowFish
ImportError: No module named blowfish

最后于 2020-6-30 07:35 被真难取编辑 ,原因:
雪    币: 3704
活跃值: 活跃值 (1248)
能力值: ( LV12,RANK:210 )
在线值:
发帖
回帖
粉丝
baolongshou 活跃值 2 2020-6-30 09:40
4
0
同学,你可以看一下代码。。。
雪    币: 115
活跃值: 活跃值 (99)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
真难取 活跃值 2020-6-30 09:42
5
0

我还没学过Py,看不懂:

Traceback (most recent call last):

  File "keygen.py", line 6, in <module>

    from blowfish import BlowFish

  File "X:\pypy\blowfish.py", line 193

    def __init__(self, key : bytes):

                                      ^

SyntaxError: invalid syntax (expected ')')


最后于 2020-6-30 09:45 被真难取编辑 ,原因:
雪    币: 115
活跃值: 活跃值 (99)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
真难取 活跃值 2020-6-30 09:59
6
0
key : bytes 改为 key = bytes,错误提示变为:
please input a username: bill
Traceback (most recent call last):
  File "keygen.py", line 210, in <module>
    main()
  File "keygen.py", line 193, in main
    username = input('please input a username: ')
  File "<string>", line 1, in <module>
NameError: global name 'bill' is not defined
雪    币: 4947
活跃值: 活跃值 (37)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
NightGuard 活跃值 1 2020-6-30 14:33
7
0
厉害,重装系统之后都忘记装这个软件了,必备的
注册机亲测可用,有问题的试试python 3 (我用的python 3.7)
雪    币: 3704
活跃值: 活跃值 (1248)
能力值: ( LV12,RANK:210 )
在线值:
发帖
回帖
粉丝
baolongshou 活跃值 2 2020-6-30 14:52
8
0
FastStone Capture对应的版本是9.3。一次不行的话,多试几次,总会出现注册码的
雪    币: 115
活跃值: 活跃值 (99)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
真难取 活跃值 5天前
9
0
baolongshou FastStone Capture对应的版本是9.3。一次不行的话,多试几次,总会出现注册码的
能否直接给个注册码?谢谢!
雪    币: 174
活跃值: 活跃值 (46)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
揰掵佲 活跃值 5天前
10
1

转载一个 注册机,很久之前的 貌似还可以用~

上传的附件:
游客
登录 | 注册 方可回帖
返回