doesitarm/helpers/scanner/parsers/macho.js
2022-07-18 18:06:00 -05:00

121 lines
3.6 KiB
JavaScript

import { Buffer } from 'buffer';
// Tends to not support universal architecture
// but support some MachoManiac doesn't and fails faster
// so we run it first
// https://github.com/indutny/macho
export class MachoNode {
constructor ({ machoFileInstance, FileApi }) {
this.machoFileInstance = machoFileInstance
this.FileApi = FileApi
}
// MachNode cpu types mapped to MachoManiac cpu types
// MachoNode types - https://github.com/indutny/macho/blob/c9d02419b36a468ebb4dcef66d0f9b98b6f22dbd/lib/macho/constants.js#L9
// MachoManiac types - https://github.com/MTJailed/MachoManiac/blob/98d2d31d38d3ea3c911468181eed6e5f445eb556/macho.cpu.js#L13
cpuMap = new Map([
['vax', 'VAX'],
['mc680x0', 'MC680'],
// https://superuser.com/a/74354/412612
['i386', 'X86'],
['x86_64', 'X86'],
['mc98000', 'MC98000'],
['hppa', 'HPPA'],
['arm', 'ARM'],
['arm64', 'ARM64'],
// arm64_32 is a variant of arm64 with 32-bit pointer sizes, used on Apple Watch Series 4 and later.
// https://stackoverflow.com/a/68248923/1397641
['arm64_32', 'ARM64'],
['mc88000', 'MC88000'],
['sparc', 'SPARC'],
['i860', 'I860'],
// ['alpha', '???']
['powerpc', 'POWERPC'],
['powerpc64', 'POWERPC64']
])
fileBuffer () {
const machoBuffer = new Buffer.alloc( this.machoFileInstance.buffer.byteLength )
for (var i = 0; i < this.machoFileInstance.buffer.length; i++)
machoBuffer[i] = this.machoFileInstance.buffer[i];
// console.log( 'this.machoFileInstance', this.machoFileInstance.buffer.byteLength )
return machoBuffer
}
mapNodeMetaTOManiacMeta ( machoNodeMeta ) {
return {
// Single entry since MachoNode doesn't support universal architectures
architectures: [{
bits: machoNodeMeta.bits,
fileType: machoNodeMeta.filetype,
// header: architecture.header,
// loadCommandsInfo: architecture.loadCommandsInfo,
magic: machoNodeMeta.magic,
// offset: architecture.offset,
processorSubType: machoNodeMeta.subtype,
processorType: this.cpuMap.get( machoNodeMeta.cpu.type ),
}]
}
}
async run () {
const { parse } = await import( 'macho' )
const machoNodeMeta = parse( this.fileBuffer() )
// console.log( 'machoNodeMeta', machoNodeMeta.cpu )
return this.mapNodeMetaTOManiacMeta( machoNodeMeta )
}
}
// https://github.com/MTJailed/MachoManiac
export class MachoManiac {
constructor ({ machoFileInstance, FileApi }) {
this.machoFileInstance = machoFileInstance
this.FileApi = FileApi
}
async run () {
// import parseMacho from '~/helpers/macho/index.js'
const { default: parseMacho } = await import( '~/helpers/macho/index.js' )
return await parseMacho( this.machoFileInstance, this.FileApi )
}
}
export async function extractMachoMeta ({ machoFileInstance, FileApi = null }) {
const parsers = [
MachoNode,
MachoManiac
]
// Run through each parser
for ( const Parser of parsers ) {
try {
// Run the parser
const parserInstance = new Parser({
machoFileInstance,
FileApi
})
const meta = await parserInstance.run()
return meta
} catch ( err ) {
console.log( 'Macho parser failed', Parser, err )
// throw new Error( 'Macho parser failed' )
}
}
return null
}