FastStone Capture 注册算法分析
前言
前几日准备找一个可以将录屏转成gif图的软件,无意间发现了FastStone Capture。安装之后还需要注册码,碰巧还要申请一个大学的暑假实习,就花了四五天来分析一下注册算法,并写一下注册机。温馨提示:想要注册码的可以直接到文章结尾去下代码,跑一跑就出来了。
注册算法总流程图
用户名: 可以输入任意长度的内容。
注册码: 输入20个字节的字母,其中不能有数字。每五个字符之间用横线分割,如: ZYXWV-UTSRQ-PONML-KJIHG。
注册算法主要分为两部分的验证,将注册码分为三部分: rcode_one(前8字节),rcode_two(中间8字节),rcode_three(后4字节).
验证算法一
关键函数0x6D4FEC --> 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()
加密函数
加密函数涉及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'))
函数0x6C4D78
(Sha1, blowfish)和(sha512, IDEA)都在此函数中完成,但传入的参数不同,应该是使用面向对象中的某些性质. 此函数主要完成hash函数和子密钥的生成.
校验部分
提取密文中的大写字符,与rcode_two进行比较.
验证算法二
函数0x6D50C0 --> 0x6D4BB8, 交叉函数和验证算法一一样.
加密函数
加密函数涉及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
破解思路
整个验证思路:
-
- username和rcode_one进行组合,结果为intersection_string。
-
- 验证算法一对intersection_string进行运算,提取前8个大写字符,与rcode_two比较。
-
- 验证算法二对intersection_string进行运算,提取前8个大写字符,与rcode_three比较。
-
- 两个比较结果都为真,即可验证成功。
破解方法:
-
- 输入用户名username和随机生成8字节字符串s1,组合后结果为s。
-
- 验证算法一对s进行运算,提取前8个大写字符,作为s2。
-
- 验证算法二对s进行运算,提取前4个大写字符,作为s2。
-
- 最终的注册码为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 Viewer
为96332
, FastStone Capture
为96338
. 将FastStone Viewer
这篇文章中提到的注册机中的字符串96332
修改为96338
,生成的注册码也是可以用的.
心得
这是第一次真正的破解一个软件,虽然看了别人破解内容,但自己实地操作还是遇到许多坑,尤其是面向对象的一些性质。另外,就是一些加密算法要非常熟悉,这样才能整个数据的变化非常清楚,例如:FastStone Capture
的BlowFish加密的内容不是用户名和注册码交叉的部分。
注册机
Github