添加混淆加密的workers

This commit is contained in:
violettools
2026-01-24 13:36:20 +08:00
parent e19e2fce88
commit 7fe49d6485
2 changed files with 647 additions and 0 deletions

1
.gitignore vendored
View File

@@ -15,6 +15,7 @@ edgetunnel_proxy.py
test.py
test_*.py
*.html
!x27cn-pages/index.html
# 镜像输出目录
mirror/

646
x27cn-pages/index.html Normal file
View File

@@ -0,0 +1,646 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CFspider X27CN Decrypt - 专用加密解密工具</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
}
.container {
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(10px);
border-radius: 20px;
padding: 40px;
max-width: 900px;
width: 100%;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
border: 1px solid rgba(255, 255, 255, 0.1);
}
h1 {
color: #e94560;
text-align: center;
margin-bottom: 10px;
font-size: 2rem;
}
.subtitle {
color: #888;
text-align: center;
margin-bottom: 30px;
font-size: 0.9rem;
}
.input-group {
margin-bottom: 20px;
}
label {
display: block;
color: #fff;
margin-bottom: 8px;
font-weight: 500;
}
textarea, input[type="text"] {
width: 100%;
padding: 15px;
border: 2px solid rgba(233, 69, 96, 0.3);
border-radius: 10px;
background: rgba(0, 0, 0, 0.3);
color: #fff;
font-size: 14px;
font-family: 'Consolas', monospace;
transition: all 0.3s ease;
}
textarea:focus, input:focus {
outline: none;
border-color: #e94560;
box-shadow: 0 0 15px rgba(233, 69, 96, 0.3);
}
textarea {
min-height: 180px;
resize: vertical;
}
.btn {
width: 100%;
padding: 15px;
border: none;
border-radius: 10px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
margin-top: 10px;
}
.btn-primary {
background: linear-gradient(135deg, #e94560, #f45c73);
color: #fff;
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 5px 20px rgba(233, 69, 96, 0.4);
}
.btn-secondary {
background: rgba(255, 255, 255, 0.1);
color: #fff;
border: 1px solid rgba(255, 255, 255, 0.2);
}
.btn-secondary:hover {
background: rgba(255, 255, 255, 0.2);
}
.result {
margin-top: 25px;
padding: 20px;
background: rgba(0, 0, 0, 0.3);
border-radius: 10px;
display: none;
}
.result.show {
display: block;
animation: fadeIn 0.3s ease;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
.result-title {
color: #4ade80;
margin-bottom: 15px;
font-weight: 600;
}
.result-content {
background: rgba(0, 0, 0, 0.4);
padding: 15px;
border-radius: 8px;
word-break: break-all;
font-family: 'Consolas', monospace;
color: #4ade80;
font-size: 13px;
max-height: 400px;
overflow-y: auto;
}
.field-row {
margin-bottom: 12px;
padding-bottom: 12px;
border-bottom: 1px solid rgba(255,255,255,0.1);
}
.field-row:last-child {
border-bottom: none;
margin-bottom: 0;
padding-bottom: 0;
}
.field-key {
color: #60a5fa;
font-weight: bold;
margin-bottom: 4px;
}
.field-value {
color: #4ade80;
word-break: break-all;
cursor: pointer;
}
.field-value:hover {
color: #86efac;
}
.vless-link {
color: #fbbf24;
font-weight: bold;
}
.copy-success {
color: #4ade80;
text-align: center;
margin-top: 10px;
font-size: 14px;
display: none;
}
.copy-success.show {
display: block;
animation: fadeIn 0.3s ease;
}
.info-box {
background: rgba(96, 165, 250, 0.1);
border: 1px solid rgba(96, 165, 250, 0.3);
border-radius: 10px;
padding: 15px;
margin-bottom: 20px;
color: #93c5fd;
font-size: 13px;
line-height: 1.6;
}
.info-box code {
background: rgba(0, 0, 0, 0.3);
padding: 2px 6px;
border-radius: 4px;
font-family: 'Consolas', monospace;
}
.btn-group {
display: flex;
gap: 10px;
margin-top: 15px;
flex-wrap: wrap;
}
.btn-group .btn {
flex: 1;
min-width: 150px;
margin-top: 0;
}
.json-view {
background: rgba(0,0,0,0.5);
border-radius: 8px;
padding: 15px;
margin-top: 15px;
white-space: pre-wrap;
font-family: 'Consolas', monospace;
font-size: 12px;
color: #e2e8f0;
max-height: 300px;
overflow-y: auto;
}
.json-key { color: #60a5fa; }
.json-string { color: #4ade80; }
.json-number { color: #fbbf24; }
.json-boolean { color: #f472b6; }
.json-null { color: #9ca3af; }
.tab-group {
display: flex;
gap: 5px;
margin-bottom: 15px;
}
.tab {
padding: 8px 16px;
background: rgba(255,255,255,0.1);
border: none;
border-radius: 8px;
color: #888;
cursor: pointer;
transition: all 0.2s;
}
.tab.active {
background: #e94560;
color: #fff;
}
.tab:hover:not(.active) {
background: rgba(255,255,255,0.2);
}
</style>
</head>
<body>
<div class="container">
<h1>CFspider X27CN Decrypt</h1>
<p class="subtitle">CFspider 项目专用加密解密工具 v2.0 - 支持智能识别多种格式</p>
<div class="info-box">
<strong>CFspider 项目专用解密工具</strong><br><br>
本工具用于解密 CFspider Workers 返回的 X27CN 加密响应。<br><br>
<strong>支持的格式:</strong><br>
• 纯十六进制 X27CN 加密字符串(新版)<br>
• 带颜文字/生僻字的混淆格式(旧版)<br>
• JSON 格式 {"d":"..."} 包装的加密数据
</div>
<div class="input-group">
<label>粘贴 Workers 响应 (任何格式均可)</label>
<textarea id="encryptedData" placeholder="直接粘贴从 Workers 获取的任何响应...
示例1 (加密字符串):
(◕‿◕)龖7f8a2b3c龘d5e6f7a8(◠‿◠)靐b9c0d1e2...
示例2 (旧版JSON):
{&quot;s&quot;:&quot;ok&quot;,&quot;d&quot;:&quot;7f8a2b3c...&quot;}
直接粘贴,自动识别!"></textarea>
</div>
<div class="input-group">
<label>解密密钥 (Key) - 默认无需修改</label>
<input type="text" id="decryptKey" value="x27cn2026" placeholder="x27cn2026">
</div>
<button class="btn btn-primary" onclick="decrypt()">Decrypt</button>
<div class="result" id="result">
<div class="result-title">Decrypted Successfully</div>
<div class="tab-group">
<button class="tab active" onclick="showTab('formatted')">格式化视图</button>
<button class="tab" onclick="showTab('json')">JSON 视图</button>
<button class="tab" onclick="showTab('raw')">原始数据</button>
</div>
<div id="tab-formatted" class="result-content"></div>
<div id="tab-json" class="json-view" style="display:none;"></div>
<div id="tab-raw" class="result-content" style="display:none;"></div>
<div class="btn-group">
<button class="btn btn-secondary" onclick="copyVless()">Copy VLESS</button>
<button class="btn btn-secondary" onclick="copyUUID()">Copy UUID</button>
<button class="btn btn-secondary" onclick="copyJson()">Copy JSON</button>
</div>
<div class="copy-success" id="copySuccess">Copied!</div>
</div>
<div style="margin-top: 30px; padding-top: 20px; border-top: 1px solid rgba(255,255,255,0.1); text-align: center; color: #666; font-size: 12px;">
<p><strong>CFspider</strong> - Cloudflare Workers Proxy Solution</p>
<p>X27CN 加密算法 · XOR + 位旋转 + 颜文字混淆</p>
<p style="margin-top: 10px; color: #888;">© 2026 CFspider Project · Apache 2.0 License</p>
</div>
</div>
<script>
const X27CN_KEY = 'x27cn2026';
// 颜文字和中文乱码列表
const KAOMOJI = ['(◕‿◕)','(。◕‿◕。)','(◠‿◠)','(✿◠‿◠)','(◡‿◡)','(◕ᴗ◕)','(◔‿◔)','(✧ω✧)','(◕◡◕)','(◠ᴗ◠)','♪(´▽`)','(◕‿◕✿)','(✿╹◡╹)','(◕ˇ∀ˇ◕)','(◔◡◔)'];
const CHAOS = ['龖','龘','靐','齉','齾','爨','灪','麤','鱻','驫','骉','羴','猋','蟲','贔','矗','飝','厵','靇','雥'];
let decryptedData = null;
let decryptedJson = null;
// 清理加密字符串 - 支持纯hex和混淆格式
function cleanEncryptedString(str) {
console.log('[清理] 输入长度:', str.length);
// 检查是否为纯hex格式新版Worker
if (/^[0-9a-fA-F]+$/.test(str.trim())) {
console.log('[清理] 检测到纯hex格式');
return str.trim();
}
// 移除所有非hex字符适用于混淆格式和乱码格式
let result = str.replace(/[^0-9a-fA-F]/g, '');
console.log('[清理] 清理后长度:', result.length);
// 确保长度是偶数
if (result.length % 2 !== 0) {
result = result.substring(0, result.length - 1);
}
return result;
}
// x27cn 解密 - 增强版
function x27cnDecrypt(encryptedStr, key = X27CN_KEY) {
if (!encryptedStr) {
console.log('[x27cn] 错误: 输入为空');
return null;
}
const hex = cleanEncryptedString(encryptedStr);
console.log(`[x27cn] 清理后十六进制长度: ${hex.length}, 前32字符: ${hex.substring(0, 32)}`);
if (hex.length === 0) {
console.log('[x27cn] 错误: 清理后没有有效的十六进制字符');
return null;
}
// 如果长度是奇数,尝试移除末尾字符
let finalHex = hex;
if (hex.length % 2 !== 0) {
console.log('[x27cn] 警告: 十六进制长度为奇数,尝试修复');
finalHex = hex.substring(0, hex.length - 1);
}
if (finalHex.length < 4) {
console.log('[x27cn] 错误: 数据太短');
return null;
}
const keyBytes = new TextEncoder().encode(key);
const bytes = new Uint8Array(finalHex.length / 2);
for (let i = 0; i < bytes.length; i++) {
bytes[i] = parseInt(finalHex.substr(i * 2, 2), 16);
}
const result = new Uint8Array(bytes.length);
for (let i = 0; i < bytes.length; i++) {
let b = bytes[i];
b = (b - i + 256) & 0xFF;
b = ((b >> 3) | (b << 5)) & 0xFF;
b = b ^ keyBytes[i % keyBytes.length];
result[i] = b;
}
try {
const decoded = new TextDecoder('utf-8', { fatal: false }).decode(result);
console.log(`[x27cn] 解密成功,长度: ${decoded.length}, 前50字符: ${decoded.substring(0, 50)}`);
return decoded;
} catch (e) {
console.log('[x27cn] UTF-8解码失败尝试其他编码');
return new TextDecoder('utf-8').decode(result);
}
}
// 智能提取加密数据
function extractEncryptedData(input) {
input = input.trim();
// 1. 尝试解析为JSON提取d字段
try {
const json = JSON.parse(input);
if (json.d) return json.d;
if (json.data) return json.data;
// 如果整个JSON就是加密后的内容不太可能
} catch (e) {}
// 2. 检查是否包含JSON中的d字段
const dMatch = input.match(/"d"\s*:\s*"([^"]+)"/);
if (dMatch) return dMatch[1];
const dataMatch = input.match(/"data"\s*:\s*"([^"]+)"/);
if (dataMatch) return dataMatch[1];
// 3. 查找包含颜文字的加密字符串
for (const k of KAOMOJI) {
if (input.includes(k)) {
// 找到颜文字,整个输入就是加密字符串
return input;
}
}
// 4. 查找包含生僻字的加密字符串
for (const c of CHAOS) {
if (input.includes(c)) {
return input;
}
}
// 5. 检查是否是纯十六进制
const hexOnly = input.replace(/\s/g, '');
if (/^[0-9a-fA-F]+$/.test(hexOnly) && hexOnly.length >= 20) {
return hexOnly;
}
// 6. 尝试提取任何看起来像加密数据的部分
const hexMatch = input.match(/[0-9a-fA-F]{20,}/);
if (hexMatch) return hexMatch[0];
// 7. 返回原始输入
return input;
}
// JSON 语法高亮
function syntaxHighlight(json) {
if (typeof json !== 'string') {
json = JSON.stringify(json, null, 2);
}
json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
let cls = 'json-number';
if (/^"/.test(match)) {
if (/:$/.test(match)) {
cls = 'json-key';
} else {
cls = 'json-string';
}
} else if (/true|false/.test(match)) {
cls = 'json-boolean';
} else if (/null/.test(match)) {
cls = 'json-null';
}
return '<span class="' + cls + '">' + match + '</span>';
});
}
function showTab(tabName) {
document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
document.querySelectorAll('[id^="tab-"]').forEach(t => t.style.display = 'none');
document.querySelector(`[onclick="showTab('${tabName}')"]`).classList.add('active');
document.getElementById('tab-' + tabName).style.display = 'block';
}
function decrypt() {
const input = document.getElementById('encryptedData').value.trim();
const key = document.getElementById('decryptKey').value.trim() || X27CN_KEY;
const resultDiv = document.getElementById('result');
if (!input) {
alert('请输入加密数据!');
return;
}
try {
// 智能提取加密数据
const encryptedData = extractEncryptedData(input);
// 解密
const decrypted = x27cnDecrypt(encryptedData, key);
if (!decrypted) {
throw new Error('解密失败 - 无法解析数据');
}
decryptedData = decrypted;
// 尝试解析JSON
try {
decryptedJson = JSON.parse(decrypted);
// 格式化视图
let html = '';
for (const [key, value] of Object.entries(decryptedJson)) {
const isVless = key === 'vless' || (typeof value === 'string' && value.startsWith('vless://'));
const isUuid = key === 'uuid' || key === 'UUID';
const displayValue = typeof value === 'object' ? JSON.stringify(value, null, 2) : value;
html += `<div class="field-row">
<div class="field-key">${key}:</div>
<div class="field-value ${isVless ? 'vless-link' : ''}"
onclick="copyField('${key}')"
title="点击复制">${displayValue}</div>
</div>`;
}
document.getElementById('tab-formatted').innerHTML = html;
// JSON视图
document.getElementById('tab-json').innerHTML = syntaxHighlight(decryptedJson);
} catch (e) {
decryptedJson = null;
document.getElementById('tab-formatted').innerHTML = `<code>${decrypted}</code>`;
document.getElementById('tab-json').innerHTML = '<span style="color:#f87171;">非 JSON 格式</span>';
}
// 原始数据
document.getElementById('tab-raw').textContent = decrypted;
resultDiv.classList.add('show');
showTab('formatted');
} catch (e) {
// 显示更详细的错误信息
const hex = cleanEncryptedString(extractEncryptedData(input));
alert(`解密失败: ${e.message}\n\n调试信息:\n- 输入长度: ${input.length}\n- 清理后十六进制长度: ${hex.length}\n- 前32字符: ${hex.substring(0, 32)}\n\n请确保粘贴了完整的 Workers 响应\n\n如果问题持续,请检查控制台(F12)获取更多信息`);
}
}
function copyField(key) {
if (!decryptedJson || decryptedJson[key] === undefined) return;
const value = typeof decryptedJson[key] === 'object'
? JSON.stringify(decryptedJson[key])
: String(decryptedJson[key]);
copyToClipboard(value);
}
function copyVless() {
let vless = '';
if (decryptedJson) {
vless = decryptedJson.vless || decryptedJson.l || '';
if (!vless) {
for (const v of Object.values(decryptedJson)) {
if (typeof v === 'string' && v.startsWith('vless://')) {
vless = v;
break;
}
}
}
}
if (!vless && decryptedData) {
const m = decryptedData.match(/vless:\/\/[^\s"]+/);
if (m) vless = m[0];
}
if (vless) {
copyToClipboard(vless);
} else {
alert('未找到 VLESS 链接!');
}
}
function copyUUID() {
let uuid = '';
if (decryptedJson) {
uuid = decryptedJson.uuid || decryptedJson.UUID || decryptedJson.u || '';
}
if (!uuid && decryptedData) {
const m = decryptedData.match(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i);
if (m) uuid = m[0];
}
if (uuid) {
copyToClipboard(uuid);
} else {
alert('未找到 UUID');
}
}
function copyJson() {
if (decryptedData) {
copyToClipboard(decryptedData);
}
}
function copyToClipboard(text) {
navigator.clipboard.writeText(text).then(() => {
showCopySuccess();
}).catch(() => {
const ta = document.createElement('textarea');
ta.value = text;
document.body.appendChild(ta);
ta.select();
document.execCommand('copy');
document.body.removeChild(ta);
showCopySuccess();
});
}
function showCopySuccess() {
const el = document.getElementById('copySuccess');
el.classList.add('show');
setTimeout(() => el.classList.remove('show'), 2000);
}
// 粘贴时自动解密
document.getElementById('encryptedData').addEventListener('paste', function() {
setTimeout(() => {
if (this.value.trim().length > 50) {
decrypt();
}
}, 100);
});
</script>
</body>
</html>