免责声明
破解代码如下:
package main
import (
"bytes"
"crypto"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"encoding/hex"
"encoding/json"
"encoding/pem"
"flag"
//"fmt"
"io/ioutil"
"os"
"strings"
"time"
"log"
)
var (
originPubKeyPem = `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2K+PRbp/yumhaVnN92JS
GuQiwj7df64jHAo8MvXLWjYxU/yvqB4LbGty8ymKQy33qaDNpu9jgE2s8cXrtftm
/UcvwDb8sTqWXpDhxYhcvJM30agxz3/8VwNJ4JOvhk9Gn+msYIUz+gXZMBuUFKhi
BOd6C2Pro03GYwVTNjfwH/Y9C5EfPKIKNU/5t2cYo+TuOBk5ooP+NTaDzB6rb7fd
E5uuNnF21x3rdiI9rZcKPbuU97/0OWNcIUh5wfxPNWwcmjYmFuZcxk/7dOUD65s4
pTplCoMLOelacB0l442dM4w2xNpn+Yg7i/ujmg37F+VguCZJWnoyImdhp/raccNG
+wIDAQAB
-----END PUBLIC KEY-----`
newPublicKeyPem = `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtKvyFB24hIEVwMs4Xi00
FCW41tqELGYb7f63A/lAsBPVSOvGrQ5UzuKmttatQF/IDD9UcHqqbi+B80pydiGS
eKJOaly0GuX6hfDd51/uo7E44LyzJSSBhTc1vtbL5JbNcapnxo4P6rJ1Uh9V7y8z
pRvc1G2da00mQSYoIg/9ty21j4So+Fz/v37qhK50EEIeXGJZb4uz9I9iKCHaazjI
Lf293Gzvp7EFEpZkKrh2VktKaERh+jHmJqEe0z7U/sz0cCa9ohS+TF5nxmkAZBel
CwEMXjkjGnCWO3wXJoyrXMn1GY/ilNPDFT7rSZBKLEIi7PrBD1pVLGdq2zTboenV
6wIDAQAB
-----END PUBLIC KEY-----`
newPrivateKeyPem = `-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAtKvyFB24hIEVwMs4Xi00FCW41tqELGYb7f63A/lAsBPVSOvG
rQ5UzuKmttatQF/IDD9UcHqqbi+B80pydiGSeKJOaly0GuX6hfDd51/uo7E44Lyz
JSSBhTc1vtbL5JbNcapnxo4P6rJ1Uh9V7y8zpRvc1G2da00mQSYoIg/9ty21j4So
+Fz/v37qhK50EEIeXGJZb4uz9I9iKCHaazjILf293Gzvp7EFEpZkKrh2VktKaERh
+jHmJqEe0z7U/sz0cCa9ohS+TF5nxmkAZBelCwEMXjkjGnCWO3wXJoyrXMn1GY/i
lNPDFT7rSZBKLEIi7PrBD1pVLGdq2zTboenV6wIDAQABAoIBAQCu3PSxr4pVBLLP
JGFsFQggr9nUaS4f4rwJfswXlnibcratmzVxbTt7+TYuJF0OvyVZZToOm0q01lpJ
5LYfy6J+C2kl3I+csRXl6Rh8xgase+x252vj+Q86phLon/A7UBGLf8htDjYti4et
chK0KtUramozV9xSbBsoVwvk2+FOFdiLsc+B3PyuydB0Lvov5EDBtZJ1GbnyWk/3
c++aL+lkjQbIs11A4Nwp7hUdPmM/Va8VK+DqWxbFCIr6rli5d9VOE//EHJ7S7aPp
+fxV9gyv1d0WBRNktH2t8O2JVn90379/EgWuonSlRG+HrhqZKrXIKuIFJEUmGUjs
8qJNzoERAoGBAOLjiGbXuOQHkshDqdB4xF1b4rvCBrr881dBAOnYqSyEUWuUD3et
4qX/7GaxWlSU2IteB+r5FyfEpmqUNmKVsgLkGh3lgeTU0Mss2+2xIAODNXvba8MV
UIawpvDFnLN2HEY/d+LYycBjWDk+6B1+dGlPZIxXF+8HqGnlqyBNFjP/AoGBAMva
WVB02FK4oXa8APTtvuQ2MP67Q95WdhZXdy8CEWnwJaknSTE3dXJ9nZZmFgHt54lo
KjbGfIOSCLeCqXm3ZGs5HQr2kY/xJXDJga6uNh71w66/q/W2z+30FFzta6BjYE/8
3pB+P4vUUsp/vb3SkNfRKdcNrtoL29UYdXM7QG4VAoGAQqLw/MN+2fofchHtXf0a
LxE9lkd2EpUYIxhEXGn1xc1W3HGv2UaIuphfpgmQribJMqV7Tde6pUNsXQEKuAmf
Lpov0XgGnl6itAmIzlanQGDY5HedPr6T1/sqDKz9SPf3depOG6HwH0EOOEHxijgJ
mKRos48gyGNHY1LA38vEKaECgYEAmu8fRsknyOdOwMFvMLiphyWw40pM8OVh5uUf
TnkR5ySAWynitSdjelsCtNZuD5VTjtm+i9cbt5v8SA1k5X9/MQc9jaGNTIuJW0mr
6Km7tJgx29UNyzjgnAgQmfhQ/pvJDcIxHjz16z66lfG0slshfwYX+L0LkenFcRaf
3a7A72kCgYEAhSSGHVkCTGteSyKxhbMVqTlxQQQWZKv4b+usqss00CKgs3CAKL8H
Crds7fq96xVDVCvxJGYMKQzG61MBa+e1f8YSdhl5EY1IltlHkZstgts7avG6MP6A
xMNjyLp1b84s2VVXTpSFA7i6KEUhl4NjqhZTslJht5Dfiy2Mmvfk2so=
-----END RSA PRIVATE KEY-----`
licenseVersion2Byte = []byte{0x02}
pre2Bytes = []byte{0x00, 0x01}
aesKeyNew, _ = hex.DecodeString("B293C506E0C7F60353C604961837B810")
)
var (
licenseName string
originLicense string
xrayFilePath string
xrayArchitecture string
)
func main() {
flag.StringVar(&licenseName, "g", "", "生成一个永久license,需要指定用户名")
flag.StringVar(&originLicense, "p", "", "解析官方证书,需要指定证书路径")
flag.StringVar(&xrayFilePath, "c", "", "patch xray,需要指定xray程序文件路径")
flag.StringVar(&xrayArchitecture,"a","exe64","xray平台和架构[exe64|elf64],默认为exe64")
flag.Parse()
if originLicense != "" {
parseAlready(originLicense)
}
if licenseName != "" {
genNew(licenseName)
}
if xrayFilePath != "" {
patch(xrayFilePath)
}
}
func parseAlready(licenseFile string) {
// 加载公钥
pubKey := importPublicKey(originPubKeyPem)
// 解析 xray-license.lic 文件
licenseFileData, err := ioutil.ReadFile(licenseFile)
if err != nil {
log.Panic("[!]",err)
}
licenseString := string(licenseFileData)
tmpStrings := strings.Split(licenseString, "n")
licenseString = ""
for _, line := range tmpStrings {
if !strings.HasPrefix(line, "#") && line != "" {
licenseString += line
}
}
//fmt.Println("your license:", licenseString)
base64DecodeData, err := base64.StdEncoding.DecodeString(licenseString)
if err != nil {
log.Panic("[!]",err)
}
//fmt.Println("base64 decode data:", hex.EncodeToString(base64DecodeData))
licenseVersion := base64DecodeData[0]
if licenseVersion == 2 {
log.Println("[*] Version OK: 2")
}
//解密前有一个简单的变换处理
right := len(base64DecodeData) - 1
for l := 1; l < right; l++ {
r := right - l
if l >= r {
break
}
base64DecodeData[l], base64DecodeData[r] = base64DecodeData[r], base64DecodeData[l]
}
//fmt.Println("trans bytes:", hex.EncodeToString(base64DecodeData))
// aes解密license
// | 1B : version | 16B : aes iv | 480B : cipher |
aesDecData, err := Decrypt(base64DecodeData[17:], base64DecodeData[1:17])
if err != nil {
log.Panic("[!]",err)
}
//fmt.Printf("AES DEC: %xn", aesDecData)
//fmt.Println(string(aesDecData))
//另一个异或变换
for i := 0; i < len(aesDecData); i++ {
aesDecData[i] = aesDecData[i] ^ 0x44
}
//fmt.Println("trans 2 :", hex.EncodeToString(aesDecData))
//fmt.Println("trans 2 string:", string(aesDecData))
// 后半部分是明文的json
licensePlainJsonBytes := aesDecData[0x102:]
//fmt.Println("license info json:", string(licensePlainJsonBytes))
//fmt.Println("pre2bytes:", hex.EncodeToString(aesDecData[:0x2]))
license := License{}
err = json.Unmarshal([]byte(licensePlainJsonBytes), &license)
if err != nil {
log.Panic("[!]",err)
}
log.Println("[*] License Parsed:", license)
// rsa 验证签名 pss
sum := sha256.Sum256(licensePlainJsonBytes)
//fmt.Println(sum)
// rsa使用 sha256算法,对 aes解密后的数据第三个字节开始,到后面json明文前面为止是签名
//fmt.Println("解析出来的签名:", aesDecData[2:0x102])
err = rsa.VerifyPSS(pubKey, crypto.SHA256, sum[:], aesDecData[2:0x102], nil)
if err != nil {
log.Println("[!]",err)
} else {
log.Println("[+] Varify Success!")
}
}
func genNew(name string) {
validTime, err := time.Parse("2006-01-02 15:04:05", "9999-09-09 00:00:00")
license := License{
LicenseId: "88888888888888888888888888888888",
UserId: "88888888888888888888888888888888",
UserName: name,
Distribution: "ADVANCED-Infiltrator",
NotValidBefore: 1591891200,
NotValidAfter: validTime.Unix(),
}
licensePlainJsonBytes, _ := json.Marshal(license)
//licensePlainJson := string(licensePlainJsonBytes)
//fmt.Println("明文license信息:", licensePlainJson)
// rsa sign
priKey := importPrivateKey(newPrivateKeyPem)
//sha256sum
sum := sha256.Sum256(licensePlainJsonBytes)
signature, err := rsa.SignPSS(rand.Reader, priKey, crypto.SHA256, sum[:], nil)
if err != nil {
log.Panic("[!]",err)
}
licenseInfoWithSign := append(signature, licensePlainJsonBytes...)
data2Enc := append(pre2Bytes, licenseInfoWithSign...)
// 加密前一次异或
for i := 0; i < len(data2Enc); i++ {
data2Enc[i] = data2Enc[i] ^ 0x44
}
// session iv
iv := make([]byte, 16)
_, _ = rand.Read(iv)
log.Println("[*] Temp AES IV:", hex.EncodeToString(iv))
aesEnc, err := Encrypt(data2Enc, iv)
if err != nil {
log.Panic("[!]",err)
}
//fmt.Println(aesEnc)
allBytes := append(iv, aesEnc...)
allBytes = append(licenseVersion2Byte, allBytes...)
// 左右交换
right := len(allBytes) - 1
for l := 1; l < right; l++ {
r := right - l
if l >= r {
break
}
allBytes[l], allBytes[r] = allBytes[r], allBytes[l]
}
licenseText := base64.StdEncoding.EncodeToString(allBytes)
fileText := `# xray license
# 需要重命名为 xray-license.lic 和 xray 可执行程序放在同一个文件夹中
# user_name: Chinese
# distribution: COMMUNITY-ADVANCED
# 仅对修改后的xray有效
` + licenseText + `
`
err = ioutil.WriteFile("xray-license.lic", []byte(fileText), os.ModePerm)
if err == nil {
log.Println("[+] 证书已写入文件:xray-license.lic")
}
}
func Decrypt(decodeData []byte, iv []byte) ([]byte, error) {
block, _ := aes.NewCipher(aesKeyNew)
blockMode := cipher.NewCBCDecrypter(block, iv)
origin_data := make([]byte, len(decodeData))
blockMode.CryptBlocks(origin_data, decodeData)
return unpad(origin_data), nil
}
func unpad(ciphertext []byte) []byte {
length := len(ciphertext)
unpadding := int(ciphertext[length-1])
return ciphertext[:(length - unpadding)]
}
func Encrypt(text []byte, iv []byte) ([]byte, error) {
block, _ := aes.NewCipher(aesKeyNew)
blockSize := block.BlockSize()
originData := pad(text, blockSize)
blockMode := cipher.NewCBCEncrypter(block, iv)
crypted := make([]byte, len(originData))
blockMode.CryptBlocks(crypted, originData)
//fmt.Println(len(originData))
return crypted, nil
}
func pad(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}
type License struct {
LicenseId string `json:"license_id"`
UserId string `json:"user_id"`
UserName string `json:"user_name"`
Distribution string `json:"distribution"`
NotValidBefore int64 `json:"not_valid_before"`
NotValidAfter int64 `json:"not_valid_after"`
}
func importPublicKey(key string) *rsa.PublicKey {
block, _ := pem.Decode([]byte(key))
if block == nil {
log.Panic("[!] Unable To Decode PublicKey To Request!")
}
pub, _ := x509.ParsePKIXPublicKey(block.Bytes)
return pub.(*rsa.PublicKey)
}
func importPrivateKey(key string) *rsa.PrivateKey {
block, _ := pem.Decode([]byte(key))
privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
log.Panic("[!]",err)
}
return privateKey
}
func patch(filePath string) {
amd64Bytes := make(map[string]string)
if xrayArchitecture == "exe64"{
// jl loc_B5CB83 改为 ja loc_B5CB83
amd64Bytes["48394B380F8C0F030000"] = "48394B380F870F030000"
// jnz loc_B687EC 改为 jz loc_B687EC
amd64Bytes["0F856202000031C0"] = "0F846202000031C0"
// jz loc_BB9D2E 改为 jmp loc_BB9D2E
amd64Bytes["84C00F84CFFEFFFF"] = "84C0E9D0FEFFFFFF"
}
// Linux amd64
//cmp qword ptr [rsp+2F8h+var_2F8+8], 0 改为 1
//jz short loc_1434748 -> call os_Exit
if xrayArchitecture == "elf64"{
//jl loc_B40BE3
amd64Bytes["0F8CF9020000"] = "0F87F9020000"
//jnz loc_B4C78C
amd64Bytes["0F8566020000"] = "0F8466020000"
//jz loc_B9CC27
amd64Bytes["84C00F84C8FEFFFF"] = "84C0E9C9FEFFFFFF"
}
for originBytes, newBytes := range amd64Bytes {
origin, err := ioutil.ReadFile(filePath)
originTmpBytes, _ := hex.DecodeString(originBytes)
newTmpBytes, _ := hex.DecodeString(newBytes)
loc := bytes.LastIndex(origin, originTmpBytes)
if loc > 0 {
log.Printf("[*] Signature Index: %#xn", loc)
newFile := replace(origin, newTmpBytes, loc)
err = ioutil.WriteFile(filePath, newFile, os.ModePerm)
if err == nil {
log.Println("[+] Patch Success:", filePath)
}
} else {
log.Println("[!] Can't Find Signature!",originBytes)
}
}
}
func replace(origin, new []byte, index int) []byte {
n := make([]byte, len(origin))
copy(n[:index], origin[:index])
copy(n[index:index+len(new)], new)
copy(n[index+len(new):], origin[index+len(new):])
return n
}
# xray license
# user_name: xray team
# user_id: c2a60b56f75189a74fe684ec0cb65add
# license_id: 1b76efc317ac09ececdf1f1338f5b4d6
# distribution: COMMUNITY-ADVANCED
# not_valid_before: 2021-01-10
# not_valid_after: 2021-04-10
AsFUXefZmgucJvUeivLDC8bCsyQjUxkEFm5Z8aZ29ujjXKBjUevNqQUhYlLwDAEcO+UarCjYqTsy6VTi9ewHLeEqPx4NI8ese/ALO0Oa6JBucvKNN+V0CphEGQw6vfr60KT0OKc7mcnnK+azYihSXRbHW98EZgyRr3vzLb9TWITZJwzZDPhoR4kDMHq86CLhpdfV6wDoOjvWdcxmRuDrbdRkWKkuXSrYiZpfsMsrhq4dDLfdvgT4LjnHJjlOdQBhfablZKeRlEx/6DWhJ/5AwgIFzkf9o5sumCkK+gvmK3w0zkmzTM2Sd2ydqSveRrfnl2apS+t5xwM/BMSWdnYQvIzH9KrpwE+rsNDUMUDMnurSqTr652rMZrzqmg+ckloka7uhHsj2TCLopzv9N62fFPf9/akSox+unvXhdluUI9TRYFVecXqJ9YJzDDGJKcjXGgxIDWfmYoXvgfAutSuIzi5qkEvEjFs6yGmZNJTvuorqKL82AO4DqQI3Axi6FjbFRvnmapIWHFtWZZbd0/mcUrhmwQ9fjXamiXm+IyVh7t38CqLXahupGili1WV2oVGy84tPZZQFTZVmoXlSSwCW4qRcYwOHk7OhQA9RLsx8DLkfahf2upzkdIgXdq7GAOm+bmp5dmJtOHRJTW5MNTg5eZU=
1.9.0破解过程
在1.8.5的基础上修改证书验证逻辑,将jl loc_BD3DAF改为ja loc_BD3DAF,即48 39 4B 38 0F 8C 25 02 00 00改为48 39 4B 38 0F 87 25 02 00 00即可:
if xrayArchitecture == "elf64"{
//jl loc_B40BE3
amd64Bytes["48394B380F8C25020000"] = "48394B380F8725020000"
//jnz loc_B4C78C
amd64Bytes["0F8566020000"] = "0F8466020000"
//jz loc_B9CC27
amd64Bytes["84C00F84C8FEFFFF"] = "84C0E9C9FEFFFFFF"
}
破解结果如下:
1.9.1破解过程
破解结果:
破解代码如下:
package main
import (
"bytes"
"crypto"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"encoding/hex"
"encoding/json"
"encoding/pem"
"flag"
//"fmt"
"io/ioutil"
"os"
"strings"
"time"
"log"
)
var (
originPubKeyPem = `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2K+PRbp/yumhaVnN92JS
GuQiwj7df64jHAo8MvXLWjYxU/yvqB4LbGty8ymKQy33qaDNpu9jgE2s8cXrtftm
/UcvwDb8sTqWXpDhxYhcvJM30agxz3/8VwNJ4JOvhk9Gn+msYIUz+gXZMBuUFKhi
BOd6C2Pro03GYwVTNjfwH/Y9C5EfPKIKNU/5t2cYo+TuOBk5ooP+NTaDzB6rb7fd
E5uuNnF21x3rdiI9rZcKPbuU97/0OWNcIUh5wfxPNWwcmjYmFuZcxk/7dOUD65s4
pTplCoMLOelacB0l442dM4w2xNpn+Yg7i/ujmg37F+VguCZJWnoyImdhp/raccNG
+wIDAQAB
-----END PUBLIC KEY-----`
newPublicKeyPem = `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtKvyFB24hIEVwMs4Xi00
FCW41tqELGYb7f63A/lAsBPVSOvGrQ5UzuKmttatQF/IDD9UcHqqbi+B80pydiGS
eKJOaly0GuX6hfDd51/uo7E44LyzJSSBhTc1vtbL5JbNcapnxo4P6rJ1Uh9V7y8z
pRvc1G2da00mQSYoIg/9ty21j4So+Fz/v37qhK50EEIeXGJZb4uz9I9iKCHaazjI
Lf293Gzvp7EFEpZkKrh2VktKaERh+jHmJqEe0z7U/sz0cCa9ohS+TF5nxmkAZBel
CwEMXjkjGnCWO3wXJoyrXMn1GY/ilNPDFT7rSZBKLEIi7PrBD1pVLGdq2zTboenV
6wIDAQAB
-----END PUBLIC KEY-----`
newPrivateKeyPem = `-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAtKvyFB24hIEVwMs4Xi00FCW41tqELGYb7f63A/lAsBPVSOvG
rQ5UzuKmttatQF/IDD9UcHqqbi+B80pydiGSeKJOaly0GuX6hfDd51/uo7E44Lyz
JSSBhTc1vtbL5JbNcapnxo4P6rJ1Uh9V7y8zpRvc1G2da00mQSYoIg/9ty21j4So
+Fz/v37qhK50EEIeXGJZb4uz9I9iKCHaazjILf293Gzvp7EFEpZkKrh2VktKaERh
+jHmJqEe0z7U/sz0cCa9ohS+TF5nxmkAZBelCwEMXjkjGnCWO3wXJoyrXMn1GY/i
lNPDFT7rSZBKLEIi7PrBD1pVLGdq2zTboenV6wIDAQABAoIBAQCu3PSxr4pVBLLP
JGFsFQggr9nUaS4f4rwJfswXlnibcratmzVxbTt7+TYuJF0OvyVZZToOm0q01lpJ
5LYfy6J+C2kl3I+csRXl6Rh8xgase+x252vj+Q86phLon/A7UBGLf8htDjYti4et
chK0KtUramozV9xSbBsoVwvk2+FOFdiLsc+B3PyuydB0Lvov5EDBtZJ1GbnyWk/3
c++aL+lkjQbIs11A4Nwp7hUdPmM/Va8VK+DqWxbFCIr6rli5d9VOE//EHJ7S7aPp
+fxV9gyv1d0WBRNktH2t8O2JVn90379/EgWuonSlRG+HrhqZKrXIKuIFJEUmGUjs
8qJNzoERAoGBAOLjiGbXuOQHkshDqdB4xF1b4rvCBrr881dBAOnYqSyEUWuUD3et
4qX/7GaxWlSU2IteB+r5FyfEpmqUNmKVsgLkGh3lgeTU0Mss2+2xIAODNXvba8MV
UIawpvDFnLN2HEY/d+LYycBjWDk+6B1+dGlPZIxXF+8HqGnlqyBNFjP/AoGBAMva
WVB02FK4oXa8APTtvuQ2MP67Q95WdhZXdy8CEWnwJaknSTE3dXJ9nZZmFgHt54lo
KjbGfIOSCLeCqXm3ZGs5HQr2kY/xJXDJga6uNh71w66/q/W2z+30FFzta6BjYE/8
3pB+P4vUUsp/vb3SkNfRKdcNrtoL29UYdXM7QG4VAoGAQqLw/MN+2fofchHtXf0a
LxE9lkd2EpUYIxhEXGn1xc1W3HGv2UaIuphfpgmQribJMqV7Tde6pUNsXQEKuAmf
Lpov0XgGnl6itAmIzlanQGDY5HedPr6T1/sqDKz9SPf3depOG6HwH0EOOEHxijgJ
mKRos48gyGNHY1LA38vEKaECgYEAmu8fRsknyOdOwMFvMLiphyWw40pM8OVh5uUf
TnkR5ySAWynitSdjelsCtNZuD5VTjtm+i9cbt5v8SA1k5X9/MQc9jaGNTIuJW0mr
6Km7tJgx29UNyzjgnAgQmfhQ/pvJDcIxHjz16z66lfG0slshfwYX+L0LkenFcRaf
3a7A72kCgYEAhSSGHVkCTGteSyKxhbMVqTlxQQQWZKv4b+usqss00CKgs3CAKL8H
Crds7fq96xVDVCvxJGYMKQzG61MBa+e1f8YSdhl5EY1IltlHkZstgts7avG6MP6A
xMNjyLp1b84s2VVXTpSFA7i6KEUhl4NjqhZTslJht5Dfiy2Mmvfk2so=
-----END RSA PRIVATE KEY-----`
licenseVersion2Byte = []byte{0x02}
pre2Bytes = []byte{0x00, 0x01}
aesKeyNew, _ = hex.DecodeString("B293C506E0C7F60353C604961837B810")
)
var (
licenseName string
originLicense string
xrayFilePath string
xrayArchitecture string
)
func main() {
flag.StringVar(&licenseName, "g", "", "生成一个永久license,需要指定用户名")
flag.StringVar(&originLicense, "p", "", "解析官方证书,需要指定证书路径")
flag.StringVar(&xrayFilePath, "c", "", "patch xray,需要指定xray程序文件路径")
flag.StringVar(&xrayArchitecture,"a","exe64","xray平台和架构[exe64|elf64],默认为exe64")
flag.Parse()
if originLicense != "" {
parseAlready(originLicense)
}
if licenseName != "" {
genNew(licenseName)
}
if xrayFilePath != "" {
patch(xrayFilePath)
}
}
func parseAlready(licenseFile string) {
// 加载公钥
pubKey := importPublicKey(originPubKeyPem)
// 解析 xray-license.lic 文件
licenseFileData, err := ioutil.ReadFile(licenseFile)
if err != nil {
log.Panic("[!]",err)
}
licenseString := string(licenseFileData)
tmpStrings := strings.Split(licenseString, "n")
licenseString = ""
for _, line := range tmpStrings {
if !strings.HasPrefix(line, "#") && line != "" {
licenseString += line
}
}
//fmt.Println("your license:", licenseString)
base64DecodeData, err := base64.StdEncoding.DecodeString(licenseString)
if err != nil {
log.Panic("[!]",err)
}
//fmt.Println("base64 decode data:", hex.EncodeToString(base64DecodeData))
licenseVersion := base64DecodeData[0]
if licenseVersion == 2 {
log.Println("[*] Version OK: 2")
}
//解密前有一个简单的变换处理
right := len(base64DecodeData) - 1
for l := 1; l < right; l++ {
r := right - l
if l >= r {
break
}
base64DecodeData[l], base64DecodeData[r] = base64DecodeData[r], base64DecodeData[l]
}
//fmt.Println("trans bytes:", hex.EncodeToString(base64DecodeData))
// aes解密license
// | 1B : version | 16B : aes iv | 480B : cipher |
aesDecData, err := Decrypt(base64DecodeData[17:], base64DecodeData[1:17])
if err != nil {
log.Panic("[!]",err)
}
//fmt.Printf("AES DEC: %xn", aesDecData)
//fmt.Println(string(aesDecData))
//另一个异或变换
for i := 0; i < len(aesDecData); i++ {
aesDecData[i] = aesDecData[i] ^ 0x44
}
//fmt.Println("trans 2 :", hex.EncodeToString(aesDecData))
//fmt.Println("trans 2 string:", string(aesDecData))
// 后半部分是明文的json
licensePlainJsonBytes := aesDecData[0x102:]
//fmt.Println("license info json:", string(licensePlainJsonBytes))
//fmt.Println("pre2bytes:", hex.EncodeToString(aesDecData[:0x2]))
license := License{}
err = json.Unmarshal([]byte(licensePlainJsonBytes), &license)
if err != nil {
log.Panic("[!]",err)
}
log.Println("[*] License Parsed:", license)
// rsa 验证签名 pss
sum := sha256.Sum256(licensePlainJsonBytes)
//fmt.Println(sum)
// rsa使用 sha256算法,对 aes解密后的数据第三个字节开始,到后面json明文前面为止是签名
//fmt.Println("解析出来的签名:", aesDecData[2:0x102])
err = rsa.VerifyPSS(pubKey, crypto.SHA256, sum[:], aesDecData[2:0x102], nil)
if err != nil {
log.Println("[!]",err)
} else {
log.Println("[+] Varify Success!")
}
}
func genNew(name string) {
validTime, err := time.Parse("2006-01-02 15:04:05", "9999-09-09 00:00:00")
license := License{
LicenseId: "88888888888888888888888888888888",
UserId: "88888888888888888888888888888888",
UserName: name,
Distribution: "ADVANCED-Infiltrator",
NotValidBefore: 1591891200,
NotValidAfter: validTime.Unix(),
}
licensePlainJsonBytes, _ := json.Marshal(license)
//licensePlainJson := string(licensePlainJsonBytes)
//fmt.Println("明文license信息:", licensePlainJson)
// rsa sign
priKey := importPrivateKey(newPrivateKeyPem)
//sha256sum
sum := sha256.Sum256(licensePlainJsonBytes)
signature, err := rsa.SignPSS(rand.Reader, priKey, crypto.SHA256, sum[:], nil)
if err != nil {
log.Panic("[!]",err)
}
licenseInfoWithSign := append(signature, licensePlainJsonBytes...)
data2Enc := append(pre2Bytes, licenseInfoWithSign...)
// 加密前一次异或
for i := 0; i < len(data2Enc); i++ {
data2Enc[i] = data2Enc[i] ^ 0x44
}
// session iv
iv := make([]byte, 16)
_, _ = rand.Read(iv)
log.Println("[*] Temp AES IV:", hex.EncodeToString(iv))
aesEnc, err := Encrypt(data2Enc, iv)
if err != nil {
log.Panic("[!]",err)
}
//fmt.Println(aesEnc)
allBytes := append(iv, aesEnc...)
allBytes = append(licenseVersion2Byte, allBytes...)
// 左右交换
right := len(allBytes) - 1
for l := 1; l < right; l++ {
r := right - l
if l >= r {
break
}
allBytes[l], allBytes[r] = allBytes[r], allBytes[l]
}
licenseText := base64.StdEncoding.EncodeToString(allBytes)
fileText := `# xray license
# 需要重命名为 xray-license.lic 和 xray 可执行程序放在同一个文件夹中
# user_name: Chinese
# distribution: COMMUNITY-ADVANCED
# 仅对修改后的xray有效
` + licenseText + `
`
err = ioutil.WriteFile("xray-license.lic", []byte(fileText), os.ModePerm)
if err == nil {
log.Println("[+] 证书已写入文件:xray-license.lic")
}
}
func Decrypt(decodeData []byte, iv []byte) ([]byte, error) {
block, _ := aes.NewCipher(aesKeyNew)
blockMode := cipher.NewCBCDecrypter(block, iv)
origin_data := make([]byte, len(decodeData))
blockMode.CryptBlocks(origin_data, decodeData)
return unpad(origin_data), nil
}
func unpad(ciphertext []byte) []byte {
length := len(ciphertext)
unpadding := int(ciphertext[length-1])
return ciphertext[:(length - unpadding)]
}
func Encrypt(text []byte, iv []byte) ([]byte, error) {
block, _ := aes.NewCipher(aesKeyNew)
blockSize := block.BlockSize()
originData := pad(text, blockSize)
blockMode := cipher.NewCBCEncrypter(block, iv)
crypted := make([]byte, len(originData))
blockMode.CryptBlocks(crypted, originData)
//fmt.Println(len(originData))
return crypted, nil
}
func pad(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}
type License struct {
LicenseId string `json:"license_id"`
UserId string `json:"user_id"`
UserName string `json:"user_name"`
Distribution string `json:"distribution"`
NotValidBefore int64 `json:"not_valid_before"`
NotValidAfter int64 `json:"not_valid_after"`
}
func importPublicKey(key string) *rsa.PublicKey {
block, _ := pem.Decode([]byte(key))
if block == nil {
log.Panic("[!] Unable To Decode PublicKey To Request!")
}
pub, _ := x509.ParsePKIXPublicKey(block.Bytes)
return pub.(*rsa.PublicKey)
}
func importPrivateKey(key string) *rsa.PrivateKey {
block, _ := pem.Decode([]byte(key))
privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
log.Panic("[!]",err)
}
return privateKey
}
func patch(filePath string) {
amd64Bytes := make(map[string]string)
/*
if xrayArchitecture == "exe64"{
// jl loc_B5CB83 改为 ja loc_B5CB83
amd64Bytes["48394B380F8C0F030000"] = "48394B380F870F030000"
// jnz loc_B687EC 改为 jz loc_B687EC
amd64Bytes["0F856202000031C0"] = "0F846202000031C0"
// jz loc_BB9D2E 改为 jmp loc_BB9D2E
amd64Bytes["84C00F84CFFEFFFF"] = "84C0E9D0FEFFFFFF"
}
// Linux amd64
//cmp qword ptr [rsp+2F8h+var_2F8+8], 0 改为 1
//jz short loc_1434748 -> call os_Exit
if xrayArchitecture == "elf64"{
//jl loc_B40BE3
amd64Bytes["4883FB010F8566020000"] = "4883FB010F8466020000"
//jnz loc_B4C78C
//amd64Bytes["0F8566020000"] = "0F8466020000"
//jz loc_B9CC27
amd64Bytes["4839FB0F8C77010000"] = "4839FB0F8777010000"
}
*/
amd64Bytes["4883FB010F8566020000"] = "4883FB010F8466020000"
amd64Bytes["4839FB0F8C77010000"] = "4839FB0F8777010000"
for originBytes, newBytes := range amd64Bytes {
origin, err := ioutil.ReadFile(filePath)
originTmpBytes, _ := hex.DecodeString(originBytes)
newTmpBytes, _ := hex.DecodeString(newBytes)
loc := bytes.LastIndex(origin, originTmpBytes)
if loc > 0 {
log.Printf("[*] Signature Index: %#xn", loc)
newFile := replace(origin, newTmpBytes, loc)
err = ioutil.WriteFile(filePath, newFile, os.ModePerm)
if err == nil {
log.Println("[+] Patch Success:", filePath)
}
} else {
log.Println("[!] Can't Find Signature!",originBytes)
}
}
}
func replace(origin, new []byte, index int) []byte {
n := make([]byte, len(origin))
copy(n[:index], origin[:index])
copy(n[index:index+len(new)], new)
copy(n[index+len(new):], origin[index+len(new):])
return n
}
1.9.3破解过程
原文始发于微信公众号(Hack All):【随时删除】Xray社区高级版白嫖历史(下)
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论