This commit is contained in:
cilame 2021-09-28 22:53:40 +08:00
parent 29c464bfe0
commit 62c2f8f44a
7 changed files with 13410 additions and 58 deletions

View File

@ -1 +1,27 @@
// background.js
// background.js
// 后续想做一个右键将选中的代码进行优化处理的功能。
// chrome.contextMenus.create({
// title: "测试右键菜单",
// onclick: function(){alert('您点击了右键菜单!');}
// });
// chrome.contextMenus.create({
// title: '使用度娘搜索:%s', // %s表示选中的文字
// contexts: ['selection'], // 只有当选中文字时才会出现此右键菜单
// onclick: function(params)
// {
// // 注意不能使用location.href因为location是属于background的window对象
// chrome.tabs.create({url: 'https://www.baidu.com/s?ie=utf-8&wd=' + encodeURI(params.selectionText)});
// }
// });

273
inject.js

File diff suppressed because one or more lines are too long

View File

@ -2,7 +2,8 @@
"name": "v_jstools",
"version": "0.0.0",
"description": "v_jstools js hook工具",
"permissions": ["storage", "activeTab", "tabs", "debugger", "storage", "extension", "scripting"],
"permissions": ["storage", "activeTab", "tabs", "debugger", "storage", "extension", "scripting", "contextMenus"],
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
"browser_action": {
"default_popup": "popup.html"
},

View File

@ -7,13 +7,15 @@
<title>Document</title>
</head>
<body style="width: 600px;">
<label ><input type="checkbox" data-key="config-hook-global">是否挂钩总开关</label>
<br/>
<label ><input type="checkbox" data-key="config-hook-test">test</label>
<br/>
<label ><input type="checkbox" data-key="config-hook-console">hook-console</label>
<label ><input type="checkbox" data-key="config-hook-console">hook-console(使用 v_log 替换 console.log 并将其他属性设置为空函数)</label>
<br/>
<label ><input type="checkbox" data-key="config-hook-Function">hook-Function</label>
<br/>
<label ><input type="checkbox" data-key="config-hook-eval">hook-eval</label>
<label ><input type="checkbox" data-key="config-hook-eval">hook-evaleval函数会记录上下文若 eval 用到封闭的上下文参数可能报错)</label>
<br/>
<label ><input type="checkbox" data-key="config-hook-remove-dyn-debugger">remove-dyn-debugger(need selected "hook-Function" or "hook-eval")</label>
<br/>
@ -41,20 +43,29 @@
<br/>
<label ><input type="checkbox" data-key="config-hook-domobj">hook-domobj</label>
<br/>
<label ><input type="checkbox" data-key="config-hook-domobj-get"> - hook-domobj-显示get输出</label>
<br/>
<label ><input type="checkbox" data-key="config-hook-domobj-set"> - hook-domobj-显示set输出</label>
<br/>
<label ><input type="checkbox" data-key="config-hook-domobj-func"> - hook-domobj-显示func输出</label>
<br/>
<br/>
<div>这里暂时考虑是用来做 ast 解混淆的</div>
<textarea style="width: 593px; height: 400px">
<div>AST解密混淆</div>
<button id='ob'>解密ob混淆</button>
<button id='obnormal'>普通解混淆</button>
<button id='uglify'>仅变量压缩</button>
<button id='uglify_mini'>完全压缩脚本</button>
<br/>
<textarea id='txt' style="width: 593px; height: 500px">
</textarea>
<br/>
<script src="popup.js"></script>
<script src="babel_asttool.js"></script>
<script src="tools/babel_asttool.js"></script>
<script src="tools/uglify_es.js"></script>
<script src="tools/popup_utils.js"></script>
</body>
</html>

View File

@ -32259,4 +32259,517 @@
return i(e);
};
}, {} ]
}, {}, [ 1 ]);
}, {}, [ 1 ]);
function FormatMember(path) {
// _0x19882c['removeCookie']['toString']()
// |
// |
// |
// v
// _0x19882c.removeCookie.toString()
var curNode = path.node;
if(!t.isStringLiteral(curNode.property))
return;
if(curNode.computed === undefined || !curNode.computed === true)
return;
if (!/[a-zA-Z_$][0-9a-zA-Z_$]*/.test(curNode.property.value))
return;
curNode.property = t.identifier(curNode.property.value);
curNode.computed = false;
}
function TransCondition(path) {
// a = m?11:22;
// |
// |
// |
// v
// m ? a = 11 : a = 22;
let {test, consequent, alternate} = path.node;
const ParentPath = path.parentPath;
if (ParentPath.isAssignmentExpression()) {
let {operator, left} = ParentPath.node;
if (operator === "=") {
consequent = t.AssignmentExpression("=", left, consequent)
alternate = t.AssignmentExpression("=", left, alternate)
ParentPath.replaceWith(t.conditionalExpression(test, consequent, alternate))
}
}
}
function ConditionToIf(path) {
// m ? a = 11 : a = 22;
// |
// |
// |
// v
// if (m) {
// a = 11;
// } else {
// a = 22;
// }
let {expression} = path.node;
if(!t.isConditionalExpression(expression)) return;
let {test, consequent, alternate} = expression;
path.replaceWith(t.ifStatement(
test,
t.blockStatement([t.expressionStatement(consequent),]),
t.blockStatement([t.expressionStatement(alternate),])
));
}
function ConditionVarToIf(path) {
// var m ? a = 11 : a = 22;
// |
// |
// |
// v
// if (m) {
// var a = 11;
// } else {
// var a = 22;
// }
let {id, init} = path.node;
if (!t.isConditionalExpression(init)) return;
const ParentPath = path.parentPath;
const ParentNode = path.parent;
if (!t.isVariableDeclaration(ParentNode)) return;
if (t.isForStatement(ParentPath.parentPath)) return;
let kind = ParentNode.kind;
let {test, consequent, alternate} = init;
ParentPath.replaceWith(t.ifStatement(
test,
t.blockStatement([t.variableDeclaration(kind, [t.variableDeclarator(id, consequent)]),]),
t.blockStatement([t.variableDeclaration(kind, [t.variableDeclarator(id, alternate)]),])
));
}
function RemoveComma(path) {
// a = 1, b = ddd(), c = null;
// |
// |
// |
// v
// a = 1;
// b = ddd();
// c = null;
let {expression} = path.node
if (!t.isSequenceExpression(expression))
return;
let body = []
expression.expressions.forEach(
express => {
body.push(t.expressionStatement(express))
}
)
path.replaceInline(body)
}
function RemoveVarComma(path) {
// var a = 1, b = ddd(), c = null;
// |
// |
// |
// v
// var a = 1;
// var b = ddd();
// var c = null;
let {kind, declarations} = path.node;
if (declarations.length < 2) return;
if (t.isForStatement(path.parentPath)) return;
temp = [];
declarations.forEach(
VariableDeclarator => {
temp.push(t.variableDeclaration(kind, [VariableDeclarator]))
}
)
path.replaceInline(temp);
}
function MergeObj(path) {
// var _0xb28de8 = {};
// _0xb28de8["abcd"] = function(_0x22293f, _0x5a165e) {
// return _0x22293f == _0x5a165e;
// };
// _0xb28de8.dbca = function(_0xfbac1e, _0x23462f, _0x556555) {
// return _0xfbac1e(_0x23462f, _0x556555);
// };
// _0xb28de8.aaa = function(_0x57e640) {
// return _0x57e640();
// };
// _0xb28de8["bbb"] = "eee";
// var _0x15e145 = _0xb28de8;
// |
// |
// |
// v
// var _0xb28de8 = {
// "abcd": function (_0x22293f, _0x5a165e) {
// return _0x22293f == _0x5a165e;
// },
// "dbca": function (_0xfbac1e, _0x23462f, _0x556555) {
// return _0xfbac1e(_0x23462f, _0x556555);
// },
// "aaa": function (_0x57e640) {
// return _0x57e640();
// },
// "bbb": "eee"
// };
const {id, init} = path.node;
if (!t.isObjectExpression(init)) // 判断是否是定义对象
return;
let name = id.name;
let properties = init.properties;
let scope = path.scope;
let binding = scope.getBinding(name);
if (!binding || binding.constantViolations.length > 0) { // 确认该对象没有被多次定义
return;
}
let paths = binding.referencePaths;
scope.traverse(scope.block, {
AssignmentExpression: function(_path) {
const left = _path.get("left");
const right = _path.get("right");
if (!left.isMemberExpression())
return;
const object = left.get("object");
const property = left.get("property");
if (object.isIdentifier({name: name}) && property.isStringLiteral() && _path.scope == scope) {
properties.push(t.ObjectProperty(t.valueToNode(property.node.value), right.node));
_path.remove();
}
if (object.isIdentifier({name: name}) && property.isIdentifier() && _path.scope == scope) {
properties.push(t.ObjectProperty(t.valueToNode(property.node.name), right.node));
_path.remove();
}
}
})
paths.map(function(refer_path) {
let bindpath = refer_path.parentPath;
if (!t.isVariableDeclarator(bindpath.node)) return;
let bindname = bindpath.node.id.name;
bindpath.scope.rename(bindname, name, bindpath.scope.block);
bindpath.remove();
});
}
function CallToStr(path) {
// var _0xb28de8 = {
// "abcd": function(_0x22293f, _0x5a165e) {
// return _0x22293f == _0x5a165e;
// },
// "dbca": function(_0xfbac1e, _0x23462f, _0x556555) {
// return _0xfbac1e(_0x23462f, _0x556555);
// },
// "aaa": function(_0x57e640) {
// return _0x57e640();
// },
// "bbb": "eee"
// };
// var aa = _0xb28de8["abcd"](123, 456);
// var bb = _0xb28de8["dbca"](bcd, 11, 22);
// var cc = _0xb28de8["aaa"](dcb);
// var dd = _0xb28de8["bbb"];
// |
// |
// |
// v
// var aa = 123 == 456;
// var bb = bcd(11, 22);
// var cc = dcb();
// var dd = "eee";
var node = path.node;
if (!t.isObjectExpression(node.init)) // 判断是否使用对象
return;
var objPropertiesList = node.init.properties;
if (objPropertiesList.length == 0)
return;
var objName = node.id.name;
// 是否可删除该对象:发生替换时可删除,否则不删除
var del_flag = false
objPropertiesList.forEach(prop => {
var key = prop.key.value;
if(t.isFunctionExpression(prop.value)) {
var retStmt = prop.value.body.body[0];
var fnPath = path.getFunctionParent() || path.scope.path;
fnPath.traverse({
CallExpression: function (_path) {
var _node = _path.node.callee;
if (!t.isMemberExpression(_path.node.callee))
return;
if (!t.isIdentifier(_node.object) || _node.object.name !== objName)
return;
if (!(t.isStringLiteral(_node.property) || t.isIdentifier(_node.property)))
return;
if (!(_node.property.value == key || _node.property.name == key))
return;
var args = _path.node.arguments;
// 二元运算, 逻辑运算, 函数调用
if (t.isBinaryExpression(retStmt.argument) && args.length===2) {
_path.replaceWith(t.binaryExpression(retStmt.argument.operator, args[0], args[1]));
}
else if(t.isLogicalExpression(retStmt.argument) && args.length==2) {
_path.replaceWith(t.logicalExpression(retStmt.argument.operator, args[0], args[1]));
}
else if(t.isCallExpression(retStmt.argument) && t.isIdentifier(retStmt.argument.callee)) {
_path.replaceWith(t.callExpression(args[0], args.slice(1)))
}
del_flag = true;
}
})
}
else if (t.isStringLiteral(prop.value)){
var retStmt = prop.value.value;
var fnPath = path.getFunctionParent() || path.scope.path;
fnPath.traverse({
MemberExpression:function (_path) {
var _node = _path.node;
if (!t.isIdentifier(_node.object) || _node.object.name !== objName)
return;
if (!(t.isStringLiteral(_node.property) || t.isIdentifier(_node.property)))
return;
if (!(_node.property.value == key || _node.property.name == key))
return;
_path.replaceWith(t.stringLiteral(retStmt))
del_flag = true;
}
})
}
});
if (del_flag) {
// 如果发生替换,则删除该对象, 该处可能出问题,因为字典的内容未必会饱和使用
path.remove();
}
}
function delExtra(path) {
// ['\x49\x63\x4b\x72\x77\x70\x2f\x44\x6c\x67\x3d\x3d',0x123];
// |
// |
// |
// v
// ["IcKrwp/Dlg==", 291];
delete path.node.extra;
}
function AddCatchLog(path){
var err_name = path.node.param.name
path.node.body.body.unshift({
"type": "ExpressionStatement",
"expression": {
"type": "CallExpression",
"callee": {
"type": "MemberExpression",
"computed": false,
"object": {
"type": "Identifier",
"name": "console"
},
"property": {
"type": "Identifier",
"name": "log"
}
},
"arguments": [
{
"type": "Identifier",
"name": err_name
}
]
}
})
}
function get_ob_enc(ast) {
var first_idx = 0
for (var i = 0; i < ast.program.body.length; i++) {
if (ast.program.body[i].type != 'EmptyStatement'){
first_idx = i;
break
}
}
var decrypt_code = ast.program.body.slice(first_idx, first_idx+3)
var rest_code = ast.program.body.slice(first_idx+3)
ast.program.body = decrypt_code
var {code} = generator(ast, {
compact: true
})
global_code = code
decryptStr = decrypt_code[2].declarations[0].id.name
ast.program.body = rest_code
return ast
}
function pas_ob_enc(ast) {
eval(global_code)
traverse(ast, {
CallExpression: funToStr,
StringLiteral: delExtra,
NumericLiteral: delExtra,
})
return ast;
function funToStr(path) {
var node = path.node;
if (!t.isIdentifier(node.callee, {name: decryptStr}))
return;
let value = eval(path.toString())
// console.log("还原前:" + path.toString(), "还原后:" + value);
path.replaceWith(t.valueToNode(value));
}
function delExtra(path) {
delete path.node.extra;
}
}
function ReplaceWhile(path) {
var node = path.node;
if (!(t.isBooleanLiteral(node.test) || t.isUnaryExpression(node.test)))
return;
if (!(node.test.prefix || node.test.value))
return;
if (!t.isBlockStatement(node.body))
return;
var body = node.body.body;
if (!t.isSwitchStatement(body[0]) || !t.isMemberExpression(body[0].discriminant) || !t.isBreakStatement(body[1]))
return;
var swithStm = body[0];
var arrName = swithStm.discriminant.object.name;
var argName = swithStm.discriminant.property.argument.name
let arr = [];
let all_presibling = path.getAllPrevSiblings();
all_presibling.forEach(pre_path => {
const {declarations} = pre_path.node;
let {id, init} = declarations[0]
if (arrName == id.name) {
arr = init.callee.object.value.split('|');
pre_path.remove()
}
if (argName == id.name) {
pre_path.remove()
}
})
var caseList = swithStm.cases;
var resultBody = [];
arr.map(targetIdx => {
var targetBody = caseList[targetIdx].consequent;
if (t.isContinueStatement(targetBody[targetBody.length - 1]))
targetBody.pop();
resultBody = resultBody.concat(targetBody)
});
path.replaceInline(resultBody);
}
function muti_process_defusion(jscode){
var ast = parser.parse(jscode);
// ob 解混淆处理部分
// ast = get_ob_enc(ast)
// ast = pas_ob_enc(ast)
// traverse(ast, {VariableDeclarator: {exit: MergeObj},}); // 可能出问题(不可通用)
// traverse(ast, {VariableDeclarator: {exit: CallToStr},}); // 可能出问题(不可通用)
// traverse(ast, {WhileStatement: {exit: [ReplaceWhile]},}); // 反控制流平坦化
// 通用解混淆部分
traverse(ast, {StringLiteral: delExtra,}) // 清理二进制显示内容
traverse(ast, {NumericLiteral: delExtra,}) // 清理二进制显示内容
traverse(ast, {ConditionalExpression: TransCondition,}); // 三元表达式
traverse(ast, {ExpressionStatement: ConditionToIf,}); // 三元表达式转换成if
traverse(ast, {VariableDeclarator: ConditionVarToIf,}); // 赋值语句的 三元表达式转换成if
traverse(ast, {ExpressionStatement: RemoveComma,}); // 逗号表达式转换
traverse(ast, {VariableDeclaration: RemoveVarComma,}); // 赋值语句的 逗号表达式转换
traverse(ast, {MemberExpression: FormatMember,}); // obj['func1']['func2']() --> obj.func1.func2()
traverse(ast, {CatchClause: AddCatchLog}); // 给所有的 catch(e){} 后面第一条语句添加异常输出。
var { code } = generator(ast, { jsescOption: { minimal: true, } });
return code;
}
function muti_process_obdefusion(jscode){
var ast = parser.parse(jscode);
// ob 解混淆处理部分
ast = get_ob_enc(ast)
ast = pas_ob_enc(ast)
traverse(ast, {VariableDeclarator: {exit: MergeObj},}); // 可能出问题(不可通用)
traverse(ast, {VariableDeclarator: {exit: CallToStr},}); // 可能出问题(不可通用)
traverse(ast, {WhileStatement: {exit: [ReplaceWhile]},}); // 反控制流平坦化
// 通用解混淆部分
traverse(ast, {StringLiteral: delExtra,}) // 清理二进制显示内容
traverse(ast, {NumericLiteral: delExtra,}) // 清理二进制显示内容
traverse(ast, {ConditionalExpression: TransCondition,}); // 三元表达式
traverse(ast, {ExpressionStatement: ConditionToIf,}); // 三元表达式转换成if
traverse(ast, {VariableDeclarator: ConditionVarToIf,}); // 赋值语句的 三元表达式转换成if
traverse(ast, {ExpressionStatement: RemoveComma,}); // 逗号表达式转换
traverse(ast, {VariableDeclaration: RemoveVarComma,}); // 赋值语句的 逗号表达式转换
traverse(ast, {MemberExpression: FormatMember,}); // obj['func1']['func2']() --> obj.func1.func2()
traverse(ast, {CatchClause: AddCatchLog}); // 给所有的 catch(e){} 后面第一条语句添加异常输出。
var { code } = generator(ast, { jsescOption: { minimal: true, } });
return code;
}

45
tools/popup_utils.js Normal file
View File

@ -0,0 +1,45 @@
var obtn = document.getElementById('ob')
var obnormalbtn = document.getElementById('obnormal')
var uglifybtn = document.getElementById('uglify')
var uglify_minibtn = document.getElementById('uglify_mini')
var txt = document.getElementById('txt')
obtn.addEventListener('click', function(e){
try{
txt.value = muti_process_obdefusion(txt.value)
}catch(e){
txt.value = e.stack
}
})
uglifybtn.addEventListener('click', function(e){
var r = UglifyJS.minify(txt.value, {
compress: {
drop_debugger: false,
hoist_vars: false,
join_vars: false,
sequences: false,
inline: false,
loops: false,
reduce_funcs: false,
reduce_vars: false,
collapse_vars: false,
comparisons: false,
computed_props: false,
conditionals: true,
evaluate: true,
expression: false,
},
output: {
bracketize: true,
beautify: true,
},
})
txt.value = r.code?r.code:r.error;
})
uglify_minibtn.addEventListener('click', function(e){
var r = UglifyJS.minify(txt.value)
txt.value = r.code?r.code:r.error;
})

12573
tools/uglify_es.js Normal file

File diff suppressed because one or more lines are too long