Files
smallfawn-decode_action/src/visitor/merge-object.js
smallfawn 644ea3a59d TEST
2024-06-27 21:29:59 +08:00

212 lines
5.1 KiB
JavaScript

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,
}