// 改枪方案数据采集器 // 在 Windows 上运行: node scrape_schemes.js // 原理: 加载原版 app 的解密模块来解密方案数据 const https = require('https'); const http = require('http'); const crypto = require('crypto'); const fs = require('fs'); const path = require('path'); // ========== 配置 ========== const API_BASE = 'maqt.top'; const TOKEN = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NDc5MTcsInVzZXJuYW1lIjoic2l4dGVlbnRoIiwidG9rZW5WZXJzaW9uIjozLCJpYXQiOjE3NzgyMTI0MDUsImV4cCI6MjA5Mzc4ODQwNX0.B_J0CDtaiiF2jJ592yKtD4RtQDIR3cDF_EYgn2UM2ko'; const CATEGORIES = ['AR','SMG','SR','LMG','SG','Pistol','Launcher']; const OUR_API = 'http://100.105.17.52:3001'; // 导入到自建后端 // ========== 尝试多种 AES 密钥 ========== const KEYS_TO_TRY = [ Buffer.from('maqt-encryption-key-32bytes!', 'utf-8'), // 28 bytes Buffer.from('maqt-encryption-key-32bytes!!', 'utf-8'), // 29 bytes Buffer.from('0123456789abcdef0123456789abcdef', 'utf-8'), // 32 bytes (HEX) Buffer.from('maqt-encryption-key-32byte!', 'utf-8'), // 27 bytes ]; function aesDecrypt(ivHex, dataHex, key) { try { // Pad key to 32 bytes with zeros if needed const keyBuf = key.length === 32 ? key : Buffer.concat([key, Buffer.alloc(32 - key.length)]); const iv = Buffer.from(ivHex, 'hex'); const encrypted = Buffer.from(dataHex, 'hex'); const decipher = crypto.createDecipheriv('aes-256-cbc', keyBuf, iv); let d = decipher.update(encrypted, undefined, 'utf-8'); d += decipher.final('utf-8'); return JSON.parse(d); } catch (e) { return null; } } function fetch(url, postData) { return new Promise((resolve, reject) => { const opts = { hostname: API_BASE, path: url, method: postData ? 'POST' : 'GET', headers: { 'Authorization': `Bearer ${TOKEN}`, 'User-Agent': 'MaQiangTang/7.0.4', 'Accept': 'application/json', }, }; if (postData) { opts.headers['Content-Type'] = 'application/json'; } const req = https.request(opts, res => { let d = ''; res.on('data', c => d += c); res.on('end', () => { try { resolve(JSON.parse(d)); } catch { resolve({ error: 'parse', raw: d.slice(0,100) }); } }); }); req.on('error', reject); if (postData) req.write(JSON.stringify(postData)); req.end(); }); } function tryDecrypt(encrypted) { if (!encrypted.encrypted) return encrypted; for (const key of KEYS_TO_TRY) { const result = aesDecrypt(encrypted.iv, encrypted.data, key); if (result) { console.log(` ✅ 解密成功! 密钥: ${key.toString('utf-8')}`); return result; } } return null; } async function main() { console.log('=== 码枪堂方案数据采集器 ===\n'); // 1. 测试解密 console.log('--- 获取测试数据 ---'); const testData = await fetch('/api/schemes?sort=hot&page=1&limit=2&weaponCategory=AR'); if (testData.encrypted) { console.log(` 加密数据: iv=${testData.iv} data_len=${testData.data.length}`); const decrypted = tryDecrypt(testData); if (!decrypted) { console.log(' ❌ 所有密钥都不匹配'); console.log(' 请从 deobfuscated main.js 中找到正确的密钥'); console.log(' 或在原始应用中运行:'); console.log(' require("crypto").createDecipheriv("aes-256-cbc", , )'); return; } fs.writeFileSync('decrypted_schemes.json', JSON.stringify(decrypted, null, 2)); console.log(' 已保存到 decrypted_schemes.json'); } else { console.log(' 明文响应:', JSON.stringify(testData).slice(0, 500)); } // 2. 如果解密成功,采集所有分类 if (fs.existsSync('decrypted_schemes.json')) { console.log('\n--- 全量采集 ---'); const allSchemes = []; for (const cat of CATEGORIES) { console.log(`\n分类: ${cat}`); for (let page = 1; page <= 5; page++) { const data = await fetch(`/api/schemes?sort=hot&page=${page}&limit=12&weaponCategory=${encodeURIComponent(cat)}`); if (data.encrypted) { const decrypted = tryDecrypt(data); if (decrypted && Array.isArray(decrypted)) { allSchemes.push(...decrypted); console.log(` 第${page}页: ${decrypted.length} 条`); if (decrypted.length < 12) break; } else break; } else break; } } console.log(`\n共采集 ${allSchemes.length} 条方案`); fs.writeFileSync('all_schemes.json', JSON.stringify(allSchemes, null, 2)); } console.log('\n完成'); } main().catch(console.error);