@banana020/ast-plugin-system
Version:
AST插件系统 - 支持JavaScript/TypeScript代码转换,包含十六进制转换、代码清理等功能
1,067 lines (1,066 loc) • 34.4 kB
JavaScript
import { p as parseCode, g as generateCode } from "./index-Cq5607iS.js";
import traverseModule from "@babel/traverse";
import { d as delExtra } from "./del-extra-DOJZIMAt.js";
import { d as removeVarComma, f as formatMember, i as renameVar, t as transCondition, c as conditionToIf, a as andToIf, b as conditionVarToIf, r as removeComma, e as clearBinaryIfDeadCode, g as calcBinary, h as addCatchLog } from "./rename-var-BF8V_HJx.js";
import t from "@babel/types";
import generatorModule from "@babel/generator";
function isUnusedFunction(path, functionName) {
const binding = path.scope.getBinding(functionName);
if (!binding) {
return false;
}
if (binding.constantViolations.length > 0) {
return false;
}
return binding.referencePaths.length === 0;
}
const clearNotUseFunction = (path) => {
if (!t.isFunctionDeclaration(path.node)) {
return;
}
const functionNode = path.node;
if (!functionNode.id || !functionNode.id.name) {
return;
}
const functionName = functionNode.id.name;
if (isUnusedFunction(path, functionName)) {
console.log(`🗑️ 移除未使用的函数: ${functionName}`);
path.remove();
}
};
const clearNotUseVar = (path) => {
if (!t.isVariableDeclaration(path.node)) {
return;
}
if (!path.getFunctionParent()) {
return;
}
const variableDeclaration = path.node;
const usedDeclarations = [];
for (const declarator of variableDeclaration.declarations) {
if (t.isIdentifier(declarator.id)) {
const variableName = declarator.id.name;
if (isVariableUsed(path, variableName)) {
usedDeclarations.push(declarator);
}
} else {
usedDeclarations.push(declarator);
}
}
if (usedDeclarations.length > 0) {
variableDeclaration.declarations = usedDeclarations;
} else {
path.remove();
}
};
function isVariableUsed(path, variableName) {
const binding = path.scope.getBinding(variableName);
if (!binding) {
return true;
}
if (binding.constantViolations.length > 0) {
return true;
}
return binding.referencePaths.length > 0;
}
const traverse$4 = traverseModule.default || traverseModule;
const generator$1 = generatorModule.default || generatorModule;
function executeInSandbox$1(code, targetVarName) {
try {
const func = new Function(`
${code}
return typeof ${targetVarName} !== 'undefined' ? ${targetVarName} : null;
`);
const result = func();
return { success: true, result };
} catch (error) {
console.error("代码执行错误:", error);
return { success: false, error };
}
}
const getDecodeFn$1 = (ast) => {
let decodeFnName = null;
const initNodes = [];
traverse$4(ast, {
FunctionDeclaration(path) {
const { id, params, body } = path.node;
if (id && params.length === 0 && body.body.length === 0) {
decodeFnName = id.name;
console.log(`找到载体函数: ${decodeFnName}`);
path.stop();
}
}
});
if (!decodeFnName) {
throw new Error("未能动态找到载体函数!");
}
traverse$4(ast, {
AssignmentExpression(path) {
const { left } = path.node;
if (t.isMemberExpression(left) && t.isIdentifier(left.object, { name: decodeFnName })) {
initNodes.push(path.parentPath.node);
}
}
});
console.log(`找到 ${initNodes.length} 个相关的初始化/代理节点`);
let decodeFnObject = null;
try {
let initScript = `function ${decodeFnName}() {}
`;
initScript += initNodes.map((node) => generator$1(node).code).join("\n");
const executionResult = executeInSandbox$1(initScript, decodeFnName);
if (!executionResult.success) {
throw executionResult.error;
}
decodeFnObject = executionResult.result;
console.log("沙箱执行成功, 载体对象已初始化。");
} catch (e) {
console.error("沙箱执行失败:", e);
throw new Error(`沙箱执行失败: ${e}`);
}
if (!decodeFnObject) {
throw new Error("沙箱执行失败, 载体对象未初始化。");
}
return { decodeFnName, decodeFnObject };
};
const removeAndReplace$1 = (path, options) => {
if (!(options == null ? void 0 : options.decodeFnName) || !(options == null ? void 0 : options.decodeFnObject)) {
return;
}
const { decodeFnName, decodeFnObject } = options;
if (!t.isFunction(path.node)) {
return;
}
const aliasMap = /* @__PURE__ */ new Map();
const functionName = getFunctionName$1(path.node);
try {
buildAliasMapping$1(path, decodeFnName, aliasMap);
removeShiftStatements$1(path, aliasMap);
replaceDecryptedCalls$1(path, aliasMap, decodeFnObject);
} catch (error) {
console.warn(`处理函数 "${functionName}" 时发生错误:`, error);
}
};
function getFunctionName$1(node) {
if (t.isFunctionDeclaration(node) && node.id) {
return node.id.name;
}
if (t.isFunctionExpression(node) && node.id) {
return node.id.name;
}
return "anonymous";
}
function buildAliasMapping$1(functionPath, decodeFnName, aliasMap) {
if (!t.isFunction(functionPath.node) || !functionPath.node.body) {
return;
}
const bodyPath = functionPath.get("body");
if (!bodyPath || Array.isArray(bodyPath)) {
return;
}
bodyPath.traverse({
VariableDeclarator(declPath) {
if (!t.isIdentifier(declPath.node.id) || !declPath.node.init) {
return;
}
const varName = declPath.node.id.name;
const init = declPath.get("init");
if (!init || Array.isArray(init)) {
return;
}
if (handleDirectAssignment$1(init, decodeFnName, varName, aliasMap, declPath)) {
return;
}
if (handleAliasTransfer$1(init, varName, aliasMap)) {
declPath.remove();
return;
}
if (handleConcatPattern$1(init, varName, aliasMap, declPath)) {
return;
}
if (handleArrayAccess$1(init, varName, aliasMap, declPath)) {
return;
}
}
});
}
function handleDirectAssignment$1(init, decodeFnName, varName, aliasMap, declPath) {
if (!init.isMemberExpression()) {
return false;
}
const objectPath = init.get("object");
if (!objectPath.isIdentifier({ name: decodeFnName })) {
return false;
}
const targetName = generatorModule(init.node).code;
const parts = targetName.split(".");
if (parts.length === 2) {
aliasMap.set(varName, {
targetName,
propertyName: parts[1]
});
declPath.remove();
return true;
}
return false;
}
function handleAliasTransfer$1(init, varName, aliasMap) {
if (!init.isIdentifier()) {
return false;
}
const sourceAlias = aliasMap.get(init.node.name);
if (sourceAlias) {
aliasMap.set(varName, sourceAlias);
return true;
}
return false;
}
function handleConcatPattern$1(init, varName, aliasMap, declPath) {
if (!init.isCallExpression()) {
return false;
}
const callee = init.get("callee");
if (!callee.isMemberExpression()) {
return false;
}
const property = callee.get("property");
if (!property.isIdentifier({ name: "concat" })) {
return false;
}
const args = init.get("arguments");
if (args.length !== 1 || !args[0].isIdentifier()) {
return false;
}
const aliasSource = args[0].node.name;
const sourceAlias = aliasMap.get(aliasSource);
if (sourceAlias) {
const arrayKey = `${varName}[1]`;
aliasMap.set(arrayKey, sourceAlias);
declPath.remove();
return true;
}
return false;
}
function handleArrayAccess$1(init, varName, aliasMap, declPath) {
if (!init.isMemberExpression()) {
return false;
}
const objectPath = init.get("object");
const propertyPath = init.get("property");
if (!objectPath.isIdentifier() || !propertyPath.isNumericLiteral()) {
return false;
}
const arrayName = objectPath.node.name;
const index = propertyPath.node.value;
const arrayKey = `${arrayName}[${index}]`;
const sourceAlias = aliasMap.get(arrayKey);
if (sourceAlias) {
aliasMap.set(varName, sourceAlias);
declPath.remove();
return true;
}
return false;
}
function removeShiftStatements$1(functionPath, aliasMap) {
if (!t.isFunction(functionPath.node) || !functionPath.node.body) {
return;
}
const bodyPath = functionPath.get("body");
if (!bodyPath || Array.isArray(bodyPath)) {
return;
}
const statementsToRemove = [];
bodyPath.traverse({
ExpressionStatement(stmtPath) {
const expression = stmtPath.get("expression");
if (!expression.isCallExpression()) {
return;
}
const callee = expression.get("callee");
if (!callee.isMemberExpression()) {
return;
}
const calleeObject = callee.get("object");
const calleeProperty = callee.get("property");
if (!calleeObject.isIdentifier() || !calleeProperty.isIdentifier({ name: "shift" })) {
return;
}
const calleeName = calleeObject.node.name;
const arrayKey = `${calleeName}[1]`;
if (aliasMap.has(calleeName) || aliasMap.has(arrayKey)) {
statementsToRemove.push(stmtPath);
}
}
});
for (const stmt of statementsToRemove) {
stmt.remove();
}
}
function replaceDecryptedCalls$1(functionPath, aliasMap, decodeFnObject) {
if (!t.isFunction(functionPath.node) || !functionPath.node.body) {
return;
}
const bodyPath = functionPath.get("body");
if (!bodyPath || Array.isArray(bodyPath)) {
return;
}
bodyPath.traverse({
CallExpression(callPath) {
const callee = callPath.get("callee");
if (!callee.isIdentifier()) {
return;
}
const calleeName = callee.node.name;
const aliasInfo = aliasMap.get(calleeName);
if (!(aliasInfo == null ? void 0 : aliasInfo.propertyName)) {
return;
}
const args = callPath.get("arguments");
if (args.length !== 1 || !args[0].isNumericLiteral()) {
return;
}
const argValue = args[0].node.value;
try {
const decodeFn = decodeFnObject[aliasInfo.propertyName];
if (typeof decodeFn === "function") {
const realValue = decodeFn(argValue);
if (typeof realValue === "string") {
callPath.replaceWith(t.stringLiteral(realValue));
}
}
} catch (error) {
console.warn(`解密调用 ${calleeName}(${argValue}) 失败:`, error);
}
}
});
}
const removeFor$1 = (path, options) => {
if (!options) {
return;
}
const { decodeFnObject, decodeFnName } = options;
if (!t.isForStatement(path.node)) {
return;
}
const forStatement = path.node;
const prevSiblingPath = path.getPrevSibling();
const variableDeclaration = validateAndGetVariableDeclaration$1(prevSiblingPath, decodeFnName, decodeFnObject);
if (!variableDeclaration) {
return;
}
const forStatementInfo = validateForStatement$1(forStatement);
if (!forStatementInfo) {
return;
}
const { switchStatement, forTest } = forStatementInfo;
const initialValue = calculateMemberExpressionValue$1(variableDeclaration.init, decodeFnName, decodeFnObject);
const breakValue = calculateMemberExpressionValue$1(forTest.right, decodeFnName, decodeFnObject);
if (initialValue === null || breakValue === null) {
return;
}
const resultBody = processSwitchCases$1(
switchStatement.cases,
initialValue,
breakValue,
decodeFnName,
decodeFnObject
);
path.replaceWithMultiple(resultBody);
prevSiblingPath.remove();
};
function validateAndGetVariableDeclaration$1(prevSiblingPath, decodeFnName, decodeFnObject) {
if (!Array.isArray(prevSiblingPath.container)) {
return null;
}
const firstStatement = prevSiblingPath.container[0];
if (!t.isVariableDeclaration(firstStatement)) {
return null;
}
const declaration = firstStatement.declarations[0];
if (!declaration || !declaration.init) {
return null;
}
if (!isValidDecodeMemberExpression$1(declaration.init)) {
return null;
}
const memberExpr = declaration.init;
const callExpr = memberExpr.object.object;
const callee = callExpr.callee;
if (!t.isIdentifier(callee.object) || callee.object.name !== decodeFnName) {
return null;
}
if (!t.isIdentifier(callee.property) || !decodeFnObject[callee.property.name]) {
return null;
}
const originDecodeFn = decodeFnObject[callee.property.name];
const decodeFn = (first, second) => originDecodeFn()[first][second];
return { init: declaration.init, decodeFn };
}
function validateForStatement$1(forStatement) {
if (!t.isBlockStatement(forStatement.body)) {
return null;
}
const body = forStatement.body.body;
if (body.length === 0 || !t.isSwitchStatement(body[0])) {
return null;
}
const switchStatement = body[0];
if (!t.isIdentifier(switchStatement.discriminant)) {
return null;
}
if (!t.isBinaryExpression(forStatement.test)) {
return null;
}
const forTest = forStatement.test;
if (!isValidDecodeMemberExpression$1(forTest.right)) {
return null;
}
return { switchStatement, forTest };
}
function calculateMemberExpressionValue$1(node, decodeFnName, decodeFnObject) {
if (!isValidDecodeMemberExpression$1(node)) {
return null;
}
try {
const memberExpr = node;
const firstIndex = memberExpr.object.property.value;
const secondIndex = memberExpr.property.value;
const callExpr = memberExpr.object.object;
const callee = callExpr.callee;
if (!t.isIdentifier(callee.object) || callee.object.name !== decodeFnName) {
return null;
}
if (!t.isIdentifier(callee.property) || !decodeFnObject[callee.property.name]) {
return null;
}
const originDecodeFn = decodeFnObject[callee.property.name];
const decodeFn = (first, second) => originDecodeFn()[first][second];
return decodeFn(firstIndex, secondIndex);
} catch {
return null;
}
}
function processSwitchCases$1(cases, initialValue, breakValue, decodeFnName, decodeFnObject) {
const resultBody = [];
let currentValue = initialValue;
while (currentValue !== breakValue) {
let foundCase = false;
for (const switchCase of cases) {
if (!switchCase.test || !t.isMemberExpression(switchCase.test)) {
continue;
}
const caseValue = calculateMemberExpressionValue$1(switchCase.test, decodeFnName, decodeFnObject);
if (caseValue === currentValue) {
foundCase = true;
const caseBody = [...switchCase.consequent];
if (caseBody.length > 0 && t.isBreakStatement(caseBody[caseBody.length - 1])) {
caseBody.pop();
}
const nextValue = processStateUpdate$1(caseBody, decodeFnName, decodeFnObject);
if (nextValue !== null) {
currentValue = nextValue;
} else {
resultBody.push(...caseBody);
return resultBody;
}
resultBody.push(...caseBody);
break;
}
}
if (!foundCase) {
break;
}
}
return resultBody;
}
function processStateUpdate$1(caseBody, decodeFnName, decodeFnObject) {
if (caseBody.length < 1) {
return null;
}
const lastStatement = caseBody[caseBody.length - 1];
if (t.isExpressionStatement(lastStatement)) {
const expr = lastStatement.expression;
if (t.isAssignmentExpression(expr) && isValidDecodeMemberExpression$1(expr.right)) {
caseBody.pop();
return calculateMemberExpressionValue$1(expr.right, decodeFnName, decodeFnObject);
}
}
return null;
}
function isValidDecodeMemberExpression$1(node) {
if (!t.isMemberExpression(node)) return false;
if (!t.isMemberExpression(node.object)) return false;
if (!t.isCallExpression(node.object.object)) return false;
if (!t.isMemberExpression(node.object.object.callee)) return false;
if (!t.isNumericLiteral(node.object.property)) return false;
if (!t.isNumericLiteral(node.property)) return false;
return true;
}
const traverse$3 = traverseModule.default || traverseModule;
function geetest3Defusion(jscode) {
let ast = parseCode(jscode);
const code = multiProcessDefusion(jscode, { clearNotUse: true });
ast = parseCode(code);
traverse$3(ast, { VariableDeclarator: removeVarComma });
const { decodeFnName, decodeFnObject } = getDecodeFn$1(ast);
traverse$3(ast, { Function: (path) => removeAndReplace$1(path, { decodeFnName, decodeFnObject }) });
traverse$3(ast, { ForStatement: (path) => removeFor$1(path, { decodeFnObject, decodeFnName }) });
traverse$3(ast, { MemberExpression: formatMember });
return generateCode(ast);
}
function getTsfq(jscode) {
const code = geetest3Defusion(jscode);
let ast = parseCode(code);
let tsfq = "";
traverse$3(ast, {
StringLiteral(path) {
if (path.node.value.includes("tsfq")) {
tsfq = path.node.value.split('"tsfq":')[1].split('"')[1];
}
}
});
if (!tsfq) throw new Error("tsfq not found");
return tsfq;
}
const traverse$2 = traverseModule.default || traverseModule;
const generator = generatorModule.default || generatorModule;
function executeInSandbox(code, targetVarName) {
try {
const func = new Function(`
${code}
return typeof ${targetVarName} !== 'undefined' ? ${targetVarName} : null;
`);
const result = func();
return { success: true, result };
} catch (error) {
console.error("代码执行错误:", error);
return { success: false, error };
}
}
const getDecodeFn = (ast) => {
let decodeFnName = null;
const initNodes = [];
traverse$2(ast, {
FunctionDeclaration(path) {
const { id, params, body } = path.node;
if (id && params.length === 0 && body.body.length === 0) {
decodeFnName = id.name;
console.log(`找到载体函数: ${decodeFnName}`);
path.stop();
}
}
});
if (!decodeFnName) {
throw new Error("未能动态找到载体函数!");
}
traverse$2(ast, {
AssignmentExpression(path) {
const { left } = path.node;
if (t.isMemberExpression(left) && t.isIdentifier(left.object, { name: decodeFnName })) {
initNodes.push(path.parentPath.node);
}
}
});
console.log(`找到 ${initNodes.length} 个相关的初始化/代理节点`);
let decodeFnObject = null;
try {
let initScript = `function ${decodeFnName}() {}
`;
initScript += initNodes.map((node) => generator(node).code).join("\n");
const executionResult = executeInSandbox(initScript, decodeFnName);
if (!executionResult.success) {
throw executionResult.error;
}
decodeFnObject = executionResult.result;
console.log("沙箱执行成功, 载体对象已初始化。");
} catch (e) {
console.error("沙箱执行失败:", e);
throw new Error(`沙箱执行失败: ${e}`);
}
if (!decodeFnObject) {
throw new Error("沙箱执行失败, 载体对象未初始化。");
}
return { decodeFnName, decodeFnObject };
};
const removeAndReplace = (path, options) => {
if (!(options == null ? void 0 : options.decodeFnName) || !(options == null ? void 0 : options.decodeFnObject)) {
return;
}
const { decodeFnName, decodeFnObject } = options;
if (!t.isFunction(path.node)) {
return;
}
const aliasMap = /* @__PURE__ */ new Map();
const functionName = getFunctionName(path.node);
try {
buildAliasMapping(path, decodeFnName, aliasMap);
removeShiftStatements(path, aliasMap);
replaceDecryptedCalls(path, aliasMap, decodeFnObject);
} catch (error) {
console.warn(`处理函数 "${functionName}" 时发生错误:`, error);
}
};
function getFunctionName(node) {
if (t.isFunctionDeclaration(node) && node.id) {
return node.id.name;
}
if (t.isFunctionExpression(node) && node.id) {
return node.id.name;
}
return "anonymous";
}
function buildAliasMapping(functionPath, decodeFnName, aliasMap) {
if (!t.isFunction(functionPath.node) || !functionPath.node.body) {
return;
}
const bodyPath = functionPath.get("body");
if (!bodyPath || Array.isArray(bodyPath)) {
return;
}
bodyPath.traverse({
VariableDeclarator(declPath) {
if (!t.isIdentifier(declPath.node.id) || !declPath.node.init) {
return;
}
const varName = declPath.node.id.name;
const init = declPath.get("init");
if (!init || Array.isArray(init)) {
return;
}
if (handleDirectAssignment(init, decodeFnName, varName, aliasMap, declPath)) {
return;
}
if (handleAliasTransfer(init, varName, aliasMap)) {
declPath.remove();
return;
}
if (handleConcatPattern(init, varName, aliasMap, declPath)) {
return;
}
if (handleArrayAccess(init, varName, aliasMap, declPath)) {
return;
}
}
});
}
function handleDirectAssignment(init, decodeFnName, varName, aliasMap, declPath) {
if (!init.isMemberExpression()) {
return false;
}
const objectPath = init.get("object");
if (!objectPath.isIdentifier({ name: decodeFnName })) {
return false;
}
const targetName = generatorModule(init.node).code;
const parts = targetName.split(".");
if (parts.length === 2) {
aliasMap.set(varName, {
targetName,
propertyName: parts[1]
});
declPath.remove();
return true;
}
return false;
}
function handleAliasTransfer(init, varName, aliasMap) {
if (!init.isIdentifier()) {
return false;
}
const sourceAlias = aliasMap.get(init.node.name);
if (sourceAlias) {
aliasMap.set(varName, sourceAlias);
return true;
}
return false;
}
function handleConcatPattern(init, varName, aliasMap, declPath) {
if (!init.isCallExpression()) {
return false;
}
const callee = init.get("callee");
if (!callee.isMemberExpression()) {
return false;
}
const property = callee.get("property");
if (!property.isIdentifier({ name: "concat" })) {
return false;
}
const args = init.get("arguments");
if (args.length !== 1 || !args[0].isIdentifier()) {
return false;
}
const aliasSource = args[0].node.name;
const sourceAlias = aliasMap.get(aliasSource);
if (sourceAlias) {
const arrayKey = `${varName}[1]`;
aliasMap.set(arrayKey, sourceAlias);
declPath.remove();
return true;
}
return false;
}
function handleArrayAccess(init, varName, aliasMap, declPath) {
if (!init.isMemberExpression()) {
return false;
}
const objectPath = init.get("object");
const propertyPath = init.get("property");
if (!objectPath.isIdentifier() || !propertyPath.isNumericLiteral()) {
return false;
}
const arrayName = objectPath.node.name;
const index = propertyPath.node.value;
const arrayKey = `${arrayName}[${index}]`;
const sourceAlias = aliasMap.get(arrayKey);
if (sourceAlias) {
aliasMap.set(varName, sourceAlias);
declPath.remove();
return true;
}
return false;
}
function removeShiftStatements(functionPath, aliasMap) {
if (!t.isFunction(functionPath.node) || !functionPath.node.body) {
return;
}
const bodyPath = functionPath.get("body");
if (!bodyPath || Array.isArray(bodyPath)) {
return;
}
const statementsToRemove = [];
bodyPath.traverse({
ExpressionStatement(stmtPath) {
const expression = stmtPath.get("expression");
if (!expression.isCallExpression()) {
return;
}
const callee = expression.get("callee");
if (!callee.isMemberExpression()) {
return;
}
const calleeObject = callee.get("object");
const calleeProperty = callee.get("property");
if (!calleeObject.isIdentifier() || !calleeProperty.isIdentifier({ name: "shift" })) {
return;
}
const calleeName = calleeObject.node.name;
const arrayKey = `${calleeName}[1]`;
if (aliasMap.has(calleeName) || aliasMap.has(arrayKey)) {
statementsToRemove.push(stmtPath);
}
}
});
for (const stmt of statementsToRemove) {
stmt.remove();
}
}
function replaceDecryptedCalls(functionPath, aliasMap, decodeFnObject) {
if (!t.isFunction(functionPath.node) || !functionPath.node.body) {
return;
}
const bodyPath = functionPath.get("body");
if (!bodyPath || Array.isArray(bodyPath)) {
return;
}
bodyPath.traverse({
CallExpression(callPath) {
const callee = callPath.get("callee");
if (!callee.isIdentifier()) {
return;
}
const calleeName = callee.node.name;
const aliasInfo = aliasMap.get(calleeName);
if (!(aliasInfo == null ? void 0 : aliasInfo.propertyName)) {
return;
}
const args = callPath.get("arguments");
if (args.length !== 1 || !args[0].isNumericLiteral()) {
return;
}
const argValue = args[0].node.value;
try {
const decodeFn = decodeFnObject[aliasInfo.propertyName];
if (typeof decodeFn === "function") {
const realValue = decodeFn(argValue);
if (typeof realValue === "string") {
callPath.replaceWith(t.stringLiteral(realValue));
}
}
} catch (error) {
console.warn(`解密调用 ${calleeName}(${argValue}) 失败:`, error);
}
}
});
}
const removeFor = (path, options) => {
if (!options) {
return;
}
const { decodeFnObject, decodeFnName } = options;
if (!t.isForStatement(path.node)) {
return;
}
const forStatement = path.node;
const prevSiblingPath = path.getPrevSibling();
const variableDeclaration = validateAndGetVariableDeclaration(prevSiblingPath, decodeFnName, decodeFnObject);
if (!variableDeclaration) {
return;
}
const forStatementInfo = validateForStatement(forStatement);
if (!forStatementInfo) {
return;
}
const { switchStatement, forTest } = forStatementInfo;
const initialValue = calculateMemberExpressionValue(variableDeclaration.init, decodeFnName, decodeFnObject);
const breakValue = calculateMemberExpressionValue(forTest.right, decodeFnName, decodeFnObject);
if (initialValue === null || breakValue === null) {
return;
}
const resultBody = processSwitchCases(
switchStatement.cases,
initialValue,
breakValue,
decodeFnName,
decodeFnObject
);
path.replaceWithMultiple(resultBody);
prevSiblingPath.remove();
};
function validateAndGetVariableDeclaration(prevSiblingPath, decodeFnName, decodeFnObject) {
if (!Array.isArray(prevSiblingPath.container)) {
return null;
}
const firstStatement = prevSiblingPath.container[0];
if (!t.isVariableDeclaration(firstStatement)) {
return null;
}
const declaration = firstStatement.declarations[0];
if (!declaration || !declaration.init) {
return null;
}
if (!isValidDecodeMemberExpression(declaration.init)) {
return null;
}
const memberExpr = declaration.init;
const callExpr = memberExpr.object.object;
const callee = callExpr.callee;
if (!t.isIdentifier(callee.object) || callee.object.name !== decodeFnName) {
return null;
}
if (!t.isIdentifier(callee.property) || !decodeFnObject[callee.property.name]) {
return null;
}
const originDecodeFn = decodeFnObject[callee.property.name];
const decodeFn = (first, second) => originDecodeFn()[first][second];
return { init: declaration.init, decodeFn };
}
function validateForStatement(forStatement) {
if (!t.isBlockStatement(forStatement.body)) {
return null;
}
const body = forStatement.body.body;
if (body.length === 0 || !t.isSwitchStatement(body[0])) {
return null;
}
const switchStatement = body[0];
if (!t.isIdentifier(switchStatement.discriminant)) {
return null;
}
if (!t.isBinaryExpression(forStatement.test)) {
return null;
}
const forTest = forStatement.test;
if (!isValidDecodeMemberExpression(forTest.right)) {
return null;
}
return { switchStatement, forTest };
}
function calculateMemberExpressionValue(node, decodeFnName, decodeFnObject) {
if (!isValidDecodeMemberExpression(node)) {
return null;
}
try {
const memberExpr = node;
const firstIndex = memberExpr.object.property.value;
const secondIndex = memberExpr.property.value;
const callExpr = memberExpr.object.object;
const callee = callExpr.callee;
if (!t.isIdentifier(callee.object) || callee.object.name !== decodeFnName) {
return null;
}
if (!t.isIdentifier(callee.property) || !decodeFnObject[callee.property.name]) {
return null;
}
const originDecodeFn = decodeFnObject[callee.property.name];
const decodeFn = (first, second) => originDecodeFn()[first][second];
return decodeFn(firstIndex, secondIndex);
} catch {
return null;
}
}
function processSwitchCases(cases, initialValue, breakValue, decodeFnName, decodeFnObject) {
const resultBody = [];
let currentValue = initialValue;
while (currentValue !== breakValue) {
let foundCase = false;
for (const switchCase of cases) {
if (!switchCase.test || !t.isMemberExpression(switchCase.test)) {
continue;
}
const caseValue = calculateMemberExpressionValue(switchCase.test, decodeFnName, decodeFnObject);
if (caseValue === currentValue) {
foundCase = true;
const caseBody = [...switchCase.consequent];
if (caseBody.length > 0 && t.isBreakStatement(caseBody[caseBody.length - 1])) {
caseBody.pop();
}
const nextValue = processStateUpdate(caseBody, decodeFnName, decodeFnObject);
if (nextValue !== null) {
currentValue = nextValue;
} else {
resultBody.push(...caseBody);
return resultBody;
}
resultBody.push(...caseBody);
break;
}
}
if (!foundCase) {
break;
}
}
return resultBody;
}
function processStateUpdate(caseBody, decodeFnName, decodeFnObject) {
if (caseBody.length < 1) {
return null;
}
const lastStatement = caseBody[caseBody.length - 1];
if (t.isExpressionStatement(lastStatement)) {
const expr = lastStatement.expression;
if (t.isAssignmentExpression(expr) && isValidDecodeMemberExpression(expr.right)) {
caseBody.pop();
return calculateMemberExpressionValue(expr.right, decodeFnName, decodeFnObject);
}
}
return null;
}
function isValidDecodeMemberExpression(node) {
if (!t.isMemberExpression(node)) return false;
if (!t.isMemberExpression(node.object)) return false;
if (!t.isCallExpression(node.object.object)) return false;
if (!t.isMemberExpression(node.object.object.callee)) return false;
if (!t.isNumericLiteral(node.object.property)) return false;
if (!t.isNumericLiteral(node.property)) return false;
return true;
}
const traverse$1 = traverseModule.default || traverseModule;
function geetest4Defusion(jscode) {
let ast = parseCode(jscode);
const code = multiProcessDefusion(jscode, { clearNotUse: true });
ast = parseCode(code);
traverse$1(ast, { VariableDeclarator: removeVarComma });
traverse$1(ast, { Scope: renameVar });
const { decodeFnName, decodeFnObject } = getDecodeFn(ast);
traverse$1(ast, { Function: (path) => removeAndReplace(path, { decodeFnName, decodeFnObject }) });
traverse$1(ast, { ForStatement: (path) => removeFor(path, { decodeFnObject, decodeFnName }) });
traverse$1(ast, { MemberExpression: formatMember });
return generateCode(ast);
}
function getLibAndAbo(jscode) {
const code = geetest4Defusion(jscode);
let ast = parseCode(code);
let lib = null;
let _abo = null;
traverse$1(ast, {
AssignmentExpression(path) {
const node = path.node;
if (!t.isMemberExpression(node.left)) return;
if (!t.isIdentifier(node.left.property)) return;
if (node.left.property.name !== "_lib") return;
if (!t.isObjectExpression(node.right)) return;
if (node.right.properties.length !== 1) {
console.log("lib 有不止一个key value值");
return;
}
if (!t.isObjectProperty(node.right.properties[0])) return;
const property = node.right.properties[0];
if (!t.isIdentifier(property.key)) return;
if (!t.isStringLiteral(property.value)) return;
lib = {
[property.key.name]: property.value.value
};
}
});
traverse$1(ast, {
AssignmentExpression(path) {
const node = path.node;
if (!t.isMemberExpression(node.left)) return;
if (!t.isIdentifier(node.left.property)) return;
if (node.left.property.name !== "_abo") return;
if (!t.isObjectExpression(node.right)) return;
if (node.right.properties.length !== 1) {
console.log("_abo 有不止一个key value值");
return;
}
if (!t.isObjectProperty(node.right.properties[0])) return;
const property = node.right.properties[0];
if (!t.isStringLiteral(property.key)) return;
if (!t.isStringLiteral(property.value)) return;
_abo = {
[property.key.value]: property.value.value
};
}
});
return { lib, _abo };
}
const traverse = traverseModule.default || traverseModule;
function multiProcessDefusion(jscode, config = {}) {
let ast = parseCode(jscode);
traverse(ast, { StringLiteral: delExtra });
traverse(ast, { NumericLiteral: delExtra });
traverse(ast, { ConditionalExpression: transCondition });
traverse(ast, { ExpressionStatement: conditionToIf });
traverse(ast, { ExpressionStatement: andToIf });
traverse(ast, { VariableDeclaration: conditionVarToIf });
traverse(ast, { ExpressionStatement: removeComma });
traverse(ast, { VariableDeclaration: removeVarComma });
traverse(ast, { MemberExpression: formatMember });
traverse(ast, { IfStatement: clearBinaryIfDeadCode });
traverse(ast, { BinaryExpression: { exit: calcBinary } });
traverse(ast, { CatchClause: addCatchLog });
if (config.clearNotUse) {
ast = parseCode(generateCode(ast));
traverse(ast, { FunctionDeclaration: clearNotUseFunction });
traverse(ast, { VariableDeclaration: clearNotUseVar });
traverse(ast, { StringLiteral: delExtra });
traverse(ast, { NumericLiteral: delExtra });
}
return generateCode(ast);
}
const transformFunctions = {
multiProcessDefusion,
geetest3Defusion,
geetest4Defusion
};
const defusion = {
/** 多阶段解混淆函数 - 通用解混淆处理 */
multiProcess: multiProcessDefusion,
/** 极验3专用解混淆函数 */
geetest3: geetest3Defusion,
getTsfq,
/** 极验4专用解混淆函数 */
geetest4: geetest4Defusion,
/** 极验4专用获取 lib 和 _abo 的函数, 用户创建临时参数 */
getLibAndAbo
};
export {
defusion,
geetest3Defusion,
geetest4Defusion,
getLibAndAbo,
getTsfq,
multiProcessDefusion,
transformFunctions
};