diff --git a/package-lock.json b/package-lock.json
index 3b4cf4d..b1b0acc 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,10 +9,9 @@
"version": "2.0.5",
"license": "MIT",
"dependencies": {
- "flast": "^2.1.1",
- "isolated-vm": "^5.0.2",
- "jsdom": "^25.0.1",
- "obfuscation-detector": "^2.0.4"
+ "flast": "2.2.1",
+ "isolated-vm": "^5.0.3",
+ "obfuscation-detector": "^2.0.5"
},
"bin": {
"restringer": "bin/deobfuscate.js"
@@ -449,9 +448,9 @@
}
},
"node_modules/@eslint/js": {
- "version": "9.16.0",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.16.0.tgz",
- "integrity": "sha512-tw2HxzQkrbeuvyj1tG2Yqq+0H9wGoI2IMk4EOsQeX+vmd75FtJAzf+gTA69WF+baUKRYQ3x2kbLE08js5OsTVg==",
+ "version": "9.17.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.17.0.tgz",
+ "integrity": "sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==",
"dev": true,
"license": "MIT",
"engines": {
@@ -557,9 +556,9 @@
}
},
"node_modules/@jridgewell/gen-mapping": {
- "version": "0.3.5",
- "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
- "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
+ "version": "0.3.8",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz",
+ "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==",
"dev": true,
"license": "MIT",
"peer": true,
@@ -659,15 +658,6 @@
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
}
},
- "node_modules/agent-base": {
- "version": "7.1.3",
- "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz",
- "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==",
- "license": "MIT",
- "engines": {
- "node": ">= 14"
- }
- },
"node_modules/ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@@ -708,12 +698,6 @@
"dev": true,
"license": "Python-2.0"
},
- "node_modules/asynckit": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
- "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
- "license": "MIT"
- },
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -764,9 +748,9 @@
}
},
"node_modules/browserslist": {
- "version": "4.24.2",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz",
- "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==",
+ "version": "4.24.3",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.3.tgz",
+ "integrity": "sha512-1CPmv8iobE2fyRMV97dAcMVegvvWKxmq94hkLiAkUGwKVTyDLw33K+ZxiFrREKmmps4rIw6grcCFCnTMSZ/YiA==",
"dev": true,
"funding": [
{
@@ -785,9 +769,9 @@
"license": "MIT",
"peer": true,
"dependencies": {
- "caniuse-lite": "^1.0.30001669",
- "electron-to-chromium": "^1.5.41",
- "node-releases": "^2.0.18",
+ "caniuse-lite": "^1.0.30001688",
+ "electron-to-chromium": "^1.5.73",
+ "node-releases": "^2.0.19",
"update-browserslist-db": "^1.1.1"
},
"bin": {
@@ -832,9 +816,9 @@
}
},
"node_modules/caniuse-lite": {
- "version": "1.0.30001687",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001687.tgz",
- "integrity": "sha512-0S/FDhf4ZiqrTUiQ39dKeUjYRjkv7lOZU1Dgif2rIqrTzX/1wV2hfKu9TOm1IHkdSijfLswxTFzl/cvir+SLSQ==",
+ "version": "1.0.30001690",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001690.tgz",
+ "integrity": "sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w==",
"dev": true,
"funding": [
{
@@ -896,18 +880,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/combined-stream": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
- "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
- "license": "MIT",
- "dependencies": {
- "delayed-stream": "~1.0.0"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -938,35 +910,11 @@
"node": ">= 8"
}
},
- "node_modules/cssstyle": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.1.0.tgz",
- "integrity": "sha512-h66W1URKpBS5YMI/V8PyXvTMFT8SupJ1IzoIV8IeBC/ji8WVmrO8dGlTi+2dh6whmdk6BiKJLD/ZBkhWbcg6nA==",
- "license": "MIT",
- "dependencies": {
- "rrweb-cssom": "^0.7.1"
- },
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/data-urls": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz",
- "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==",
- "license": "MIT",
- "dependencies": {
- "whatwg-mimetype": "^4.0.0",
- "whatwg-url": "^14.0.0"
- },
- "engines": {
- "node": ">=18"
- }
- },
"node_modules/debug": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
"integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
@@ -980,12 +928,6 @@
}
}
},
- "node_modules/decimal.js": {
- "version": "10.4.3",
- "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz",
- "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==",
- "license": "MIT"
- },
"node_modules/decompress-response": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
@@ -1016,15 +958,6 @@
"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
"license": "MIT"
},
- "node_modules/delayed-stream": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
- "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
- "license": "MIT",
- "engines": {
- "node": ">=0.4.0"
- }
- },
"node_modules/detect-libc": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz",
@@ -1035,9 +968,9 @@
}
},
"node_modules/electron-to-chromium": {
- "version": "1.5.71",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.71.tgz",
- "integrity": "sha512-dB68l59BI75W1BUGVTAEJy45CEVuEGy9qPVVQ8pnHyHMn36PLPPoE1mjLH+lo9rKulO3HC2OhbACI/8tCqJBcA==",
+ "version": "1.5.75",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.75.tgz",
+ "integrity": "sha512-Lf3++DumRE/QmweGjU+ZcKqQ+3bKkU/qjaKYhIJKEOhgIO9Xs6IiAQFkfFoj+RhgDk4LUeNsLo6plExHqSyu6Q==",
"dev": true,
"license": "ISC",
"peer": true
@@ -1051,18 +984,6 @@
"once": "^1.4.0"
}
},
- "node_modules/entities": {
- "version": "4.5.0",
- "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
- "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
- "license": "BSD-2-Clause",
- "engines": {
- "node": ">=0.12"
- },
- "funding": {
- "url": "https://github.com/fb55/entities?sponsor=1"
- }
- },
"node_modules/escalade": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
@@ -1157,9 +1078,9 @@
}
},
"node_modules/eslint": {
- "version": "9.16.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.16.0.tgz",
- "integrity": "sha512-whp8mSQI4C8VXd+fLgSM0lh3UlmcFtVwUQjyKCFfsp+2ItAIYhlq/hqGahGqHE6cv9unM41VlqKk2VtKYR2TaA==",
+ "version": "9.17.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.17.0.tgz",
+ "integrity": "sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1168,7 +1089,7 @@
"@eslint/config-array": "^0.19.0",
"@eslint/core": "^0.9.0",
"@eslint/eslintrc": "^3.2.0",
- "@eslint/js": "9.16.0",
+ "@eslint/js": "9.17.0",
"@eslint/plugin-kit": "^0.2.3",
"@humanfs/node": "^0.16.6",
"@humanwhocodes/module-importer": "^1.0.1",
@@ -1177,7 +1098,7 @@
"@types/json-schema": "^7.0.15",
"ajv": "^6.12.4",
"chalk": "^4.0.0",
- "cross-spawn": "^7.0.5",
+ "cross-spawn": "^7.0.6",
"debug": "^4.3.2",
"escape-string-regexp": "^4.0.0",
"eslint-scope": "^8.2.0",
@@ -1445,15 +1366,14 @@
}
},
"node_modules/flast": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/flast/-/flast-2.1.1.tgz",
- "integrity": "sha512-C2DY6cpUzQerbVw+K3YzFWehz8SSiQFcUZMV4dUd/2W8RXlue4qWPvh8oD0tnQK/RjhZvVtgUZVrI3aSIUm8YA==",
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/flast/-/flast-2.2.1.tgz",
+ "integrity": "sha512-04Pd2dulGdhZ9GJ1CNzsx9gTAu8oAvlwFm6n0HLDVdHhcaTGOb3xzntZSFeHEFsYf5QkVy7koFFqvZKmKLrZqA==",
"license": "MIT",
"dependencies": {
"escodegen": "npm:@javascript-obfuscator/escodegen",
"eslint-scope": "^8.2.0",
- "espree": "^10.3.0",
- "estraverse": "^5.3.0"
+ "espree": "^10.3.0"
}
},
"node_modules/flast/node_modules/eslint-scope": {
@@ -1502,20 +1422,6 @@
"dev": true,
"license": "ISC"
},
- "node_modules/form-data": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz",
- "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==",
- "license": "MIT",
- "dependencies": {
- "asynckit": "^0.4.0",
- "combined-stream": "^1.0.8",
- "mime-types": "^2.1.12"
- },
- "engines": {
- "node": ">= 6"
- }
- },
"node_modules/fs-constants": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
@@ -1553,9 +1459,9 @@
}
},
"node_modules/globals": {
- "version": "15.13.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-15.13.0.tgz",
- "integrity": "sha512-49TewVEz0UxZjr1WYYsWpPrhyC/B/pA8Bq0fUmet2n+eR7yn0IvNzNaoBwnK6mdkzcN+se7Ez9zUgULTz2QH4g==",
+ "version": "15.14.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-15.14.0.tgz",
+ "integrity": "sha512-OkToC372DtlQeje9/zHIo5CT8lRP/FUgEOKBEhU4e0abL7J7CD24fD9ohiLN5hagG/kWCYj4K5oaxxtj2Z0Dig==",
"dev": true,
"license": "MIT",
"engines": {
@@ -1575,44 +1481,6 @@
"node": ">=8"
}
},
- "node_modules/html-encoding-sniffer": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz",
- "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==",
- "license": "MIT",
- "dependencies": {
- "whatwg-encoding": "^3.1.1"
- },
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/http-proxy-agent": {
- "version": "7.0.2",
- "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
- "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
- "license": "MIT",
- "dependencies": {
- "agent-base": "^7.1.0",
- "debug": "^4.3.4"
- },
- "engines": {
- "node": ">= 14"
- }
- },
- "node_modules/https-proxy-agent": {
- "version": "7.0.6",
- "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
- "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
- "license": "MIT",
- "dependencies": {
- "agent-base": "^7.1.2",
- "debug": "4"
- },
- "engines": {
- "node": ">= 14"
- }
- },
"node_modules/husky": {
"version": "9.1.7",
"resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz",
@@ -1629,18 +1497,6 @@
"url": "https://github.com/sponsors/typicode"
}
},
- "node_modules/iconv-lite": {
- "version": "0.6.3",
- "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
- "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
- "license": "MIT",
- "dependencies": {
- "safer-buffer": ">= 2.1.2 < 3.0.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
@@ -1733,12 +1589,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/is-potential-custom-element-name": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
- "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==",
- "license": "MIT"
- },
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@@ -1747,9 +1597,9 @@
"license": "ISC"
},
"node_modules/isolated-vm": {
- "version": "5.0.2",
- "resolved": "https://registry.npmjs.org/isolated-vm/-/isolated-vm-5.0.2.tgz",
- "integrity": "sha512-q8zQIbVIg83nmV2x1r60gWGjgjaJ2srGMzJ5B4TIlvnWZMuZDIM0OxOOj+5FF9oui1XdAU29xWwT9M4ih6RJiQ==",
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/isolated-vm/-/isolated-vm-5.0.3.tgz",
+ "integrity": "sha512-GNqX0j7dkwdaNQfFogLLb/tSuPZbXtKlk5ldaJ084ngjaW9/bn34x9FQFL856p20KSZoubIIummmiJf+2hzhCw==",
"hasInstallScript": true,
"license": "ISC",
"dependencies": {
@@ -1780,50 +1630,10 @@
"js-yaml": "bin/js-yaml.js"
}
},
- "node_modules/jsdom": {
- "version": "25.0.1",
- "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-25.0.1.tgz",
- "integrity": "sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==",
- "license": "MIT",
- "dependencies": {
- "cssstyle": "^4.1.0",
- "data-urls": "^5.0.0",
- "decimal.js": "^10.4.3",
- "form-data": "^4.0.0",
- "html-encoding-sniffer": "^4.0.0",
- "http-proxy-agent": "^7.0.2",
- "https-proxy-agent": "^7.0.5",
- "is-potential-custom-element-name": "^1.0.1",
- "nwsapi": "^2.2.12",
- "parse5": "^7.1.2",
- "rrweb-cssom": "^0.7.1",
- "saxes": "^6.0.0",
- "symbol-tree": "^3.2.4",
- "tough-cookie": "^5.0.0",
- "w3c-xmlserializer": "^5.0.0",
- "webidl-conversions": "^7.0.0",
- "whatwg-encoding": "^3.1.1",
- "whatwg-mimetype": "^4.0.0",
- "whatwg-url": "^14.0.0",
- "ws": "^8.18.0",
- "xml-name-validator": "^5.0.0"
- },
- "engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "canvas": "^2.11.2"
- },
- "peerDependenciesMeta": {
- "canvas": {
- "optional": true
- }
- }
- },
"node_modules/jsesc": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz",
- "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==",
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
+ "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
"dev": true,
"license": "MIT",
"peer": true,
@@ -1927,27 +1737,6 @@
"yallist": "^3.0.2"
}
},
- "node_modules/mime-db": {
- "version": "1.52.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
- "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/mime-types": {
- "version": "2.1.35",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
- "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
- "license": "MIT",
- "dependencies": {
- "mime-db": "1.52.0"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
"node_modules/mimic-response": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
@@ -1992,6 +1781,7 @@
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true,
"license": "MIT"
},
"node_modules/napi-build-utils": {
@@ -2032,26 +1822,20 @@
}
},
"node_modules/node-releases": {
- "version": "2.0.18",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz",
- "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==",
+ "version": "2.0.19",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
+ "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==",
"dev": true,
"license": "MIT",
"peer": true
},
- "node_modules/nwsapi": {
- "version": "2.2.16",
- "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.16.tgz",
- "integrity": "sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ==",
- "license": "MIT"
- },
"node_modules/obfuscation-detector": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/obfuscation-detector/-/obfuscation-detector-2.0.4.tgz",
- "integrity": "sha512-d8DhD7j6pQ68z1XcpWgEjNKtQAnLM2Opx464jU3tu3+dT4ycux9YgEeVmX4QEYmSfMWJXivvyTooj/Iz61Igrw==",
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/obfuscation-detector/-/obfuscation-detector-2.0.5.tgz",
+ "integrity": "sha512-g4VLMZronO5ZTZUWzTY9k8YfevkT1YGp0go514WStGAvHSQ6Yh2d9LzG1q4rJ+goDqYo0+tPOrP/xKLxptqkUw==",
"license": "MIT",
"dependencies": {
- "flast": "^2.1.1"
+ "flast": "^2.2.1"
},
"bin": {
"obfuscation-detector": "bin/obfuscation-detector.js"
@@ -2129,18 +1913,6 @@
"node": ">=6"
}
},
- "node_modules/parse5": {
- "version": "7.2.1",
- "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz",
- "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==",
- "license": "MIT",
- "dependencies": {
- "entities": "^4.5.0"
- },
- "funding": {
- "url": "https://github.com/inikulin/parse5?sponsor=1"
- }
- },
"node_modules/path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
@@ -2219,6 +1991,7 @@
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
@@ -2272,12 +2045,6 @@
"node": ">=4"
}
},
- "node_modules/rrweb-cssom": {
- "version": "0.7.1",
- "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz",
- "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==",
- "license": "MIT"
- },
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
@@ -2298,24 +2065,6 @@
],
"license": "MIT"
},
- "node_modules/safer-buffer": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
- "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
- "license": "MIT"
- },
- "node_modules/saxes": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz",
- "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==",
- "license": "ISC",
- "dependencies": {
- "xmlchars": "^2.2.0"
- },
- "engines": {
- "node": ">=v12.22.7"
- }
- },
"node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
@@ -2439,12 +2188,6 @@
"node": ">=8"
}
},
- "node_modules/symbol-tree": {
- "version": "3.2.4",
- "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
- "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==",
- "license": "MIT"
- },
"node_modules/tar-fs": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz",
@@ -2473,48 +2216,6 @@
"node": ">=6"
}
},
- "node_modules/tldts": {
- "version": "6.1.66",
- "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.66.tgz",
- "integrity": "sha512-l3ciXsYFel/jSRfESbyKYud1nOw7WfhrBEF9I3UiarYk/qEaOOwu3qXNECHw4fHGHGTEOuhf/VdKgoDX5M/dhQ==",
- "license": "MIT",
- "dependencies": {
- "tldts-core": "^6.1.66"
- },
- "bin": {
- "tldts": "bin/cli.js"
- }
- },
- "node_modules/tldts-core": {
- "version": "6.1.66",
- "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.66.tgz",
- "integrity": "sha512-s07jJruSwndD2X8bVjwioPfqpIc1pDTzszPe9pL1Skbh4bjytL85KNQ3tolqLbCvpQHawIsGfFi9dgerWjqW4g==",
- "license": "MIT"
- },
- "node_modules/tough-cookie": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.0.0.tgz",
- "integrity": "sha512-FRKsF7cz96xIIeMZ82ehjC3xW2E+O2+v11udrDYewUbszngYhsGa8z6YUMMzO9QJZzzyd0nGGXnML/TReX6W8Q==",
- "license": "BSD-3-Clause",
- "dependencies": {
- "tldts": "^6.1.32"
- },
- "engines": {
- "node": ">=16"
- }
- },
- "node_modules/tr46": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz",
- "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==",
- "license": "MIT",
- "dependencies": {
- "punycode": "^2.3.1"
- },
- "engines": {
- "node": ">=18"
- }
- },
"node_modules/tunnel-agent": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
@@ -2588,61 +2289,6 @@
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"license": "MIT"
},
- "node_modules/w3c-xmlserializer": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz",
- "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==",
- "license": "MIT",
- "dependencies": {
- "xml-name-validator": "^5.0.0"
- },
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/webidl-conversions": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
- "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
- "license": "BSD-2-Clause",
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/whatwg-encoding": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz",
- "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==",
- "license": "MIT",
- "dependencies": {
- "iconv-lite": "0.6.3"
- },
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/whatwg-mimetype": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz",
- "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==",
- "license": "MIT",
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/whatwg-url": {
- "version": "14.1.0",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.1.0.tgz",
- "integrity": "sha512-jlf/foYIKywAt3x/XWKZ/3rz8OSJPiWktjmk891alJUEjiVxKX9LEO92qH3hv4aJ0mN3MWPvGMCy8jQi95xK4w==",
- "license": "MIT",
- "dependencies": {
- "tr46": "^5.0.0",
- "webidl-conversions": "^7.0.0"
- },
- "engines": {
- "node": ">=18"
- }
- },
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -2674,42 +2320,6 @@
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
"license": "ISC"
},
- "node_modules/ws": {
- "version": "8.18.0",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
- "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
- "license": "MIT",
- "engines": {
- "node": ">=10.0.0"
- },
- "peerDependencies": {
- "bufferutil": "^4.0.1",
- "utf-8-validate": ">=5.0.2"
- },
- "peerDependenciesMeta": {
- "bufferutil": {
- "optional": true
- },
- "utf-8-validate": {
- "optional": true
- }
- }
- },
- "node_modules/xml-name-validator": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz",
- "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==",
- "license": "Apache-2.0",
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/xmlchars": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
- "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
- "license": "MIT"
- },
"node_modules/yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
diff --git a/package.json b/package.json
index 1fe7630..62eb5ce 100644
--- a/package.json
+++ b/package.json
@@ -12,10 +12,9 @@
"test": "tests"
},
"dependencies": {
- "flast": "^2.1.1",
- "isolated-vm": "^5.0.2",
- "jsdom": "^25.0.1",
- "obfuscation-detector": "^2.0.4"
+ "flast": "2.2.1",
+ "isolated-vm": "^5.0.3",
+ "obfuscation-detector": "^2.0.5"
},
"scripts": {
"test": "node --test --trace-warnings --no-node-snapshot",
diff --git a/src/modules/config.js b/src/modules/config.js
index 1ea0dc2..77fb23e 100644
--- a/src/modules/config.js
+++ b/src/modules/config.js
@@ -15,7 +15,9 @@ const defaultMaxIterations = {
valueOf() {return this.value--;},
};
-const propertiesThatModifyContent = ['push', 'forEach', 'pop', 'insert', 'add', 'set', 'delete'];
+const propertiesThatModifyContent = [
+ 'push', 'forEach', 'pop', 'insert', 'add', 'set', 'delete', 'shift', 'unshift', 'splice'
+];
// Builtin functions that shouldn't be resolved in the deobfuscation context.
const skipBuiltinFunctions = [
diff --git a/src/modules/safe/rearrangeSwitches.js b/src/modules/safe/rearrangeSwitches.js
index 3688bfa..0942aeb 100644
--- a/src/modules/safe/rearrangeSwitches.js
+++ b/src/modules/safe/rearrangeSwitches.js
@@ -23,16 +23,32 @@ function rearrangeSwitches(arb, candidateFilter = () => true) {
let counter = 0;
while (currentVal !== undefined && counter < maxRepetition) {
// A matching case or the default case
- let currentCase = cases.find(c => c.test?.value === currentVal) || cases.find(c => !c.test);
+ let currentCase;
+ for (let j = 0; j < cases.length; j++) {
+ if (cases[j].test?.value === currentVal || !cases[j].test) {
+ currentCase = cases[j];
+ break;
+ }
+ }
if (!currentCase) break;
- ordered.push(...currentCase.consequent.filter(c => c.type !== 'BreakStatement'));
-
+ for (let j = 0; j < currentCase.consequent.length; j++) {
+ if (currentCase.consequent[j].type !== 'BreakStatement') {
+ ordered.push(currentCase.consequent[j]);
+ }
+ }
let allDescendants = [];
- currentCase.consequent.forEach(c => allDescendants.push(...getDescendants(c)));
- const assignments2Next = allDescendants.filter(d =>
- d.declNode === n.discriminant.declNode &&
- d.parentKey === 'left' &&
- d.parentNode.type === 'AssignmentExpression');
+ for (let j = 0; j < currentCase.consequent.length; j++) {
+ allDescendants.push(...getDescendants(currentCase.consequent[j]));
+ }
+ const assignments2Next = [];
+ for (let j = 0; j < allDescendants.length; j++) {
+ const d = allDescendants[j];
+ if (d.declNode === n.discriminant.declNode &&
+ d.parentKey === 'left' &&
+ d.parentNode.type === 'AssignmentExpression') {
+ assignments2Next.push(d);
+ }
+ }
if (assignments2Next.length === 1) {
currentVal = assignments2Next[0].parentNode.right.value;
} else {
diff --git a/src/modules/safe/resolveFunctionConstructorCalls.js b/src/modules/safe/resolveFunctionConstructorCalls.js
index 84084e1..396db60 100644
--- a/src/modules/safe/resolveFunctionConstructorCalls.js
+++ b/src/modules/safe/resolveFunctionConstructorCalls.js
@@ -11,24 +11,27 @@ function resolveFunctionConstructorCalls(arb, candidateFilter = () => true) {
const relevantNodes = [
...(arb.ast[0].typeMap.CallExpression || []),
];
- for (let i = 0; i < relevantNodes.length; i++) {
+ nodeLoop: for (let i = 0; i < relevantNodes.length; i++) {
const n = relevantNodes[i];
if (n.callee?.type === 'MemberExpression' &&
(n.callee.property?.name || n.callee.property?.value) === 'constructor' &&
- n.arguments.length && n.arguments.slice(-1)[0].type === 'Literal' &&
- candidateFilter(n)) {let args = '';
+ candidateFilter(n)) {
+ let args = '';
+ let code = '';
if (n.arguments.length > 1) {
- const originalArgs = n.arguments.slice(0, -1);
- if (originalArgs.find(n => n.type !== 'Literal')) continue;
- args = originalArgs.map(n => n.value).join(', ');
- }
+ for (let j = 0; j < n.arguments.length; j++) {
+ if (n.arguments[j].type !== 'Literal') continue nodeLoop;
+ if (code) args += (args.length ? ', ' : '') + code;
+ code = n.arguments[j].value;
+ }
+ } else code = n.arguments[0].value;
// Wrap the code in a valid anonymous function in the same way Function.constructor would.
// Give the anonymous function any arguments it may require.
// Wrap the function in an expression to make it a valid code (since it's anonymous).
// Generate an AST without nodeIds (to avoid duplicates with the rest of the code).
// Extract just the function expression from the AST.
try {
- const codeNode = generateFlatAST(`(function (${args}) {${n.arguments.slice(-1)[0].value}})`,
+ const codeNode = generateFlatAST(`(function (${args}) {${code}})`,
{detailed: false, includeSrc: false})[2];
if (codeNode) arb.markNode(n, codeNode);
} catch {}
diff --git a/src/modules/safe/resolveMemberExpressionsWithDirectAssignment.js b/src/modules/safe/resolveMemberExpressionsWithDirectAssignment.js
index 6a61bb1..12ac68e 100644
--- a/src/modules/safe/resolveMemberExpressionsWithDirectAssignment.js
+++ b/src/modules/safe/resolveMemberExpressionsWithDirectAssignment.js
@@ -13,20 +13,26 @@ function resolveMemberExpressionsWithDirectAssignment(arb, candidateFilter = ()
const relevantNodes = [
...(arb.ast[0].typeMap.MemberExpression || []),
];
- for (let i = 0; i < relevantNodes.length; i++) {
+ rnLoop: for (let i = 0; i < relevantNodes.length; i++) {
const n = relevantNodes[i];
if (n.object.declNode &&
n.parentNode.type === 'AssignmentExpression' &&
n.parentNode.right.type === 'Literal' &&
candidateFilter(n)) {
const prop = n.property?.value || n.property?.name;
- const valueUses = n.object.declNode.references.filter(ref =>
- ref.parentNode !== n && ref.parentNode.type === 'MemberExpression' &&
- prop === ref.parentNode.property[ref.parentNode.property.computed ? 'value' : 'name']);
+ const valueUses = [];
+ for (let j = 0; j < n.object.declNode.references.length; j++) {
+ /** @type {ASTNode} */
+ const ref = n.object.declNode.references[j];
+ if (ref.parentNode !== n && ref.parentNode.type === 'MemberExpression' &&
+ prop === ref.parentNode.property[ref.parentNode.property.computed ? 'value' : 'name']) {
+ // Skip if the value is reassigned
+ if (ref.parentNode.parentNode.type === 'UpdateExpression' ||
+ (ref.parentNode.parentNode.type === 'AssignmentExpression' && ref.parentNode.parentKey === 'left')) continue rnLoop;
+ valueUses.push(ref);
+ }
+ }
if (valueUses.length) {
- // Skip if the value is reassigned
- if (valueUses.some(v => v.parentNode.parentNode.type === 'UpdateExpression' ||
- (v.parentNode.parentNode.type === 'AssignmentExpression' && v.parentNode.parentKey === 'left'))) continue;
const replacementNode = n.parentNode.right;
for (let j = 0; j < valueUses.length; j++) {
arb.markNode(valueUses[j].parentNode, replacementNode);
diff --git a/src/modules/safe/resolveProxyReferences.js b/src/modules/safe/resolveProxyReferences.js
index 71aa567..cb4cc8a 100644
--- a/src/modules/safe/resolveProxyReferences.js
+++ b/src/modules/safe/resolveProxyReferences.js
@@ -1,5 +1,5 @@
-import {getDescendants} from '../utils/getDescendants.js';
import {areReferencesModified} from '../utils/areReferencesModified.js';
+import {doesDescendantMatchCondition} from '../utils/doesDescendantMatchCondition.js';
import {getMainDeclaredObjectOfMemberExpression} from '../utils/getMainDeclaredObjectOfMemberExpression.js';
/**
@@ -28,7 +28,7 @@ function resolveProxyReferences(arb, candidateFilter = () => true) {
const replacementMainIdentifier = getMainDeclaredObjectOfMemberExpression(n.init)?.declNode;
if (replacementMainIdentifier && replacementMainIdentifier === relevantIdentifier) continue;
// Exclude changes in the identifier's own init
- if (getDescendants(n.init).find(n => n.declNode === relevantIdentifier)) continue;
+ if (doesDescendantMatchCondition(n.init, n => n === relevantIdentifier)) continue;
if (refs.length && !areReferencesModified(arb.ast, refs) && !areReferencesModified(arb.ast, [replacementNode])) {
for (const ref of refs) {
arb.markNode(ref, replacementNode);
diff --git a/src/modules/unsafe/resolveAugmentedFunctionWrappedArrayReplacements.js b/src/modules/unsafe/resolveAugmentedFunctionWrappedArrayReplacements.js
index bea7e0d..1aa51f2 100644
--- a/src/modules/unsafe/resolveAugmentedFunctionWrappedArrayReplacements.js
+++ b/src/modules/unsafe/resolveAugmentedFunctionWrappedArrayReplacements.js
@@ -2,6 +2,7 @@ import {badValue} from '../config.js';
import {Sandbox} from '../utils/sandbox.js';
import {evalInVm} from '../utils/evalInVm.js';
import {getDescendants} from '../utils/getDescendants.js';
+import {doesDescendantMatchCondition} from '../utils/doesDescendantMatchCondition.js';
/**
* A special case of function array replacement where the function is wrapped in another function, the array is
@@ -17,49 +18,60 @@ export default function resolveAugmentedFunctionWrappedArrayReplacements(arb, ca
];
for (let i = 0; i < relevantNodes.length; i++) {
const n = relevantNodes[i];
- if (n.id && candidateFilter(n)) {
- const descendants = getDescendants(n);
- if (descendants.find(d =>
+ if (n.id &&
+ doesDescendantMatchCondition(n, d =>
d.type === 'AssignmentExpression' &&
- d.left?.name === n.id?.name)) {
- const arrDecryptor = n;
- const arrCandidates = descendants.filter(c =>
- c.type === 'MemberExpression' && c.object.type === 'Identifier')
- .map(n => n.object);
-
- for (let j = 0; j < arrCandidates.length; j++) {
- const ac = arrCandidates[j];
- // If a direct reference to a global variable pointing at an array
- let arrRef;
- if (!ac.declNode) continue;
- if (ac.declNode.scope.type === 'global') {
- if (ac.declNode.parentNode?.init?.type === 'ArrayExpression') {
- arrRef = ac.declNode.parentNode?.parentNode || ac.declNode.parentNode;
- }
- } else if (ac.declNode.parentNode?.init?.type === 'CallExpression') {
- arrRef = ac.declNode.parentNode.init.callee?.declNode?.parentNode;
+ d.left?.name === n.id?.name) &&
+ candidateFilter(n)) {
+ const descendants = getDescendants(n);
+ const arrDecryptor = n;
+ const arrCandidates = [];
+ for (let q = 0; q < descendants.length; q++) {
+ const c = descendants[q];
+ if (c.type === 'MemberExpression' && c.object.type === 'Identifier') arrCandidates.push(c.object);
+ }
+ for (let j = 0; j < arrCandidates.length; j++) {
+ const ac = arrCandidates[j];
+ // If a direct reference to a global variable pointing at an array
+ let arrRef;
+ if (!ac.declNode) continue;
+ if (ac.declNode.scope.type === 'global') {
+ if (ac.declNode.parentNode?.init?.type === 'ArrayExpression') {
+ arrRef = ac.declNode.parentNode?.parentNode || ac.declNode.parentNode;
}
- if (arrRef) {
- const iife = (arb.ast[0].typeMap.ExpressionStatement || []).find(c =>
- c.type === 'ExpressionStatement' &&
- c.expression.type === 'CallExpression' &&
- c.expression.callee.type === 'FunctionExpression' &&
- c.expression.arguments.length &&
- c.expression.arguments[0].type === 'Identifier' &&
- c.expression.arguments[0].declNode === ac.declNode);
- if (iife) {
- const context = [arrRef.src, arrDecryptor.src, iife.src].join('\n');
- const skipScopes = [arrRef.scope, arrDecryptor.scope, iife.expression.callee.scope];
- const replacementCandidates = (arb.ast[0].typeMap.CallExpression || []).filter(c =>
- c?.callee?.name === arrDecryptor.id.name &&
- !skipScopes.includes(c.scope));
+ } else if (ac.declNode.parentNode?.init?.type === 'CallExpression') {
+ arrRef = ac.declNode.parentNode.init.callee?.declNode?.parentNode;
+ }
+ if (arrRef) {
+ const expressionStatements = arb.ast[0].typeMap.ExpressionStatement || [];
+ for (let k = 0; k < expressionStatements.length; k++) {
+ const exp = expressionStatements[k];
+ if (exp.expression.type === 'CallExpression' &&
+ exp.expression.callee.type === 'FunctionExpression' &&
+ exp.expression.arguments.length &&
+ exp.expression.arguments[0].type === 'Identifier' &&
+ exp.expression.arguments[0].declNode === ac.declNode) {
+ const context = [arrRef.src, arrDecryptor.src, exp.src].join('\n');
+ const skipScopes = [arrRef.scope, arrDecryptor.scope, exp.expression.callee.scope];
+ const callExpressions = arb.ast[0].typeMap.CallExpression || [];
+ const replacementCandidates = [];
+ for (let r = 0; r < callExpressions.length; r++) {
+ const c = callExpressions[r];
+ if (c.callee?.name === arrDecryptor.id.name &&
+ !skipScopes.includes(c.scope)) {
+ replacementCandidates.push(c);
+ }
+ }
const sb = new Sandbox();
sb.run(context);
for (let p = 0; p < replacementCandidates.length; p++) {
const rc = replacementCandidates[p];
const replacementNode = evalInVm(`\n${rc.src}`, sb);
- if (replacementNode !== badValue) arb.markNode(rc, replacementNode);
+ if (replacementNode !== badValue) {
+ arb.markNode(rc, replacementNode);
+ }
}
+ break;
}
}
}
diff --git a/src/modules/unsafe/resolveEvalCallsOnNonLiterals.js b/src/modules/unsafe/resolveEvalCallsOnNonLiterals.js
index 4da1611..35ae2ed 100644
--- a/src/modules/unsafe/resolveEvalCallsOnNonLiterals.js
+++ b/src/modules/unsafe/resolveEvalCallsOnNonLiterals.js
@@ -27,8 +27,9 @@ function resolveEvalCallsOnNonLiterals(arb, candidateFilter = () => true) {
// The code inside the eval might contain references to outside code that should be included.
const contextNodes = getDeclarationWithContext(n, true);
// In case any of the target candidate is included in the context it should be removed.
- for (const redundantNode in [n, n?.parentNode, n?.parentNode?.parentNode]) {
- if (contextNodes.includes(redundantNode)) contextNodes.splice(contextNodes.indexOf(redundantNode), 1);
+ const possiblyRedundantNodes = [n, n?.parentNode, n?.parentNode?.parentNode];
+ for (let i = 0; i < possiblyRedundantNodes.length; i++) {
+ if (contextNodes.includes(possiblyRedundantNodes[i])) contextNodes.splice(contextNodes.indexOf(possiblyRedundantNodes[i]), 1);
}
const context = contextNodes.length ? createOrderedSrc(contextNodes) : '';
const src = `${context}\n;var __a_ = ${createOrderedSrc([n.arguments[0]])}\n;__a_`;
diff --git a/src/modules/unsafe/resolveLocalCalls.js b/src/modules/unsafe/resolveLocalCalls.js
index 6ac7694..0d2f714 100644
--- a/src/modules/unsafe/resolveLocalCalls.js
+++ b/src/modules/unsafe/resolveLocalCalls.js
@@ -57,15 +57,19 @@ export default function resolveLocalCalls(arb, candidateFilter = () => true) {
candidates.sort(sortByApperanceFrequency);
const modifiedRanges = [];
- for (let i = 0; i < candidates.length; i++) {
+ candidateLoop: for (let i = 0; i < candidates.length; i++) {
const c = candidates[i];
- if (c.arguments.some(a => badArgumentTypes.includes(a.type)) || isNodeInRanges(c, modifiedRanges)) continue;
+ if (isNodeInRanges(c, modifiedRanges)) continue;
+ for (let j = 0; j < c.arguments.length; j++) {
+ const arg = c.arguments[j];
+ if (badArgumentTypes.includes(arg.type)) continue candidateLoop;
+ }
const callee = c.callee?.object || c.callee;
const declNode = c.callee?.declNode || c.callee?.object?.declNode;
if (declNode?.parentNode?.body?.body?.[0]?.type === 'ReturnStatement') {
// Leave this replacement to a safe function
const returnArg = declNode.parentNode.body.body[0].argument;
- if (['Literal', 'Identifier'].includes(returnArg.type) || /Function/.test(returnArg.type)) continue; // Unwrap identifier
+ if (['Literal', 'Identifier'].includes(returnArg.type) || returnArg.type.includes('unction')) continue; // Unwrap identifier
else if (returnArg.type === 'CallExpression' &&
returnArg.callee?.object?.type === 'FunctionExpression' &&
(returnArg.callee.property?.name || returnArg.callee.property?.value) === 'apply') continue; // Unwrap function shells
@@ -96,7 +100,7 @@ export default function resolveLocalCalls(arb, candidateFilter = () => true) {
// Prevent resolving a function's toString as it might be an anti-debugging mechanism
// which will spring if the code is beautified
if (c.callee.type === 'MemberExpression' && (c.callee.property?.name || c.callee.property?.value) === 'toString' &&
- (new RegExp('^function ')).test(replacementNode?.value)) continue;
+ replacementNode?.value.substring(0, 8) === 'function') continue;
arb.markNode(c, replacementNode);
modifiedRanges.push(c.range);
}
diff --git a/src/modules/unsafe/resolveMinimalAlphabet.js b/src/modules/unsafe/resolveMinimalAlphabet.js
index f63902c..161661d 100644
--- a/src/modules/unsafe/resolveMinimalAlphabet.js
+++ b/src/modules/unsafe/resolveMinimalAlphabet.js
@@ -1,6 +1,6 @@
import {badValue} from '../config.js';
import {evalInVm} from '../utils/evalInVm.js';
-import {getDescendants} from '../utils/getDescendants.js';
+import {doesDescendantMatchCondition} from '../utils/doesDescendantMatchCondition.js';
/**
* Resolve unary expressions on values which aren't numbers such as +true, +[], +[...], etc,
@@ -25,7 +25,7 @@ export default function resolveMinimalAlphabet(arb, candidateFilter = () => true
(n.left.type !== 'MemberExpression' && Number.isNaN(parseFloat(n.left?.value))) &&
![n.left?.type, n.right?.type].includes('ThisExpression')) &&
candidateFilter(n)) {
- if (getDescendants(n).some(n => n.type === 'ThisExpression')) continue;
+ if (doesDescendantMatchCondition(n, n => n.type === 'ThisExpression')) continue;
const replacementNode = evalInVm(n.src);
if (replacementNode !== badValue) {
arb.markNode(n, replacementNode);
diff --git a/src/modules/utils/areReferencesModified.js b/src/modules/utils/areReferencesModified.js
index cd84d07..de16b4d 100644
--- a/src/modules/utils/areReferencesModified.js
+++ b/src/modules/utils/areReferencesModified.js
@@ -1,5 +1,20 @@
import {propertiesThatModifyContent} from '../config.js';
+/**
+ * @param {ASTNode} r
+ * @param {ASTNode[]} assignmentExpressions
+ * @return {boolean}
+ */
+function isMemberExpressionAssignedTo(r, assignmentExpressions) {
+ for (let i = 0; i < assignmentExpressions.length; i++) {
+ const n = assignmentExpressions[i];
+ if (n.left.type === 'MemberExpression' &&
+ (n.left.object.declNode && (r.object.declNode || r.object) === n.left.object.declNode) &&
+ ((n.left.property?.name || n.left.property?.value) === (r.property?.name || r.property?.value))) return true;
+ }
+ return false;
+}
+
/**
* @param {ASTNode[]} ast
* @param {ASTNode[]} refs
@@ -7,8 +22,9 @@ import {propertiesThatModifyContent} from '../config.js';
*/
function areReferencesModified(ast, refs) {
// Verify no reference is on the left side of an assignment
- return refs.some(r =>
- (r.parentKey === 'left' && ['AssignmentExpression', 'ForInStatement', 'ForOfStatement'].includes(r.parentNode.type)) ||
+ for (let i = 0; i < refs.length; i++) {
+ const r = refs[i];
+ if ((r.parentKey === 'left' && ['AssignmentExpression', 'ForInStatement', 'ForOfStatement'].includes(r.parentNode.type)) ||
// Verify no reference is part of an update expression
r.parentNode.type === 'UpdateExpression' ||
// Verify no variable with the same name is declared in a subscope
@@ -23,11 +39,9 @@ function areReferencesModified(ast, refs) {
r.parentNode.parentKey === 'left')) ||
// Verify there are no member expressions among the references which are being assigned to
(r.type === 'MemberExpression' &&
- (ast[0].typeMap.AssignmentExpression || []).some(n =>
- n.left.type === 'MemberExpression' &&
- n.left.object?.name === r.object?.name &&
- (n.left.property?.name || n.left.property?.value === r.property?.name || r.property?.value) &&
- (n.left.object.declNode && (r.object.declNode || r.object) === n.left.object.declNode))));
+ isMemberExpressionAssignedTo(r, ast[0].typeMap.AssignmentExpression || []))) return true;
+ }
+ return false;
}
export {areReferencesModified};
\ No newline at end of file
diff --git a/src/modules/utils/createOrderedSrc.js b/src/modules/utils/createOrderedSrc.js
index dbfea1d..3c5f703 100644
--- a/src/modules/utils/createOrderedSrc.js
+++ b/src/modules/utils/createOrderedSrc.js
@@ -36,8 +36,14 @@ function createOrderedSrc(nodes, preserveOrder = false) {
nodes[i] = n.parentNode;
if (!preserveOrder && n.callee.type === 'FunctionExpression') {
// Set nodeId to place IIFE just after its argument's declaration
- const argDeclNodeId = n.arguments.find(a => a.nodeId === Math.max(...n.arguments.filter(arg => arg?.declNode?.nodeId).map(arg => arg.nodeId)))?.nodeId;
- nodes[i].nodeId = argDeclNodeId ? argDeclNodeId + 1 : nodes[i].nodeId + largeNumber;
+ let maxArgNodeId = 0;
+ for (let j = 0; j < n.arguments.length; j++) {
+ const arg = n.arguments[j];
+ if (arg?.declNode?.nodeId > maxArgNodeId) {
+ maxArgNodeId = arg.declNode.nodeId;
+ }
+ }
+ nodes[i].nodeId = maxArgNodeId ? maxArgNodeId + 1 : nodes[i].nodeId + largeNumber;
}
} else if (n.callee.type === 'FunctionExpression') {
if (!preserveOrder) {
diff --git a/src/modules/utils/doesDescendantMatchCondition.js b/src/modules/utils/doesDescendantMatchCondition.js
new file mode 100644
index 0000000..f54610e
--- /dev/null
+++ b/src/modules/utils/doesDescendantMatchCondition.js
@@ -0,0 +1,18 @@
+/**
+ *
+ * @param {ASTNode} targetNode
+ * @param {function} condition
+ * @param {boolean} [returnNode] Return the node that matches the condition
+ * @return {boolean|ASTNode}
+ */
+function doesDescendantMatchCondition(targetNode, condition, returnNode = false) {
+ const stack = [targetNode];
+ while (stack.length) {
+ const currentNode = stack.pop();
+ if (condition(currentNode)) return returnNode ? currentNode : true;
+ if (currentNode.childNodes?.length) stack.push(...currentNode.childNodes);
+ }
+ return false;
+}
+
+export {doesDescendantMatchCondition};
\ No newline at end of file
diff --git a/src/modules/utils/evalInVm.js b/src/modules/utils/evalInVm.js
index 4107992..0ec49e7 100644
--- a/src/modules/utils/evalInVm.js
+++ b/src/modules/utils/evalInVm.js
@@ -1,14 +1,11 @@
-import {logger} from 'flast';
import {Sandbox} from './sandbox.js';
-import * as assert from 'node:assert';
import {badValue} from '../config.js';
import {getObjType} from './getObjType.js';
import {generateHash} from './generateHash.js';
import {createNewNode} from './createNewNode.js';
-const badTypes = [ // Types of objects which can't be resolved in the deobfuscation context.
- 'Promise',
-];
+// Types of objects which can't be resolved in the deobfuscation context.
+const badTypes = ['Promise'];
const matchingObjectKeys = {
[Object.keys(console).sort().join('')]: {type: 'Identifier', name: 'console'},
@@ -52,23 +49,15 @@ function evalInVm(stringToEval, sb) {
}
let vm = sb || new Sandbox();
let res = vm.run(stringToEval);
- // noinspection JSUnresolvedVariable
if (vm.isReference(res) && !badTypes.includes(getObjType(res))) {
+ // noinspection JSUnresolvedVariable
res = res.copySync();
// If the result is a builtin object / function, return a matching identifier
const objKeys = Object.keys(res).sort().join('');
if (matchingObjectKeys[objKeys]) cache[cacheName] = matchingObjectKeys[objKeys];
- else {
- // To exclude results based on randomness or timing, eval again and compare results
- vm = sb || new Sandbox();
- const res2 = vm.run(stringToEval).copySync();
- assert.deepEqual(res.toString(), res2.toString());
- cache[cacheName] = createNewNode(res);
- }
+ else cache[cacheName] = createNewNode(res);
}
- } catch (e) {
- logger.debug(`[-] Error in _evalInVm: ${e.message}`);
- }
+ } catch {}
}
return cache[cacheName];
}
diff --git a/src/modules/utils/evalWithDom.js b/src/modules/utils/evalWithDom.js
deleted file mode 100644
index 501b58d..0000000
--- a/src/modules/utils/evalWithDom.js
+++ /dev/null
@@ -1,56 +0,0 @@
-// noinspection HtmlRequiredLangAttribute,HtmlRequiredTitleElement
-
-import fs from 'node:fs';
-import {Sandbox} from './sandbox.js';
-// eslint-disable-next-line no-unused-vars
-import {JSDOM} from 'jsdom';
-import {logger} from 'flast';
-import {generateHash} from './generateHash.js';
-
-let jQuerySrc = '';
-
-let cache = {};
-const maxCacheSize = 100;
-
-/**
- * Place a string into a file and evaluate it with a simulated browser environment.
- * @param {string} stringToEval
- * @param {boolean} injectjQuery Inject jQuery into the VM if true.
- * @return {string} The output string if successful; empty string otherwise.
- */
-function evalWithDom(stringToEval, injectjQuery = false) {
- const cacheName = `evalWithDom-${generateHash(stringToEval)}`;
- if (!cache[cacheName]) {
- if (Object.keys(cache).length >= maxCacheSize) cache = {};
- let out = '';
- const vm = new Sandbox();
- try {
- // Set up the DOM, and allow script to run wild:
- let runString = 'const dom = new JSDOM(`