diff --git a/.npmignore b/.npmignore index 0d8740a..d874eed 100644 --- a/.npmignore +++ b/.npmignore @@ -1 +1 @@ -!agent.dist.js \ No newline at end of file +!agent/tiny.js \ No newline at end of file diff --git a/README.md b/README.md index 649ac43..1be3df7 100644 --- a/README.md +++ b/README.md @@ -10,20 +10,21 @@ Yet another frida based App decryptor. Requires jailbroken iOS device and [frida ### On device +With Cydia: + * [frida.re](https://www.frida.re/docs/ios/) -That's all. No SSH required. +Rootless: -### On desktop +If your are using rootless jailbreak, another project of mine [fruity-frida](https://github.com/ChiChou/fruity-frida/) might help. Use the `run-frida-server` to automatically download, deploy and run frida-server on your device. -* [node.js](https://nodejs.org/) -* `zip` command (optional). We'll generate an ipa archive when this command is avaliable +### On desktop -That's all. Npm can handle all dependencies. +* [node.js](https://nodejs.org/). If you have issues on `npm install`, your node.js might be either too new or too old. Try to use `nvm` to install a compatible version or download the correct installer. +* `zip` or `7z` command is needed to create zip archive. On most of the distros, you don't need to install them manually. ### Windows Compatibility -* Before `frida@12.5.5` it was unable to connect device via USB (ref: [12.5 release note](https://frida.re/news/2019/05/15/frida-12-5-released/)). Please use up-to-date frida to overcome this; * Filesystem of iOS differs from Windows. If you are running bagbak on Windows, **some of the file attributes (e.g., executable bit) will be lost**, thus the repacked ipa may not be able to reinstall on your phone. But it does not matter if you only indend to do static analysis. ## Install @@ -37,17 +38,16 @@ npm install -g bagbak bagbak [bundle id or name] ``` - Options: - -l, --list list apps - -H, --host hostname - -u, --uuid uuid of USB device - -o, --output output directory - -f, --override override existing - -e, --executable-only dump executables only - -z, --zip create zip archive (ipa) - -h, --help output usage information +Options: + -l, --list list apps + -U, --usb connect to USB device (default) + -R, --remote connect to remote frida-server + -D, --device connect to device with the given ID + -H, --host connect to remote frida-server on HOST + -o, --output ipa filename + -h, --help display help for command ``` ## 国内用户 frida 安装失败问题 -请参考 [使用国内镜像加速安装](https://github.com/chaitin/passionfruit/wiki/%E4%BD%BF%E7%94%A8%E5%9B%BD%E5%86%85%E9%95%9C%E5%83%8F%E5%8A%A0%E9%80%9F%E5%AE%89%E8%A3%85#%E9%A2%84%E7%BC%96%E8%AF%91%E5%8C%85%E5%A4%B1%E8%B4%A5) +[使用国内镜像加速安装](https://github.com/chaitin/passionfruit/wiki/%E4%BD%BF%E7%94%A8%E5%9B%BD%E5%86%85%E9%95%9C%E5%83%8F%E5%8A%A0%E9%80%9F%E5%AE%89%E8%A3%85#%E9%A2%84%E7%BC%96%E8%AF%91%E5%8C%85%E5%A4%B1%E8%B4%A5) diff --git a/bin/bagbak.js b/bin/bagbak.js index e17b671..3c83ec7 100755 --- a/bin/bagbak.js +++ b/bin/bagbak.js @@ -99,24 +99,29 @@ async function main() { return `${val} ${unit}`; } - if (!debugEnabled()) { - job - .on('mkdir', (remote) => { - process.stdout.write(`${chalk.cyanBright('mkdir')} ${chalk.gray(remote)}\r`); - }) - .on('download', (remote, size) => { - process.stderr.write(`${chalk.gray(remote)}\r`); - }) - .on('progress', (remote, downloaded, size) => { - process.stdout.write(`${humanFileSize(downloaded)}/${humanFileSize(size)} ${chalk.gray(remote)}\r`); - }) - .on('done', (remote) => { - process.stdout.write(`${chalk.green('ok')} ${chalk.gray(remote)}\r`); - }) - .on('patch', (remote) => { - console.log(chalk.redBright('decrypt'), remote); - }) - } + // todo: UI + job + .on('mkdir', (remote) => { + + }) + .on('download', (remote, size) => { + + }) + .on('progress', (remote, downloaded, size) => { + + }) + .on('done', (remote) => { + + }) + .on('sshBegin', () => { + console.log(chalk.greenBright('[info]'), 'pulling app bundle from device, please be patient'); + }) + .on('sshFinish', () => { + console.log(chalk.greenBright('[info]'), 'app bundle downloaded'); + }) + .on('patch', (remote) => { + console.log(chalk.redBright('[decrypt]'), remote); + }) const saved = await job.packTo(program.output); console.log(`Saved to ${chalk.yellow(saved)}`); diff --git a/index.js b/index.js index 9d9f7a9..be3c516 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,5 @@ import { EventEmitter } from "events"; -import { mkdir, open, readFile, rename, rm } from "fs/promises"; +import { mkdir, open, rename, rm } from "fs/promises"; import { tmpdir } from "os"; import { basename, join } from "path"; @@ -8,10 +8,10 @@ import { Device } from "frida"; import { findEncryptedBinaries } from './lib/scan.js'; import { Pull } from './lib/scp.js'; import { connect } from './lib/ssh.js'; -import { debug, directoryExists, passthrough } from './lib/utils.js'; +import { debug, directoryExists, passthrough, readAgent } from './lib/utils.js'; import zip from './lib/zip.js'; -export { enumerateApps } from './lib/utils.js'; +export { enumerateApps, readAgent } from './lib/utils.js'; /** * @typedef MessagePayload @@ -78,11 +78,13 @@ export class Main extends EventEmitter { debug('copy to', parent); const localRoot = join(parent, basename(remoteRoot)); + this.emit('sshBegin'); await this.copyToLocal(remoteRoot, parent); + this.emit('sshFinish'); // find all encrypted binaries const map = await findEncryptedBinaries(localRoot); - const agentScript = await readFile(join('agent', 'tiny.js')); + const agentScript = await readAgent(); /** * @type {Map} */ diff --git a/lib/utils.js b/lib/utils.js index 7d23346..b92fe41 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -1,8 +1,11 @@ import { Device } from 'frida'; -import { stat } from 'fs/promises'; +import { readFile, stat } from 'fs/promises'; -import { apps } from './installation.js'; import { EventEmitter } from 'events'; +import { dirname, join } from 'path'; +import { fileURLToPath } from 'url'; + +import { apps } from './installation.js'; export const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms)); @@ -48,6 +51,18 @@ export function passthrough(source, destination) { } } +/** + * @returns {Promise} + */ +export function readAgent() { + const __filename = fileURLToPath(import.meta.url); + const __dirname = dirname(__filename); + + const agent = join(__dirname, '..', 'agent', 'tiny.js'); + return readFile(agent, 'utf8'); +} + + const __debug = 'DEBUG' in process.env; export function debug() { if (__debug) diff --git a/package-lock.json b/package-lock.json index 6990baf..2871bb9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "bagbak", - "version": "2.6.6", + "version": "3.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "bagbak", - "version": "2.6.6", + "version": "3.0.0", "license": "MIT", "dependencies": { "bplist-creator": "^0.1.1", @@ -18,7 +18,7 @@ "ssh2": "^1.11.0" }, "bin": { - "bagbak": "go.js" + "bagbak": "bin/bagbak.js" }, "devDependencies": { "@types/frida-gum": "^18.3.1", diff --git a/package.json b/package.json index 1ae302c..30a582d 100644 --- a/package.json +++ b/package.json @@ -1,21 +1,20 @@ { "name": "bagbak", - "version": "2.6.6", + "version": "3.0.0", "description": "Dump iOS app from a jailbroken device, based on frida.re", - "main": "go.js", + "main": "index.js", "scripts": { - "prepack": "npm run build", - "build": "npm --prefix agent run build", - "watch": "npm --prefix agent run watch" + "test": "echo 'Not supported'" }, "author": "CodeColorist", "license": "MIT", "bin": { - "bagbak": "./go.js" + "bagbak": "./bin/bagbak.js" }, "files": [ - "/agent.dist.js", - "/go.js", + "index.js", + "/agent/tiny.js", + "/bin", "/lib/" ], "type": "module",