Report app status

This commit is contained in:
Sam Carlton 2021-01-30 18:13:06 -06:00
parent 50b1c46678
commit 918a703df7
2 changed files with 180 additions and 75 deletions

View file

@ -3,11 +3,11 @@
//Licensed under the MIT License
import { mime_binary } from './mimetypes.js'
import { ReadUint32, ReadUint16LE, ReadUint32LE } from './memory.js'
import { ReadUint32, ReadUint16LE, ReadUint32LE, ReadUint16 } from './memory.js'
import { uint32_t, uint64_t } from './macho.constants.js'
import { MAGIC } from './macho.magic.js'
import { MachoHeader64 } from './macho.header.js'
import { MachoHeader64, MachoHeader } from './macho.header.js'
import { LOAD_COMMAND_TYPE, LoadCommand } from './macho.loadcommand.js'
import { CPU_TYPE, CPU_SUB_TYPE } from './macho.cpu.js'
import { FILE_FLAGS, FILE_TYPE } from './macho.file.js'
@ -53,17 +53,21 @@ var ChunkReader = function ChunkReader(file, chunksize = (1024 * 1024), callback
free("window.readers");
};
export default function MachoParser(file, callbackElement = document.body) {
export function MachoParser(file, callback) {
const machoOutputData = {}
//properties
this.reader = new FileReader();
function writeToCallback(val) {
if(callbackElement) {
callbackElement.innerHTML +='<tr>'+val+'</tr>';
} else {
throw new Error('Invalid callback.');
}
return
// if(callbackElement) {
// callbackElement.innerHTML +='<tr>'+val+'</tr>';
// } else {
// throw new Error('Invalid callback.');
// }
}
/*
@ -147,8 +151,11 @@ export default function MachoParser(file, callbackElement = document.body) {
window.tempFile = blob;
//Set up the file and print out for verbosity
writeToCallback('<td><strong>File</strong></td><td>'+file.name.toString()+'</td>');
writeToCallback('<td><strong>Size</strong></td><td>' + filesize.toFixed(2).toString() + 'MB</td>');
machoOutputData.file = file
machoOutputData.fileSize = filesize
machoOutputData.architectures = []
// writeToCallback('<td><strong>File</strong></td><td>'+file.name.toString()+'</td>');
// writeToCallback('<td><strong>Size</strong></td><td>' + filesize.toFixed(2).toString() + 'MB</td>');
//Construct a new 8-bit array from the file buffer
let data = new Uint8Array(e.target.result);
@ -161,27 +168,29 @@ export default function MachoParser(file, callbackElement = document.body) {
for(var cMagic = 0; cMagic < magics.length; cMagic++) { //Start parsing the binary from each found magic's offset
const architecture = {}
let magicOff = magics[cMagic]; //The offset of the magic currently being parsed
let magic = ReadUint32(data, magicOff); //Read the magic from the byte array
let littleendian = MAGIC.ISLITTLEENDIAN(magic); //Get the endianness of the magic
let x64 = MAGIC.IS64BIT(magic); //Check which bit architecture is being used
window.machoObj = {}; //Create the Mach-O information object
window.machoObj.bits = (x64 ? "64-bit" : "32-bit"); //Get the architecture
window.machoObj.endianness = (littleendian ? "little endian" : "big endian"); //Get the endianness
window.machoObj.header = (x64 ? new MachoHeader64() : new MachoHeader()); //Depending on architecture, construct a new header
window.machoObj.header.magic = magic; //Add the magic to the header
window.machoObj.header.cputype = (littleendian ? ReadUint16LE(data, magicOff+uint32_t) : ReadUint16(data, magicOff+uint32_t)); //Read the cputype which comes after the magic
window.machoObj.header.cpusubtype = (littleendian ? ReadUint16LE(data, magicOff+(2*uint32_t)) : ReadUint16(data, magicOff+(2*uint32_t))); //Read the cpu subtype which comes after the cputype
window.machoObj.header.filetype = (littleendian ? ReadUint32LE(data, magicOff+(3*uint32_t)) : ReadUint32(data, magicOff+(3*uint32_t))); //Read the file type which comes after the cpu subtype
window.machoObj.header.ncmds = (littleendian ? ReadUint32LE(data, magicOff+(4*uint32_t)) : ReadUint32(data, magicOff+(4*uint32_t))); //Read the number of commands which comes after the filetype
window.machoObj.header.sizeofcmds =(littleendian ? ReadUint32LE(data, magicOff+(5*uint32_t)) : ReadUint32(data, magicOff+(5*uint32_t))); //Read the size of the commands which comes after the number of commands
window.machoObj.header.flags = (littleendian ? ReadUint32LE(data, magicOff+(6*uint32_t)) : ReadUint32(data, magicOff+(6*uint32_t))); //Read the flags which come after the size of the commands
window.machoObj.loadcommands = [];
// machoOutputData = {}; //Create the Mach-O information object
architecture.bits = (x64 ? "64-bit" : "32-bit"); //Get the architecture
architecture.endianness = (littleendian ? "little endian" : "big endian"); //Get the endianness
architecture.header = (x64 ? new MachoHeader64() : new MachoHeader()); //Depending on architecture, construct a new header
architecture.header.magic = magic; //Add the magic to the header
architecture.header.cputype = (littleendian ? ReadUint16LE(data, magicOff+uint32_t) : ReadUint16(data, magicOff+uint32_t)); //Read the cputype which comes after the magic
architecture.header.cpusubtype = (littleendian ? ReadUint16LE(data, magicOff+(2*uint32_t)) : ReadUint16(data, magicOff+(2*uint32_t))); //Read the cpu subtype which comes after the cputype
architecture.header.filetype = (littleendian ? ReadUint32LE(data, magicOff+(3*uint32_t)) : ReadUint32(data, magicOff+(3*uint32_t))); //Read the file type which comes after the cpu subtype
architecture.header.ncmds = (littleendian ? ReadUint32LE(data, magicOff+(4*uint32_t)) : ReadUint32(data, magicOff+(4*uint32_t))); //Read the number of commands which comes after the filetype
architecture.header.sizeofcmds =(littleendian ? ReadUint32LE(data, magicOff+(5*uint32_t)) : ReadUint32(data, magicOff+(5*uint32_t))); //Read the size of the commands which comes after the number of commands
architecture.header.flags = (littleendian ? ReadUint32LE(data, magicOff+(6*uint32_t)) : ReadUint32(data, magicOff+(6*uint32_t))); //Read the flags which come after the size of the commands
architecture.loadcommands = [];
var align = (x64 ? uint64_t : uint32_t); //Depending on our architecture set an align for parsing the load commands
for(var i = 0, off = magicOff; off < data.length, i < window.machoObj.header.ncmds; i++) {
for(var i = 0, off = magicOff; off < data.length, i < architecture.header.ncmds; i++) {
var curr_cmd = {};
curr_cmd.cmd = (littleendian ? ReadUint32LE(data, off) : ReadUint32(data, off)); //Read the command type from the offset
@ -191,45 +200,65 @@ export default function MachoParser(file, callbackElement = document.body) {
curr_cmd = ParseCommand(curr_cmd.cmd, curr_cmd.data, curr_cmd.cmdsize, curr_cmd.fileoff);
if(curr_cmd.cmdsize > 0) { //Commands with a size of zero are not valid or not interesting
window.machoObj.loadcommands.push(curr_cmd);
architecture.loadcommands.push(curr_cmd);
}
off+=8;
i++; //Increate the loadcommand counter
}
}
architecture.offset = magicOff.toString(16)
architecture.magic = architecture.header.magic.toString(16)
architecture.processorType = CPU_TYPE.DESCRIPTION(architecture.header.cputype)
architecture.processorSubType = CPU_SUB_TYPE.ARM.DESCRIPTION(architecture.header.cpusubtype)
architecture.fileType = FILE_TYPE.DESCRIPTION(architecture.header.filetype)
/* Parse all collected information to Human Readable strings */
writeToCallback('');
writeToCallback('<td><strong>Header</strong></td>');
writeToCallback('<td><strong>Offset</strong></td><td>0x'+magicOff.toString(16)+'</td>');
writeToCallback('<td><strong>Magic</strong></td><td>0x'+window.machoObj.header.magic.toString(16)+'</td>');
writeToCallback('<td><strong>Bits</strong></td><td>'+window.machoObj.bits+'</td>');
writeToCallback('<td><strong>Endianness</strong></td><td>'+window.machoObj.endianness+'</td>');
writeToCallback('<td><strong>Processor type</strong></td><td>' + CPU_TYPE.DESCRIPTION(window.machoObj.header.cputype)+'</td>');
writeToCallback('<td><strong>Processor subtype</strong></td><td>'+ CPU_SUB_TYPE.ARM.DESCRIPTION(window.machoObj.header.cpusubtype)+'</td>');
writeToCallback('<td><strong>File type</strong></td><td>'+FILE_TYPE.DESCRIPTION(window.machoObj.header.filetype)+'</td>');
writeToCallback('<td><strong>Number of commands</strong></td><td>'+window.machoObj.header.ncmds+'</td>');
writeToCallback('<td><strong>Size of commands</strong></td><td>'+window.machoObj.header.sizeofcmds+'</td>');
// writeToCallback('');
// writeToCallback('<td><strong>Header</strong></td>');
// writeToCallback('<td><strong>Offset</strong></td><td>0x'+magicOff.toString(16)+'</td>');
// writeToCallback('<td><strong>Magic</strong></td><td>0x'+architecture.header.magic.toString(16)+'</td>');
// writeToCallback('<td><strong>Bits</strong></td><td>'+architecture.bits+'</td>');
// writeToCallback('<td><strong>Endianness</strong></td><td>'+architecture.endianness+'</td>');
// writeToCallback('<td><strong>Processor type</strong></td><td>' + CPU_TYPE.DESCRIPTION(architecture.header.cputype)+'</td>');
// writeToCallback('<td><strong>Processor subtype</strong></td><td>'+ CPU_SUB_TYPE.ARM.DESCRIPTION(architecture.header.cpusubtype)+'</td>');
// writeToCallback('<td><strong>File type</strong></td><td>'+FILE_TYPE.DESCRIPTION(architecture.header.filetype)+'</td>');
// writeToCallback('<td><strong>Number of commands</strong></td><td>'+architecture.header.ncmds+'</td>');
// writeToCallback('<td><strong>Size of commands</strong></td><td>'+architecture.header.sizeofcmds+'</td>');
window.machoObj.header.flags = MapFlags(window.machoObj.header.flags, FILE_FLAGS);
window.machoObj.header.flags = Object.keys(window.machoObj.header.flags).map(function(k) { if(k){return k}});
architecture.header.flags = MapFlags(architecture.header.flags, FILE_FLAGS);
architecture.header.flags = Object.keys(architecture.header.flags).map(function(k) { if(k){return k}});
// writeToCallback('<td><strong>Flags</strong></td><td>'+architecture.header.flags.toString().replace(',','<br>').replace(',','<br>')+"</td>");
// writeToCallback('');
// writeToCallback('<td><strong>Load Command</strong></td><td><strong>Size</strong></td><td><strong>Offset</strong></td>');
architecture.loadCommandsInfo = []
for(var curr_lc = 0; curr_lc < architecture.loadcommands.length; curr_lc++) {
architecture.loadCommandsInfo.push({
description: LOAD_COMMAND_TYPE.DESCRIPTION(architecture.loadcommands[curr_lc].cmd),
size: architecture.loadcommands[curr_lc].cmdsize,
offset: ` 0x${architecture.loadcommands[curr_lc].fileoff.toString(16)}`
})
// writeToCallback(
// '<td>'+
// LOAD_COMMAND_TYPE.DESCRIPTION(architecture.loadcommands[curr_lc].cmd) +
// '</td>'+
// '<td>'+
// architecture.loadcommands[curr_lc].cmdsize+
// '</td>'+
// '<td>'+
// ' 0x' + architecture.loadcommands[curr_lc].fileoff.toString(16) +
// '</td>');
}
writeToCallback('<td><strong>Flags</strong></td><td>'+window.machoObj.header.flags.toString().replace(',','<br>').replace(',','<br>')+"</td>");
writeToCallback('');
writeToCallback('<td><strong>Load Command</strong></td><td><strong>Size</strong></td><td><strong>Offset</strong></td>');
for(var curr_lc = 0; curr_lc < window.machoObj.loadcommands.length; curr_lc++) {
writeToCallback(
'<td>'+
LOAD_COMMAND_TYPE.DESCRIPTION(window.machoObj.loadcommands[curr_lc].cmd) +
'</td>'+
'<td>'+
window.machoObj.loadcommands[curr_lc].cmdsize+
'</td>'+
'<td>'+
' 0x' + window.machoObj.loadcommands[curr_lc].fileoff.toString(16) +
'</td>');
}
magicOff = null;
littleendian = null;
x64 = null;
@ -239,11 +268,19 @@ export default function MachoParser(file, callbackElement = document.body) {
arrayBufferToBlob(data.buffer, fileType).then(function(blob){
if(!window.tempFiles) { window.tempFiles = []; }
window.tempFiles[window.tempFiles.length] = blob;
}).catch(console.log.bind(console));
}
console.log('The parser has finished');
}).catch(console.log.bind(console));
machoOutputData.architectures.push( architecture )
}
callback( machoOutputData )
console.log('The parser has finished')
} else { //(magics.length <= 0) (If we end up here it means no magics were found in the file).
writeToCallback('This is not a valid Mach-O file.');
// writeToCallback('This is not a valid Mach-O file.');
throw new Error('This is not a valid Mach-O file.')
}
}).catch(console.log.bind(console));
@ -254,3 +291,15 @@ export default function MachoParser(file, callbackElement = document.body) {
console.log('Parsing, please wait...');
};
export default async function ( file ) {
return new Promise( ( resolve, reject ) => {
try {
(new MachoParser( file, resolve ))
} catch ( error ) {
reject( error )
}
} )
}