mirror of
https://github.com/smallfawn/decode_action.git
synced 2025-12-20 00:35:19 +08:00
TEST
This commit is contained in:
211
src/visitor/merge-object.js
Normal file
211
src/visitor/merge-object.js
Normal file
@@ -0,0 +1,211 @@
|
||||
const t = require('@babel/types')
|
||||
|
||||
function mergeObject(path) {
|
||||
const { id, init } = path.node
|
||||
if (!t.isObjectExpression(init)) {
|
||||
// 判断是否是定义对象
|
||||
return
|
||||
}
|
||||
let name = id.name
|
||||
let scope = path.scope
|
||||
let binding = scope.getBinding(name)
|
||||
const start = path.node.end
|
||||
let end = -1
|
||||
let violation = null
|
||||
if (!binding.constant) {
|
||||
// Find the first constantViolation after this declaration
|
||||
for (let item of binding.constantViolations) {
|
||||
if (item.node.start <= start) {
|
||||
continue
|
||||
}
|
||||
if (item.isVariableDeclarator()) {
|
||||
end = item.node.start
|
||||
violation = item
|
||||
break
|
||||
}
|
||||
if (item.isAssignmentExpression()) {
|
||||
end = item.node.start
|
||||
violation = item
|
||||
break
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
// 添加已有的key
|
||||
let keys = {}
|
||||
let properties = init.properties
|
||||
for (let prop of properties) {
|
||||
let key = null
|
||||
if (t.isStringLiteral(prop.key)) {
|
||||
key = prop.key.value
|
||||
}
|
||||
if (t.isIdentifier(prop.key)) {
|
||||
key = prop.key.name
|
||||
}
|
||||
if (key) {
|
||||
keys[key] = true
|
||||
}
|
||||
}
|
||||
// 遍历作用域检测是否含有局部混淆特征并合并成员
|
||||
let merges = []
|
||||
const container = path.parentPath.parentPath
|
||||
let cur = 0
|
||||
let valid = true
|
||||
// Check references in sequence
|
||||
while (cur < binding.references) {
|
||||
const ref = binding.referencePaths[cur]
|
||||
// Ignore the references before this declaration
|
||||
if (ref.node.start <= start) {
|
||||
++cur
|
||||
continue
|
||||
}
|
||||
// Ignore the references after the first constantViolation
|
||||
if (end >= 0 && ref.node.end >= end) {
|
||||
break
|
||||
}
|
||||
if (ref.key !== 'object' || !ref.parentPath.isMemberExpression()) {
|
||||
break
|
||||
}
|
||||
const me = ref.parentPath
|
||||
if (me.key !== 'left' || !me.parentPath.isAssignmentExpression()) {
|
||||
break
|
||||
}
|
||||
const ae = me.parentPath
|
||||
let bk = ae
|
||||
let stop = false
|
||||
while (bk.parentPath !== container) {
|
||||
if (
|
||||
bk.parentPath.isSequenceExpression() ||
|
||||
bk.parentPath.isVariableDeclarator() ||
|
||||
bk.parentPath.isVariableDeclaration() ||
|
||||
bk.parentPath.isExpressionStatement()
|
||||
) {
|
||||
bk = bk.parentPath
|
||||
continue
|
||||
}
|
||||
stop = true
|
||||
break
|
||||
}
|
||||
if (stop) {
|
||||
break
|
||||
}
|
||||
const property = me.node.property
|
||||
let key = null
|
||||
if (t.isStringLiteral(property)) {
|
||||
key = property.value
|
||||
}
|
||||
if (t.isIdentifier(property)) {
|
||||
key = property.name
|
||||
}
|
||||
if (!key) {
|
||||
valid = false
|
||||
break
|
||||
}
|
||||
// 不允许出现重定义
|
||||
if (Object.prototype.hasOwnProperty.call(keys, key)) {
|
||||
valid = false
|
||||
break
|
||||
}
|
||||
// 添加到列表
|
||||
properties.push(t.ObjectProperty(t.valueToNode(key), ae.node.right))
|
||||
keys[key] = true
|
||||
merges.push(ae)
|
||||
++cur
|
||||
}
|
||||
if (!merges.length || !valid) {
|
||||
return
|
||||
}
|
||||
// Remove code
|
||||
console.log(`尝试性合并: ${name}`)
|
||||
for (let ref of merges) {
|
||||
const left = ref.node.left
|
||||
if (ref.parentPath.isSequenceExpression() && ref.container.length === 1) {
|
||||
ref = ref.parentPath
|
||||
}
|
||||
if (
|
||||
ref.parentPath.isVariableDeclarator() ||
|
||||
ref.parentPath.isAssignmentExpression()
|
||||
) {
|
||||
ref.replaceWith(left)
|
||||
} else {
|
||||
ref.remove()
|
||||
}
|
||||
}
|
||||
// Check the remaining references
|
||||
const ref1 = binding.referencePaths[cur++]
|
||||
if (!ref1) {
|
||||
scope.crawl()
|
||||
return
|
||||
}
|
||||
const ref2 = binding.referencePaths[cur]
|
||||
// Don't replace the declarator if there exists more than one reference
|
||||
if (ref2 && ref2.node.end < end) {
|
||||
scope.crawl()
|
||||
return
|
||||
}
|
||||
// Check if the only reference is an assignment
|
||||
let key = ref1.key
|
||||
let up1 = ref1.parentPath
|
||||
if (up1.isSequenceExpression() && ref1.container.length === 1) {
|
||||
key = up1.key
|
||||
up1 = up1.parentPath
|
||||
}
|
||||
if (!up1.isVariableDeclarator() || key !== 'init') {
|
||||
scope.crawl()
|
||||
return
|
||||
}
|
||||
// Move the definition to its reference
|
||||
up1.node.init = path.node.init
|
||||
// Delete the original definition
|
||||
if (violation?.isAssignmentExpression()) {
|
||||
path.node.init = undefined
|
||||
} else {
|
||||
path.remove()
|
||||
}
|
||||
scope.crawl()
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect the properties of one object and move it back to the declaration.
|
||||
*
|
||||
* One example made by ObjectExpressionKeysTransformer:
|
||||
*
|
||||
* ```javascript
|
||||
* 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;
|
||||
* ```
|
||||
*
|
||||
* The result:
|
||||
*
|
||||
* ```javascript
|
||||
* var _0x15e145 = {
|
||||
* "abcd": function (_0x22293f, _0x5a165e) {
|
||||
* return _0x22293f == _0x5a165e;
|
||||
* },
|
||||
* "dbca": function (_0xfbac1e, _0x23462f, _0x556555) {
|
||||
* return _0xfbac1e(_0x23462f, _0x556555);
|
||||
* },
|
||||
* "aaa": function (_0x57e640) {
|
||||
* return _0x57e640();
|
||||
* },
|
||||
* "bbb": "eee"
|
||||
* };
|
||||
* ```
|
||||
*
|
||||
* Note:
|
||||
* - Constant objects in the original code can be splitted
|
||||
* - AssignmentExpression can be moved to ReturnStatement
|
||||
*/
|
||||
module.exports = {
|
||||
VariableDeclarator: mergeObject,
|
||||
}
|
||||
Reference in New Issue
Block a user