From 1100a6d4f74bda7c749bfb949d7364cc67ddc7e6 Mon Sep 17 00:00:00 2001
From: smallfawn <860562056@qq.com>
Date: Sat, 1 Mar 2025 17:06:50 +0800
Subject: [PATCH] update
---
package.json | 1 +
src/main.js | 93 ++++++++++++++++++++++++++--------------
src/plugin/awsc.js | 12 +++---
src/plugin/common.js | 20 +++++----
src/plugin/eval.js | 12 +++---
src/plugin/jjencode.js | 2 +-
src/plugin/obfuscator.js | 49 +++++++++------------
src/plugin/sojson.js | 26 +++++------
src/plugin/sojsonv7.js | 43 +++++++++++++------
9 files changed, 151 insertions(+), 107 deletions(-)
diff --git a/package.json b/package.json
index c7ab5d3..5efae18 100644
--- a/package.json
+++ b/package.json
@@ -1,5 +1,6 @@
{
"name": "decode-js",
+ "type": "module",
"scripts": {
"decode": "node src/main.js",
"deob": "node src/main.js -t obfuscator",
diff --git a/src/main.js b/src/main.js
index 8400646..4b9e752 100644
--- a/src/main.js
+++ b/src/main.js
@@ -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:https://github.com/echo094/decode-js",
+ "//Modify:https://github.com/smallfawn/decode_action"
+ ].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(`所有插件处理后的代码与原代码一致,未写入文件。`);
-}
-
+}
\ No newline at end of file
diff --git a/src/plugin/awsc.js b/src/plugin/awsc.js
index cbb9519..fe56bb7 100644
--- a/src/plugin/awsc.js
+++ b/src/plugin/awsc.js
@@ -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, {
diff --git a/src/plugin/common.js b/src/plugin/common.js
index 471657b..e0674e8 100644
--- a/src/plugin/common.js
+++ b/src/plugin/common.js
@@ -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
diff --git a/src/plugin/eval.js b/src/plugin/eval.js
index 142638f..a1c49eb 100644
--- a/src/plugin/eval.js
+++ b/src/plugin/eval.js
@@ -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,
}
diff --git a/src/plugin/jjencode.js b/src/plugin/jjencode.js
index af14f8c..2a79fc0 100644
--- a/src/plugin/jjencode.js
+++ b/src/plugin/jjencode.js
@@ -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
diff --git a/src/plugin/obfuscator.js b/src/plugin/obfuscator.js
index 44131b6..59cee75 100644
--- a/src/plugin/obfuscator.js
+++ b/src/plugin/obfuscator.js
@@ -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, {
diff --git a/src/plugin/sojson.js b/src/plugin/sojson.js
index 9babebc..fdfc0eb 100644
--- a/src/plugin/sojson.js
+++ b/src/plugin/sojson.js
@@ -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)
diff --git a/src/plugin/sojsonv7.js b/src/plugin/sojsonv7.js
index 6a1013e..26a476f 100644
--- a/src/plugin/sojsonv7.js
+++ b/src/plugin/sojsonv7.js
@@ -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)