UNPKG

react-native-decompiler

Version:

react native decompile apk and ipa(soon)

280 lines (278 loc) 30.7 kB
#!/usr/bin/env node "use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const fs_extra_1 = __importDefault(require("fs-extra")); const perf_hooks_1 = require("perf_hooks"); const prettier_1 = __importDefault(require("prettier")); const generator_1 = __importDefault(require("@babel/generator")); const command_line_args_1 = __importDefault(require("command-line-args")); const chalk_1 = __importDefault(require("chalk")); const crypto_1 = __importDefault(require("crypto")); const eslint_1 = require("eslint"); const taggerList_1 = __importDefault(require("./taggers/taggerList")); const editorList_1 = __importDefault(require("./editors/editorList")); const router_1 = __importDefault(require("./router")); const decompilerList_1 = __importDefault(require("./decompilers/decompilerList")); const cacheParse_1 = __importDefault(require("./cacheParse")); const eslintConfig_1 = __importDefault(require("./eslintConfig")); const fileParserRouter_1 = __importDefault(require("./fileParsers/fileParserRouter")); const performanceTracker_1 = __importDefault(require("./util/performanceTracker")); const progressBar_1 = __importDefault(require("./util/progressBar")); function calculateModulesToIgnore(argValues, modules) { if (argValues.agressiveCache) return []; return modules.filter((mod) => { const dependentModules = modules.filter((otherMod) => otherMod.dependencies.includes(mod.moduleId)); return !mod.ignored && dependentModules.length > 0 && dependentModules.every((otherMod) => otherMod.ignored || mod.dependencies.includes(otherMod.moduleId)); }); } const argValues = command_line_args_1.default([ { name: 'in', alias: 'i' }, { name: 'out', alias: 'o' }, { name: 'entry', alias: 'e', type: Number }, { name: 'performance', alias: 'p', type: Boolean }, { name: 'verbose', alias: 'v', type: Boolean }, { name: 'es6', type: Boolean }, { name: 'noEslint', type: Boolean }, { name: 'noPrettier', type: Boolean }, { name: 'decompileIgnored', type: Boolean }, { name: 'agressiveCache', type: Boolean }, { name: 'unpackOnly', type: Boolean }, { name: 'noProgress', type: Boolean }, { name: 'debug', type: Number }, ]); if (!argValues.in || !argValues.out) { console.log(`react-native-decompiler Example command: react-native-decompiler -i index.android.bundle -o ./output Command params: -i (required) - the path to the input file/folder -o (required) - the path to the output folder -e - a module ID, if specified will only decompile that module & it's dependencies. also creates cache file to speed up future load times (useful for developing new plugins) -p - performance monitoring flag, will print out runtime for each decompiler plugin -v - verbose flag, does not include debug logging (use DEBUG=react-native-decompiler:* env flag for that) --es6 - attempts to decompile to ES6 module syntax. --noEslint - does not run ESLint after doing decompilation --noPrettier - does not run Prettier after doing decompilation --unpackOnly - only unpacks the app with no other adjustments --decompileIgnored - decompile ignored modules(modules are generally ignored if they are flagged as an NPM module) --agressiveCache - skips some cache checks at the expense of possible cache desync`); process.exit(0); } if (argValues.performance) { performanceTracker_1.default.enable(); } if (argValues.noProgress) { progressBar_1.default.disable(); } async function start() { var _a; try { const progressBar = progressBar_1.default.getInstance(); const cacheFileName = `${argValues.out}/${(_a = argValues.entry) !== null && _a !== void 0 ? _a : 'null'}.cache`; let startTime = perf_hooks_1.performance.now(); fs_extra_1.default.ensureDirSync(argValues.out); if (!fs_extra_1.default.existsSync(argValues.in)) { console.error(`${chalk_1.default.red('[!]')} "${argValues.in}" does not exist!"`); process.exit(1); } console.log('Reading file...'); const fileParserRouter = new fileParserRouter_1.default(); const modules = await fileParserRouter.route(argValues); if (modules == null || modules.length === 0) { console.error(`${chalk_1.default.red('[!]')} No modules were found!`); console.error(`${chalk_1.default.red('[!]')} Possible reasons:`); console.error(`${chalk_1.default.red('[!]')} - The React Native app is unbundled. If it is, export the "js-modules" folder from the app and provide it as the --js-modules argument`); console.error(`${chalk_1.default.red('[!]')} - The bundle is a Hermes/binary file (ex. Facebook, Instagram). These files are not supported`); console.error(`${chalk_1.default.red('[!]')} - The provided Webpack bundle input is not or does not contain the entrypoint bundle`); console.error(`${chalk_1.default.red('[!]')} - The provided Webpack bundle was built from V5, which is not supported`); console.error(`${chalk_1.default.red('[!]')} - The file provided is not a React Native or Webpack bundle.`); process.exit(1); } if (argValues.entry != null && (!argValues.agressiveCache)) { console.log('Entry module provided, filtering out unused modules'); const entryModuleDependencies = new Set(); let lastDependenciesSize = 0; entryModuleDependencies.add(argValues.entry); while (lastDependenciesSize !== entryModuleDependencies.size) { lastDependenciesSize = entryModuleDependencies.size; entryModuleDependencies.forEach((moduleId) => { const module = modules.find((mod) => (mod === null || mod === void 0 ? void 0 : mod.moduleId) === moduleId); if (module) { module.dependencies.forEach((dep) => entryModuleDependencies.add(dep)); } }); } modules.forEach((mod, i) => { if (!entryModuleDependencies.has(mod.moduleId)) { delete modules[i]; } }); } let nonIgnoredModules = modules.filter((mod) => argValues.decompileIgnored || !mod.ignored); console.log(`Took ${perf_hooks_1.performance.now() - startTime}ms`); startTime = perf_hooks_1.performance.now(); console.log('Pre-parsing modules...'); progressBar.start(0, nonIgnoredModules.length); nonIgnoredModules.forEach((module) => { module.validate(); module.unpack(); progressBar.increment(); }); progressBar.stop(); console.log(`Took ${perf_hooks_1.performance.now() - startTime}ms`); if (!argValues.unpackOnly) { startTime = perf_hooks_1.performance.now(); console.log('Tagging...'); progressBar.start(0, nonIgnoredModules.length); const taggerRouters = nonIgnoredModules.map((m) => new router_1.default(taggerList_1.default, m, modules, argValues)); for (let pass = 1; pass <= taggerRouters[0].maxPass; pass += 1) { taggerRouters.forEach((r) => r.runPass(pass)); if (pass === taggerRouters[0].maxPass) { progressBar.increment(); } } progressBar.stop(); if (argValues.performance) { console.log(`Traversal took ${router_1.default.traverseTimeTaken}ms`); console.log(router_1.default.timeTaken); router_1.default.timeTaken = {}; router_1.default.traverseTimeTaken = 0; } console.log(`Took ${perf_hooks_1.performance.now() - startTime}ms`); startTime = perf_hooks_1.performance.now(); console.log('Filtering out modules only depended on ignored modules...'); let modulesToIgnore = []; modulesToIgnore = calculateModulesToIgnore(argValues, modules); while (modulesToIgnore.length) { modulesToIgnore.forEach((mod) => { mod.ignored = true; }); modulesToIgnore = calculateModulesToIgnore(argValues, modules); } if (argValues.verbose) { console.table(modules.map((mod) => { const dependentModules = modules.filter((otherMod) => otherMod.dependencies.includes(mod.moduleId)); return { moduleName: mod.moduleName, ignored: mod.ignored, dependencies: mod.dependencies.filter((e) => e != null), dependents: dependentModules.map((m) => m.moduleId), }; })); console.table(modules.filter((m) => !m.ignored || m.isNpmModule).map((mod) => { const dependentModules = modules.filter((otherMod) => otherMod.dependencies.includes(mod.moduleId)); if (mod.isNpmModule && !dependentModules.filter((m) => !m.ignored).length) return null; return { moduleName: mod.moduleName, ignored: mod.ignored, dependencies: mod.dependencies.filter((e) => e != null), dependents: dependentModules.filter((m) => !m.ignored).map((m) => m.moduleId), }; }).filter((e) => e != null)); } nonIgnoredModules = modules.filter((mod) => argValues.decompileIgnored || !mod.ignored); console.log(`${nonIgnoredModules.length} remain to be decompiled`); console.log(`Took ${perf_hooks_1.performance.now() - startTime}ms`); startTime = perf_hooks_1.performance.now(); console.log('Decompiling...'); progressBar.start(0, nonIgnoredModules.length); const editorRouters = nonIgnoredModules.map((m) => new router_1.default(editorList_1.default, m, modules, argValues)); for (let pass = 1; pass <= editorRouters[0].maxPass; pass += 1) { editorRouters.forEach((r) => r.runPass(pass)); } const decompilerRouter = nonIgnoredModules.map((m) => new router_1.default(decompilerList_1.default, m, modules, argValues)); for (let pass = 1; pass <= decompilerRouter[0].maxPass; pass += 1) { decompilerRouter.forEach((r) => r.runPass(pass)); if (pass === decompilerRouter[0].maxPass) { progressBar.increment(); } } progressBar.stop(); if (argValues.performance) { console.log(`Traversal took ${router_1.default.traverseTimeTaken}ms`); console.log(`Recrawl took ${router_1.default.recrawlTimeTaken}ms`); console.log(router_1.default.timeTaken); } console.log(`Took ${perf_hooks_1.performance.now() - startTime}ms`); } startTime = perf_hooks_1.performance.now(); console.log('Generating code...'); progressBar.start(0, nonIgnoredModules.length); const eslint = new eslint_1.ESLint({ fix: true, ignore: false, useEslintrc: false, extensions: ['.js', '.jsx'], overrideConfig: eslintConfig_1.default, }); const generatedFiles = await Promise.all(nonIgnoredModules.map(async (module) => { var _a; if (module.previousRunChecksum === crypto_1.default.createHash('md5').update(JSON.stringify(module.moduleCode.body)).digest('hex')) return null; const returnValue = { name: module.moduleId, extension: module.tags.includes('jsx') ? 'jsx' : 'js', code: generator_1.default({ ...module.originalFile.program, type: 'Program', body: module.moduleCode.body, }).code, }; if (!argValues.noEslint && !argValues.unpackOnly) { try { const lintedCode = await eslint.lintText(returnValue.code); returnValue.code = (_a = lintedCode[0].output) !== null && _a !== void 0 ? _a : returnValue.code; } catch (e) { } } if (!argValues.noPrettier) { try { returnValue.code = prettier_1.default.format(returnValue.code, { parser: 'babel', singleQuote: true, printWidth: 180 }); } catch (e) { } } progressBar.increment(); return returnValue; })); progressBar.stop(); console.log(`Took ${perf_hooks_1.performance.now() - startTime}ms`); startTime = perf_hooks_1.performance.now(); console.log('Saving...'); progressBar.start(0, nonIgnoredModules.length); generatedFiles.forEach((file) => { if (file == null) return; const filePath = `${argValues.out}/${file.name}.${file.extension}`; if (!fs_extra_1.default.existsSync(filePath) || fs_extra_1.default.readFileSync(filePath, 'utf-8') !== file.code) { fs_extra_1.default.writeFileSync(filePath, file.code); } progressBar.increment(); }); modules.forEach((m) => { if (!m.isStatic) return; const filePath = `${argValues.out}/${m.moduleId}.${m.tags.includes('css') ? 'css' : '?'}`; if (!fs_extra_1.default.existsSync(filePath) || fs_extra_1.default.readFileSync(filePath, 'utf-8') !== m.staticContent) { fs_extra_1.default.writeFileSync(filePath, m.staticContent); } }); progressBar.stop(); if (!fs_extra_1.default.existsSync(cacheFileName) || !argValues.agressiveCache) { console.log('Writing to cache...'); await new cacheParse_1.default(argValues).writeCache(cacheFileName, modules); } console.log(`Took ${perf_hooks_1.performance.now() - startTime}ms`); console.log('Done!'); } catch (e) { console.error(`${chalk_1.default.red('[!]')} Error occurred! You should probably report this.`); console.error(e); process.exit(1); } } start(); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFpbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9tYWluLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQWlCQSx3REFBK0I7QUFDL0IsMkNBQXlDO0FBQ3pDLHdEQUFnQztBQUNoQyxpRUFBeUM7QUFDekMsMEVBQWdEO0FBQ2hELGtEQUEwQjtBQUMxQixvREFBNEI7QUFDNUIsbUNBQWdDO0FBRWhDLHNFQUE4QztBQUM5QyxzRUFBOEM7QUFDOUMsc0RBQThCO0FBQzlCLGtGQUEwRDtBQUMxRCw4REFBc0M7QUFDdEMsa0VBQTBDO0FBRTFDLHNGQUE4RDtBQUM5RCxtRkFBMkQ7QUFDM0QscUVBQTZDO0FBRTdDLFNBQVMsd0JBQXdCLENBQUMsU0FBa0IsRUFBRSxPQUFpQjtJQUNyRSxJQUFJLFNBQVMsQ0FBQyxjQUFjO1FBQUUsT0FBTyxFQUFFLENBQUM7SUFDeEMsT0FBTyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUMsR0FBRyxFQUFFLEVBQUU7UUFDNUIsTUFBTSxnQkFBZ0IsR0FBRyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUMsUUFBUSxFQUFFLEVBQUUsQ0FBQyxRQUFRLENBQUMsWUFBWSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQztRQUNwRyxPQUFPLENBQUMsR0FBRyxDQUFDLE9BQU8sSUFBSSxnQkFBZ0IsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxJQUFJLGdCQUFnQixDQUFDLEtBQUssQ0FBQyxDQUFDLFFBQVEsRUFBRSxFQUFFLENBQUMsUUFBUSxDQUFDLE9BQU8sSUFBSSxHQUFHLENBQUMsWUFBWSxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQztJQUMvSixDQUFDLENBQUMsQ0FBQztBQUNMLENBQUM7QUFFRCxNQUFNLFNBQVMsR0FBRywyQkFBZSxDQUFVO0lBQ3pDLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsR0FBRyxFQUFFO0lB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