├── .gitattributes ├── .gitignore ├── README.md ├── main.js ├── package-lock.json ├── package.json ├── script.js └── transformations ├── hCalls.js ├── listPlacements.js ├── magicNumber.js ├── replaceDictCalls.js └── replaceVariableCalls.js /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | README.final.md 3 | transformed_script.js -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Perimeter X Deobfuscator 2 | 3 | This is a quick personal project to deobfuscate the Perimeter X main file. It is not perfect, but it works for the most part. 4 | Was needed a quick solution. It works for the base file but isn't designed for the captcha file. 5 | 6 | ## Usage 7 | 8 | ```bash 9 | node main.js 10 | ``` -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const babel = require('@babel/core'); 3 | const { default: generate } = require('@babel/generator'); 4 | 5 | 6 | const decodeMagicNumberCalls = require('./transformations/magicNumber'); 7 | const decodeHCalls = require('./transformations/hCalls'); 8 | const decodeListPlacements = require('./transformations/listPlacements'); 9 | const replaceVariableCallsWithValues = require('./transformations/replaceVariableCalls'); 10 | const replaceDictCalls = require('./transformations/replaceDictCalls'); 11 | 12 | // Read the code 13 | const passedFile = process.argv[2]; 14 | const file = passedFile || 'script.js'; 15 | const outputFile = passedFile ? `${passedFile}_transformed.js` : 'transformed_script.js'; 16 | const code = fs.readFileSync(file, 'utf8'); 17 | const ast = babel.parse(code,); 18 | 19 | // Apply transformations 20 | replaceDictCalls(ast); 21 | replaceVariableCallsWithValues(ast); 22 | decodeListPlacements(ast); 23 | decodeMagicNumberCalls(ast); 24 | decodeHCalls(ast); 25 | 26 | 27 | const transformedCode = generate(ast).code; 28 | fs.writeFileSync(outputFile, transformedCode, 'utf8'); 29 | console.log(`Code transformed and written to ${outputFile}`); -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "PerimeterX-Deobfuscator", 3 | "lockfileVersion": 2, 4 | "requires": true, 5 | "packages": { 6 | "": { 7 | "dependencies": { 8 | "@babel/core": "^7.22.11", 9 | "@babel/traverse": "^7.22.11" 10 | } 11 | }, 12 | "node_modules/@ampproject/remapping": { 13 | "version": "2.2.1", 14 | "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", 15 | "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", 16 | "dependencies": { 17 | "@jridgewell/gen-mapping": "^0.3.0", 18 | "@jridgewell/trace-mapping": "^0.3.9" 19 | }, 20 | "engines": { 21 | "node": ">=6.0.0" 22 | } 23 | }, 24 | "node_modules/@babel/code-frame": { 25 | "version": "7.22.13", 26 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", 27 | "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", 28 | "dependencies": { 29 | "@babel/highlight": "^7.22.13", 30 | "chalk": "^2.4.2" 31 | }, 32 | "engines": { 33 | "node": ">=6.9.0" 34 | } 35 | }, 36 | "node_modules/@babel/compat-data": { 37 | "version": "7.22.9", 38 | "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", 39 | "integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==", 40 | "engines": { 41 | "node": ">=6.9.0" 42 | } 43 | }, 44 | "node_modules/@babel/core": { 45 | "version": "7.22.11", 46 | "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.11.tgz", 47 | "integrity": "sha512-lh7RJrtPdhibbxndr6/xx0w8+CVlY5FJZiaSz908Fpy+G0xkBFTvwLcKJFF4PJxVfGhVWNebikpWGnOoC71juQ==", 48 | "dependencies": { 49 | "@ampproject/remapping": "^2.2.0", 50 | "@babel/code-frame": "^7.22.10", 51 | "@babel/generator": "^7.22.10", 52 | "@babel/helper-compilation-targets": "^7.22.10", 53 | "@babel/helper-module-transforms": "^7.22.9", 54 | "@babel/helpers": "^7.22.11", 55 | "@babel/parser": "^7.22.11", 56 | "@babel/template": "^7.22.5", 57 | "@babel/traverse": "^7.22.11", 58 | "@babel/types": "^7.22.11", 59 | "convert-source-map": "^1.7.0", 60 | "debug": "^4.1.0", 61 | "gensync": "^1.0.0-beta.2", 62 | "json5": "^2.2.3", 63 | "semver": "^6.3.1" 64 | }, 65 | "engines": { 66 | "node": ">=6.9.0" 67 | }, 68 | "funding": { 69 | "type": "opencollective", 70 | "url": "https://opencollective.com/babel" 71 | } 72 | }, 73 | "node_modules/@babel/generator": { 74 | "version": "7.22.10", 75 | "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.10.tgz", 76 | "integrity": "sha512-79KIf7YiWjjdZ81JnLujDRApWtl7BxTqWD88+FFdQEIOG8LJ0etDOM7CXuIgGJa55sGOwZVwuEsaLEm0PJ5/+A==", 77 | "dependencies": { 78 | "@babel/types": "^7.22.10", 79 | "@jridgewell/gen-mapping": "^0.3.2", 80 | "@jridgewell/trace-mapping": "^0.3.17", 81 | "jsesc": "^2.5.1" 82 | }, 83 | "engines": { 84 | "node": ">=6.9.0" 85 | } 86 | }, 87 | "node_modules/@babel/helper-compilation-targets": { 88 | "version": "7.22.10", 89 | "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.10.tgz", 90 | "integrity": "sha512-JMSwHD4J7SLod0idLq5PKgI+6g/hLD/iuWBq08ZX49xE14VpVEojJ5rHWptpirV2j020MvypRLAXAO50igCJ5Q==", 91 | "dependencies": { 92 | "@babel/compat-data": "^7.22.9", 93 | "@babel/helper-validator-option": "^7.22.5", 94 | "browserslist": "^4.21.9", 95 | "lru-cache": "^5.1.1", 96 | "semver": "^6.3.1" 97 | }, 98 | "engines": { 99 | "node": ">=6.9.0" 100 | } 101 | }, 102 | "node_modules/@babel/helper-environment-visitor": { 103 | "version": "7.22.5", 104 | "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", 105 | "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==", 106 | "engines": { 107 | "node": ">=6.9.0" 108 | } 109 | }, 110 | "node_modules/@babel/helper-function-name": { 111 | "version": "7.22.5", 112 | "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", 113 | "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", 114 | "dependencies": { 115 | "@babel/template": "^7.22.5", 116 | "@babel/types": "^7.22.5" 117 | }, 118 | "engines": { 119 | "node": ">=6.9.0" 120 | } 121 | }, 122 | "node_modules/@babel/helper-hoist-variables": { 123 | "version": "7.22.5", 124 | "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", 125 | "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", 126 | "dependencies": { 127 | "@babel/types": "^7.22.5" 128 | }, 129 | "engines": { 130 | "node": ">=6.9.0" 131 | } 132 | }, 133 | "node_modules/@babel/helper-module-imports": { 134 | "version": "7.22.5", 135 | "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz", 136 | "integrity": "sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==", 137 | "dependencies": { 138 | "@babel/types": "^7.22.5" 139 | }, 140 | "engines": { 141 | "node": ">=6.9.0" 142 | } 143 | }, 144 | "node_modules/@babel/helper-module-transforms": { 145 | "version": "7.22.9", 146 | "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz", 147 | "integrity": "sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ==", 148 | "dependencies": { 149 | "@babel/helper-environment-visitor": "^7.22.5", 150 | "@babel/helper-module-imports": "^7.22.5", 151 | "@babel/helper-simple-access": "^7.22.5", 152 | "@babel/helper-split-export-declaration": "^7.22.6", 153 | "@babel/helper-validator-identifier": "^7.22.5" 154 | }, 155 | "engines": { 156 | "node": ">=6.9.0" 157 | }, 158 | "peerDependencies": { 159 | "@babel/core": "^7.0.0" 160 | } 161 | }, 162 | "node_modules/@babel/helper-simple-access": { 163 | "version": "7.22.5", 164 | "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", 165 | "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", 166 | "dependencies": { 167 | "@babel/types": "^7.22.5" 168 | }, 169 | "engines": { 170 | "node": ">=6.9.0" 171 | } 172 | }, 173 | "node_modules/@babel/helper-split-export-declaration": { 174 | "version": "7.22.6", 175 | "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", 176 | "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", 177 | "dependencies": { 178 | "@babel/types": "^7.22.5" 179 | }, 180 | "engines": { 181 | "node": ">=6.9.0" 182 | } 183 | }, 184 | "node_modules/@babel/helper-string-parser": { 185 | "version": "7.22.5", 186 | "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", 187 | "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", 188 | "engines": { 189 | "node": ">=6.9.0" 190 | } 191 | }, 192 | "node_modules/@babel/helper-validator-identifier": { 193 | "version": "7.22.5", 194 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", 195 | "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", 196 | "engines": { 197 | "node": ">=6.9.0" 198 | } 199 | }, 200 | "node_modules/@babel/helper-validator-option": { 201 | "version": "7.22.5", 202 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz", 203 | "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==", 204 | "engines": { 205 | "node": ">=6.9.0" 206 | } 207 | }, 208 | "node_modules/@babel/helpers": { 209 | "version": "7.22.11", 210 | "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.11.tgz", 211 | "integrity": "sha512-vyOXC8PBWaGc5h7GMsNx68OH33cypkEDJCHvYVVgVbbxJDROYVtexSk0gK5iCF1xNjRIN2s8ai7hwkWDq5szWg==", 212 | "dependencies": { 213 | "@babel/template": "^7.22.5", 214 | "@babel/traverse": "^7.22.11", 215 | "@babel/types": "^7.22.11" 216 | }, 217 | "engines": { 218 | "node": ">=6.9.0" 219 | } 220 | }, 221 | "node_modules/@babel/highlight": { 222 | "version": "7.22.13", 223 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.13.tgz", 224 | "integrity": "sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ==", 225 | "dependencies": { 226 | "@babel/helper-validator-identifier": "^7.22.5", 227 | "chalk": "^2.4.2", 228 | "js-tokens": "^4.0.0" 229 | }, 230 | "engines": { 231 | "node": ">=6.9.0" 232 | } 233 | }, 234 | "node_modules/@babel/parser": { 235 | "version": "7.22.14", 236 | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.14.tgz", 237 | "integrity": "sha512-1KucTHgOvaw/LzCVrEOAyXkr9rQlp0A1HiHRYnSUE9dmb8PvPW7o5sscg+5169r54n3vGlbx6GevTE/Iw/P3AQ==", 238 | "bin": { 239 | "parser": "bin/babel-parser.js" 240 | }, 241 | "engines": { 242 | "node": ">=6.0.0" 243 | } 244 | }, 245 | "node_modules/@babel/template": { 246 | "version": "7.22.5", 247 | "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", 248 | "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", 249 | "dependencies": { 250 | "@babel/code-frame": "^7.22.5", 251 | "@babel/parser": "^7.22.5", 252 | "@babel/types": "^7.22.5" 253 | }, 254 | "engines": { 255 | "node": ">=6.9.0" 256 | } 257 | }, 258 | "node_modules/@babel/traverse": { 259 | "version": "7.22.11", 260 | "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.11.tgz", 261 | "integrity": "sha512-mzAenteTfomcB7mfPtyi+4oe5BZ6MXxWcn4CX+h4IRJ+OOGXBrWU6jDQavkQI9Vuc5P+donFabBfFCcmWka9lQ==", 262 | "dependencies": { 263 | "@babel/code-frame": "^7.22.10", 264 | "@babel/generator": "^7.22.10", 265 | "@babel/helper-environment-visitor": "^7.22.5", 266 | "@babel/helper-function-name": "^7.22.5", 267 | "@babel/helper-hoist-variables": "^7.22.5", 268 | "@babel/helper-split-export-declaration": "^7.22.6", 269 | "@babel/parser": "^7.22.11", 270 | "@babel/types": "^7.22.11", 271 | "debug": "^4.1.0", 272 | "globals": "^11.1.0" 273 | }, 274 | "engines": { 275 | "node": ">=6.9.0" 276 | } 277 | }, 278 | "node_modules/@babel/types": { 279 | "version": "7.22.11", 280 | "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.11.tgz", 281 | "integrity": "sha512-siazHiGuZRz9aB9NpHy9GOs9xiQPKnMzgdr493iI1M67vRXpnEq8ZOOKzezC5q7zwuQ6sDhdSp4SD9ixKSqKZg==", 282 | "dependencies": { 283 | "@babel/helper-string-parser": "^7.22.5", 284 | "@babel/helper-validator-identifier": "^7.22.5", 285 | "to-fast-properties": "^2.0.0" 286 | }, 287 | "engines": { 288 | "node": ">=6.9.0" 289 | } 290 | }, 291 | "node_modules/@jridgewell/gen-mapping": { 292 | "version": "0.3.3", 293 | "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", 294 | "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", 295 | "dependencies": { 296 | "@jridgewell/set-array": "^1.0.1", 297 | "@jridgewell/sourcemap-codec": "^1.4.10", 298 | "@jridgewell/trace-mapping": "^0.3.9" 299 | }, 300 | "engines": { 301 | "node": ">=6.0.0" 302 | } 303 | }, 304 | "node_modules/@jridgewell/resolve-uri": { 305 | "version": "3.1.1", 306 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", 307 | "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", 308 | "engines": { 309 | "node": ">=6.0.0" 310 | } 311 | }, 312 | "node_modules/@jridgewell/set-array": { 313 | "version": "1.1.2", 314 | "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", 315 | "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", 316 | "engines": { 317 | "node": ">=6.0.0" 318 | } 319 | }, 320 | "node_modules/@jridgewell/sourcemap-codec": { 321 | "version": "1.4.15", 322 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", 323 | "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" 324 | }, 325 | "node_modules/@jridgewell/trace-mapping": { 326 | "version": "0.3.19", 327 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", 328 | "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", 329 | "dependencies": { 330 | "@jridgewell/resolve-uri": "^3.1.0", 331 | "@jridgewell/sourcemap-codec": "^1.4.14" 332 | } 333 | }, 334 | "node_modules/ansi-styles": { 335 | "version": "3.2.1", 336 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 337 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 338 | "dependencies": { 339 | "color-convert": "^1.9.0" 340 | }, 341 | "engines": { 342 | "node": ">=4" 343 | } 344 | }, 345 | "node_modules/browserslist": { 346 | "version": "4.21.10", 347 | "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", 348 | "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", 349 | "funding": [ 350 | { 351 | "type": "opencollective", 352 | "url": "https://opencollective.com/browserslist" 353 | }, 354 | { 355 | "type": "tidelift", 356 | "url": "https://tidelift.com/funding/github/npm/browserslist" 357 | }, 358 | { 359 | "type": "github", 360 | "url": "https://github.com/sponsors/ai" 361 | } 362 | ], 363 | "dependencies": { 364 | "caniuse-lite": "^1.0.30001517", 365 | "electron-to-chromium": "^1.4.477", 366 | "node-releases": "^2.0.13", 367 | "update-browserslist-db": "^1.0.11" 368 | }, 369 | "bin": { 370 | "browserslist": "cli.js" 371 | }, 372 | "engines": { 373 | "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" 374 | } 375 | }, 376 | "node_modules/caniuse-lite": { 377 | "version": "1.0.30001525", 378 | "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001525.tgz", 379 | "integrity": "sha512-/3z+wB4icFt3r0USMwxujAqRvaD/B7rvGTsKhbhSQErVrJvkZCLhgNLJxU8MevahQVH6hCU9FsHdNUFbiwmE7Q==", 380 | "funding": [ 381 | { 382 | "type": "opencollective", 383 | "url": "https://opencollective.com/browserslist" 384 | }, 385 | { 386 | "type": "tidelift", 387 | "url": "https://tidelift.com/funding/github/npm/caniuse-lite" 388 | }, 389 | { 390 | "type": "github", 391 | "url": "https://github.com/sponsors/ai" 392 | } 393 | ] 394 | }, 395 | "node_modules/chalk": { 396 | "version": "2.4.2", 397 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 398 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 399 | "dependencies": { 400 | "ansi-styles": "^3.2.1", 401 | "escape-string-regexp": "^1.0.5", 402 | "supports-color": "^5.3.0" 403 | }, 404 | "engines": { 405 | "node": ">=4" 406 | } 407 | }, 408 | "node_modules/color-convert": { 409 | "version": "1.9.3", 410 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 411 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 412 | "dependencies": { 413 | "color-name": "1.1.3" 414 | } 415 | }, 416 | "node_modules/color-name": { 417 | "version": "1.1.3", 418 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 419 | "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" 420 | }, 421 | "node_modules/convert-source-map": { 422 | "version": "1.9.0", 423 | "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", 424 | "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" 425 | }, 426 | "node_modules/debug": { 427 | "version": "4.3.4", 428 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 429 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 430 | "dependencies": { 431 | "ms": "2.1.2" 432 | }, 433 | "engines": { 434 | "node": ">=6.0" 435 | }, 436 | "peerDependenciesMeta": { 437 | "supports-color": { 438 | "optional": true 439 | } 440 | } 441 | }, 442 | "node_modules/electron-to-chromium": { 443 | "version": "1.4.508", 444 | "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.508.tgz", 445 | "integrity": "sha512-FFa8QKjQK/A5QuFr2167myhMesGrhlOBD+3cYNxO9/S4XzHEXesyTD/1/xF644gC8buFPz3ca6G1LOQD0tZrrg==" 446 | }, 447 | "node_modules/escalade": { 448 | "version": "3.1.1", 449 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", 450 | "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", 451 | "engines": { 452 | "node": ">=6" 453 | } 454 | }, 455 | "node_modules/escape-string-regexp": { 456 | "version": "1.0.5", 457 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 458 | "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", 459 | "engines": { 460 | "node": ">=0.8.0" 461 | } 462 | }, 463 | "node_modules/gensync": { 464 | "version": "1.0.0-beta.2", 465 | "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", 466 | "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", 467 | "engines": { 468 | "node": ">=6.9.0" 469 | } 470 | }, 471 | "node_modules/globals": { 472 | "version": "11.12.0", 473 | "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", 474 | "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", 475 | "engines": { 476 | "node": ">=4" 477 | } 478 | }, 479 | "node_modules/has-flag": { 480 | "version": "3.0.0", 481 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 482 | "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", 483 | "engines": { 484 | "node": ">=4" 485 | } 486 | }, 487 | "node_modules/js-tokens": { 488 | "version": "4.0.0", 489 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 490 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" 491 | }, 492 | "node_modules/jsesc": { 493 | "version": "2.5.2", 494 | "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", 495 | "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", 496 | "bin": { 497 | "jsesc": "bin/jsesc" 498 | }, 499 | "engines": { 500 | "node": ">=4" 501 | } 502 | }, 503 | "node_modules/json5": { 504 | "version": "2.2.3", 505 | "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", 506 | "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", 507 | "bin": { 508 | "json5": "lib/cli.js" 509 | }, 510 | "engines": { 511 | "node": ">=6" 512 | } 513 | }, 514 | "node_modules/lru-cache": { 515 | "version": "5.1.1", 516 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", 517 | "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", 518 | "dependencies": { 519 | "yallist": "^3.0.2" 520 | } 521 | }, 522 | "node_modules/ms": { 523 | "version": "2.1.2", 524 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 525 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 526 | }, 527 | "node_modules/node-releases": { 528 | "version": "2.0.13", 529 | "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", 530 | "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==" 531 | }, 532 | "node_modules/picocolors": { 533 | "version": "1.0.0", 534 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", 535 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" 536 | }, 537 | "node_modules/semver": { 538 | "version": "6.3.1", 539 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", 540 | "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", 541 | "bin": { 542 | "semver": "bin/semver.js" 543 | } 544 | }, 545 | "node_modules/supports-color": { 546 | "version": "5.5.0", 547 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 548 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 549 | "dependencies": { 550 | "has-flag": "^3.0.0" 551 | }, 552 | "engines": { 553 | "node": ">=4" 554 | } 555 | }, 556 | "node_modules/to-fast-properties": { 557 | "version": "2.0.0", 558 | "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", 559 | "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", 560 | "engines": { 561 | "node": ">=4" 562 | } 563 | }, 564 | "node_modules/update-browserslist-db": { 565 | "version": "1.0.11", 566 | "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", 567 | "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", 568 | "funding": [ 569 | { 570 | "type": "opencollective", 571 | "url": "https://opencollective.com/browserslist" 572 | }, 573 | { 574 | "type": "tidelift", 575 | "url": "https://tidelift.com/funding/github/npm/browserslist" 576 | }, 577 | { 578 | "type": "github", 579 | "url": "https://github.com/sponsors/ai" 580 | } 581 | ], 582 | "dependencies": { 583 | "escalade": "^3.1.1", 584 | "picocolors": "^1.0.0" 585 | }, 586 | "bin": { 587 | "update-browserslist-db": "cli.js" 588 | }, 589 | "peerDependencies": { 590 | "browserslist": ">= 4.21.0" 591 | } 592 | }, 593 | "node_modules/yallist": { 594 | "version": "3.1.1", 595 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", 596 | "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" 597 | } 598 | }, 599 | "dependencies": { 600 | "@ampproject/remapping": { 601 | "version": "2.2.1", 602 | "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", 603 | "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", 604 | "requires": { 605 | "@jridgewell/gen-mapping": "^0.3.0", 606 | "@jridgewell/trace-mapping": "^0.3.9" 607 | } 608 | }, 609 | "@babel/code-frame": { 610 | "version": "7.22.13", 611 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", 612 | "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", 613 | "requires": { 614 | "@babel/highlight": "^7.22.13", 615 | "chalk": "^2.4.2" 616 | } 617 | }, 618 | "@babel/compat-data": { 619 | "version": "7.22.9", 620 | "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", 621 | "integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==" 622 | }, 623 | "@babel/core": { 624 | "version": "7.22.11", 625 | "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.11.tgz", 626 | "integrity": "sha512-lh7RJrtPdhibbxndr6/xx0w8+CVlY5FJZiaSz908Fpy+G0xkBFTvwLcKJFF4PJxVfGhVWNebikpWGnOoC71juQ==", 627 | "requires": { 628 | "@ampproject/remapping": "^2.2.0", 629 | "@babel/code-frame": "^7.22.10", 630 | "@babel/generator": "^7.22.10", 631 | "@babel/helper-compilation-targets": "^7.22.10", 632 | "@babel/helper-module-transforms": "^7.22.9", 633 | "@babel/helpers": "^7.22.11", 634 | "@babel/parser": "^7.22.11", 635 | "@babel/template": "^7.22.5", 636 | "@babel/traverse": "^7.22.11", 637 | "@babel/types": "^7.22.11", 638 | "convert-source-map": "^1.7.0", 639 | "debug": "^4.1.0", 640 | "gensync": "^1.0.0-beta.2", 641 | "json5": "^2.2.3", 642 | "semver": "^6.3.1" 643 | } 644 | }, 645 | "@babel/generator": { 646 | "version": "7.22.10", 647 | "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.10.tgz", 648 | "integrity": "sha512-79KIf7YiWjjdZ81JnLujDRApWtl7BxTqWD88+FFdQEIOG8LJ0etDOM7CXuIgGJa55sGOwZVwuEsaLEm0PJ5/+A==", 649 | "requires": { 650 | "@babel/types": "^7.22.10", 651 | "@jridgewell/gen-mapping": "^0.3.2", 652 | "@jridgewell/trace-mapping": "^0.3.17", 653 | "jsesc": "^2.5.1" 654 | } 655 | }, 656 | "@babel/helper-compilation-targets": { 657 | "version": "7.22.10", 658 | "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.10.tgz", 659 | "integrity": "sha512-JMSwHD4J7SLod0idLq5PKgI+6g/hLD/iuWBq08ZX49xE14VpVEojJ5rHWptpirV2j020MvypRLAXAO50igCJ5Q==", 660 | "requires": { 661 | "@babel/compat-data": "^7.22.9", 662 | "@babel/helper-validator-option": "^7.22.5", 663 | "browserslist": "^4.21.9", 664 | "lru-cache": "^5.1.1", 665 | "semver": "^6.3.1" 666 | } 667 | }, 668 | "@babel/helper-environment-visitor": { 669 | "version": "7.22.5", 670 | "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", 671 | "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==" 672 | }, 673 | "@babel/helper-function-name": { 674 | "version": "7.22.5", 675 | "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", 676 | "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", 677 | "requires": { 678 | "@babel/template": "^7.22.5", 679 | "@babel/types": "^7.22.5" 680 | } 681 | }, 682 | "@babel/helper-hoist-variables": { 683 | "version": "7.22.5", 684 | "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", 685 | "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", 686 | "requires": { 687 | "@babel/types": "^7.22.5" 688 | } 689 | }, 690 | "@babel/helper-module-imports": { 691 | "version": "7.22.5", 692 | "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz", 693 | "integrity": "sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==", 694 | "requires": { 695 | "@babel/types": "^7.22.5" 696 | } 697 | }, 698 | "@babel/helper-module-transforms": { 699 | "version": "7.22.9", 700 | "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz", 701 | "integrity": "sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ==", 702 | "requires": { 703 | "@babel/helper-environment-visitor": "^7.22.5", 704 | "@babel/helper-module-imports": "^7.22.5", 705 | "@babel/helper-simple-access": "^7.22.5", 706 | "@babel/helper-split-export-declaration": "^7.22.6", 707 | "@babel/helper-validator-identifier": "^7.22.5" 708 | } 709 | }, 710 | "@babel/helper-simple-access": { 711 | "version": "7.22.5", 712 | "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", 713 | "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", 714 | "requires": { 715 | "@babel/types": "^7.22.5" 716 | } 717 | }, 718 | "@babel/helper-split-export-declaration": { 719 | "version": "7.22.6", 720 | "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", 721 | "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", 722 | "requires": { 723 | "@babel/types": "^7.22.5" 724 | } 725 | }, 726 | "@babel/helper-string-parser": { 727 | "version": "7.22.5", 728 | "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", 729 | "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==" 730 | }, 731 | "@babel/helper-validator-identifier": { 732 | "version": "7.22.5", 733 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", 734 | "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==" 735 | }, 736 | "@babel/helper-validator-option": { 737 | "version": "7.22.5", 738 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz", 739 | "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==" 740 | }, 741 | "@babel/helpers": { 742 | "version": "7.22.11", 743 | "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.11.tgz", 744 | "integrity": "sha512-vyOXC8PBWaGc5h7GMsNx68OH33cypkEDJCHvYVVgVbbxJDROYVtexSk0gK5iCF1xNjRIN2s8ai7hwkWDq5szWg==", 745 | "requires": { 746 | "@babel/template": "^7.22.5", 747 | "@babel/traverse": "^7.22.11", 748 | "@babel/types": "^7.22.11" 749 | } 750 | }, 751 | "@babel/highlight": { 752 | "version": "7.22.13", 753 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.13.tgz", 754 | "integrity": "sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ==", 755 | "requires": { 756 | "@babel/helper-validator-identifier": "^7.22.5", 757 | "chalk": "^2.4.2", 758 | "js-tokens": "^4.0.0" 759 | } 760 | }, 761 | "@babel/parser": { 762 | "version": "7.22.14", 763 | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.14.tgz", 764 | "integrity": "sha512-1KucTHgOvaw/LzCVrEOAyXkr9rQlp0A1HiHRYnSUE9dmb8PvPW7o5sscg+5169r54n3vGlbx6GevTE/Iw/P3AQ==" 765 | }, 766 | "@babel/template": { 767 | "version": "7.22.5", 768 | "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", 769 | "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", 770 | "requires": { 771 | "@babel/code-frame": "^7.22.5", 772 | "@babel/parser": "^7.22.5", 773 | "@babel/types": "^7.22.5" 774 | } 775 | }, 776 | "@babel/traverse": { 777 | "version": "7.22.11", 778 | "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.11.tgz", 779 | "integrity": "sha512-mzAenteTfomcB7mfPtyi+4oe5BZ6MXxWcn4CX+h4IRJ+OOGXBrWU6jDQavkQI9Vuc5P+donFabBfFCcmWka9lQ==", 780 | "requires": { 781 | "@babel/code-frame": "^7.22.10", 782 | "@babel/generator": "^7.22.10", 783 | "@babel/helper-environment-visitor": "^7.22.5", 784 | "@babel/helper-function-name": "^7.22.5", 785 | "@babel/helper-hoist-variables": "^7.22.5", 786 | "@babel/helper-split-export-declaration": "^7.22.6", 787 | "@babel/parser": "^7.22.11", 788 | "@babel/types": "^7.22.11", 789 | "debug": "^4.1.0", 790 | "globals": "^11.1.0" 791 | } 792 | }, 793 | "@babel/types": { 794 | "version": "7.22.11", 795 | "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.11.tgz", 796 | "integrity": "sha512-siazHiGuZRz9aB9NpHy9GOs9xiQPKnMzgdr493iI1M67vRXpnEq8ZOOKzezC5q7zwuQ6sDhdSp4SD9ixKSqKZg==", 797 | "requires": { 798 | "@babel/helper-string-parser": "^7.22.5", 799 | "@babel/helper-validator-identifier": "^7.22.5", 800 | "to-fast-properties": "^2.0.0" 801 | } 802 | }, 803 | "@jridgewell/gen-mapping": { 804 | "version": "0.3.3", 805 | "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", 806 | "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", 807 | "requires": { 808 | "@jridgewell/set-array": "^1.0.1", 809 | "@jridgewell/sourcemap-codec": "^1.4.10", 810 | "@jridgewell/trace-mapping": "^0.3.9" 811 | } 812 | }, 813 | "@jridgewell/resolve-uri": { 814 | "version": "3.1.1", 815 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", 816 | "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==" 817 | }, 818 | "@jridgewell/set-array": { 819 | "version": "1.1.2", 820 | "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", 821 | "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==" 822 | }, 823 | "@jridgewell/sourcemap-codec": { 824 | "version": "1.4.15", 825 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", 826 | "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" 827 | }, 828 | "@jridgewell/trace-mapping": { 829 | "version": "0.3.19", 830 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", 831 | "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", 832 | "requires": { 833 | "@jridgewell/resolve-uri": "^3.1.0", 834 | "@jridgewell/sourcemap-codec": "^1.4.14" 835 | } 836 | }, 837 | "ansi-styles": { 838 | "version": "3.2.1", 839 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 840 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 841 | "requires": { 842 | "color-convert": "^1.9.0" 843 | } 844 | }, 845 | "browserslist": { 846 | "version": "4.21.10", 847 | "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", 848 | "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", 849 | "requires": { 850 | "caniuse-lite": "^1.0.30001517", 851 | "electron-to-chromium": "^1.4.477", 852 | "node-releases": "^2.0.13", 853 | "update-browserslist-db": "^1.0.11" 854 | } 855 | }, 856 | "caniuse-lite": { 857 | "version": "1.0.30001525", 858 | "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001525.tgz", 859 | "integrity": "sha512-/3z+wB4icFt3r0USMwxujAqRvaD/B7rvGTsKhbhSQErVrJvkZCLhgNLJxU8MevahQVH6hCU9FsHdNUFbiwmE7Q==" 860 | }, 861 | "chalk": { 862 | "version": "2.4.2", 863 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 864 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 865 | "requires": { 866 | "ansi-styles": "^3.2.1", 867 | "escape-string-regexp": "^1.0.5", 868 | "supports-color": "^5.3.0" 869 | } 870 | }, 871 | "color-convert": { 872 | "version": "1.9.3", 873 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 874 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 875 | "requires": { 876 | "color-name": "1.1.3" 877 | } 878 | }, 879 | "color-name": { 880 | "version": "1.1.3", 881 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 882 | "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" 883 | }, 884 | "convert-source-map": { 885 | "version": "1.9.0", 886 | "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", 887 | "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" 888 | }, 889 | "debug": { 890 | "version": "4.3.4", 891 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 892 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 893 | "requires": { 894 | "ms": "2.1.2" 895 | } 896 | }, 897 | "electron-to-chromium": { 898 | "version": "1.4.508", 899 | "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.508.tgz", 900 | "integrity": "sha512-FFa8QKjQK/A5QuFr2167myhMesGrhlOBD+3cYNxO9/S4XzHEXesyTD/1/xF644gC8buFPz3ca6G1LOQD0tZrrg==" 901 | }, 902 | "escalade": { 903 | "version": "3.1.1", 904 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", 905 | "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" 906 | }, 907 | "escape-string-regexp": { 908 | "version": "1.0.5", 909 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 910 | "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" 911 | }, 912 | "gensync": { 913 | "version": "1.0.0-beta.2", 914 | "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", 915 | "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" 916 | }, 917 | "globals": { 918 | "version": "11.12.0", 919 | "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", 920 | "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" 921 | }, 922 | "has-flag": { 923 | "version": "3.0.0", 924 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 925 | "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" 926 | }, 927 | "js-tokens": { 928 | "version": "4.0.0", 929 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 930 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" 931 | }, 932 | "jsesc": { 933 | "version": "2.5.2", 934 | "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", 935 | "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" 936 | }, 937 | "json5": { 938 | "version": "2.2.3", 939 | "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", 940 | "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==" 941 | }, 942 | "lru-cache": { 943 | "version": "5.1.1", 944 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", 945 | "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", 946 | "requires": { 947 | "yallist": "^3.0.2" 948 | } 949 | }, 950 | "ms": { 951 | "version": "2.1.2", 952 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 953 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 954 | }, 955 | "node-releases": { 956 | "version": "2.0.13", 957 | "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", 958 | "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==" 959 | }, 960 | "picocolors": { 961 | "version": "1.0.0", 962 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", 963 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" 964 | }, 965 | "semver": { 966 | "version": "6.3.1", 967 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", 968 | "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" 969 | }, 970 | "supports-color": { 971 | "version": "5.5.0", 972 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 973 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 974 | "requires": { 975 | "has-flag": "^3.0.0" 976 | } 977 | }, 978 | "to-fast-properties": { 979 | "version": "2.0.0", 980 | "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", 981 | "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" 982 | }, 983 | "update-browserslist-db": { 984 | "version": "1.0.11", 985 | "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", 986 | "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", 987 | "requires": { 988 | "escalade": "^3.1.1", 989 | "picocolors": "^1.0.0" 990 | } 991 | }, 992 | "yallist": { 993 | "version": "3.1.1", 994 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", 995 | "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" 996 | } 997 | } 998 | } 999 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "@babel/core": "^7.22.11", 4 | "@babel/traverse": "^7.22.11" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /transformations/hCalls.js: -------------------------------------------------------------------------------- 1 | 2 | const babel = require('@babel/core'); 3 | const { default: traverse } = require('@babel/traverse'); 4 | 5 | var D = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", 6 | Z = /[^+/=0-9A-Za-z]/, 7 | Q = function () { 8 | try { 9 | return p.atob; 10 | } catch (t) { } 11 | }(); 12 | V = "function" 13 | 14 | function l(t) { 15 | return l = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (t) { 16 | return typeof t; 17 | } : function (t) { 18 | return t && "function" == typeof Symbol && t.constructor === Symbol && t !== Symbol.prototype ? "symbol" : typeof t; 19 | }, l(t); 20 | } 21 | 22 | function H(t) { 23 | return l(Q) === V ? Q(t) : function (t) { 24 | var e, 25 | n, 26 | r, 27 | a, 28 | o = [], 29 | i = 0, 30 | c = t.length; 31 | if (Z.test(t) || /=/.test(t) && (/=[^=]/.test(t) || /={3}/.test(t))) return null; 32 | for (c % 4 > 0 && (c = (t += Array(4 - c % 4 + 1).join("=")).length); i < c;) { 33 | for (n = [], a = i; i < a + 4;) n.push(D.indexOf(t.charAt(i++))); 34 | for (r = [((e = (n[0] << 18) + (n[1] << 12) + ((63 & n[2]) << 6) + (63 & n[3])) & 255 << 16) >> 16, 64 === n[2] ? -1 : (65280 & e) >> 8, 64 === n[3] ? -1 : 255 & e], a = 0; a < 3; ++a) (r[a] >= 0 || 0 === a) && o.push(String.fromCharCode(r[a])); 35 | } 36 | return o.join(""); 37 | }(t); 38 | } 39 | 40 | function decodeHCalls(ast) { 41 | console.log('-> Decoding H() calls'); 42 | let matches = 0; 43 | // identify the function name by checking the most 44 | // common function called with a single string argument 45 | // and one letter name 46 | 47 | let functionName = ''; 48 | let functionCalls = {}; 49 | traverse(ast, { 50 | CallExpression(path) { 51 | if ( 52 | path.node.arguments.length === 1 && 53 | babel.types.isStringLiteral(path.node.arguments[0]) 54 | ) { 55 | const functionName = path.node.callee.name; 56 | if (functionCalls[functionName]) { 57 | functionCalls[functionName] += 1; 58 | } else { 59 | functionCalls[functionName] = 1; 60 | } 61 | } 62 | } 63 | }); 64 | 65 | // Find the function name with the most calls 66 | let maxCalls = 0; 67 | for (const [name, calls] of Object.entries(functionCalls)) { 68 | if (calls > maxCalls) { 69 | maxCalls = calls; 70 | functionName = name; 71 | } 72 | } 73 | 74 | console.log(`Identified function name: ${functionName}`); 75 | 76 | 77 | traverse(ast, { 78 | CallExpression(path) { 79 | // Check if the function call has only one argument 80 | if (path.node.arguments.length !== 1) { 81 | return; 82 | } 83 | 84 | // Check if the function name is "H" 85 | if (path.node.callee.name !== functionName) { 86 | return; 87 | } 88 | 89 | const arg = path.node.arguments[0]; 90 | 91 | // Check if the argument is a string literal 92 | if (babel.types.isStringLiteral(arg)) { 93 | // Replace the call with a call to decodeHvalue 94 | decodedValue = H(arg.value); 95 | try{ 96 | path.replaceWith(babel.types.stringLiteral(decodedValue)); 97 | matches += 1; 98 | } catch (e) { 99 | return 100 | } 101 | } 102 | } 103 | }); 104 | 105 | console.log(`Replaced ${matches} function calls`); 106 | console.log(' ------------------'); 107 | } 108 | 109 | module.exports = decodeHCalls; -------------------------------------------------------------------------------- /transformations/listPlacements.js: -------------------------------------------------------------------------------- 1 | 2 | const babel = require('@babel/core'); 3 | const { default: traverse } = require('@babel/traverse'); 4 | const { default: generate } = require('@babel/generator'); 5 | const vm = require('vm'); 6 | 7 | function decodeListPlacements(ast){ 8 | console.log('-> Replacing List call '); 9 | let matches = 0; 10 | let backupScripts = {} 11 | let trFunctionNames = {}; // Placeholder for the identified function's name 12 | 13 | traverse(ast, { 14 | FunctionDeclaration(path) { 15 | // 1. Check if the function has no arguments 16 | if (path.node.params.length !== 0) { 17 | return; 18 | } 19 | 20 | // 2. Check if there's a single variable declaration with an array initializer 21 | const bodyStatements = path.node.body.body; 22 | if (bodyStatements.length !== 2) { 23 | return; 24 | } 25 | 26 | const varDeclaration = bodyStatements[0]; 27 | if (!babel.types.isVariableDeclaration(varDeclaration) || varDeclaration.declarations.length !== 1) { 28 | return; 29 | } 30 | 31 | const arrayInitializer = varDeclaration.declarations[0].init; 32 | if (!babel.types.isArrayExpression(arrayInitializer)) { 33 | return; 34 | } 35 | 36 | // 3. Check for the return statement 37 | const returnStatement = bodyStatements[1]; 38 | if (!babel.types.isReturnStatement(returnStatement)) { 39 | return; 40 | } 41 | 42 | const returnedFunctionCall = returnStatement.argument; 43 | if (!babel.types.isCallExpression(returnedFunctionCall)) { 44 | return; 45 | } 46 | 47 | const returnedFunction = returnedFunctionCall.callee; 48 | if (!babel.types.isAssignmentExpression(returnedFunction) || returnedFunction.operator !== "=") { 49 | return; 50 | } 51 | 52 | const leftAssignment = returnedFunction.left; 53 | const rightAssignment = returnedFunction.right; 54 | 55 | if (!babel.types.isIdentifier(leftAssignment) || !babel.types.isFunctionExpression(rightAssignment)) { 56 | return; 57 | } 58 | 59 | trFunctionNames[leftAssignment.name] = generate(path.node).code; 60 | 61 | } 62 | }); 63 | 64 | // Output the identified function names 65 | const identifiedFunctions = Object.keys(trFunctionNames); 66 | if (identifiedFunctions.length > 0) { 67 | //console.log(`Functions similar to 'Tr' identified as: ${identifiedFunctions.join(", ")}`); 68 | } else { 69 | //console.log("No functions similar to 'Tr' were found."); 70 | } 71 | 72 | let grFunctionNames = {}; // Placeholder for the identified function names and their associated Tr-like functions 73 | let grFunctionsAssociations = {}; 74 | traverse(ast, { 75 | FunctionDeclaration(path) { 76 | // 1. Check if the function has two arguments 77 | if (path.node.params.length !== 2) { 78 | return; 79 | } 80 | 81 | // 2. Check for a variable declaration that calls one of the functions identified in step 1 82 | let associatedTrFunction = null; 83 | path.traverse({ 84 | VariableDeclarator(innerPath) { 85 | const init = innerPath.node.init; 86 | if (babel.types.isCallExpression(init) && 87 | babel.types.isIdentifier(init.callee) && 88 | trFunctionNames[init.callee.name]) { 89 | associatedTrFunction = init.callee.name; 90 | } 91 | } 92 | }); 93 | 94 | if (!associatedTrFunction) { 95 | return; 96 | } 97 | 98 | // 3. Check for a return statement that redefines the function itself 99 | const returnStatement = path.node.body.body.find(statement => 100 | babel.types.isReturnStatement(statement) && 101 | babel.types.isCallExpression(statement.argument) && 102 | babel.types.isAssignmentExpression(statement.argument.callee) && 103 | babel.types.isIdentifier(statement.argument.callee.left, { name: path.node.id.name }) 104 | ); 105 | 106 | if (!returnStatement) { 107 | return; 108 | } 109 | 110 | grFunctionNames[path.node.id.name] = generate(path.node).code; 111 | grFunctionsAssociations[associatedTrFunction] = path.node.id.name; 112 | 113 | } 114 | }); 115 | 116 | let shufflingFunctions = {}; // Placeholder for the identified shuffling functions 117 | 118 | traverse(ast, { 119 | CallExpression(path) { 120 | // 1. Check if the function takes one of the `Tr`-like functions as an argument 121 | const callee = path.node.callee; 122 | const argument = path.node.arguments[0]; 123 | if (path.node.arguments.length !== 1 || !babel.types.isIdentifier(argument) || !trFunctionNames[argument.name]) { 124 | return; 125 | } 126 | 127 | // 2. Inside this function, look for a loop with arithmetic operations 128 | let hasLoopWithArithmetic = false; 129 | path.traverse({ 130 | ForStatement(innerPath) { 131 | innerPath.traverse({ 132 | BinaryExpression(binaryPath) { 133 | if (["+", "-", "*", "/", "%"].includes(binaryPath.node.operator)) { 134 | hasLoopWithArithmetic = true; 135 | } 136 | } 137 | }); 138 | } 139 | }); 140 | 141 | if (!hasLoopWithArithmetic) { 142 | return; 143 | } 144 | 145 | // If all checks pass, we've identified the shuffling function 146 | functionCode = path.node; 147 | shufflingFunctions[argument.name] = generate(callee).code 148 | //console.log(`Identified shuffling function for ${argument.name}: ${generate(callee).code}`); 149 | 150 | 151 | } 152 | }); 153 | 154 | function executeInVM(trFunctionNames, grFunctionNames, shufflingFunctions) { 155 | // Creating a sandboxed environment 156 | let sandbox = { 157 | console: console, 158 | ...trFunctionNames, 159 | ...grFunctionNames, 160 | }; 161 | 162 | const context = vm.createContext(sandbox); 163 | 164 | for (const [name, shuffleFunction] of Object.entries(shufflingFunctions)) { 165 | const trFunctionName = name; // Assuming the shuffling function's name corresponds to the trFunction's name 166 | const trFunction = trFunctionNames[trFunctionName]; 167 | const grFunctionName = grFunctionsAssociations[trFunctionName]; 168 | const grFunction = grFunctionNames[grFunctionName]; 169 | 170 | if (trFunction) { 171 | // Executing the shuffling function with the trFunction 172 | let scriptCode = ` 173 | ${trFunction} 174 | ${grFunction} 175 | (${shuffleFunction})(${trFunctionName}) 176 | ` 177 | const script = new vm.Script(scriptCode); 178 | backupScripts[grFunctionName] = scriptCode; 179 | //console.log(`Executing ${trFunctionName} with ${shuffleFunction}`); 180 | script.runInContext(context); 181 | }else { 182 | //console.log(`No trFunction found for ${trFunctionName}`); 183 | } 184 | } 185 | 186 | // Return the sandbox for potential further use or inspection 187 | return sandbox; 188 | } 189 | 190 | 191 | context = executeInVM( 192 | trFunctionNames, 193 | grFunctionNames, 194 | shufflingFunctions 195 | ) 196 | 197 | // 1. Identify variable associations for each grFunctionName 198 | let grFunctionAssociations = {}; 199 | traverse(ast, { 200 | VariableDeclaration(path) { 201 | path.node.declarations.forEach(declaration => { 202 | if ( 203 | babel.types.isIdentifier(declaration.init) 204 | && 205 | Object.keys(grFunctionNames).includes(declaration.init.name) 206 | ) { 207 | // this declaration.id.name may have different gr associations 208 | // so we wanna have grFunctionAssociations like k: [...] 209 | if (grFunctionAssociations[declaration.id.name]) { 210 | grFunctionAssociations[declaration.id.name].push(declaration.init.name); 211 | }else { 212 | grFunctionAssociations[declaration.id.name] = [declaration.init.name]; 213 | } 214 | 215 | //console.log(`Found association between ${declaration.init.name} and ${declaration.id.name}`); 216 | // Remove the declaration 217 | } 218 | }); 219 | } 220 | }); 221 | 222 | //console.log(grFunctionAssociations) 223 | 224 | let brokenReplace = []; 225 | // Now we check all the function calls 226 | // if the function is inside replacableFunctions 227 | // and the argument is one int, we replace it by running the function 228 | traverse(ast, { 229 | CallExpression(path) { 230 | if ( 231 | Object.keys(grFunctionAssociations).includes(path.node.callee.name) 232 | && 233 | path.node.arguments.length === 1 234 | && 235 | babel.types.isNumericLiteral(path.node.arguments[0]) 236 | ) { 237 | const functionName = path.node.callee.name; 238 | const argument = path.node.arguments[0].value; 239 | const grFunctionNames = grFunctionAssociations[functionName]; 240 | // we need to execute in the context and get the output 241 | 242 | // Loop trought grFunctionNames 243 | matched = false; 244 | for (const grFunctionName of grFunctionNames) { 245 | let output = context[grFunctionName](argument); 246 | // Output can be from undefined to string 247 | if (output === undefined) { 248 | //console.log(`Undefined output for ${functionName}(${argument})`); 249 | continue 250 | } 251 | else if (typeof output === "string") { 252 | matched = true; 253 | //console.log(`Replaced ${functionName}(${argument}) with ${output} from ${grFunctionName}`); 254 | path.replaceWith(babel.types.stringLiteral(output)); 255 | matches += 1; 256 | break 257 | } 258 | } 259 | if (!matched) { 260 | brokenReplace.push(functionName) 261 | } 262 | } 263 | } 264 | }); 265 | //console.log(grFunctionAssociations) 266 | 267 | // Now brokenReplace are probably because sometimes the Object.keys(grFunctionAssociations) 268 | // get associated to other variables, for example 269 | // x = Aa 270 | // So what we need to do now is to make a traverse similar to the 271 | // previous one that is going to search for the variables that are 272 | // associated to one of the keys of grFunctionAssociations, keep in mind that are not initialized 273 | // with a 'var' 274 | let associationsOfAssociations = {} 275 | traverse(ast, { 276 | VariableDeclaration(path) { 277 | path.node.declarations.forEach(declaration => { 278 | if ( 279 | declaration.init 280 | && 281 | Object.keys(grFunctionAssociations).includes(declaration.init.name) 282 | ) { 283 | // this declaration.id.name may have different gr associations 284 | // so we wanna have grFunctionAssociations like k: [...] 285 | if (associationsOfAssociations[declaration.id.name]) { 286 | associationsOfAssociations[declaration.id.name].push(declaration.init.name); 287 | }else { 288 | associationsOfAssociations[declaration.id.name] = [declaration.init.name]; 289 | } 290 | 291 | //console.log(`Found association between ${declaration.init.name} and ${declaration.id.name}`); 292 | // Remove the declaration 293 | } 294 | }); 295 | } 296 | }); 297 | 298 | const brokenAgain = [] 299 | // Now like before we need to check the calls and replace them 300 | traverse(ast, { 301 | CallExpression(path) { 302 | if ( 303 | Object.keys(associationsOfAssociations).includes(path.node.callee.name) 304 | && 305 | path.node.arguments.length === 1 306 | && 307 | babel.types.isNumericLiteral(path.node.arguments[0]) 308 | ) { 309 | const functionName = path.node.callee.name; 310 | const argument = path.node.arguments[0].value; 311 | const associationFunctionNames = associationsOfAssociations[functionName]; 312 | // we need to execute in the context and get the output 313 | match = false; 314 | // Loop trought grFunctionNames 315 | for (const associationFunctionName of associationFunctionNames) { 316 | grFunctionNames = grFunctionAssociations[associationFunctionName] 317 | for (const grFunctionName of grFunctionNames) { 318 | let output = context[grFunctionName](argument); 319 | // Output can be from undefined to string 320 | if (output === undefined) { 321 | //console.log(`Undefined output for ${functionName}(${argument})`); 322 | continue 323 | } 324 | else if (typeof output === "string") { 325 | match = true; 326 | path.replaceWith(babel.types.stringLiteral(output)); 327 | break 328 | } 329 | } 330 | } 331 | if (!match) { 332 | brokenAgain.push(functionName) 333 | } 334 | } 335 | } 336 | }); 337 | 338 | console.log(`Replaced ${matches} function calls`); 339 | 340 | } 341 | 342 | module.exports = decodeListPlacements; -------------------------------------------------------------------------------- /transformations/magicNumber.js: -------------------------------------------------------------------------------- 1 | 2 | const babel = require('@babel/core'); 3 | const { default: traverse } = require('@babel/traverse'); 4 | const { default: generate } = require('@babel/generator'); 5 | 6 | // Define the decodeChat function 7 | base64decoder = function () { 8 | try { 9 | if (atob && "test" === atob("dGVzdA==")) 10 | return atob 11 | } catch (t) {} 12 | 13 | function t(t) { 14 | this.message = t 15 | } 16 | t.prototype = new Error, 17 | t.prototype.name = "InvalidCharacterError"; 18 | return function (e) { 19 | var n = String(e).replace(/[=]+$/, ""); 20 | if (n.length % 4 == 1) 21 | throw new t("'atob' failed: The string to be decoded is not correctly encoded."); 22 | for (var r, a, o = 0, i = 0, c = ""; a = n.charAt(i++); ~a && (r = o % 4 ? 64 * r + a : a, 23 | o++ % 4) ? c += String.fromCharCode(255 & r >> (-2 * o & 6)) : 0) 24 | a = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(a); 25 | return c 26 | } 27 | }() 28 | 29 | function decodeChat(n, magicNumber) { 30 | for (var c = base64decoder(n), u = "", l = 0; l < c.length; ++l) { 31 | var f = magicNumber.charCodeAt(l % 7); 32 | u += String.fromCharCode(f ^ c.charCodeAt(l)) 33 | } 34 | return u 35 | } 36 | 37 | function decodeMagicNumberCalls(ast) { 38 | console.log('-> Decoding MagicNumber calls '); 39 | // We beed to get all the function calls with one string argument 40 | // Find the most common 3 starting char and make a regex 41 | let matches = 0; 42 | let functionCalls = {}; 43 | let regexPattern = ''; 44 | 45 | traverse(ast, { 46 | CallExpression(path) { 47 | if ( 48 | path.node.arguments.length === 1 && 49 | babel.types.isStringLiteral(path.node.arguments[0]) 50 | ) { 51 | // we need to store the first 3 chars of the string 52 | const arg = path.node.arguments[0]; 53 | const firstThreeChars = arg.value.substring(0, 3); 54 | if (functionCalls[firstThreeChars]) { 55 | functionCalls[firstThreeChars] += 1; 56 | } else { 57 | functionCalls[firstThreeChars] = 1; 58 | } 59 | } 60 | } 61 | }); 62 | 63 | 64 | // Find the most common 3 starting char and make a regex 65 | const sortedFunctionCalls = Object.keys(functionCalls).sort((a, b) => functionCalls[b] - functionCalls[a]); 66 | const mostCommonThreeChars = sortedFunctionCalls[0]; 67 | regexPattern = new RegExp(`^${mostCommonThreeChars}`); 68 | 69 | traverse(ast, { 70 | FunctionDeclaration(path) { 71 | // Check the structure 72 | const body = path.node.body.body; 73 | if (body.length >= 2 && 74 | body[0].type === 'VariableDeclaration' && 75 | body[1].type === 'IfStatement' && 76 | body[1].alternate && 77 | body[1].alternate.body && 78 | body[1].alternate.body[0].type === 'ForStatement' && 79 | body[1].alternate.body[0].body.body && 80 | body[1].alternate.body[0].body.body[0].type === 'VariableDeclaration' && 81 | body[1].alternate.body[0].body.body[0].declarations[0].init && 82 | body[1].alternate.body[0].body.body[0].declarations[0].init.type === 'CallExpression' && 83 | body[1].alternate.body[0].body.body[0].declarations[0].init.callee.property.name === 'charCodeAt' 84 | ) { 85 | let code = generate(body[1].alternate.body[0].body.body[0].declarations[0].init).code; 86 | magicNumber = code.split('"')[1]; 87 | } 88 | } 89 | }); 90 | 91 | console.log(`Identified magic number: ${magicNumber}`); 92 | 93 | 94 | 95 | traverse(ast, { 96 | CallExpression(path) { 97 | // Check if the function call has only one argument 98 | if (path.node.arguments.length !== 1) { 99 | return; 100 | } 101 | 102 | const arg = path.node.arguments[0]; 103 | 104 | // Check if the argument is a string literal and matches the format starting with F29 105 | if (babel.types.isStringLiteral(arg) && regexPattern.test(arg.value)) { 106 | let decodedValue; 107 | try{ 108 | decodedValue = decodeChat(arg.value, magicNumber); 109 | matches += 1; 110 | } catch (e) { 111 | return; 112 | } 113 | 114 | // Replace the call with the decoded value 115 | //console.log(`Replaced ${arg.value} with ${decodedValue}`); 116 | path.replaceWith(babel.types.stringLiteral(decodedValue)); 117 | } 118 | } 119 | }); 120 | console.log(`Replaced ${matches} function calls`); 121 | } 122 | 123 | module.exports = decodeMagicNumberCalls; -------------------------------------------------------------------------------- /transformations/replaceDictCalls.js: -------------------------------------------------------------------------------- 1 | 2 | const babel = require('@babel/core'); 3 | const { default: traverse } = require('@babel/traverse'); 4 | const { default: generate } = require('@babel/generator'); 5 | 6 | function replaceDictCalls(ast) { 7 | console.log(' ------------------'); 8 | console.log('-> Replacing Dict call '); 9 | let matches = 0; 10 | const localDicts = {}; 11 | traverse(ast, { 12 | VariableDeclarator(path) { 13 | if (path.node.init && path.node.init.type === 'ObjectExpression') { 14 | const dictName = path.node.id.name; 15 | localDicts[dictName] = {}; 16 | 17 | for (const property of path.node.init.properties) { 18 | if (property.key.type === 'Identifier' && ['NumericLiteral', 'StringLiteral'].includes(property.value.type)) { 19 | localDicts[dictName][property.key.name] = property.value; 20 | } 21 | } 22 | } 23 | } 24 | }); 25 | 26 | traverse(ast, { 27 | MemberExpression(path) { 28 | if (path.parent.type === "AssignmentExpression" && path.parent.left === path.node) { 29 | return; 30 | } 31 | 32 | const objectName = path.node.object.name; 33 | const propName = path.node.property.name; 34 | 35 | if (localDicts[objectName] && localDicts[objectName][propName]) { 36 | const replacementValue = localDicts[objectName][propName]; 37 | if (replacementValue.type === 'NumericLiteral' || replacementValue.type === 'StringLiteral') { 38 | path.replaceWith(replacementValue); 39 | matches += 1; 40 | } 41 | } 42 | } 43 | 44 | 45 | }); 46 | traverse(ast, { 47 | VariableDeclarator(path) { 48 | if (path.node.init && path.node.init.type === 'ObjectExpression') { 49 | const dictName = path.node.id.name; 50 | localDicts[dictName] = {}; 51 | 52 | for (const property of path.node.init.properties) { 53 | if (property.key.type === 'Identifier' && ['NumericLiteral', 'StringLiteral'].includes(property.value.type)) { 54 | localDicts[dictName][property.key.name] = property.value; 55 | } 56 | } 57 | } 58 | }, 59 | MemberExpression(path) { 60 | if (path.parent.type === "AssignmentExpression" && path.parent.left === path.node) { 61 | // Skip replacing if this MemberExpression is the left side of an assignment 62 | return; 63 | } 64 | 65 | const objectName = path.node.object.name; 66 | const propName = path.node.property.name; 67 | 68 | if (localDicts[objectName] && localDicts[objectName][propName]) { 69 | const replacementValue = localDicts[objectName][propName]; 70 | if (replacementValue.type === 'NumericLiteral' || replacementValue.type === 'StringLiteral') { 71 | path.replaceWith(replacementValue); 72 | matches += 1; 73 | } 74 | } 75 | } 76 | }); 77 | console.log(`Replaced ${matches} dict calls`); 78 | } 79 | 80 | module.exports = replaceDictCalls; -------------------------------------------------------------------------------- /transformations/replaceVariableCalls.js: -------------------------------------------------------------------------------- 1 | const { default: traverse } = require('@babel/traverse'); 2 | const types = require('@babel/types'); 3 | 4 | function replaceVariableCallsWithValues(ast) { 5 | console.log('-> Replacing Variable call '); 6 | let matches = 0; 7 | traverse(ast, { 8 | FunctionDeclaration(path) { 9 | // For each function, collect replacements within its scope 10 | let localReplacements = {}; 11 | 12 | // Collect variable assignments within the function 13 | path.traverse({ 14 | VariableDeclarator(innerPath) { 15 | if (types.isNumericLiteral(innerPath.node.init)) { 16 | localReplacements[innerPath.node.id.name] = innerPath.node.init.value; 17 | } 18 | } 19 | }); 20 | 21 | // Replace the variable calls with their values within the function 22 | path.traverse({ 23 | Identifier(innerPath) { 24 | if ( 25 | innerPath.parent.type === 'ObjectProperty' && innerPath.key === 'key' || 26 | innerPath.parentPath.isFunction() && innerPath.listKey === 'params' || 27 | innerPath.parent.type === 'MemberExpression' && innerPath.key === 'object' || 28 | innerPath.parent.type === 'NewExpression' && innerPath.key === 'callee' || 29 | innerPath.parent.type === 'CallExpression' && innerPath.key === 'callee' || 30 | innerPath.parent.type === 'MemberExpression' && innerPath.key === 'property' || 31 | innerPath.parent.type === 'ForInStatement' && innerPath.key === 'left' || 32 | innerPath.parent.type === 'VariableDeclarator' && innerPath.key === 'id' || 33 | innerPath.parent.type === 'AssignmentExpression' && innerPath.key === 'left' || 34 | innerPath.parent.type === 'MemberExpression' && innerPath.key === 'property' || 35 | innerPath.parent.type === 'FunctionDeclaration' && innerPath.key === 'id' || 36 | innerPath.parent.type === 'CatchClause' && innerPath.key === 'param' 37 | ) { 38 | return; 39 | } 40 | 41 | 42 | if (localReplacements[innerPath.node.name] && 43 | path.scope.hasBinding(innerPath.node.name)) { 44 | if (typeof localReplacements[innerPath.node.name] === 'number') { 45 | matches += 1; 46 | innerPath.replaceWith(types.numericLiteral(localReplacements[innerPath.node.name])); 47 | } 48 | } 49 | } 50 | }); 51 | } 52 | }); 53 | 54 | console.log(`Replaced ${matches} variable calls`); 55 | } 56 | 57 | module.exports = replaceVariableCallsWithValues; 58 | --------------------------------------------------------------------------------