解混淆
This commit is contained in:
550
background.js
Normal file
550
background.js
Normal file
@@ -0,0 +1,550 @@
|
||||
/**
|
||||
* 虚拟身份池
|
||||
* 用于生成随机持卡人姓名
|
||||
*/
|
||||
const FIRST_NAMES = ["John", "Michael", "David", "James", "Robert", "William", "Richard", "Joseph", "Charles", "Thomas", "Christopher", "Daniel", "Matthew", "Anthony", "Mark", "Donald", "Steven", "Paul", "Andrew", "Joshua", "Kenneth", "Kevin", "Brian", "Mary", "Patricia", "Jennifer", "Linda", "Barbara", "Elizabeth", "Susan", "Jessica", "Sarah", "Karen", "Nancy", "Lisa", "Betty", "Margaret", "Sandra"];
|
||||
const LAST_NAMES = ["Smith", "Johnson", "Williams", "Brown", "Jones", "Garcia", "Miller", "Davis", "Rodriguez", "Martinez", "Hernandez", "Lopez", "Gonzalez", "Wilson", "Anderson", "Thomas", "Taylor", "Moore", "Jackson", "Martin", "Lee", "Thompson", "White", "Harris", "Sanchez", "Clark", "Ramirez", "Lewis", "Robinson", "Walker", "Young"];
|
||||
|
||||
/**
|
||||
* 默认地址配置
|
||||
*/
|
||||
const DEFAULT_ADDRESSES = [{
|
||||
name: "John Smith",
|
||||
firstName: "John",
|
||||
lastName: "Smith",
|
||||
address1: "69 Adams Street",
|
||||
address2: "",
|
||||
city: "Brooklyn",
|
||||
state: "New York",
|
||||
stateCode: "NY",
|
||||
postal: "11201",
|
||||
countryText: "United States",
|
||||
countryValue: "US"
|
||||
}, {
|
||||
name: "Michael Johnson",
|
||||
firstName: "Michael",
|
||||
lastName: "Johnson",
|
||||
address1: "3511 Carlisle Avenue",
|
||||
address2: "",
|
||||
city: "Covington",
|
||||
state: "Kentucky",
|
||||
stateCode: "KY",
|
||||
postal: "41015",
|
||||
countryText: "United States",
|
||||
countryValue: "US"
|
||||
}];
|
||||
|
||||
// ==========================================
|
||||
// 算法工具函数 (Luhn Algorithm)
|
||||
// ==========================================
|
||||
|
||||
function randomChoice(array) {
|
||||
return array[Math.floor(Math.random() * array.length)];
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据卡号前缀识别卡组织类型
|
||||
*/
|
||||
function getCardType(cardNumber) {
|
||||
const patterns = {
|
||||
Visa: /^4/,
|
||||
Mastercard: /^5[1-5]/,
|
||||
"American Express": /^3[47]/,
|
||||
Discover: /^6(?:011|5)/,
|
||||
JCB: /^35/,
|
||||
"Diners Club": /^3(?:0[0-5]|[68])/,
|
||||
Maestro: /^(?:5[0678]\d\d|6304|6390|67\d\d)/,
|
||||
UnionPay: /^62/
|
||||
};
|
||||
for (const [type, regex] of Object.entries(patterns)) {
|
||||
if (regex.test(cardNumber)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算 Luhn 校验位 (模10算法)
|
||||
* 用于确保生成的卡号在数学上是有效的
|
||||
*/
|
||||
function calculateLuhnCheckDigit(digits) {
|
||||
let sum = 0;
|
||||
let shouldDouble = true;
|
||||
for (let i = digits.length - 1; i >= 0; i--) {
|
||||
let digit = parseInt(digits[i]);
|
||||
if (shouldDouble) {
|
||||
digit *= 2;
|
||||
if (digit > 9) {
|
||||
digit -= 9;
|
||||
}
|
||||
}
|
||||
sum += digit;
|
||||
shouldDouble = !shouldDouble;
|
||||
}
|
||||
return (10 - sum % 10) % 10;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证卡号是否符合 Luhn 算法
|
||||
*/
|
||||
function validateLuhn(number) {
|
||||
const digits = number.replace(/\D/g, "");
|
||||
let sum = 0;
|
||||
let shouldDouble = false;
|
||||
for (let i = digits.length - 1; i >= 0; i--) {
|
||||
let digit = parseInt(digits[i]);
|
||||
if (shouldDouble) {
|
||||
digit *= 2;
|
||||
if (digit > 9) {
|
||||
digit -= 9;
|
||||
}
|
||||
}
|
||||
sum += digit;
|
||||
shouldDouble = !shouldDouble;
|
||||
}
|
||||
return sum % 10 === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成符合校验规则的卡号
|
||||
* @param {string} binPattern - BIN 格式 (如 "552461xxxxxxxxxx")
|
||||
*/
|
||||
function generateValidCardNumber(binPattern) {
|
||||
let rawNumber = "";
|
||||
// 1. 填充随机数
|
||||
for (let i = 0; i < binPattern.length - 1; i++) {
|
||||
if (binPattern[i] === "x" || binPattern[i] === "X") {
|
||||
rawNumber += Math.floor(Math.random() * 10);
|
||||
} else {
|
||||
rawNumber += binPattern[i];
|
||||
}
|
||||
}
|
||||
// 2. 计算最后一位校验码
|
||||
const checkDigit = calculateLuhnCheckDigit(rawNumber);
|
||||
rawNumber += checkDigit;
|
||||
return rawNumber;
|
||||
}
|
||||
|
||||
function generateExpiryDate() {
|
||||
const now = new Date();
|
||||
const currentYear = now.getFullYear();
|
||||
const currentMonth = now.getMonth() + 1;
|
||||
|
||||
// 随机生成 1 到 60 个月后的日期
|
||||
const randomMonths = Math.floor(Math.random() * 60) + 1;
|
||||
let targetMonth = currentMonth + randomMonths;
|
||||
let targetYear = currentYear;
|
||||
|
||||
while (targetMonth > 12) {
|
||||
targetMonth -= 12;
|
||||
targetYear += 1;
|
||||
}
|
||||
|
||||
return {
|
||||
month: targetMonth.toString().padStart(2, "0"),
|
||||
year: targetYear.toString()
|
||||
};
|
||||
}
|
||||
|
||||
function generateCVV(length = 3) {
|
||||
let cvv = "";
|
||||
for (let i = 0; i < length; i++) {
|
||||
cvv += Math.floor(Math.random() * 10);
|
||||
}
|
||||
return cvv;
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 核心生成逻辑
|
||||
// ==========================================
|
||||
|
||||
/**
|
||||
* 本地生成模式:使用内置算法生成卡号
|
||||
*/
|
||||
function generateCardsLocally(bin, amount = 10) {
|
||||
const cards = [];
|
||||
const uniqueSet = new Set();
|
||||
console.log(`🎲 Generating ${amount} valid cards from BIN: ${bin}`);
|
||||
|
||||
let attempts = 0;
|
||||
const maxAttempts = amount * 10;
|
||||
|
||||
while (cards.length < amount && attempts < maxAttempts) {
|
||||
attempts++;
|
||||
const number = generateValidCardNumber(bin);
|
||||
|
||||
if (uniqueSet.has(number)) continue;
|
||||
if (!validateLuhn(number)) {
|
||||
console.warn("⚠️ Generated invalid card (should not happen):", number);
|
||||
continue;
|
||||
}
|
||||
|
||||
uniqueSet.add(number);
|
||||
const expiry = generateExpiryDate();
|
||||
const cvv = generateCVV(3);
|
||||
const type = getCardType(number);
|
||||
|
||||
cards.push({
|
||||
serial_number: cards.length + 1,
|
||||
card_number: number,
|
||||
expiry_month: expiry.month,
|
||||
expiry_year: expiry.year,
|
||||
cvv: cvv,
|
||||
card_type: type,
|
||||
full_format: `${number}|${expiry.month}|${expiry.year}|${cvv}`,
|
||||
luhn_valid: true
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`[cardbingenerator] Successfully generated ${cards.length} valid cards`);
|
||||
|
||||
// 最后的完整性检查
|
||||
const invalid = cards.filter(c => !validateLuhn(c.card_number));
|
||||
if (invalid.length > 0) {
|
||||
console.error(`❌ Found ${invalid.length} invalid cards!`);
|
||||
} else {
|
||||
console.log("[cardbingenerator] All cards passed Luhn validation");
|
||||
}
|
||||
|
||||
// 统计卡种分布
|
||||
const stats = {};
|
||||
cards.forEach(c => {
|
||||
stats[c.card_type] = (stats[c.card_type] || 0) + 1;
|
||||
});
|
||||
console.log("📊 Card types:", stats);
|
||||
|
||||
return cards;
|
||||
}
|
||||
|
||||
/**
|
||||
* 简单生成模式:仅生成随机数,不进行 Luhn 校验 (用于某些不需要校验的测试场景)
|
||||
*/
|
||||
function generateCardsSimple(bin, amount = 10) {
|
||||
const cards = [];
|
||||
const uniqueSet = new Set();
|
||||
console.log(`🎲 Generating ${amount} cards (no validation) from BIN: ${bin}`);
|
||||
|
||||
for (let i = 0; i < amount; i++) {
|
||||
let number = "";
|
||||
for (let j = 0; j < bin.length; j++) {
|
||||
if (bin[j] === "x" || bin[j] === "X") {
|
||||
number += Math.floor(Math.random() * 10);
|
||||
} else {
|
||||
number += bin[j];
|
||||
}
|
||||
}
|
||||
|
||||
if (uniqueSet.has(number)) {
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
uniqueSet.add(number);
|
||||
const expiry = generateExpiryDate();
|
||||
const cvv = generateCVV(3);
|
||||
const type = getCardType(number);
|
||||
|
||||
cards.push({
|
||||
serial_number: i + 1,
|
||||
card_number: number,
|
||||
expiry_month: expiry.month,
|
||||
expiry_year: expiry.year,
|
||||
cvv: cvv,
|
||||
card_type: type,
|
||||
full_format: `${number}|${expiry.month}|${expiry.year}|${cvv}`,
|
||||
luhn_valid: false
|
||||
});
|
||||
}
|
||||
console.log(`[cardbingenerator] Generated ${cards.length} cards (simple mode)`);
|
||||
return cards;
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 远程生成逻辑 (AKR-Gen)
|
||||
// ==========================================
|
||||
|
||||
/**
|
||||
* 远程生成模式:操控第三方网站 (akr-gen.bigfk.com) 生成卡号
|
||||
* 当本地算法不满足需求时使用
|
||||
*/
|
||||
async function generateCardsFromAKR(bin, onComplete) {
|
||||
let tab = null;
|
||||
try {
|
||||
console.log("[cardbingenerator] Opening AKR-gen tab...");
|
||||
// 创建一个不激活的标签页(后台静默打开)
|
||||
tab = await chrome.tabs.create({
|
||||
url: "https://akr-gen.bigfk.com/",
|
||||
active: false
|
||||
});
|
||||
|
||||
console.log("[cardbingenerator] Waiting for page load...");
|
||||
await new Promise(resolve => setTimeout(resolve, 4000));
|
||||
|
||||
console.log("[cardbingenerator] Filling BIN and generating cards...");
|
||||
// 注入脚本:自动填入BIN并点击生成
|
||||
const fillResult = await chrome.scripting.executeScript({
|
||||
target: { tabId: tab.id },
|
||||
func: remotePage_fillAndClick,
|
||||
args: [bin]
|
||||
});
|
||||
console.log("Fill result:", fillResult[0]?.result);
|
||||
|
||||
console.log("⏳ Waiting a moment before checking results...");
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
console.log("📥 Getting generated cards (will wait up to 10 seconds)...");
|
||||
// 注入脚本:抓取结果
|
||||
const scrapeResult = await chrome.scripting.executeScript({
|
||||
target: { tabId: tab.id },
|
||||
func: remotePage_scrapeResults
|
||||
});
|
||||
|
||||
console.log("[cardbingenerator] Closing AKR-gen tab...");
|
||||
await chrome.tabs.remove(tab.id);
|
||||
tab = null;
|
||||
|
||||
if (scrapeResult && scrapeResult[0] && scrapeResult[0].result) {
|
||||
const parsedCards = parseScrapedCards(scrapeResult[0].result);
|
||||
console.log(`[cardbingenerator] Generated ${parsedCards.length} cards`);
|
||||
|
||||
if (parsedCards.length > 0) {
|
||||
const randomAddr = await getRandomAddress();
|
||||
// 存入 storage 供 Content Script 使用
|
||||
chrome.storage.local.set({
|
||||
generatedCards: parsedCards,
|
||||
randomData: randomAddr
|
||||
});
|
||||
onComplete({ success: true, cards: parsedCards });
|
||||
} else {
|
||||
console.error("❌ No cards generated from AKR");
|
||||
onComplete({ success: false, error: "No cards generated from AKR-gen" });
|
||||
}
|
||||
} else {
|
||||
console.error("❌ Failed to retrieve cards from result");
|
||||
onComplete({ success: false, error: "Failed to retrieve cards from page" });
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
console.error("❌ Error in generateCardsFromAKR:", err);
|
||||
if (tab) {
|
||||
try { await chrome.tabs.remove(tab.id); } catch (e) {}
|
||||
}
|
||||
onComplete({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
// -- 以下函数会被注入到目标页面执行,不能使用外部变量 --
|
||||
|
||||
function remotePage_fillAndClick(bin) {
|
||||
return new Promise(resolve => {
|
||||
function waitForElement(selector, retries = 10, delay = 300) {
|
||||
return new Promise(res => {
|
||||
let count = 0;
|
||||
const check = () => {
|
||||
const el = document.querySelector(selector) || document.getElementById(selector.replace("#", ""));
|
||||
if (el) {
|
||||
res(el);
|
||||
} else if (count < retries) {
|
||||
count++;
|
||||
setTimeout(check, delay);
|
||||
} else {
|
||||
res(null);
|
||||
}
|
||||
};
|
||||
check();
|
||||
});
|
||||
}
|
||||
|
||||
waitForElement("bin").then(input => {
|
||||
if (input) {
|
||||
console.log("[cardbingenerator] Found BIN input, filling with:", bin);
|
||||
input.value = bin;
|
||||
input.dispatchEvent(new Event("input", { bubbles: true }));
|
||||
input.dispatchEvent(new Event("change", { bubbles: true }));
|
||||
|
||||
setTimeout(() => {
|
||||
waitForElement("button[type=\"submit\"]").then(btn => {
|
||||
if (btn) {
|
||||
console.log("[cardbingenerator] Found generate button, clicking...");
|
||||
btn.click();
|
||||
resolve(true);
|
||||
} else {
|
||||
console.error("❌ Generate button not found");
|
||||
resolve(false);
|
||||
}
|
||||
});
|
||||
}, 500);
|
||||
} else {
|
||||
console.error("❌ BIN input not found");
|
||||
resolve(false);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function remotePage_scrapeResults() {
|
||||
return new Promise(resolve => {
|
||||
function waitLoop(retries = 20, delay = 500) {
|
||||
let count = 0;
|
||||
const check = () => {
|
||||
const resultArea = document.getElementById("result");
|
||||
if (resultArea && resultArea.value.trim()) {
|
||||
console.log("[cardbingenerator] Found generated cards:", resultArea.value.split("\n").length, "lines");
|
||||
resolve(resultArea.value);
|
||||
} else if (count < retries) {
|
||||
count++;
|
||||
console.log(`[cardbingenerator] Waiting for cards... attempt ${count}/${retries}`);
|
||||
setTimeout(check, delay);
|
||||
} else {
|
||||
console.error("❌ Timeout waiting for cards");
|
||||
resolve("");
|
||||
}
|
||||
};
|
||||
check();
|
||||
}
|
||||
waitLoop();
|
||||
});
|
||||
}
|
||||
|
||||
// ----------------------------------------------------
|
||||
|
||||
function parseScrapedCards(text) {
|
||||
if (!text) return [];
|
||||
const lines = text.trim().split("\n");
|
||||
const cards = [];
|
||||
|
||||
lines.forEach((line, index) => {
|
||||
if (line.trim()) {
|
||||
const parts = line.trim().split("|");
|
||||
if (parts.length === 4) {
|
||||
cards.push({
|
||||
serial_number: index + 1,
|
||||
card_number: parts[0],
|
||||
expiry_month: parts[1],
|
||||
expiry_year: parts[2],
|
||||
cvv: parts[3],
|
||||
full_format: line.trim()
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
return cards;
|
||||
}
|
||||
|
||||
/**
|
||||
* 辅助:获取随机地址
|
||||
*/
|
||||
async function getRandomAddress() {
|
||||
return new Promise(resolve => {
|
||||
chrome.storage.local.get(["customAddresses"], data => {
|
||||
const custom = data.customAddresses || [];
|
||||
const pool = [...custom, ...DEFAULT_ADDRESSES];
|
||||
if (pool.length === 0) {
|
||||
resolve(DEFAULT_ADDRESSES[0]);
|
||||
} else {
|
||||
const selected = randomChoice(pool);
|
||||
resolve(selected);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 数据清理逻辑 (Browsing Data API)
|
||||
// ==========================================
|
||||
|
||||
async function clearStripeBrowsingData(sendResponse) {
|
||||
try {
|
||||
const domains = ["stripe.com", "checkout.stripe.com", "js.stripe.com", "hooks.stripe.com"];
|
||||
|
||||
// 1. 深度清理 Cookies (针对特定域)
|
||||
for (const domain of domains) {
|
||||
const cookies = await chrome.cookies.getAll({ domain: domain });
|
||||
for (const cookie of cookies) {
|
||||
await chrome.cookies.remove({
|
||||
url: "https://" + cookie.domain + cookie.path,
|
||||
name: cookie.name
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 清理浏览器缓存和存储 (针对特定 Origin)
|
||||
await chrome.browsingData.remove({
|
||||
origins: domains.map(d => "https://" + d)
|
||||
}, {
|
||||
cache: true,
|
||||
cookies: true,
|
||||
localStorage: true,
|
||||
indexedDB: true,
|
||||
serviceWorkers: true,
|
||||
cacheStorage: true
|
||||
});
|
||||
|
||||
console.log("[cardbingenerator] Deep clear completed for Stripe domains");
|
||||
if (sendResponse) sendResponse({ success: true });
|
||||
|
||||
} catch (err) {
|
||||
console.error("Error in deep clear:", err);
|
||||
if (sendResponse) sendResponse({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 消息监听与路由
|
||||
// ==========================================
|
||||
|
||||
// 安装时初始化默认 BIN
|
||||
chrome.runtime.onInstalled.addListener(() => {
|
||||
chrome.storage.local.get(["currentBin", "binHistory"], data => {
|
||||
if (!data.currentBin) {
|
||||
chrome.storage.local.set({
|
||||
currentBin: "552461xxxxxxxxxx",
|
||||
binHistory: ["552461xxxxxxxxxx"]
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 主消息处理器
|
||||
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
||||
if (request.action === "generateCards") {
|
||||
// 路由到生成逻辑
|
||||
generateCardsHandler(request.bin, request.useValidation, sendResponse);
|
||||
return true; // 保持消息通道打开以进行异步响应
|
||||
}
|
||||
if (request.action === "clearBrowsingData") {
|
||||
// 路由到清理逻辑
|
||||
clearStripeBrowsingData(sendResponse);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
async function generateCardsHandler(bin, useValidation = true, sendResponse) {
|
||||
try {
|
||||
console.log(`[cardbingenerator] Starting card generation... (Luhn: ${useValidation ? "ON" : "OFF"})`);
|
||||
|
||||
// 根据配置决定是验证 Luhn 还是简单生成
|
||||
const cards = useValidation ?
|
||||
generateCardsLocally(bin, 10) :
|
||||
generateCardsSimple(bin, 10);
|
||||
|
||||
if (cards.length > 0) {
|
||||
const address = await getRandomAddress();
|
||||
|
||||
// 将结果存入 storage,这样 Content Script (第一部分代码) 就能读到了
|
||||
chrome.storage.local.set({
|
||||
generatedCards: cards,
|
||||
randomData: address
|
||||
});
|
||||
|
||||
console.log(`[cardbingenerator] Generated and saved ${cards.length} cards`);
|
||||
sendResponse({ success: true, cards: cards });
|
||||
} else {
|
||||
console.error("❌ No cards generated");
|
||||
sendResponse({ success: false, error: "Failed to generate cards" });
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("❌ Error in generateCardsHandler:", err);
|
||||
sendResponse({ success: false, error: err.message });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user