mirror of
https://github.com/ThatGuySam/doesitarm.git
synced 2026-05-18 06:44:46 -07:00
Add MachoNode locally
This commit is contained in:
parent
b62236d9e8
commit
15ddc6c4b8
2 changed files with 783 additions and 0 deletions
308
helpers/scanner/parsers/macho-node/constants.js
Normal file
308
helpers/scanner/parsers/macho-node/constants.js
Normal file
|
|
@ -0,0 +1,308 @@
|
||||||
|
// Adapted from https://github.com/indutny/macho/blob/master/lib/macho/constants.js
|
||||||
|
|
||||||
|
export const constants = {}
|
||||||
|
|
||||||
|
constants.cpuArch = {
|
||||||
|
mask: 0xff000000,
|
||||||
|
abi64: 0x01000000,
|
||||||
|
abi32: 0x02000000
|
||||||
|
};
|
||||||
|
|
||||||
|
constants.cpuType = {
|
||||||
|
0x01: 'vax',
|
||||||
|
0x06: 'mc680x0',
|
||||||
|
0x07: 'i386',
|
||||||
|
0x01000007: 'x86_64',
|
||||||
|
0x0a: 'mc98000',
|
||||||
|
0x0b: 'hppa',
|
||||||
|
0x0c: 'arm',
|
||||||
|
0x0100000c: 'arm64',
|
||||||
|
0x0200000c: 'arm64_32',
|
||||||
|
0x0d: 'mc88000',
|
||||||
|
0x0e: 'sparc',
|
||||||
|
0x0f: 'i860',
|
||||||
|
0x10: 'alpha',
|
||||||
|
0x12: 'powerpc',
|
||||||
|
0x01000012: 'powerpc64'
|
||||||
|
};
|
||||||
|
|
||||||
|
constants.endian = {
|
||||||
|
0xffffffff: 'multiple',
|
||||||
|
0: 'le',
|
||||||
|
1: 'be'
|
||||||
|
};
|
||||||
|
|
||||||
|
constants.cpuSubType = {
|
||||||
|
mask: 0x00ffffff,
|
||||||
|
vax: {
|
||||||
|
0: 'all',
|
||||||
|
1: '780',
|
||||||
|
2: '785',
|
||||||
|
3: '750',
|
||||||
|
4: '730',
|
||||||
|
5: 'I',
|
||||||
|
6: 'II',
|
||||||
|
7: '8200',
|
||||||
|
8: '8500',
|
||||||
|
9: '8600',
|
||||||
|
10: '8650',
|
||||||
|
11: '8800',
|
||||||
|
12: 'III'
|
||||||
|
},
|
||||||
|
mc680x0: {
|
||||||
|
1: 'all',
|
||||||
|
2: '40',
|
||||||
|
3: '30_only'
|
||||||
|
},
|
||||||
|
i386: {},
|
||||||
|
x86_64: {
|
||||||
|
3: 'all',
|
||||||
|
4: 'arch1'
|
||||||
|
},
|
||||||
|
mips: {
|
||||||
|
0: 'all',
|
||||||
|
1: 'r2300',
|
||||||
|
2: 'r2600',
|
||||||
|
3: 'r2800',
|
||||||
|
4: 'r2000a',
|
||||||
|
5: 'r2000',
|
||||||
|
6: 'r3000a',
|
||||||
|
7: 'r3000'
|
||||||
|
},
|
||||||
|
mc98000: {
|
||||||
|
0: 'all',
|
||||||
|
1: 'mc98601'
|
||||||
|
},
|
||||||
|
hppa: {
|
||||||
|
0: 'all',
|
||||||
|
1: '7100lc'
|
||||||
|
},
|
||||||
|
mc88000: {
|
||||||
|
0: 'all',
|
||||||
|
1: 'mc88100',
|
||||||
|
2: 'mc88110'
|
||||||
|
},
|
||||||
|
sparc: {
|
||||||
|
0: 'all'
|
||||||
|
},
|
||||||
|
i860: {
|
||||||
|
0: 'all',
|
||||||
|
1: '860'
|
||||||
|
},
|
||||||
|
powerpc: {
|
||||||
|
0: 'all',
|
||||||
|
1: '601',
|
||||||
|
2: '602',
|
||||||
|
3: '603',
|
||||||
|
4: '603e',
|
||||||
|
5: '603ev',
|
||||||
|
6: '604',
|
||||||
|
7: '604e',
|
||||||
|
8: '620',
|
||||||
|
9: '750',
|
||||||
|
10: '7400',
|
||||||
|
11: '7450',
|
||||||
|
100: '970'
|
||||||
|
},
|
||||||
|
arm: {
|
||||||
|
0: 'all',
|
||||||
|
5: 'v4t',
|
||||||
|
6: 'v6',
|
||||||
|
7: 'v5tej',
|
||||||
|
8: 'xscale',
|
||||||
|
9: 'v7',
|
||||||
|
10: 'v7f',
|
||||||
|
11: 'v7s',
|
||||||
|
12: 'v7k',
|
||||||
|
14: 'v6m',
|
||||||
|
15: 'v7m',
|
||||||
|
16: 'v7em'
|
||||||
|
},
|
||||||
|
arm64: {
|
||||||
|
0: 'all',
|
||||||
|
1: 'v8',
|
||||||
|
2: 'e'
|
||||||
|
},
|
||||||
|
arm64_32: {
|
||||||
|
1: 'all'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function cpuSubtypeIntel(a, b, name) {
|
||||||
|
constants.cpuSubType.i386[a + (b << 4)] = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
[
|
||||||
|
[3, 0, 'all'],
|
||||||
|
[4, 0, '486'],
|
||||||
|
[4, 8, '486sx'],
|
||||||
|
[5, 0, '586'],
|
||||||
|
[6, 1, 'pentpro'],
|
||||||
|
[6, 3, 'pentII_m3'],
|
||||||
|
[6, 5, 'pentII_m5'],
|
||||||
|
[7, 6, 'celeron'],
|
||||||
|
[7, 7, 'celeron_mobile'],
|
||||||
|
[8, 0, 'pentium_3'],
|
||||||
|
[8, 1, 'pentium_3_m'],
|
||||||
|
[8, 2, 'pentium_3_xeon'],
|
||||||
|
[9, 0, 'pentium_m'],
|
||||||
|
[10, 0, 'pentium_4'],
|
||||||
|
[10, 1, 'pentium_4_m'],
|
||||||
|
[11, 0, 'itanium'],
|
||||||
|
[11, 1, 'itanium_2'],
|
||||||
|
[12, 0, 'xeon'],
|
||||||
|
[12, 1, 'xeon_mp']
|
||||||
|
].forEach(function(item) {
|
||||||
|
cpuSubtypeIntel(item[0], item[1], item[2]);
|
||||||
|
});
|
||||||
|
|
||||||
|
constants.fileType = {
|
||||||
|
1: 'object',
|
||||||
|
2: 'execute',
|
||||||
|
3: 'fvmlib',
|
||||||
|
4: 'core',
|
||||||
|
5: 'preload',
|
||||||
|
6: 'dylib',
|
||||||
|
7: 'dylinker',
|
||||||
|
8: 'bundle',
|
||||||
|
9: 'dylib_stub',
|
||||||
|
10: 'dsym',
|
||||||
|
11: 'kext'
|
||||||
|
};
|
||||||
|
|
||||||
|
constants.flags = {
|
||||||
|
0x1: 'noundefs',
|
||||||
|
0x2: 'incrlink',
|
||||||
|
0x4: 'dyldlink',
|
||||||
|
0x8: 'bindatload',
|
||||||
|
0x10: 'prebound',
|
||||||
|
0x20: 'split_segs',
|
||||||
|
0x40: 'lazy_init',
|
||||||
|
0x80: 'twolevel',
|
||||||
|
0x100: 'force_flat',
|
||||||
|
0x200: 'nomultidefs',
|
||||||
|
0x400: 'nofixprebinding',
|
||||||
|
0x800: 'prebindable',
|
||||||
|
0x1000: 'allmodsbound',
|
||||||
|
0x2000: 'subsections_via_symbols',
|
||||||
|
0x4000: 'canonical',
|
||||||
|
0x8000: 'weak_defines',
|
||||||
|
0x10000: 'binds_to_weak',
|
||||||
|
0x20000: 'allow_stack_execution',
|
||||||
|
0x40000: 'root_safe',
|
||||||
|
0x80000: 'setuid_safe',
|
||||||
|
0x100000: 'reexported_dylibs',
|
||||||
|
0x200000: 'pie',
|
||||||
|
0x400000: 'dead_strippable_dylib',
|
||||||
|
0x800000: 'has_tlv_descriptors',
|
||||||
|
0x1000000: 'no_heap_execution'
|
||||||
|
};
|
||||||
|
|
||||||
|
constants.cmdType = {
|
||||||
|
0x80000000: 'req_dyld',
|
||||||
|
0x1: 'segment',
|
||||||
|
0x2: 'symtab',
|
||||||
|
0x3: 'symseg',
|
||||||
|
0x4: 'thread',
|
||||||
|
0x5: 'unixthread',
|
||||||
|
0x6: 'loadfvmlib',
|
||||||
|
0x7: 'idfvmlib',
|
||||||
|
0x8: 'ident',
|
||||||
|
0x9: 'fmvfile',
|
||||||
|
0xa: 'prepage',
|
||||||
|
0xb: 'dysymtab',
|
||||||
|
0xc: 'load_dylib',
|
||||||
|
0xd: 'id_dylib',
|
||||||
|
0xe: 'load_dylinker',
|
||||||
|
0xf: 'id_dylinker',
|
||||||
|
0x10: 'prebound_dylib',
|
||||||
|
0x11: 'routines',
|
||||||
|
0x12: 'sub_framework',
|
||||||
|
0x13: 'sub_umbrella',
|
||||||
|
0x14: 'sub_client',
|
||||||
|
0x15: 'sub_library',
|
||||||
|
0x16: 'twolevel_hints',
|
||||||
|
0x17: 'prebind_cksum',
|
||||||
|
|
||||||
|
0x80000018: 'load_weak_dylib',
|
||||||
|
0x19: 'segment_64',
|
||||||
|
0x1a: 'routines_64',
|
||||||
|
0x1b: 'uuid',
|
||||||
|
0x8000001c: 'rpath',
|
||||||
|
0x1d: 'code_signature',
|
||||||
|
0x1e: 'segment_split_info',
|
||||||
|
0x8000001f: 'reexport_dylib',
|
||||||
|
0x20: 'lazy_load_dylib',
|
||||||
|
0x21: 'encryption_info',
|
||||||
|
0x80000022: 'dyld_info',
|
||||||
|
0x80000023: 'dyld_info_only',
|
||||||
|
0x24: 'version_min_macosx',
|
||||||
|
0x25: 'version_min_iphoneos',
|
||||||
|
0x26: 'function_starts',
|
||||||
|
0x27: 'dyld_environment',
|
||||||
|
0x80000028: 'main',
|
||||||
|
0x29: 'data_in_code',
|
||||||
|
0x2a: 'source_version',
|
||||||
|
0x2b: 'dylib_code_sign_drs',
|
||||||
|
0x2c: 'encryption_info_64',
|
||||||
|
0x2d: 'linker_option'
|
||||||
|
};
|
||||||
|
|
||||||
|
constants.prot = {
|
||||||
|
none: 0,
|
||||||
|
read: 1,
|
||||||
|
write: 2,
|
||||||
|
execute: 4
|
||||||
|
};
|
||||||
|
|
||||||
|
constants.segFlag = {
|
||||||
|
1: 'highvm',
|
||||||
|
2: 'fvmlib',
|
||||||
|
4: 'noreloc',
|
||||||
|
8: 'protected_version_1'
|
||||||
|
};
|
||||||
|
|
||||||
|
constants.segTypeMask = 0xff;
|
||||||
|
constants.segType = {
|
||||||
|
0: 'regular',
|
||||||
|
1: 'zerofill',
|
||||||
|
2: 'cstring_literals',
|
||||||
|
3: '4byte_literals',
|
||||||
|
4: '8byte_literals',
|
||||||
|
5: 'literal_pointers',
|
||||||
|
6: 'non_lazy_symbol_pointers',
|
||||||
|
7: 'lazy_symbol_pointers',
|
||||||
|
8: 'symbol_stubs',
|
||||||
|
9: 'mod_init_func_pointers',
|
||||||
|
0xa: 'mod_term_func_pointers',
|
||||||
|
0xb: 'coalesced',
|
||||||
|
0xc: 'gb_zerofill',
|
||||||
|
0xd: 'interposing',
|
||||||
|
0xe: '16byte_literals',
|
||||||
|
0xf: 'dtrace_dof',
|
||||||
|
0x10: 'lazy_dylib_symbol_pointers',
|
||||||
|
0x11: 'thread_local_regular',
|
||||||
|
0x12: 'thread_local_zerofill',
|
||||||
|
0x13: 'thread_local_variables',
|
||||||
|
0x14: 'thread_local_variable_pointers',
|
||||||
|
0x15: 'thread_local_init_function_pointers'
|
||||||
|
};
|
||||||
|
|
||||||
|
constants.segAttrUsrMask = 0xff000000;
|
||||||
|
constants.segAttrUsr = {
|
||||||
|
'-2147483648': 'pure_instructions',
|
||||||
|
0x40000000: 'no_toc',
|
||||||
|
0x20000000: 'strip_static_syms',
|
||||||
|
0x10000000: 'no_dead_strip',
|
||||||
|
0x08000000: 'live_support',
|
||||||
|
0x04000000: 'self_modifying_code',
|
||||||
|
0x02000000: 'debug'
|
||||||
|
};
|
||||||
|
|
||||||
|
constants.segAttrSysMask = 0x00ffff00;
|
||||||
|
constants.segAttrSys = {
|
||||||
|
0x400: 'some_instructions',
|
||||||
|
0x200: 'ext_reloc',
|
||||||
|
0x100: 'loc_reloc'
|
||||||
|
};
|
||||||
|
|
||||||
475
helpers/scanner/parsers/macho-node/parser.js
Normal file
475
helpers/scanner/parsers/macho-node/parser.js
Normal file
|
|
@ -0,0 +1,475 @@
|
||||||
|
import Reader from 'endian-reader'
|
||||||
|
|
||||||
|
import { constants } from './constants'
|
||||||
|
|
||||||
|
export class Parser extends Reader {
|
||||||
|
constructor () {
|
||||||
|
super()
|
||||||
|
}
|
||||||
|
|
||||||
|
execute (buf) {
|
||||||
|
var hdr = this.parseHead(buf);
|
||||||
|
if (!hdr)
|
||||||
|
throw new Error('File not in a mach-o format');
|
||||||
|
|
||||||
|
hdr.cmds = this.parseCommands(hdr, hdr.body, buf);
|
||||||
|
delete hdr.body;
|
||||||
|
|
||||||
|
return hdr;
|
||||||
|
}
|
||||||
|
|
||||||
|
mapFlags (value, map) {
|
||||||
|
var res = {};
|
||||||
|
|
||||||
|
for (var bit = 1;
|
||||||
|
(value < 0 || bit <= value) && bit !== 0; bit <<= 1)
|
||||||
|
if (value & bit)
|
||||||
|
res[map[bit]] = true;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
parseHead(buf) {
|
||||||
|
if (buf.length < 7 * 4)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var magic = buf.readUInt32LE(0);
|
||||||
|
var bits;
|
||||||
|
if (magic === 0xfeedface || magic === 0xcefaedfe)
|
||||||
|
bits = 32;
|
||||||
|
else if (magic === 0xfeedfacf || magic == 0xcffaedfe)
|
||||||
|
bits = 64;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (magic & 0xff == 0xfe)
|
||||||
|
this.setEndian('be');
|
||||||
|
else
|
||||||
|
this.setEndian('le');
|
||||||
|
|
||||||
|
if (bits === 64 && buf.length < 8 * 4)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var cputype = constants.cpuType[this.readInt32(buf, 4)];
|
||||||
|
var cpusubtype = this.readInt32(buf, 8);
|
||||||
|
var filetype = this.readUInt32(buf, 12);
|
||||||
|
var ncmds = this.readUInt32(buf, 16);
|
||||||
|
var sizeofcmds = this.readUInt32(buf, 20);
|
||||||
|
var flags = this.readUInt32(buf, 24);
|
||||||
|
|
||||||
|
// Get endian
|
||||||
|
var endian;
|
||||||
|
if ((cpusubtype & constants.endian.multiple) === constants.endian.multiple)
|
||||||
|
endian = 'multiple';
|
||||||
|
else if (cpusubtype & constants.endian.be)
|
||||||
|
endian = 'be';
|
||||||
|
else
|
||||||
|
endian = 'le';
|
||||||
|
|
||||||
|
cpusubtype &= constants.cpuSubType.mask;
|
||||||
|
|
||||||
|
// Get subtype
|
||||||
|
var subtype;
|
||||||
|
if (endian === 'multiple')
|
||||||
|
subtype = 'all';
|
||||||
|
else if (cpusubtype === 0)
|
||||||
|
subtype = 'none';
|
||||||
|
else
|
||||||
|
subtype = constants.cpuSubType[cputype][cpusubtype];
|
||||||
|
|
||||||
|
// Stringify flags
|
||||||
|
var flagMap = this.mapFlags(flags, constants.flags);
|
||||||
|
|
||||||
|
return {
|
||||||
|
bits: bits,
|
||||||
|
magic: magic,
|
||||||
|
cpu: {
|
||||||
|
type: cputype,
|
||||||
|
subtype: subtype,
|
||||||
|
endian: endian
|
||||||
|
},
|
||||||
|
filetype: constants.fileType[filetype],
|
||||||
|
ncmds: ncmds,
|
||||||
|
sizeofcmds: sizeofcmds,
|
||||||
|
flags: flagMap,
|
||||||
|
|
||||||
|
cmds: null,
|
||||||
|
hsize: bits === 32 ? 28 : 32,
|
||||||
|
body: bits === 32 ? buf.slice(28) : buf.slice(32)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
parseCommands(hdr, buf, file) {
|
||||||
|
var cmds = [];
|
||||||
|
|
||||||
|
var align;
|
||||||
|
if (hdr.bits === 32)
|
||||||
|
align = 4;
|
||||||
|
else
|
||||||
|
align = 8;
|
||||||
|
|
||||||
|
for (var offset = 0, i = 0; offset + 8 < buf.length, i < hdr.ncmds; i++) {
|
||||||
|
var type = constants.cmdType[this.readUInt32(buf, offset)];
|
||||||
|
var size = this.readUInt32(buf, offset + 4) - 8;
|
||||||
|
|
||||||
|
var fileoff = offset + hdr.hsize;
|
||||||
|
offset += 8;
|
||||||
|
if (offset + size > buf.length)
|
||||||
|
throw new Error('Command body OOB');
|
||||||
|
|
||||||
|
var body = buf.slice(offset, offset + size);
|
||||||
|
offset += size;
|
||||||
|
if (offset & align)
|
||||||
|
offset += align - (offset & align);
|
||||||
|
|
||||||
|
var cmd = this.parseCommand(type, body, file);
|
||||||
|
cmd.fileoff = fileoff;
|
||||||
|
cmds.push(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmds;
|
||||||
|
}
|
||||||
|
|
||||||
|
parseCStr(buf) {
|
||||||
|
for (var i = 0; i < buf.length; i++)
|
||||||
|
if (buf[i] === 0)
|
||||||
|
break;
|
||||||
|
return buf.slice(0, i).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
parseLCStr (buf, off) {
|
||||||
|
if (off + 4 > buf.length)
|
||||||
|
throw new Error('lc_str OOB');
|
||||||
|
|
||||||
|
var offset = this.readUInt32(buf, off) - 8;
|
||||||
|
if (offset > buf.length)
|
||||||
|
throw new Error('lc_str offset OOB');
|
||||||
|
|
||||||
|
return this.parseCStr(buf.slice(offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
parseCommand(type, buf, file) {
|
||||||
|
if (type === 'segment')
|
||||||
|
return this.parseSegmentCmd(type, buf, file);
|
||||||
|
else if (type === 'segment_64')
|
||||||
|
return this.parseSegmentCmd(type, buf, file);
|
||||||
|
else if (type === 'symtab')
|
||||||
|
return this.parseSymtab(type, buf);
|
||||||
|
else if (type === 'symseg')
|
||||||
|
return this.parseSymseg(type, buf);
|
||||||
|
else if (type === 'encryption_info')
|
||||||
|
return this.parseEncryptionInfo(type, buf);
|
||||||
|
else if (type === 'encryption_info_64')
|
||||||
|
return this.parseEncryptionInfo64(type, buf);
|
||||||
|
else if (type === 'rpath')
|
||||||
|
return this.parseRpath(type, buf);
|
||||||
|
else if (type === 'dysymtab')
|
||||||
|
return this.parseDysymtab(type, buf);
|
||||||
|
else if (type === 'load_dylib' || type === 'id_dylib')
|
||||||
|
return this.parseLoadDylib(type, buf);
|
||||||
|
else if (type === 'load_weak_dylib')
|
||||||
|
return this.parseLoadDylib(type, buf);
|
||||||
|
else if (type === 'load_dylinker' || type === 'id_dylinker')
|
||||||
|
return this.parseLoadDylinker(type, buf);
|
||||||
|
else if (type === 'version_min_macosx' || type === 'version_min_iphoneos')
|
||||||
|
return this.parseVersionMin(type, buf);
|
||||||
|
else if (type === 'code_signature' || type === 'segment_split_info')
|
||||||
|
return this.parseLinkEdit(type, buf);
|
||||||
|
else if (type === 'function_starts')
|
||||||
|
return this.parseFunctionStarts(type, buf, file);
|
||||||
|
else if (type === 'data_in_code')
|
||||||
|
return this.parseLinkEdit(type, buf);
|
||||||
|
else if (type === 'dylib_code_sign_drs')
|
||||||
|
return this.parseLinkEdit(type, buf);
|
||||||
|
else if (type === 'main')
|
||||||
|
return this.parseMain(type, buf);
|
||||||
|
else
|
||||||
|
return {
|
||||||
|
type: type,
|
||||||
|
data: buf
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
parseSegmentCmd (type, buf, file) {
|
||||||
|
var total = type === 'segment' ? 48 : 64;
|
||||||
|
if (buf.length < total)
|
||||||
|
throw new Error('Segment command OOB');
|
||||||
|
|
||||||
|
var name = this.parseCStr(buf.slice(0, 16));
|
||||||
|
|
||||||
|
if (type === 'segment') {
|
||||||
|
var vmaddr = this.readUInt32(buf, 16);
|
||||||
|
var vmsize = this.readUInt32(buf, 20);
|
||||||
|
var fileoff = this.readUInt32(buf, 24);
|
||||||
|
var filesize = this.readUInt32(buf, 28);
|
||||||
|
var maxprot = this.readUInt32(buf, 32);
|
||||||
|
var initprot = this.readUInt32(buf, 36);
|
||||||
|
var nsects = this.readUInt32(buf, 40);
|
||||||
|
var flags = this.readUInt32(buf, 44);
|
||||||
|
} else {
|
||||||
|
var vmaddr = this.readUInt64(buf, 16);
|
||||||
|
var vmsize = this.readUInt64(buf, 24);
|
||||||
|
var fileoff = this.readUInt64(buf, 32);
|
||||||
|
var filesize = this.readUInt64(buf, 40);
|
||||||
|
var maxprot = this.readUInt32(buf, 48);
|
||||||
|
var initprot = this.readUInt32(buf, 52);
|
||||||
|
var nsects = this.readUInt32(buf, 56);
|
||||||
|
var flags = this.readUInt32(buf, 60);
|
||||||
|
}
|
||||||
|
|
||||||
|
function prot(p) {
|
||||||
|
var res = {
|
||||||
|
read: false,
|
||||||
|
write: false,
|
||||||
|
exec: false
|
||||||
|
};
|
||||||
|
if (p !== constants.prot.none) {
|
||||||
|
res.read = (p & constants.prot.read) !== 0;
|
||||||
|
res.write = (p & constants.prot.write) !== 0;
|
||||||
|
res.exec = (p & constants.prot.execute) !== 0;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
var sectSize = type === 'segment' ? 32 + 9 * 4 : 32 + 8 * 4 + 2 * 8;
|
||||||
|
var sections = [];
|
||||||
|
for (var i = 0, off = total; i < nsects; i++, off += sectSize) {
|
||||||
|
if (off + sectSize > buf.length)
|
||||||
|
throw new Error('Segment OOB');
|
||||||
|
|
||||||
|
var sectname = this.parseCStr(buf.slice(off, off + 16));
|
||||||
|
var segname = this.parseCStr(buf.slice(off + 16, off + 32));
|
||||||
|
|
||||||
|
if (type === 'segment') {
|
||||||
|
var addr = this.readUInt32(buf, off + 32);
|
||||||
|
var size = this.readUInt32(buf, off + 36);
|
||||||
|
var offset = this.readUInt32(buf, off + 40);
|
||||||
|
var align = this.readUInt32(buf, off + 44);
|
||||||
|
var reloff = this.readUInt32(buf, off + 48);
|
||||||
|
var nreloc = this.readUInt32(buf, off + 52);
|
||||||
|
var flags = this.readUInt32(buf, off + 56);
|
||||||
|
} else {
|
||||||
|
var addr = this.readUInt64(buf, off + 32);
|
||||||
|
var size = this.readUInt64(buf, off + 40);
|
||||||
|
var offset = this.readUInt32(buf, off + 48);
|
||||||
|
var align = this.readUInt32(buf, off + 52);
|
||||||
|
var reloff = this.readUInt32(buf, off + 56);
|
||||||
|
var nreloc = this.readUInt32(buf, off + 60);
|
||||||
|
var flags = this.readUInt32(buf, off + 64);
|
||||||
|
}
|
||||||
|
|
||||||
|
sections.push({
|
||||||
|
sectname: sectname,
|
||||||
|
segname: segname,
|
||||||
|
addr: addr,
|
||||||
|
size: size,
|
||||||
|
offset: offset,
|
||||||
|
align: align,
|
||||||
|
reloff: reloff,
|
||||||
|
nreloc: nreloc,
|
||||||
|
type: constants.segType[flags & constants.segTypeMask],
|
||||||
|
attributes: {
|
||||||
|
usr: this.mapFlags(flags & constants.segAttrUsrMask,
|
||||||
|
constants.segAttrUsr),
|
||||||
|
sys: this.mapFlags(flags & constants.segAttrSysMask,
|
||||||
|
constants.segAttrSys)
|
||||||
|
},
|
||||||
|
data: file.slice(offset, offset + size)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: type,
|
||||||
|
name: name,
|
||||||
|
vmaddr: vmaddr,
|
||||||
|
vmsize: vmsize,
|
||||||
|
fileoff: fileoff,
|
||||||
|
filesize: filesize,
|
||||||
|
maxprot: prot(maxprot),
|
||||||
|
initprot: prot(initprot),
|
||||||
|
nsects: nsects,
|
||||||
|
flags: this.mapFlags(flags, constants.segFlag),
|
||||||
|
sections: sections
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
parseSymtab (type, buf) {
|
||||||
|
if (buf.length !== 16)
|
||||||
|
throw new Error('symtab OOB');
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: type,
|
||||||
|
symoff: this.readUInt32(buf, 0),
|
||||||
|
nsyms: this.readUInt32(buf, 4),
|
||||||
|
stroff: this.readUInt32(buf, 8),
|
||||||
|
strsize: this.readUInt32(buf, 12)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
parseSymseg(type, buf) {
|
||||||
|
if (buf.length !== 8)
|
||||||
|
throw new Error('symseg OOB');
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: type,
|
||||||
|
offset: this.readUInt32(buf, 0),
|
||||||
|
size: this.readUInt32(buf, 4)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
parseEncryptionInfo (type, buf) {
|
||||||
|
if (buf.length !== 12)
|
||||||
|
throw new Error('encryptinfo OOB');
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: type,
|
||||||
|
offset: this.readUInt32(buf, 0),
|
||||||
|
size: this.readUInt32(buf, 4),
|
||||||
|
id: this.readUInt32(buf, 8),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
parseEncryptionInfo64 (type, buf) {
|
||||||
|
if (buf.length !== 16)
|
||||||
|
throw new Error('encryptinfo64 OOB');
|
||||||
|
|
||||||
|
return this.parseEncryptionInfo(type, buf.slice(0, 12));
|
||||||
|
};
|
||||||
|
|
||||||
|
parseDysymtab (type, buf) {
|
||||||
|
if (buf.length !== 72)
|
||||||
|
throw new Error('dysymtab OOB');
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: type,
|
||||||
|
ilocalsym: this.readUInt32(buf, 0),
|
||||||
|
nlocalsym: this.readUInt32(buf, 4),
|
||||||
|
iextdefsym: this.readUInt32(buf, 8),
|
||||||
|
nextdefsym: this.readUInt32(buf, 12),
|
||||||
|
iundefsym: this.readUInt32(buf, 16),
|
||||||
|
nundefsym: this.readUInt32(buf, 20),
|
||||||
|
tocoff: this.readUInt32(buf, 24),
|
||||||
|
ntoc: this.readUInt32(buf, 28),
|
||||||
|
modtaboff: this.readUInt32(buf, 32),
|
||||||
|
nmodtab: this.readUInt32(buf, 36),
|
||||||
|
extrefsymoff: this.readUInt32(buf, 40),
|
||||||
|
nextrefsyms: this.readUInt32(buf, 44),
|
||||||
|
indirectsymoff: this.readUInt32(buf, 48),
|
||||||
|
nindirectsyms: this.readUInt32(buf, 52),
|
||||||
|
extreloff: this.readUInt32(buf, 56),
|
||||||
|
nextrel: this.readUInt32(buf, 60),
|
||||||
|
locreloff: this.readUInt32(buf, 64),
|
||||||
|
nlocrel: this.readUInt32(buf, 68)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
parseLoadDylinker (type, buf) {
|
||||||
|
return {
|
||||||
|
type: type,
|
||||||
|
cmd: this.parseLCStr(buf, 0)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
parseRpath (type, buf) {
|
||||||
|
if (buf.length < 8)
|
||||||
|
throw new Error('lc_rpath OOB');
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: type,
|
||||||
|
name: this.parseLCStr(buf, 0),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
parseLoadDylib (type, buf) {
|
||||||
|
if (buf.length < 16)
|
||||||
|
throw new Error('load_dylib OOB');
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: type,
|
||||||
|
name: this.parseLCStr(buf, 0),
|
||||||
|
timestamp: this.readUInt32(buf, 4),
|
||||||
|
current_version: this.readUInt32(buf, 8),
|
||||||
|
compatibility_version: this.readUInt32(buf, 12)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
parseVersionMin (type, buf) {
|
||||||
|
if (buf.length !== 8)
|
||||||
|
throw new Error('min version OOB');
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: type,
|
||||||
|
version: this.readUInt16(buf, 2) + '.' + buf[1] + '.' + buf[0],
|
||||||
|
sdk: this.readUInt16(buf, 6) + '.' + buf[5] + '.' + buf[4]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
parseLinkEdit (type, buf) {
|
||||||
|
if (buf.length !== 8)
|
||||||
|
throw new Error('link_edit OOB');
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: type,
|
||||||
|
dataoff: this.readUInt32(buf, 0),
|
||||||
|
datasize: this.readUInt32(buf, 4)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: returned addresses are relative to the "base address", i.e.
|
||||||
|
// the vmaddress of the first "non-null" segment [e.g. initproto!=0]
|
||||||
|
// (i.e. __TEXT ?)
|
||||||
|
parseFunctionStarts (type,
|
||||||
|
buf,
|
||||||
|
file) {
|
||||||
|
if (buf.length !== 8)
|
||||||
|
throw new Error('function_starts OOB');
|
||||||
|
|
||||||
|
var dataoff = this.readUInt32(buf, 0);
|
||||||
|
var datasize = this.readUInt32(buf, 4);
|
||||||
|
var data = file.slice(dataoff, dataoff + datasize);
|
||||||
|
|
||||||
|
var addresses = [];
|
||||||
|
var address = 0; // TODO? use start address / "base address"
|
||||||
|
|
||||||
|
// read array of uleb128-encoded deltas
|
||||||
|
var delta = 0,
|
||||||
|
shift = 0;
|
||||||
|
for (var i = 0; i < data.length; i++) {
|
||||||
|
delta |= (data[i] & 0x7f) << shift;
|
||||||
|
if ((data[i] & 0x80) !== 0) { // delta value not finished yet
|
||||||
|
shift += 7;
|
||||||
|
if (shift > 24)
|
||||||
|
throw new Error('function_starts delta too large');
|
||||||
|
else if (i + 1 === data.length)
|
||||||
|
throw new Error('function_starts delta truncated');
|
||||||
|
} else if (delta === 0) { // end of table
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
address += delta;
|
||||||
|
addresses.push(address);
|
||||||
|
delta = 0;
|
||||||
|
shift = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: type,
|
||||||
|
dataoff: dataoff,
|
||||||
|
datasize: datasize,
|
||||||
|
addresses: addresses
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
parseMain (type, buf) {
|
||||||
|
if (buf.length < 16)
|
||||||
|
throw new Error('main OOB');
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: type,
|
||||||
|
entryoff: this.readUInt64(buf, 0),
|
||||||
|
stacksize: this.readUInt64(buf, 8)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue