作者論壇帳號:暴龍獸
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)
函數0x6C4D78
與驗證算法一中的一樣.
校驗部分
提取加密結果中的大寫字符,與rcode_three相比較。
<h3 id="32643451_破解思路">破解思路
整個驗證思路:
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).
其他部分以上內容介紹的是主要的驗證算法,還有其他的一些函數,順便介紹一些。
如何生成對應類型(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加密的內容不是用戶名和註冊碼交叉的部分。
註冊機https://github.com/pwnmelife/FastStone-Capture-Key-Generate.git
--官方論壇
www.52pojie.cn
--推薦給朋友
公眾微信號:吾愛破解論壇
或搜微信號:pojie_52