UNPKG

bagbak

Version:

Dump iOS app from a jailbroken device, based on frida.re

77 lines (60 loc) 1.95 kB
const HIGH_WATER_MARK = 1024 * 1024; /** * @typedef MachO * * @property {string} path * @property {number} type * @property {EncryptInfo} encryptInfo * @property {number} encCmdOffset */ /** * @typedef EncryptInfo * * @property {number} offset * @property {number} size * @property {number} id */ rpc.exports = { /** * @param {string} root * @param {Record<string, MachO>} binaries * @returns {boolean} */ dump(root, binaries) { for (const [relative, info] of Object.entries(binaries)) { console.log('decrypt', relative); const { offset, size } = info.encryptInfo; const absolute = root + '/' + relative; const mod = Module.load(absolute); const fatOffset = Process.findRangeByAddress(mod.base).file.offset; send({ event: 'begin', name: relative, fatOffset }); recv('ack').wait(); console.log('module =>', mod.name, mod.base, mod.size); console.log('encrypted =>', offset, size); { let fileOffset = offset + fatOffset; const steps = Math.floor(size / HIGH_WATER_MARK); let remain = size; let p = mod.base.add(offset); for (let i = 0; i < steps; i++) { console.log('ptr', p); send({ event: 'trunk', fileOffset, name: relative }, p.readByteArray(HIGH_WATER_MARK)); recv('ack').wait(); remain -= HIGH_WATER_MARK; fileOffset += HIGH_WATER_MARK; p = p.add(HIGH_WATER_MARK); } if (remain > 0) { send({ event: 'trunk', fileOffset, name: relative }, p.readByteArray(remain)); recv('ack').wait(); } } const zeroFilled = new ArrayBuffer(12); // cryptoff, cryptsize, cryptid send({ event: 'trunk', fileOffset: info.encCmdOffset + 8, name: relative }, zeroFilled); recv('ack').wait(); send({ event: 'end', name: relative }); recv('ack').wait(); } return true; } }