This commit is contained in:
smallfawn committed 2025-03-01 17:06:50 +08:00
1 parent f76b8fb9bd
commit 1100a6d4f7
9 files changed
+151 -107

No files matched your search

+1
View File
@@ -1,5 +1,6 @@
{
"name": "decode-js",
"type": "module",
"scripts": {
"decode": "node src/main.js",
"deob": "node src/main.js -t obfuscator",
+60 -33
View File
@@ -1,46 +1,62 @@
const fs = require('fs')
const PluginCommon = require('./plugin/common.js')
const PluginJjencode = require('./plugin/jjencode.js')
const PluginSojson = require('./plugin/sojson.js')
const PluginSojsonV7 = require('./plugin/sojsonv7.js')
const PluginObfuscator = require('./plugin/obfuscator.js')
const PluginAwsc = require('./plugin/awsc.js')
import fs from 'fs';
import { fileURLToPath } from 'url';
import * as path from 'path';
import process from 'process';
// Dynamically import ESM modules
const commonModule = await import('./plugin/common.js');
const jjencodeModule = await import('./plugin/jjencode.js');
const sojsonModule = await import('./plugin/sojson.js');
const sojsonv7Module = await import('./plugin/sojsonv7.js');
const obfuscatorModule = await import('./plugin/obfuscator.js');
const awscModule = await import('./plugin/awsc.js');
// Provide default exports if necessary
const PluginCommon = commonModule.default || commonModule;
const PluginJjencode = jjencodeModule.default || jjencodeModule;
const PluginSojson = sojsonModule.default || sojsonModule;
const PluginSojsonV7 = sojsonv7Module.default || sojsonv7Module;
const PluginObfuscator = obfuscatorModule.default || obfuscatorModule;
const PluginAwsc = awscModule.default || awscModule;
// Read command-line arguments
let encodeFile = 'input.js';
let decodeFile = 'output.js';
// 读取参数
let encodeFile = 'input.js'
let decodeFile = 'output.js'
for (let i = 2; i < process.argv.length; i += 2) {
if (process.argv[i] === '-i') {
encodeFile = process.argv[i + 1]
}
if (process.argv[i] === '-o') {
decodeFile = process.argv[i + 1]
encodeFile = process.argv[i + 1];
} else if (process.argv[i] === '-o') {
decodeFile = process.argv[i + 1];
}
}
console.log(`输入: ${encodeFile}`)
console.log(`输出: ${decodeFile}`)
// 读取源代码
const sourceCode = fs.readFileSync(encodeFile, { encoding: 'utf-8' })
console.log(`输入: ${encodeFile}`);
console.log(`输出: ${decodeFile}`);
// Read source code
const sourceCode = fs.readFileSync(encodeFile, { encoding: 'utf-8' });
let processedCode = sourceCode;
let pluginUsed = '';
let time;
// 循环尝试不同的插件,直到源代码与处理后的代码不一致
// Try plugins in sequence until the processed code differs from the original
const plugins = [
{ name: 'obfuscator', plugin: PluginObfuscator },
{ name: 'sojsonv7', plugin: PluginSojsonV7 },
{ name: 'sojson', plugin: PluginSojson },
{ name: 'awsc', plugin: PluginAwsc },
{ name: 'jjencode', plugin: PluginJjencode },
{ name: 'common', plugin: PluginCommon },// 最后一次使用通用插件
{ name: 'common', plugin: PluginCommon }, // Use common plugin last
];
for (let plugin of plugins) {
if (sourceCode.indexOf("smEcV") != -1) {
break
for (const plugin of plugins) {
// Check for specific string in sourceCode to break early
if (sourceCode.indexOf('smEcV') !== -1) {
break;
}
try {
const code = plugin.plugin(sourceCode);
if (code && code !== processedCode) {
@@ -50,18 +66,29 @@ for (let plugin of plugins) {
}
} catch (error) {
console.error(`插件 ${plugin.name} 处理时发生错误: ${error.message}`);
// 继续循环尝试下一个插件
continue;
}
}
let time = new Date();
// Check if processed code differs from source code
if (processedCode !== sourceCode) {
// 输出代码
fs.writeFile(decodeFile, "//" + time + '\n' + "//Base:https://github.com/echo094/decode-js" + '\n' + "//Modify:https://github.com/smallfawn/decode_action" + '\n' + processedCode, (err) => {
if (err) throw err;
console.log(`使用插件 ${pluginUsed} 成功处理并写入文件 ${decodeFile}`);
time = new Date();
const header = [
`//${time}`,
"//Base:<url id=\"cv1cref6o68qmpt26ol0\" type=\"url\" status=\"parsed\" title=\"GitHub - echo094/decode-js: JS混淆代码的AST分析工具 AST analysis tool for obfuscated JS code\" wc=\"2165\">https://github.com/echo094/decode-js</url>",
"//Modify:<url id=\"cv1cref6o68qmpt26olg\" type=\"url\" status=\"parsed\" title=\"GitHub - smallfawn/decode_action: 世界上本来不存在加密,加密的人多了,也便成就了解密\" wc=\"741\">https://github.com/smallfawn/decode_action</url>"
].join('\n');
// Combine header and processed code
const outputCode = header + '\n' + processedCode;
// Write to file
fs.writeFile(decodeFile, outputCode, (err) => {
if (err) {
throw err;
} else {
console.log(`使用插件 ${pluginUsed} 成功处理并写入文件 ${decodeFile}`);
}
});
} else {
console.log(`所有插件处理后的代码与原代码一致,未写入文件。`);
}
}
+7 -5
View File
@@ -2,10 +2,12 @@
* Reference:
* * [某宝登录bx-ua参数逆向思路(fireyejs 225算法)](https://zhuanlan.zhihu.com/p/626187669)
*/
const { parse } = require('@babel/parser')
const generator = require('@babel/generator').default
const traverse = require('@babel/traverse').default
const t = require('@babel/types')
import { parse } from '@babel/parser'
import _generate from '@babel/generator'
const generator = _generate.default
import _traverse from '@babel/traverse'
const traverse = _traverse.default
import * as t from '@babel/types'
function RemoveVoid(path) {
if (path.node.operator === 'void') {
@@ -204,7 +206,7 @@ function LintBlock(path) {
path.replaceWith(t.blockStatement(arr))
}
module.exports = function (code) {
export default function (code) {
let ast = parse(code)
// Lint
traverse(ast, {
+12 -8
View File
@@ -1,8 +1,14 @@
const { parse } = require('@babel/parser')
const generator = require('@babel/generator').default
const traverse = require('@babel/traverse').default
import { parse } from '@babel/parser'
import _generate from '@babel/generator'
const generator = _generate.default
import _traverse from '@babel/traverse'
const traverse = _traverse.default
import deleteUnreachableCode from '../visitor/delete-unreachable-code.js'
import deleteNestedBlocks from '../visitor/delete-nested-blocks.js'
import calculateConstantExp from '../visitor/calculate-constant-exp.js'
import calculateRString from '../visitor/calculate-rstring.js'
module.exports = function (code) {
export default function (code) {
let ast
try {
ast = parse(code, { errorRecovery: true })
@@ -10,11 +16,9 @@ module.exports = function (code) {
console.error(`Cannot parse code: ${e.reasonCode}`)
return null
}
const deleteExtra = require('../visitor/delete-extra')
traverse(ast, deleteExtra)
const calculateConstantExp = require('../visitor/calculate-constant-exp')
traverse(ast, deleteUnreachableCode)
traverse(ast, deleteNestedBlocks)
traverse(ast, calculateConstantExp)
const calculateRString = require('../visitor/calculate-rstring')
traverse(ast, calculateRString)
code = generator(ast).code
return code
+7 -5
View File
@@ -1,7 +1,9 @@
const { parse } = require('@babel/parser')
const generator = require('@babel/generator').default
const traverse = require('@babel/traverse').default
const t = require('@babel/types')
import { parse } from '@babel/parser'
import _generate from '@babel/generator'
const generator = _generate.default
import _traverse from '@babel/traverse'
const traverse = _traverse.default
import * as t from '@babel/types'
function unpack(code) {
let ast = parse(code, { errorRecovery: true })
@@ -46,7 +48,7 @@ function pack(code) {
return code
}
module.exports = {
export default {
unpack,
pack,
}
+1 -1
View File
@@ -57,7 +57,7 @@ function getCode(code) {
* This encoding method originates from http://utf-8.jp/public/jjencode.html,
* and it does not change the original code (encoder, not obfuscation).
*/
module.exports = function (code) {
export default function (code) {
code = getCode(code)
if (!code) {
return null
+20 -29
View File
@@ -3,13 +3,24 @@
* * cilame/v_jstools
* * Cqxstevexw/decodeObfuscator
*/
const { parse } = require('@babel/parser')
const generator = require('@babel/generator').default
const traverse = require('@babel/traverse').default
const t = require('@babel/types')
const ivm = require('isolated-vm')
const PluginEval = require('./eval.js')
const calculateConstantExp = require('../visitor/calculate-constant-exp')
import { parse } from '@babel/parser'
import _generate from '@babel/generator'
const generator = _generate.default
import _traverse from '@babel/traverse'
const traverse = _traverse.default
import * as t from '@babel/types'
import ivm from 'isolated-vm'
import PluginEval from './eval.js'
import calculateConstantExp from '../visitor/calculate-constant-exp.js'
import deleteIllegalReturn from '../visitor/delete-illegal-return.js'
import deleteUnusedVar from '../visitor/delete-unused-var.js'
import lintIfStatement from '../visitor/lint-if-statement.js'
import mergeObject from '../visitor/merge-object.js'
import parseControlFlowStorage from '../visitor/parse-control-flow-storage.js'
import pruneIfBranch from '../visitor/prune-if-branch.js'
import splitAssignment from '../visitor/split-assignment.js'
import splitSequence from '../visitor/split-sequence.js'
import splitVarDeclaration from '../visitor/split-variable-declaration.js'
const isolate = new ivm.Isolate()
const globalContext = isolate.createContextSync()
@@ -609,10 +620,8 @@ function decodeCodeBlock(ast) {
// 合并字面量
traverse(ast, calculateConstantExp)
// 先合并分离的Object定义
const mergeObject = require('../visitor/merge-object')
traverse(ast, mergeObject)
// 在变量定义完成后判断是否为代码块加密内容
const parseControlFlowStorage = require('../visitor/parse-control-flow-storage')
traverse(ast, parseControlFlowStorage)
// 合并字面量(在解除区域混淆后会出现新的可合并分割)
traverse(ast, calculateConstantExp)
@@ -719,24 +728,11 @@ function cleanSwitchCode(path) {
function cleanDeadCode(ast) {
traverse(ast, calculateConstantExp)
const pruneIfBranch = require('../visitor/prune-if-branch')
traverse(ast, pruneIfBranch)
traverse(ast, { WhileStatement: { exit: cleanSwitchCode } })
return ast
}
const splitVariableDeclarator = {
VariableDeclarator(path) {
const init = path.get('init')
if (!init.isAssignmentExpression()) {
return
}
path.parentPath.insertBefore(init.node)
init.replaceWith(init.node.left)
path.parentPath.scope.crawl()
},
}
function standardIfStatement(path) {
const consequent = path.get('consequent')
const alternate = path.get('alternate')
@@ -795,9 +791,8 @@ function purifyCode(ast) {
path.remove()
},
})
traverse(ast, splitAssignment)
// 删除未使用的变量
traverse(ast, splitVariableDeclarator)
const deleteUnusedVar = require('../visitor/delete-unused-var')
traverse(ast, deleteUnusedVar)
// 替换索引器
function FormatMember(path) {
@@ -844,7 +839,6 @@ function purifyCode(ast) {
})
// 拆分语句
const splitSequence = require('../visitor/split-sequence')
traverse(ast, splitSequence)
return ast
}
@@ -1041,7 +1035,7 @@ function unlockEnv(ast) {
return ast
}
module.exports = function (code) {
export default function (code) {
let ret = PluginEval.unpack(code)
let global_eval = false
if (ret) {
@@ -1056,13 +1050,10 @@ module.exports = function (code) {
return null
}
// IllegalReturn
const deleteIllegalReturn = require('../visitor/delete-illegal-return')
traverse(ast, deleteIllegalReturn)
// Lint before split statements
const lintIfStatement = require('../visitor/lint-if-statement')
traverse(ast, lintIfStatement)
// Split declarations to avoid bugs
const splitVarDeclaration = require('../visitor/split-variable-declaration')
traverse(ast, splitVarDeclaration)
// 清理二进制显示内容
traverse(ast, {
+14 -12
View File
@@ -1,13 +1,19 @@
/**
* 在 babel_asttool.js 的基础上修改而来
*/
const { parse } = require('@babel/parser')
const generator = require('@babel/generator').default
const traverse = require('@babel/traverse').default
const t = require('@babel/types')
const ivm = require('isolated-vm')
const PluginEval = require('./eval.js')
const calculateConstantExp = require('../visitor/calculate-constant-exp')
import { parse } from '@babel/parser'
import _generate from '@babel/generator'
const generator = _generate.default
import _traverse from '@babel/traverse'
const traverse = _traverse.default
import * as t from '@babel/types'
import ivm from 'isolated-vm'
import PluginEval from './eval.js'
import calculateConstantExp from '../visitor/calculate-constant-exp.js'
import deleteUnusedVar from '../visitor/delete-unused-var.js'
import parseControlFlowStorage from '../visitor/parse-control-flow-storage.js'
import pruneIfBranch from '../visitor/prune-if-branch.js'
import splitSequence from '../visitor/split-sequence.js'
const isolate = new ivm.Isolate()
const globalContext = isolate.createContextSync()
@@ -166,7 +172,6 @@ function cleanSwitchCode(path) {
function cleanDeadCode(ast) {
traverse(ast, calculateConstantExp)
const pruneIfBranch = require('../visitor/prune-if-branch')
traverse(ast, pruneIfBranch)
traverse(ast, { WhileStatement: { exit: cleanSwitchCode } })
return ast
@@ -469,7 +474,6 @@ function purifyCode(ast) {
}
traverse(ast, { MemberExpression: FormatMember })
// 分割表达式
const splitSequence = require('../visitor/split-sequence')
traverse(ast, splitSequence)
// 删除空语句
traverse(ast, {
@@ -478,12 +482,11 @@ function purifyCode(ast) {
},
})
// 删除未使用的变量
const deleteUnusedVar = require('../visitor/delete-unused-var')
traverse(ast, deleteUnusedVar)
return ast
}
module.exports = function (code) {
export default function (code) {
let ret = PluginEval.unpack(code)
let global_eval = false
if (ret) {
@@ -508,7 +511,6 @@ module.exports = function (code) {
return null
}
console.log('处理代码块加密...')
const parseControlFlowStorage = require('../visitor/parse-control-flow-storage')
traverse(ast, parseControlFlowStorage)
console.log('清理死代码...')
ast = cleanDeadCode(ast)
+29 -14
View File
@@ -1,13 +1,20 @@
/**
* For jsjiami.com.v7
*/
const { parse } = require('@babel/parser')
const generator = require('@babel/generator').default
const traverse = require('@babel/traverse').default
const t = require('@babel/types')
const ivm = require('isolated-vm')
const PluginEval = require('./eval.js')
const calculateConstantExp = require('../visitor/calculate-constant-exp')
import { parse } from '@babel/parser'
import _generate from '@babel/generator'
const generator = _generate.default
import _traverse from '@babel/traverse'
const traverse = _traverse.default
import * as t from '@babel/types'
import ivm from 'isolated-vm'
import PluginEval from './eval.js'
import calculateConstantExp from '../visitor/calculate-constant-exp.js'
import deleteIllegalReturn from '../visitor/delete-illegal-return.js'
import deleteUnusedVar from '../visitor/delete-unused-var.js'
import parseControlFlowStorage from '../visitor/parse-control-flow-storage.js'
import pruneIfBranch from '../visitor/prune-if-branch.js'
import splitSequence from '../visitor/split-sequence.js'
const isolate = new ivm.Isolate()
const globalContext = isolate.createContextSync()
@@ -283,7 +290,11 @@ function decodeGlobal(ast) {
if (item.path.isFunctionDeclaration()) {
scope = item.path.parentPath.scope
}
const refs = scope.bindings[cur_val].referencePaths
// var is function scoped and let is block scoped
// Hence, var may not be in the current scope, e.g., in a for-loop
const binding = scope.getBinding(cur_val)
scope = binding.scope
const refs = binding.referencePaths
const refs_next = []
for (let ref of refs) {
const parent = ref.parentPath
@@ -294,12 +305,21 @@ function decodeGlobal(ast) {
path: parent,
code: 'var ' + parent,
})
} else if (ref.key === 'right') {
// AssignmentExpression
refs_next.push({
name: parent.node.left.name,
path: parent,
code: 'var ' + parent,
})
} else if (ref.key === 'object') {
// MemberExpression
memToStr(parent)
} else if (ref.key === 'callee') {
// CallExpression
funToStr(parent)
} else {
console.error('Unexpected reference')
}
}
for (let ref of refs_next) {
@@ -477,7 +497,6 @@ function cleanSwitchCode2(path) {
function cleanDeadCode(ast) {
traverse(ast, calculateConstantExp)
const pruneIfBranch = require('../visitor/prune-if-branch')
traverse(ast, pruneIfBranch)
traverse(ast, { WhileStatement: { exit: cleanSwitchCode1 } })
traverse(ast, { ForStatement: { exit: cleanSwitchCode2 } })
@@ -722,7 +741,6 @@ function purifyCode(ast) {
}
traverse(ast, { MemberExpression: FormatMember })
// 分割表达式
const splitSequence = require('../visitor/split-sequence')
traverse(ast, splitSequence)
// 删除空语句
traverse(ast, {
@@ -731,11 +749,10 @@ function purifyCode(ast) {
},
})
// 删除未使用的变量
const deleteUnusedVar = require('../visitor/delete-unused-var')
traverse(ast, deleteUnusedVar)
}
module.exports = function (code) {
export default function (code) {
let ret = PluginEval.unpack(code)
let global_eval = false
if (ret) {
@@ -750,7 +767,6 @@ module.exports = function (code) {
return null
}
// IllegalReturn
const deleteIllegalReturn = require('../visitor/delete-illegal-return')
traverse(ast, deleteIllegalReturn)
// 清理二进制显示内容
traverse(ast, {
@@ -769,7 +785,6 @@ module.exports = function (code) {
return null
}
console.log('处理代码块加密...')
const parseControlFlowStorage = require('../visitor/parse-control-flow-storage')
traverse(ast, parseControlFlowStorage)
console.log('清理死代码...')
ast = cleanDeadCode(ast)