目錄
- Beyond Compare 5 記錄
- 1、定位按鈕事件
- 2、關鍵函式"TCertDecode::LoadCertString"
- 2.0 試用時
- 2.1 TBcCertDecoder公鑰解密
- 2.2 解析license資訊
- 3、license 結構
- patch & py
Beyond Compare 5 記錄
Delphi 程式,接觸不多,對程式註冊簡單跟了下;
1、定位按鈕事件
透過資原始檔,查詢註冊視窗,
定位==》TRegisterDialog.OkClick
2、關鍵函式"TCertDecode::LoadCertString"
2.0 試用時
程式尾部附加了一個LICENSE KEY,試用時會對該key進行解析,(該key經ExeHash xor加密,當程式被篡改後(附加資料部分不在hash計算範圍)無法繼續試用)
內建key可定位TCertDecoderBase.GetEmbeddedCert:Boolean
exehah計算時,從尾部開始查詢,在LICENSE KEY之前的資料將進行hash計算,作為key的xor金鑰。
2.1 TBcCertDecoder公鑰解密
2.2 解析license資訊
利用內建公鑰解密LICENSE KEY,再對lic資訊進行解析判斷
3、license 結構
見py指令碼
patch & py
BeyondCompareKeyMaker 1位元組序號產生器(支援全平臺)
這裡直接用B.S
的單位元組patch
patch,將尾部的'1'==》'n'
//原始
++11Ik:7EFlNLs6Yqc3p-LtUOXBElimekQm8e3BTSeGhxhlpmVDeVVrrUAkLTXpZ7mK6jAPAOhyHiokPtYfmokklPELfOxt1s5HJmAnl-5r8YEvsQXY8-dm6EFwYJlXgWOCutNn2+FsvA7EXvM-2xZ1MW8LiGeYuXCA6Yt2wTuU4YWM+ZUBkIGEs1QRNRYIeGB9GB9YsS8U2-Z3uunZPgnA5pF+E8BRwYz9ZE--VFeKCPamspG7tdvjA3AJNRNrCVmJvwq5SqgEQwINdcmwwjmc4JetVK76og5A5sPOIXSwOjlYK+Sm8rvlJZoxh0XFfyioHz48JV3vXbBKjgAlPAc7Np1+wk
//patch
++11Ik:7EFlNLs6Yqc3p-LtUOXBElimekQm8e3BTSeGhxhlpmVDeVVrrUAkLTXpZ7mK6jAPAOhyHiokPtYfmokklPELfOxt1s5HJmAnl-5r8YEvsQXY8-dm6EFwYJlXgWOCutNn2+FsvA7EXvM-2xZ1MW8LiGeYuXCA6Yt2wTuU4YWM+ZUBkIGEs1QRNRYIeGB9GB9YsS8U2-Z3uunZPgnA5pF+E8BRwYz9ZE--VFeKCPamspG7tdvjA3AJNRNrCVmJvwq5SqgEQwINdcmwwjmc4JetVK76og5A5sPOIXSwOjlYK+Sm8rvlJZoxh0XFfyioHz48JV3vXbBKjgAlPAc7Npn+wk
私鑰D為B.S的BeyondCompareKeyMaker中提取而來
import base64
import os
import random
from Crypto.Util.number import long_to_bytes,bytes_to_long
from Crypto.Util.Padding import unpad,pad
import binascii
# pip install based58
import based58
STANDARD_ALPHABET = b'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
CUSTOM_ALPHABET = b'+-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
ENCODE_TRANS = bytes.maketrans(STANDARD_ALPHABET, CUSTOM_ALPHABET)
DECODE_TRANS = bytes.maketrans(CUSTOM_ALPHABET, STANDARD_ALPHABET)
def xxbase64_encode(input:bytes)->bytes:
return base64.b64encode(input).translate(ENCODE_TRANS)
def xxbase64_decode(input:bytes)->bytes:
pad=len(input)%4
if pad!=0:
input+=b'='*pad
return base64.b64decode(input.translate(DECODE_TRANS))
def int_to_bytes(n:int,order='little')->bytes:
# 獲取整數的位長度
bit_length = n.bit_length()
# 計算所需的最小位元組數
byte_length = (bit_length + 7) // 8
# 轉換為位元組序列,使用大端位元組序
byte_array = n.to_bytes(byte_length, byteorder=order)
return byte_array
def Reverse_dw(data:bytes):
ret=b''
for i in range(0,len(data),4):
ret+=data[i:i+4][::-1]
return ret
BS_PK=b'++11Ik:7EFlNLs6Yqc3p-LtUOXBElimekQm8e3BTSeGhxhlpmVDeVVrrUAkLTXpZ7mK6jAPAOhyHiokPtYfmokklPELfOxt1s5HJmAnl-5r8YEvsQXY8-dm6EFwYJlXgWOCutNn2+FsvA7EXvM-2xZ1MW8LiGeYuXCA6Yt2wTuU4YWM+ZUBkIGEs1QRNRYIeGB9GB9YsS8U2-Z3uunZPgnA5pF+E8BRwYz9ZE--VFeKCPamspG7tdvjA3AJNRNrCVmJvwq5SqgEQwINdcmwwjmc4JetVK76og5A5sPOIXSwOjlYK+Sm8rvlJZoxh0XFfyioHz48JV3vXbBKjgAlPAc7Npn+wk'
# _bs_e=b'++11Ik'
# _bs_n= b'7EFlNLs6Yqc3p-LtUOXBElimekQm8e3BTSeGhxhlpmVDeVVrrUAkLTXpZ7mK6jAPAOhyHiokPtYfmokklPELfOxt1s5HJmAnl-5r8YEvsQXY8-dm6EFwYJlXgWOCutNn2+FsvA7EXvM-2xZ1MW8LiGeYuXCA6Yt2wTuU4YWM+ZUBkIGEs1QRNRYIeGB9GB9YsS8U2-Z3uunZPgnA5pF+E8BRwYz9ZE--VFeKCPamspG7tdvjA3AJNRNrCVmJvwq5SqgEQwINdcmwwjmc4JetVK76og5A5sPOIXSwOjlYK+Sm8rvlJZoxh0XFfyioHz48JV3vXbBKjgAlPAc7Npn+wk'
_bs_e,_bs_n=BS_PK.split(B':')
_bs_e=xxbase64_decode(_bs_e)
_bs_n=xxbase64_decode(_bs_n)
_bs_e_le=Reverse_dw(_bs_e)
_bs_n_le=Reverse_dw(_bs_n)
E=int.from_bytes(_bs_e_le,'little')
N=int.from_bytes(_bs_n_le,'little')
#BeyondCompareKeyMaker_windows_amd64.exe
#5D0AB5 call sub_5E5640 ; get d
_bs_d=binascii.a2b_hex('4860d32b474ff398b0058aaf111fe820f8bebad4342cb40b6fd7652b37a92cf077d58ca7374dcf65615fe846e73ababe6a729a59ebdd8b980bbeb47f3ef8041decc465118a40d76293b5fce1271d87865b3f1dc116f2637d8dfa338a5103ef14e9c28f620c325c1e241e2bfa9258d16b1239c5c06ce13ec2fe377fac038a0ff0eb0f5910018724fd4bf429f1c0fac86af083acdab388c18e281a5ea9976b385e6c0383485135f1e68cd7a3c0ab6d36b07aa1404e081083158e523129ace077972fc3bd9424fbe86c64b33e8916e0a15c0f5a346e2260fb565ee00741268e6987b978df646c81bd72b55e0ea94f5f51956bf80ffc4c51f6fcaaab96135c888523')
D=bytes_to_long(_bs_d)
def rsa_pri_enc(i_msg:int)->int:
enc=pow(i_msg,D,N)
return enc
def rsa_pub_dec(i_msg:int)->int:
dec=pow(i_msg,E,N)
return dec
def gen_cstr(data:bytes)->bytes:
ret=b'\x00'
sz=len(data)
if sz:
ret=len(data).to_bytes(1,'little')+data
return ret
class LIC_TYPE:
WINDOWS=4
LINUX=8
MACOS=0x10
PRO=0x21
def set_lic(usernumber=99999,username='kunkun',atsite='ikun'):
lic=b'\x04SCTR'
#
lic+=gen_cstr('')
lic+=gen_cstr('')
lic+=gen_cstr('')
lic+=gen_cstr('')
lic+=gen_cstr('')
#
lic+=b'\x01'
lic+=gen_cstr(b'73051')
lic+=gen_cstr(f'{usernumber}|{atsite}'.encode())
lic+=b'\x06'
#license type
'''
4 windows
8 linux
0x10 macos
0x21 Pro Edition
0x3d==>Pro Edition for Windows/Linux/macOS
'''
lic+=(LIC_TYPE.PRO|LIC_TYPE.WINDOWS|LIC_TYPE.LINUX|LIC_TYPE.MACOS).to_bytes(1,'little')#b'\x3d'
lic+= os.urandom(5)
lic+=b'\x09'+b'-'.join([str(random.randint(1000,10000)).encode() for _ in range(2) ] )
lic+=gen_cstr(b'0')
lic+=gen_cstr(b'30')
lic+=gen_cstr(b'15')
lic+=gen_cstr(f'{username}'.encode())
lic+=gen_cstr(b'0')
lic+=gen_cstr(b'0')
lic=pad(lic,0xff)
return lic
def keygen(usernumber=99999,username='kunkun',atsite='ikun',):
lic=set_lic(usernumber,username,atsite)
# print('plain lic:',lic.hex())
imsg=int.from_bytes(lic,'little')
i_data=rsa_pri_enc(imsg)
data=int_to_bytes(i_data)
# print('rsa_pri_enc lic:',data.hex())
lickey=based58.b58encode(data)
lickey='--- BEGIN LICENSE KEY ---\r\n'+lickey.decode()+'\r\n--- END LICENSE KEY -----\r\n'
print('%s\n\n'%lickey)
return lickey
def dec_lickey(data:bytes):
licdata=based58.b58decode(data)
imsg=int.from_bytes(licdata,'little')
i_lic=rsa_pub_dec(imsg)
lic=int_to_bytes(i_lic)
print('original lic:',lic.hex())
pass
if __name__ == '__main__':
key=keygen()
# key=key.replace('--- BEGIN LICENSE KEY ---\r\n','')
# key=key.replace('\r\n--- END LICENSE KEY -----\r\n','')
# dec_lickey(key.encode())
pass