2026-02-03 04:40:23 -08:00

250 lines
10 KiB
Go

package main
import (
"encoding/json"
"fmt"
"net/url"
"os"
"strings"
pkgaes "github.com/perfect-panel/server/pkg/aes"
)
func main() {
// 通讯密钥
communicationKey := "c0qhq99a-nq8h-ropg-wrlc-ezj4dlkxqpzx"
// 真实 Nginx 日志数据 - 从用户提供的日志中选取
sampleLogs := []string{
// 加密的下载请求 - 不同平台
`172.245.180.199 - - [02/Feb/2026:04:35:47 +0000] "GET /v1/common/client/download?data=JetaR6P9e8G5lZg2KRiAhV6c%2FdMilBtP78bKmsbAxL8%3D&time=2026-02-02T04:35:15.032000 HTTP/1.1" 200 201 "https://www.hifastvpn.com/" "AdsBot-Google (+http://www.google.com/adsbot.html)"`,
`172.245.180.199 - - [02/Feb/2026:04:35:47 +0000] "GET /v1/common/client/download?data=%2FFTAxtcEd%2F8T2MzKdxxrPfWBXk4pNPbQZB3p8Yrl8XQ%3D&time=2026-02-02T04:35:15.031000 HTTP/1.1" 200 181 "https://www.hifastvpn.com/" "AdsBot-Google (+http://www.google.com/adsbot.html)"`,
`172.245.180.199 - - [02/Feb/2026:04:35:47 +0000] "GET /v1/common/client/download?data=i18AVRwlVSuFrbf4NmId0RcTbj0tRJIBFHP0MxLjDmI%3D&time=2026-02-02T04:35:15.033000 HTTP/1.1" 200 201 "https://www.hifastvpn.com/" "AdsBot-Google (+http://www.google.com/adsbot.html)"`,
`172.245.180.199 - - [02/Feb/2026:04:50:50 +0000] "GET /v1/common/client/download?platform=mac HTTP/1.1" 200 113 "https://gethifast.net/" "Mozilla/5.0 (compatible; AhrefsBot/7.0; +http://ahrefs.com/robot/)"`,
`172.245.180.199 - - [02/Feb/2026:04:50:50 +0000] "GET /v1/common/client/download?platform=windows HTTP/1.1" 200 117 "https://gethifast.net/" "Mozilla/5.0 (compatible; AhrefsBot/7.0; +http://ahrefs.com/robot/)"`,
`172.245.180.199 - - [02/Feb/2026:05:24:16 +0000] "GET /v1/common/client/download?data=XfZsgEqUUQ0YBTT51ETQp2wheSvE4SRupBfYbiLnJOc%3D&time=2026-02-02T05:24:15.462000 HTTP/1.1" 200 181 "https://www.hifastvpn.com/" "Mozilla/5.0 (X11; CrOS x86_64 14541.0.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36"`,
// 真实用户下载
`172.245.180.199 - - [02/Feb/2026:02:15:16 +0000] "GET /v1/common/client/download?data=XIZiz7c4sbUGE7Hl8fY6O2D5QKaZqx%2Fg81uR7kjenSg%3D&time=2026-02-02T02:15:16.337000 HTTP/1.1" 200 201 "https://hifastvpn.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36"`,
`172.245.180.199 - - [02/Feb/2026:02:18:09 +0000] "GET /v1/common/client/download?data=aB0HistwZTIhxJh6yIds%2B6knoyZC17KyxaXvyd3Z5LY%3D&time=2026-02-02T02:18:06.301000 HTTP/1.1" 200 201 "https://hifastvpn.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Mobile Safari/537.36"`,
// 实际文件下载
`111.55.176.116 - - [02/Feb/2026:02:19:02 +0000] "GET /v1/common/client/download/file/android-1.0.0.apk HTTP/2.0" 200 18546688 "https://hifastvpn.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Mobile Safari/537.36"`,
`111.249.202.38 - - [02/Feb/2026:03:14:46 +0000] "GET /v1/common/client/download/file/mac-1.0.0.dmg HTTP/2.0" 200 72821392 "https://hifastvpn.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 12.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.7091.96 Safari/537.36"`,
// Windows 用户
`172.245.180.199 - - [02/Feb/2026:02:23:55 +0000] "GET /v1/common/client/download?data=t8OIVjnZx1N7w5ras4oVH9V0wz4JYlR7849WYKvbj9E%3D&time=2026-02-02T02:23:56.110000 HTTP/1.1" 200 201 "https://hifastvpn.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.7149.88 Safari/537.36"`,
// Mac 用户
`172.245.180.199 - - [02/Feb/2026:03:14:10 +0000] "GET /v1/common/client/download?data=mGKSxZtL7Ptf30MgFzBJPIsURC%2FkOf2lOGaXQOQ5Ft8%3D&time=2026-02-02T03:14:07.667000 HTTP/1.1" 200 181 "https://hifastvpn.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 12.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.7091.96 Safari/537.36"`,
// Android 移动端
`172.245.180.199 - - [02/Feb/2026:03:19:41 +0000] "GET /v1/common/client/download?data=y7gttvd%2BoKf9%2BZUeNTsOvuFHwOLFBByrNjkvhPkVykg%3D&time=2026-02-02T03:19:42.192000 HTTP/1.1" 200 201 "https://hifastvpn.com/" "Mozilla/5.0 (Linux; Android 15; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.7559.59 Mobile Safari/537.36"`,
`183.171.68.186 - - [02/Feb/2026:03:19:47 +0000] "GET /v1/common/client/download/file/android-1.0.0.apk HTTP/1.1" 200 179890 "https://hifastvpn.com/" "Mozilla/5.0 (Linux; Android 15; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.7559.59 Mobile Safari/537.36"`,
}
// 如果命令行提供了参数,使用命令行参数
if len(os.Args) > 1 {
sampleLogs = os.Args[1:]
}
fmt.Println("=== Nginx 下载日志解密工具 ===")
fmt.Printf("通讯密钥: %s\n\n", communicationKey)
// 统计数据
stats := make(map[string]int)
successCount := 0
for i, logLine := range sampleLogs {
// 提取日志条目
entry := extractLogEntry(logLine)
if entry.Data == "" && entry.Platform == "" {
fmt.Printf("--- 日志 #%d ---\n", i+1)
fmt.Println("⚠️ 跳过: 未找到 data 或 platform 参数\n")
continue
}
// 如果有 platform 参数(非加密),直接使用
if entry.Platform != "" {
fmt.Printf("--- 日志 #%d ---\n", i+1)
fmt.Printf("📍 IP地址: %s\n", entry.IP)
fmt.Printf("🌐 来源: %s\n", entry.Referer)
fmt.Printf("🔓 平台: %s (未加密)\n\n", entry.Platform)
stats[entry.Platform]++
successCount++
continue
}
// 处理加密的 data 参数
if entry.Data == "" {
continue
}
// URL 解码
decodedData, err := url.QueryUnescape(entry.Data)
if err != nil {
fmt.Printf("--- 日志 #%d ---\n", i+1)
fmt.Printf("❌ 错误: URL 解码失败: %v\n\n", err)
continue
}
// 提取 nonce (IV) - 从 time 参数转换
nonce := extractNonceFromTime(entry.Time)
// AES 解密
plainText, err := pkgaes.Decrypt(decodedData, communicationKey, nonce)
if err != nil {
fmt.Printf("--- 日志 #%d ---\n", i+1)
fmt.Printf("❌ 错误: 解密失败: %v\n", err)
fmt.Printf(" IP: %s, Nonce: %s\n\n", entry.IP, nonce)
continue
}
// 解析 JSON 获取平台信息
var result map[string]interface{}
if err := json.Unmarshal([]byte(plainText), &result); err == nil {
if platform, ok := result["platform"].(string); ok {
stats[platform]++
}
}
fmt.Printf("--- 日志 #%d ---\n", i+1)
fmt.Printf("📍 IP地址: %s\n", entry.IP)
fmt.Printf("🌐 来源: %s\n", entry.Referer)
fmt.Printf("🔓 解密内容: %s\n\n", plainText)
successCount++
}
// 输出统计信息
if successCount > 0 {
fmt.Println("=" + strings.Repeat("=", 50))
fmt.Printf("📊 统计信息 (成功解密: %d)\n", successCount)
fmt.Println("=" + strings.Repeat("=", 50))
for platform, count := range stats {
fmt.Printf(" %s: %d 次\n", platform, count)
}
fmt.Println()
}
}
// LogEntry 表示解析后的日志条目
type LogEntry struct {
IP string
Data string
Time string
Referer string
Platform string
}
// extractLogEntry 从日志行中提取所有关键信息
func extractLogEntry(logLine string) *LogEntry {
entry := &LogEntry{}
// 提取 IP 地址(第一个字段)
parts := strings.Fields(logLine)
if len(parts) > 0 {
entry.IP = parts[0]
}
// 提取 Referer 和 User-Agent
// Nginx combined 格式:... "请求" 状态码 字节数 "Referer" "User-Agent"
// 需要找到最后两对引号
quotes := []int{}
for i := 0; i < len(logLine); i++ {
if logLine[i] == '"' {
quotes = append(quotes, i)
}
}
// 至少需要 6 个引号: "GET ..." "Referer" "User-Agent"
if len(quotes) >= 6 {
// 倒数第 4 和第 3 个引号之间是 Referer
refererStart := quotes[len(quotes)-4]
refererEnd := quotes[len(quotes)-3]
entry.Referer = logLine[refererStart+1 : refererEnd]
// 倒数第 2 和第 1 个引号之间是 User-Agent
// 如果需要也可以提取
// uaStart := quotes[len(quotes)-2]
// uaEnd := quotes[len(quotes)-1]
// entry.UserAgent = logLine[uaStart+1 : uaEnd]
}
// 查找 ? 后面的查询字符串
idx := strings.Index(logLine, "?")
// 如果没有查询参数,检查是否是直接文件下载
if idx == -1 {
// 检查是否包含 /v1/common/client/download/file/
filePrefix := "/v1/common/client/download/file/"
fileIdx := strings.Index(logLine, filePrefix)
if fileIdx != -1 {
// 提取文件名部分
// URL 形式可能是: /v1/common/client/download/file/Hi%E5%BF%ABVPN-windows-1.0.0.exe HTTP/1.1
// 需要截取到空格
pathStart := fileIdx + len(filePrefix)
pathEnd := strings.Index(logLine[pathStart:], " ")
if pathEnd != -1 {
filePath := logLine[pathStart : pathStart+pathEnd]
// URL 解码
decodedPath, err := url.QueryUnescape(filePath)
if err == nil {
// 转换为小写以便匹配
lowerPath := strings.ToLower(decodedPath)
if strings.Contains(lowerPath, "windows") || strings.HasSuffix(lowerPath, ".exe") {
entry.Platform = "windows"
} else if strings.Contains(lowerPath, "mac") || strings.HasSuffix(lowerPath, ".dmg") {
entry.Platform = "mac"
} else if strings.Contains(lowerPath, "android") || strings.HasSuffix(lowerPath, ".apk") {
entry.Platform = "android"
} else if strings.Contains(lowerPath, "ios") || strings.HasSuffix(lowerPath, ".ipa") {
entry.Platform = "ios"
}
}
}
}
return entry
}
queryStr := logLine[idx+1:]
// 截取到空格或 HTTP/
endIdx := strings.Index(queryStr, " ")
if endIdx != -1 {
queryStr = queryStr[:endIdx]
}
// 解析查询参数
params := strings.Split(queryStr, "&")
for _, param := range params {
kv := strings.SplitN(param, "=", 2)
if len(kv) != 2 {
continue
}
switch kv[0] {
case "data":
entry.Data = kv[1]
case "time":
entry.Time = kv[1]
case "platform":
entry.Platform = kv[1]
}
}
return entry
}
// extractNonceFromTime 从 time 参数中提取 nonce
// time 格式: 2026-02-02T04:35:15.032000
// 需要转换为纳秒时间戳的十六进制
func extractNonceFromTime(timeStr string) string {
if timeStr == "" {
return ""
}
// URL 解码
decoded, err := url.QueryUnescape(timeStr)
if err != nil {
return ""
}
// 简化处理:直接使用整个时间字符串作为 nonce
// 因为原始代码使用 time.Now().UnixNano() 的十六进制
// 但是从日志中我们无法准确还原原始的 nonce
// 所以尝试使用 time 字符串本身
return decoded
}