Add MachoManiac

This commit is contained in:
Sam Carlton 2021-01-30 16:50:33 -06:00
parent 04c0b7aeae
commit 50b1c46678
34 changed files with 5269 additions and 0 deletions

4
helpers/macho/index.js Normal file
View file

@ -0,0 +1,4 @@
import MachoParser from './macho.js'
export default MachoParser

3543
helpers/macho/jquery-blob.js vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,13 @@
export let SECTION_ATTRIBUTES_USR = 0xff000000;
export let S_ATTR_PURE_INSTRUCTIONS = 0x80000000;
export let SECTION_ATTRIBUTES_SYS = 0x00ffff00;
export let S_ATTR_SOME_INSTRUCTIONS = 0x0000400;
export let S_ATTR_EXT_RELOC = 0x00000200;
export let S_ATTR_LOC_RELOC = 0x00000100;
export let uint128_t = 16;
export let uint64_t = 8;
export let uint32_t = 4;
export let uint16_t = 2;
export let uint8_t = 1;

134
helpers/macho/macho.cpu.js Normal file
View file

@ -0,0 +1,134 @@
//Global Constants
var CPU_TYPES = [];
var CPUSubTypeARM = [];
let CPU_ARCH_CONST = {
MASK: 0x01000000,
ABI64: 0xff000000,
toString: function() {
JSON.stringify(this);
}
};
let CPU_TYPE = {
ANY: -1,
VAX: 1,
MC680: 6,
X86: 7,
MIPS: 8,
MC98000: 10,
HPPA: 11,
ARM: 12,
ARM64: 16777228,
MC88000: 13,
SPARC: 14,
I860: 15,
POWERPC: 18,
POWERPC64: 16777234,
DESCRIPTION: function(search) {
let result = CPU_TYPES[search];
return (result != undefined) ? result : search;
},
toString: function() {
return JSON.stringify(this);
}
};
CPU_TYPES[CPU_TYPE.ANY] = "Any";
CPU_TYPES[CPU_TYPE.VAX] = "VAX";
CPU_TYPES[CPU_TYPE.MC680] = "MC680";
CPU_TYPE[CPU_TYPE.HPPA] = "HPPA";
CPU_TYPES[CPU_TYPE.ARM] = "ARM";
CPU_TYPES[CPU_TYPE.ARM64] = "ARM64";
CPU_TYPES[CPU_TYPE.X86] = "X86";
CPU_TYPES[CPU_TYPE.I860] = "I860";
CPU_TYPES[CPU_TYPE.MIPS] = "Mips";
CPU_TYPES[CPU_TYPE.MC98000] = "MC98000";
CPU_TYPES[CPU_TYPE.SPARC] = "Sparc";
CPU_TYPES[CPU_TYPE.POWERPC] = "Power PC";
CPU_TYPES[CPU_TYPE.POWERPC64] = "Power PC 64-bit";
let CPU_SUB_TYPE = {
ARM: {
MULTIPLE: -1,
ALL: 0,
ARM_A500_ARCH: 1,
ARM_A500: 2,
ARM_A440: 3,
ARM_M4: 4,
V4T: 5,
V6: 6,
V5TEJ: 7,
XSCALE: 8,
V7: 9,
V7F: 10,
V7S: 11,
V7K: 12,
V8: 13,
V6M: 14,
V7M: 15,
V7EM: 16,
DESCRIPTION: function(search) {
let result = CPUSubTypeARM[search];
return (result != undefined) ? result : search;
},
toString: function() {
return JSON.stringify(this);
}
},
ARM64: {
MULTIPLE: -1,
ALL: 0,
V8: 1,
DESCRIPTION: function(search) {
var CPUSubTypeARM64 = [];
CPUSubTypeARM64[CPU_SUB_TYPE.ARM64.ALL] = 'all';
let result = CPUSubTypeARM64[search];
return (result != undefined) ? result : search;
},
toString: function() {
return JSON.stringify(this);
}
},
POWERPC64: {
MULTIPLE: -1,
POWERPC_ALL: 0,
POWERPC_601: 1,
POWERPC_602: 2,
POWERPC_603: 3,
POWERPC_603e: 4,
POWERPC_603ev: 5,
POWERPC_604: 6,
POWERPC_604e: 7,
POWERPC_620: 8,
POWERPC_750: 9,
POWERPC_7400: 10,
POWERPC_7450: 11,
POWERPC_970: 100,
POWERPC_ALL_LIB64: 2147483648,
toString: function() {
return JSON.stringify(this);
}
},
toString: function() {
return JSON.stringify(this);
}
};
CPUSubTypeARM[CPU_SUB_TYPE.ARM.ALL] = 'all';
CPUSubTypeARM[CPU_SUB_TYPE.ARM.V4T] = 'v4t';
CPUSubTypeARM[CPU_SUB_TYPE.ARM.V6] = 'v6';
CPUSubTypeARM[CPU_SUB_TYPE.ARM.V5] = 'v5';
CPUSubTypeARM[CPU_SUB_TYPE.ARM.XSCALE] = 'xscale';
CPUSubTypeARM[CPU_SUB_TYPE.ARM.V7] = 'v7';
CPUSubTypeARM[CPU_SUB_TYPE.ARM.V7F] = 'v7f';
CPUSubTypeARM[CPU_SUB_TYPE.ARM.V7S] = 'v7s';
CPUSubTypeARM[CPU_SUB_TYPE.ARM.V7K] = 'v7k';
CPUSubTypeARM[CPU_SUB_TYPE.ARM.V6M] = 'v6m';
CPUSubTypeARM[CPU_SUB_TYPE.ARM.V7M] = 'v7m';
CPUSubTypeARM[CPU_SUB_TYPE.ARM.V7EM] = 'v7em';
export { CPU_TYPES, CPUSubTypeARM, CPU_ARCH_CONST, CPU_TYPE, CPU_SUB_TYPE }

View file

@ -0,0 +1,10 @@
var Cstr = function Cstr(buf) {
this.toString = function() {
return JSON.stringify(this);
};
var cstr = '';
for(var i = 0; i < buf.length; i++) {
cstr += String.fromCharCode(buf[i]);
}
return cstr;
};

View file

@ -0,0 +1,72 @@
var Dylib = function Dylib(name, timestamp, current_version, compatibility_version) {
this.name = name || 0x00000000;
this.timestamp = timestamp || 0x00000000;
this.current_version = current_version || 0x00000000;
this.compatibility_version = compatibility_version || 0x00000000;
this.toString = function() {
return JSON.stringify(this);
};
};
var DylibCommand = function DylibCommand(cmd, cmdsize, dylib) {
this.cmd = cmd || 0x00000000;
this.cmdsize = cmdsize || 0x00000000;
this.dylib = dylib || new Dylib(); //needs better input validation
this.toString = function() {
return JSON.stringify(this);
};
};
var DylibTableOfContents = function DylibTableOfContents(symbol_index, module_index) {
this.symbol_index = symbol_index || 0x00000000;
this.module_index = module_index || 0x00000000;
this.toString = function() {
return JSON.stringify(this);
};
};
var DylibModule = function DylibModule(module_name, iextdefsym, nextdefsym, irefsym, nrefsym, ilocalsym, nlocalsym, iextrel, nextrel, iinit_iterm, ninit_nterm, objc_module_info_addr, objc_module_info_size) {
this.module_name = module_name || 0x00000000;
this.iextdefsym = iextdefsym || 0x00000000;
this.nextdefsym = nextdefsym || 0x00000000;
this.irefsym = irefsym || 0x00000000;
this.nrefsym = nrefsym || 0x00000000;
this.ilocalsym = ilocalsym || 0x00000000;
this.nlocalsym = nlocalsym || 0x00000000;
this.iextrel = iextrel || 0x00000000;
this.nextrel = nextrel || 0x00000000;
this.iinit_iterm = iinit_iterm || 0x00000000;
this.ninit_nterm = ninit_nterm || 0x00000000;
this.objc_module_info_addr = objc_module_info_addr || 0x00000000;
this.objc_module_info_size = objc_module_info_size || 0x00000000;
this.toString = function() {
return JSON.stringify(this);
};
};
var DylibModule64 = function DylibModule64(module_name, iextdefsym, nextdefsym, irefsym, nrefsym, ilocalsym, nlocalsym, iextrel, nextrel, iinit_iterm, ninit_nterm, objc_module_info_addr, objc_module_info_size) {
this.module_name = module_name || 0x00000000;
this.iextdefsym = iextdefsym || 0x00000000;
this.nextdefsym = nextdefsym || 0x00000000;
this.irefsym = irefsym || 0x00000000;
this.nrefsym = nrefsym || 0x00000000;
this.ilocalsym = ilocalsym || 0x00000000;
this.nlocalsym = nlocalsym || 0x00000000;
this.iextrel = iextrel || 0x00000000;
this.nextrel = nextrel || 0x00000000;
this.iinit_iterm = iinit_iterm || 0x00000000;
this.ninit_nterm = ninit_nterm || 0x00000000;
this.objc_module_info_addr = objc_module_info_addr || 0x00000000;
this.objc_module_info_size = objc_module_info_size || 0x0000000000000000;
this.toString = function() {
return JSON.stringify(this);
};
};
var DylibReference = {
isym:24,
flags:8,
toString: function() {
return JSON.stringify(this);
}
};

View file

@ -0,0 +1,7 @@
var DylinkerCommand = function DylinkerCommand(cmd, cmdsize) {
this.cmd = 0x00000000;
this.cmdsize = 0x00000000;
this.toString = function() {
return JSON.stringify(this);
};
};

View file

@ -0,0 +1,73 @@
var FILE_TYPES = [];
var FILE_FLAGS = [];
/*
@Class FILE_TYPE
@Description
File Type is the class for identifying what MACH-O file is being dealed with.
*/
let FILE_TYPE = {
MH_OBJECT: 0x1, /* relocatable object file */
MH_EXECUTE: 0x2, /* demand paged executable file */
MH_FVMLIB: 0x3, /* fixed VM shared library file */
MH_CORE: 0x4, /* core file */
MH_PRELOAD: 0x5, /* preloaded executable file */
MH_DYLIB: 0x6, /* dynamicly bound shared library file*/
MH_DYLINKER: 0x7, /* dynamic link editor */
MH_BUNDLE: 0x8, /* dynamicly bound bundle file */
MH_DYLIB_STUB: 0x9,
MH_DSYM: 0xa,
MH_KEXT_BUNDLE: 0xb,
DESCRIPTION: function(search) {
let result = FILE_TYPES[search];
return (result != undefined) ? result : search;
},
toString: function() {
return JSON.stringify(this);
},
debugdescription: ""
};
FILE_TYPES[FILE_TYPE.MH_OBJECT] = 'Relocatable Object File';
FILE_TYPES[FILE_TYPE.MH_EXECUTE] = 'Demand Paged Executable File';
FILE_TYPES[FILE_TYPE.MH_FVMLIB] = 'Fixed Virtual Memory Shared Library File';
FILE_TYPES[FILE_TYPE.MH_CORE] = 'Core File';
FILE_TYPES[FILE_TYPE.MH_PRELOAD] = 'Preloaded Executable File';
FILE_TYPES[FILE_TYPE.MH_DYLIB] = 'Dynamically Bound Shared Library File';
FILE_TYPES[FILE_TYPE.MH_DYLINKER] = 'Dynamic Link Editor';
FILE_TYPES[FILE_TYPE.MH_BUNDLE] = 'Dynamically Bound Bundle File';
FILE_TYPES[FILE_TYPE.MH_DYLIB_STUB] = 'Dynamic Library Predefined Symbol';
FILE_TYPES[FILE_TYPE.MH_DSYM] = 'Dynamic Symbol';
FILE_TYPES[FILE_TYPE.MH_KEXT_BUNDLE] = 'Kernel Extension Bundle';
let FILE_FLAG = {
MH_NOUNDEFS: 0x1, /* the object file has no undefined references, can be executed */
MH_INCRLINK: 0x2, /* the object file is the output of an incremental link against a base file and can't be link edited again */
MH_DYLDLINK: 0x4, /* the object file is input for the dynamic linker and can't be staticly link edited again */
MH_BINDATLOAD: 0x8, /* the object file's undefined references are bound by the dynamic linker when loaded. */
MH_PREBOUND: 0x10, /* the file has it's dynamic undefined references prebound. */
DESCRIPTION: function(search) {
let result = FILE_FLAGS[search];
return (result != undefined) ? result : search;
},
toString: function() {
return JSON.stringify(this);
}
};
FILE_FLAGS[FILE_FLAG.MH_NOUNDEFS] = 'The object file has no undefined references and is executable.';
FILE_FLAGS[FILE_FLAG.MH_INCRLINK] = 'The object file is the output of an incremental link against a base file and can not be link edited again.';
FILE_FLAGS[FILE_FLAG.MH_DYLDLINK] = 'The object file is the input for the dynamic linker and can not be staticly link edited again.';
FILE_FLAGS[FILE_FLAG.MH_BINDATLOAD] = 'The object file\'s undefined references are bound by the dynamic linker when loaded.';
FILE_FLAGS[FILE_FLAG.MH_PREBOUND] = 'The file has it\'s dynamic undefined references prebound.';
export { FILE_TYPES, FILE_FLAGS, FILE_TYPE, FILE_FLAG }

View file

@ -0,0 +1,31 @@
let FLAGS = {
NOUNDEFS: 1,
INCRLINK: 2,
DYLDLINK: 4,
BINDATLOAD: 8,
PREBOUND: 16,
SPLIT_SEGS: 32,
LAZY_INIT: 64,
TWOLEVEL: 128,
FORCE_FLAT: 256,
NOMULTIDEFS: 512,
NOFIXPREBINDING: 1024,
PREBINDABLE: 2048,
ALLMODSBOUND: 4096,
SUBSECTIONS_VIA_SYMBOLS: 8192,
CANONICAL: 32768,
WEAK_DEFINES: 32768,
BINDS_TO_WEAK: 65536,
ALLOW_STACK_EXECUTION: 131072,
ROOT_SAFE: 262144,
SETUID_SAFE: 524288,
NOREEXPORTED_DYLIBS: 1048576,
PIE: 2097152,
DEAD_STRIPPABLE_DYLIB: 4194304,
HAS_TLV_DESCRIPTORS: 8388608,
NO_HEAP_EXECUTION: 16777216,
APP_EXTENSION_SAFE: 33554432
toString: function(){
return JSON.stringify(this);
}
};

View file

@ -0,0 +1,17 @@
var Fvmlib = function Fvmlib(name, minor_version, header_addr) {
this.name = name || 0x00000000;
this.minor_version = minor_version || 0x00000000;
this.header_addr = header_addr || 0x00000000;
this.toString = function() {
return JSON.stringify(this);
};
};
var FvmlibCommand = function FvmlibCommand(cmd, cmdsize, fvmlib) {
this.cmd = cmd || 0x00000000;
this.cmdsize = cmdsize || 0x00000000;
this.fvmlib = fvmlib || new Fvmlib(); //needs better input validation
this.toString = function() {
return JSON.stringify(this);
};
};

View file

@ -0,0 +1,49 @@
//Mach-O Fat file header
export var FatHeader = function FatHeader() {
this.magic = 0x00000000;
this.nfat_arch = 0x00000000;
this.toString = function() {
return JSON.stringify(this);
}
};
//Mach-O Fat file header
export var FatArch = function FatArch() {
this.cputype = 0x00000000;
this.cpusubtype = 0x00000000;
this.offset = 0x00000000;
this.size = 0x00000000;
this.align = 0x00000000;
this.toString = function() {
return JSON.stringify(this);
}
}
//Mach-O Binary Executable header 32-bit
export var MachoHeader = function MachoHeader() {
this.magic = 0x00000000;
this.cputype = 0x00000000;
this.cpusubtype = 0x00000000;
this.filetype = 0x00000000;
this.ncmds = 0x00000000;
this.sizeofcmds = 0x00000000;
this.flags = 0x00000000;
this.toString = function() {
return JSON.stringify(this);
}
};
//Mach-O Binary Executable header 64-bit
export var MachoHeader64 = function MachoHeader64() {
this.magic = 0x00000000;
this.cputype = 0x00000000;
this.cpusubtype = 0x00000000;
this.filetype = 0x00000000;
this.ncmds = 0x00000000;
this.sizeofcmds = 0x00000000;
this.flags = 0x00000000;
this.reserved = 0x00000000;
this.toString = function() {
return JSON.stringify(this);
}
};

256
helpers/macho/macho.js Normal file
View file

@ -0,0 +1,256 @@
//macho.js
//Written by Sem Voigtländer
//Licensed under the MIT License
import { mime_binary } from './mimetypes.js'
import { ReadUint32, ReadUint16LE, ReadUint32LE } 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 { 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'
function default_callback(buffer) {
console.log('Received ' + buffer.byteLength / (1024 * 1024) + ' MB');
}
// https://stackoverflow.com/a/57139182/1397641
async function arrayBufferToBlob( buffer ) {
return new Blob([buffer])
}
var ChunkReader = function ChunkReader(file, chunksize = (1024 * 1024), callback = default_callback) {
if(file == undefined) {
throw new Error('Invalid argument for file parameter.');
}
if(window.readers == undefined) { window.readers = []; } //Free list
this.chunksize = chunksize; //Read a kilobyte at a time
this.filesize = file.size;
this.offset = 0;
//Start reading the chunks
while(this.offset + this.chunksize <= this.filesize) {
this.blob = file.slice(this.offset, this.offset+this.chunksize);
window.readers[window.readers.length] = new FileReader();
window.readers[window.readers.length-1].onloadend = function(e) {
callback(e.target.result);
};
window.readers[window.readers.length-1].readAsArrayBuffer(this.blob);
console.log('Sending chunk from 0x'+this.offset.toString(16));
this.offset+=this.chunksize;
}
for(obj = 0; obj < window.readers.length; obj++) {
window.readers[obj] = undefined;
}
free("window.readers");
};
export default function MachoParser(file, callbackElement = document.body) {
//properties
this.reader = new FileReader();
function writeToCallback(val) {
if(callbackElement) {
callbackElement.innerHTML +='<tr>'+val+'</tr>';
} else {
throw new Error('Invalid callback.');
}
}
/*
@Function FindMagic
@Params (Uint8Array) buffer, (bool) breakwhenfound
@Return (Array) offsets of found magics
*/
function FindMagic(data, breakwhenfound = false) {
var results = [];
for(var byte = 0; byte < (data.length - uint32_t); byte++) { //Read 32-bits at a time until the end of the buffer
var magic = ReadUint32(data, byte); //Read the next 32-bit magic value
if(MAGIC.VALIDATE(magic)) {
results.push(byte);
if(breakwhenfound) {
break;
}
}
}
return results;
}
/*
@Function MapFlags
@Params (Uint8Array)flags, (Object)map
@Return (Object) key-value mapped dictionary
*/
function MapFlags(value, map) {
var res = {};
for (var bit = 1; (value < 0 || bit <= value) && bit !== 0; bit <<= 1)
if (value & bit) res[map[bit]] = true; //If value and the bit are equal then map the value to the result
return res;
}
function ParseCommand(type, data, size, off) {
var cmd = null;
if(type == LOAD_COMMAND_TYPE.LC_SEGMENT) {
if(data.length < 48) {
if(window.verbose){console.log('Segment command OOB');}
return new LoadCommand(type, data, size, off);
}
let name = new Cstr(data.slice(0, (4*uint32_t)));
cmd = new SegmentCommand(
type,
size,
name,
ReadUint32(data, (4*uint32_t)),
ReadUint32(data, (5*uint32_t)),
ReadUint32(data, (6*uint32_t)),
ReadUint32(data, (7*uint32_t)),
ReadUint32(data, (8*uint32_t)),
ReadUint32(data, (9*uint32_t)),
ReadUint32(data, (10*uint32_t)),
ReadUint32(data, (11*uint32_t))
);
function prot(p) {
var res = {read: false, write: false, exec: false};
return res;
}
let sectSize = 17 * uint32_t;
var sections = [];
//for(var i = 0, off = 48; i < nsects)
return cmd;
} else {
return new LoadCommand(type, data, size, off);
}
}
this.reader.onloadend = function(e) {
let fileType = mime_binary;
//Handle the file buffer and eventually create a Blob of the result
// blobUtil.
arrayBufferToBlob(e.target.result, fileType).then(function(blob) {
let filesize = ((blob.size / 1024) / 1024); //Calculate FileSize in Megabyte
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>');
//Construct a new 8-bit array from the file buffer
let data = new Uint8Array(e.target.result);
let magics = FindMagic(data, false); //Try to find all Mach-O magics in the byte array
if(window.debug) { console.log('Parsing all magics...'); }
//If magics where found, parse the binary.
if(magics.length > 0) {
for(var cMagic = 0; cMagic < magics.length; cMagic++) { //Start parsing the binary from each found magic's offset
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 = [];
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++) {
var curr_cmd = {};
curr_cmd.cmd = (littleendian ? ReadUint32LE(data, off) : ReadUint32(data, off)); //Read the command type from the offset
curr_cmd.cmdsize = (littleendian ? ReadUint32LE(data, off+align) : ReadUint32(data, off+align)); //Read the size of the command from the offset
curr_cmd.fileoff = off; //Add the offset of the loadcommand for later use
curr_cmd.data = data.slice(off, curr_cmd.cmdsize);
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);
}
off+=8;
i++; //Increate the loadcommand counter
}
/* 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>');
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}});
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;
// blobUtil.
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');
} 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.');
}
}).catch(console.log.bind(console));
};
this.reader.readAsArrayBuffer(file);
console.log('Parsing, please wait...');
};

View file

@ -0,0 +1,9 @@
var LinkeditDataCommand = function LinkeditDataCommand(cmd, cmdsize, dataoff, datasize) {
this.cmd = cmd || 0x00000000;
this.cmdsize = cmdsize || 0x00000000;
this.dataoff = dataoff || 0x00000000;
this.datasize = datasize || 0x00000000;
this.toString = function() {
return JSON.stringify(this);
};
};

View file

@ -0,0 +1,133 @@
//Global Constants
var LOAD_COMMAND_TYPES = [];
/*
@Class LoadCommand
@Description
*/
let LOAD_COMMAND_TYPE = {
LC_UNKNOWN: 0,
LC_SEGMENT: 1,
LC_SYMTAB: 2, //Symbol table
LC_SYMSEG: 3, //Segment
LC_THREAD: 4,
LC_UNIXTHREAD: 5,
LC_LOADFVMLIB: 6, /* load a specified fixed VM shared library */
LC_IDFVMLIB: 7, /* fixed VM shared library identification */
LC_IDENT: 8, /* object identification info (obsolete) */
LC_FVMFILE: 9, /* fixed VM file inclusion (internal use) */
LC_PREPAGE: 10, /* prepage command (internal use) */
LC_DYSYMTAB: 11, /* dynamic link-edit symbol table info */
LC_LOAD_DYLIB: 12, /* load a dynamicly linked shared library */
LC_ID_DYLIB: 13, /* dynamicly linked shared lib identification */
LC_LOAD_DYLINKER: 14, /* load a dynamic linker */
LC_ID_DYLINKER: 15,
LC_PREBOUND_DYLIB: 16, /* modules prebound for a dynamicly */
LC_ROUTINES: 17,
LC_SUB_FRAMEWORK: 18,
LC_SUB_UMBRELLA: 19,
LC_SUB_CLIENT: 20,
LC_SUB_LIBRARY: 21,
LC_TWOLEVEL_HINTS: 22,
LC_PREBIND_CKSUM: 23,
LC_SEGMENT_64: 25,
LC_ROUTINES_64: 26,
LC_UUID: 27,
LC_CODE_SIGNATURE: 29,
LC_SEGMENT_SPLIT_INFO: 30,
LC_LAZY_LOAD_DYLIB: 32,
LC_ENCRYPTION_INFO: 33,
LC_DYLD_INFO: 34,
LC_VERSION_MIN_MACOSX: 36,
LC_VERSION_MIN_IPHONEOS: 37,
LC_FUNCTION_STARTS: 38,
LC_DYLD_ENVIRONMENT: 39,
LC_DATA_IN_CODE: 41,
LC_SOURCE_VERSION: 42,
LC_DYLIB_CODE_SIGN_DRS: 43,
LC_ENCRYPTION_INFO_64: 44,
LC_LINKER_OPTION: 45,
LC_LINKER_OPTIMIZATION_HINT: 46,
LC_VERSION_MIN_TVOS: 47,
LC_VERSION_MIN_WATCHOS: 48,
LC_NOTE: 49,
LC_BUILD_VERSION: 50,
LC_LOAD_WEAK_DYLIB: 2147483672,
LC_RPATH: 2147483676,
LC_REEXPORT_DYLIB: 2147483679,
LC_DYLD_INFO_ONLY: 2147483682,
LC_LOAD_UPWARD_DYLIB: 2147483683,
LC_MAIN: 2147483688,
DESCRIPTION: function(search) {
let result = LOAD_COMMAND_TYPES[search];
return (result != undefined) ? result : search;
},
toString: function() {
return JSON.stringify(this);
}
};
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_SEGMENT] = '32-bits Segment command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_SYMTAB] = 'Symbol table command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_SYMSEG] = 'Symbol segment command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_THREAD] = 'Thread command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_UNIXTHREAD] = 'UNIX Thread command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_LOADFVMLIB] = 'Fixed Virtual Memory Library Load command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_IDFVMLIB] = 'Fixed Virtual Memory Library identification information command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_IDENT] = 'Object identification information command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_FVMFILE] = 'Fixed VM File inclusion commmand';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_PREPAGE] = 'Prepage command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_DYSYMTAB] = 'Dynamic Link-Edit Symbol Table information command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_LOAD_DYLIB] = 'Dynamically linked shared library identification command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_ID_DYLIB] = 'Dynamic Library Identifier';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_LOAD_DYLINKER] = 'Dynamic Linker Load Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_ID_DYLINKER] = 'Dynamic Linker Identifier';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_PREBOUND_DYLIB] = 'Prebound Dynamic Library Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_ROUTINES] = 'Routines Load Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_SUB_FRAMEWORK] = 'Sub Framework Load Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_SUB_UMBRELLA] = 'Sub Umbrella Load Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_SUB_CLIENT] = 'Sub Client Load Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_SUB_LIBRARY] = 'Sub Library Load Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_TWOLEVEL_HINTS] = 'TwoLevel Hints Load Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_PREBIND_CKSUM] = 'Prebind Checksum Load Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_SEGMENT_64] = '64-bits Segment Load Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_ROUTINES_64] = '64-bits Routines Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_UUID] = 'UUID Load Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_CODE_SIGNATURE] = 'Code Signature';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_SEGMENT_SPLIT_INFO] = 'Segment Split Information Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_LAZY_LOAD_DYLIB] = 'Lazy Dynamic Library Load Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_ENCRYPTION_INFO] = '32-bits encryption Information';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_DYLD_INFO] = 'Dynamic Loader Information Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_VERSION_MIN_MACOSX] = 'Minimum Version Requirement Command for OSX';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_VERSION_MIN_IPHONEOS] = 'Minimum Version Requirement Command for iPhone';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_FUNCTION_STARTS] = 'Function Starts Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_DYLD_ENVIRONMENT] = 'Dynamic Loader Environment Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_DATA_IN_CODE] = 'Data In Code Load Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_SOURCE_VERSION] = 'Source Version Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_DYLIB_CODE_SIGN_DRS] = 'Dynamic Library Code Sign Directories Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_ENCRYPTION_INFO_64] = '64-bits Encryption Information';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_LINKER_OPTION] = 'Linker Option Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_LINKER_OPTIMIZATION_HINT] = 'Linker Optimization Hint';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_VERSION_MIN_TVOS] = 'Minimum Version Requirement Command for tvOS';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_VERSION_MIN_WATCHOS] = 'Minimum Version Requirement Command for watchOS';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_NOTE] = 'Additional Note';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_BUILD_VERSION] = 'Build Version';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_LOAD_WEAK_DYLIB] = 'Weak Dynamic Library Load Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_RPATH] = 'Executable Path';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_REEXPORT_DYLIB] = 'Re-Exported Dynamic Library Load Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_DYLD_INFO_ONLY] = 'Dynamic Library Loader Information Only';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_LOAD_UPWARD_DYLIB] = 'Upward Dynamic Library Load Command';
LOAD_COMMAND_TYPES[LOAD_COMMAND_TYPE.LC_MAIN] = 'Main Entrypoint';
var LoadCommand = function LoadCommand(type, data, size, fileoff) {
this.cmd = type || 0;
this.cmdsize = size || 0;
this.data = data || new Uint8Array();
this.fileoff = fileoff || 0;
};
export { LOAD_COMMAND_TYPE, LOAD_COMMAND_TYPES, LoadCommand }

View file

@ -0,0 +1,72 @@
//Global Constants
var MAGICS = [];
/*
@Class MAGIC
@Description
Magic is a specific byte that indicates what for file it is.
In Mach-O there a multiple magics differing from endianess, bits or file type.
*/
let MAGIC =
{
//Macho Magics
FAT_MAGIC: 0xcafebabe,
FAT_CIGAM: 0xbebafeca,
FAT_MAGIC64: 0xcafebabf,
FAT_CIGAM64: 0xbfbafeca,
MH_MAGIC: 0xfeedface,
MH_CIGAM: 0xcefaedfe,
MH_MAGIC64: 0xfeedfacf,
MH_CIGAM64: 0xcffaedfe,
//Retrieve the magic name of a specified magic
//If an invalid magic was specifed undefined is returned
KEYFORVALUE: function(value) {
return MAGICS[value];
},
//Validate that a specified magic is correct
VALIDATE: function(magic) {
return MAGIC.KEYFORVALUE(magic) != undefined;
},
//returns true if the specified magic is a little-endian magic
ISLITTLEENDIAN: function(magic) {
if(!MAGIC.VALIDATE(magic)) //If it is not a valid magic we are basically done here
return false;
return MAGIC.KEYFORVALUE(magic).split('CIGAM').length > 1; //hacky trick to check if the magic value's keyname contains CIGAM which basically indicates little endian
},
//returns true if the specified magic is 64-bit
IS64BIT: function(magic) {
if(!MAGIC.VALIDATE(magic))
return false;
return MAGIC.KEYFORVALUE(magic).split('64').length > 1; //hacky trick to check if the magic value's keyname contains 64 which basically indicates 64-bit
},
toString : function() {
return JSON.stringify(this);
},
debugdescription: ""
};
MAGICS[MAGIC.FAT_MAGIC] = "FAT_MAGIC";
MAGICS[MAGIC.FAT_CIGAM] = "FAT_CIGAM";
MAGICS[MAGIC.FAT_MAGIC64] = "FAT_MAGIC64";
MAGICS[MAGIC.FAT_CIGAM64] = "FAT_CIGAM64";
MAGICS[MAGIC.MH_MAGIC] = "MH_MAGIC";
MAGICS[MAGIC.MH_CIGAM] = "MH_CIGAM";
MAGICS[MAGIC.MH_MAGIC64] = "MH_MAGIC64";
MAGICS[MAGIC.MH_CIGAM64] = "MH_CIGAM64";
export { MAGIC, MAGICS }

View file

@ -0,0 +1,25 @@
let OPERATORS = {
False: 0,
True: 1,
Ident: 2,
AppleAnchor: 3,
AnchorHash: 4,
InfoKeyValue: 5,
And: 6,
Or: 7,
CDHash: 8,
Not: 9,
InfoKeyField: 10,
CertField: 11,
TrustedCert: 12,
TrustedCerts: 13,
CertGeneric: 14,
AppleGenericAnchor: 15,
EntitlementField: 16,
CertPolicy: 17,
NamedAnchor: 18,
Platform: 20,
toString: function() {
return JSON.stringify(this);
}
};

View file

@ -0,0 +1,8 @@
var PrebindCksumCommand = function PrebindCksumCommand(cmd, cmdsize, cksum) {
this.cmd = cmd || 0x00000000;
this.cmdsize = cmdsize || 0x00000000;
this.cksum = cksum || 0x00000000;
this.toString = function() {
return JSON.stringify(this);
};
};

View file

@ -0,0 +1,10 @@
var PreboundDylibCommand = function PreboundDylibCommand(cmd, cmdsize, name, nmodules, linked_modules) {
this.cmd = cmd || 0x00000000;
this.cmdsize = cmdsize || 0x00000000;
this.name = name || 0x00000000;
this.nmodules = nmodules || 0x00000000;
this.linked_modules = linked_modules || 0x00000000;
this.toString = function() {
return JSON.stringify(this);
};
};

View file

@ -0,0 +1,30 @@
var RoutinesCommand = function RoutinesCommand(cmd, cmdsize, init_address, init_module, reserved1, reserved2, reserved3, reserved4, reserved5, reserved6) {
this.cmd = cmd || 0x00000000;
this.cmdsize = cmdsize || 0x00000000;
this.init_address = init_address || 0x00000000;
this.init_module = init_module || 0x00000000;
this.reserved1 = reserved1 || 0x00000000;
this.reserved2 = reserved2 || 0x00000000;
this.reserved3 = reserved3 || 0x00000000;
this.reserved4 = reserved4 || 0x00000000;
this.reserved5 = reserved5 || 0x00000000;
this.reserved6 = reserved6 || 0x00000000;
this.toString = function() {
return JSON.stringify(this);
};
};
var RoutinesCommand64 = function RoutinesCommand64(cmd, cmdsize, init_address, init_module, reserved1, reserved2, reserved3, reserved4, reserved5, reserved6) {
this.cmd = cmd || 0x00000000;
this.cmdsize = cmdsize || 0x00000000;
this.init_address = init_address || 0x0000000000000000;
this.init_module = init_module || 0x0000000000000000;
this.reserved1 = reserved1 || 0x0000000000000000;
this.reserved2 = reserved2 || 0x0000000000000000;
this.reserved3 = reserved3 || 0x0000000000000000;
this.reserved4 = reserved4 || 0x0000000000000000;
this.reserved5 = reserved5 || 0x0000000000000000;
this.reserved6 = reserved6 || 0x0000000000000000;
this.toString = function() {
return JSON.stringify(this);
};
};

View file

@ -0,0 +1,8 @@
var RpathCommand = function RpathCommand(cmd, cmdsize, path) {
this.cmd = cmd || 0x00000000;
this.cmdsize = cmdsize || 0x00000000;
this.path = path || 0x00000000;
this.toString = function() {
JSON.stringify(this);
};
};

View file

@ -0,0 +1,90 @@
//Global Constants
let SECTION_MASK = {
SECTION_TYPE: 0x000000ff,
SECTION_ATTRIBUTES: 0xffffff00
toString = function() {
return JSON.stringify(this);
}
};
let SECTION_TYPE = {
REGULAR: 0,
ZEROFILL: 1,
CSTRING_LITERALS: 2,
BYTE4_LITERALS: 3,
BYTE8_LITERALS: 4,
LITERAL_POINTERS: 5,
NON_LAZY_SYMBOL_POINTERS: 6,
LAZY_SYMBOL_POINTERS: 7,
SYMBOL_STUBS: 8,
MOD_INIT_FUNC_POINTERS: 9,
MOD_TERM_FUNC_POINTERS: 0xa,
COALESCED: 0xb,
GB_ZEROFILL: 0xc,
INTERPOSING: 0xd,
BYTE16_LITERALS: 0xe,
DTRACE_DOF: 0xf,
LAZY_DYLIB_SYMBOL_POINTERS: 0x10,
THREAD_LOCAL_REGULAR: 0x11,
THREAD_LOCAL_ZEROFILL: 0x12,
THREAD_LOCAL_VARIABLES: 0x13,
THREAD_LOCAL_VARIABLE_POINTERS: 0x14,
THREAD_LOCAL_INIT_FUNCTION_POINTERS: 0x15,
toString: function() {
return JSON.stringify(this);
}
};
let SECTION = {
SECT_TEXT: "__text",
SECT_FVMLIB_INIT0: "__fvmlib_init0",
SECT_FVMLIB_INIT1: "__fvmlib_init1",
SECT_DATA: "__data",
SECT_BSS: "__bss",
SECT_COMMON: "__common",
SECT_OBJC_SYMBOLS: "__symbol_table",
SECT_OBJC_MODULES: "__module_info",
SECT_OBJC_STRINGS: "__selector_strs",
SECT_OBJC_REFS: "__selector_refs",
SECT_ICON_HEADER: "__header",
SECT_ICON_TIFF: "__tiff",
toString: function() {
return JSON.stringify(this);
}
};
var Section = function Section(sectname, segname, addr, size, offset, align, reloff, nreloc, flags, reserved1, reserved2) {
this.sectname = new Uint8Array(16);
this.segname = new Uint8Array(16);
this.addr = addr || 0x00000000;
this.size = size || 0x00000000;
this.offset = offset || 0x00000000;
this.align = align || 0x00000000;
this.reloff = reloff || 0x00000000;
this.nreloc = nreloc || 0x00000000;
this.flags = flags || 0x00000000;
this.reserved1 = reserved1 || 0x00000000;
this.reserved2 = reserved2 || 0x00000000;
this.toString = function() {
return JSON.stringify(this);
};
};
var Section64 = function Section64(sectname, segname, addr, size, offset, align, reloff, nreloc, flags, reserved1, reserved2, reserved3) {
this.sectname = new Uint8Array(16);
this.segname = new Uint8Array(16);
this.addr = addr || 0x0000000000000000;
this.size = size || 0x0000000000000000;
this.offset = offset || 0x00000000;
this.align = align || 0x00000000;
this.reloff = reloff || 0x00000000;
this.nreloc = nreloc || 0x00000000;
this.flags = flags || 0x00000000;
this.reserved1 = reserved1 || 0x00000000;
this.reserved2 = reserved2 || 0x00000000;
this.reserved3 = reserved3 || 0x00000000;
this.toString = function() {
return JSON.stringify(this);
};
};

View file

@ -0,0 +1,70 @@
//Global Constants
var SG_FLAGS = [];
let SG_FLAG = {
SG_HIGHVM: 0x1,
SG_FVMLIB: 0x2,
SG_NORELOC: 0x4,
DESCRIPTION: function(search) {
let result = SG_FLAGS[search];
return (result != undefined) ? result : search;
},
toString: function() {
return JSON.stringify(this);
}
};
SG_FLAGS[SG_FLAG.SG_HIGHVM] = 'SG_HIGHVM';
SG_FLAGS[SG_FLAG.SG_FVMLIB] = 'SG_FVMLIB';
SG_FLAGS[SG_FLAG.SG_NORELOC] = 'SG_NORELOC';
let SEGMENT = {
SEG_PAGEZERO: "__PAGEZERO",
SEG_TEXT: "__TEXT",
SEG_ICON: "__ICON",
SEG_OBJC: "__OBJC",
SEG_LINKEDIT: "__LINKEDIT",
SEG_UNIXSTACK: "__UNIXSTACK",
SEG_DATA: "__DATA",
toString: function() {
return JSON.stringify(this);
}
};
//32-bits segment command
var SegmentCommand = function SegmentCommand(type, size, segname, vmaddr, vmsize, fileoff, filesize, maxprot, initprot, nsects, flags) {
this.cmd = type || 0x00000000;
this.cmdsize = size || 0x00000000;
this.segname = new TextEncoder("utf-8").encode(segname) || new Uint8Array(16);
this.vmaddr = vmaddr || 0x00000000;
this.vmsize = vmsize || 0x00000000;
this.fileoff = fileoff || 0x00000000;
this.filesize = filesize || 0x00000000;
this.maxprot = maxprot || 0x00000000;
this.initprot = initprot || 0x00000000;
this.nsects = nsects || 0x00000000;
this.flags = flags || 0x00000000;
this.toString = function() {
return JSON.stringify(this);
};
};
//64-bits segment command
var SegmentCommand64 = function SegmentCommand64(cmd, cmdsize, segname, vmaddr, vmsize, fileoff, filesize, maxprot, initprot, nsects, flags) {
this.cmd = cmd || 0x00000000;
this.cmdsize = cmdsize || 0x00000000;
this.segname = new TextEncoder("utf-8").encode(segname) || new Uint8Array(16);
this.vmaddr = vmaddr || 0x0000000000000000;
this.vmsize = vmsize || 0x0000000000000000;
this.fileoff = fileoff || 0x0000000000000000;
this.filesize = filesize || 0x0000000000000000;
this.maxprot = maxprot || 0x00000000;
this.initprot = initprot || 0x00000000;
this.nsects = nsects || 0x00000000;
this.flags = flags || 0x00000000;
this.toString = function() {
return JSON.stringify(this);
};
};

View file

@ -0,0 +1,12 @@
//Global Constants
let SIGNATURES = {
REQUIREMENT: 0xfade0c00,
REQUIREMENTS: 0xfade0c01,
CODEDIRECTORY: 0xfade0c02,
ENTITLEMENT: 0xfade7171,
BLOBWRAPPER: 0xfade0b01,
EMBEDDED_SIGNATURE: 0xfade0cc0,
DETACHED_SIGNATURE: 0xfade0cc1,
CODE_SIGN_DRS: 0xfade0c05
};

View file

@ -0,0 +1,40 @@
let STABS = {
GSYM: 0x20,
FNAME: 0x22,
FUN: 0x24,
STSYM: 0x26,
LCSYM: 0x28,
MAIN: 0x2a,
BNSYM: 0x2e,
PC: 0x30,
AST: 0x32,
MAC_UNDEF: 0x3a,
OPT: 0x3c,
RSYM: 0x40,
SLINE: 0x44,
DSLINE: 0x46,
BSLINE: 0x48,
ENSYM: 0x4e,
SSYM: 0x60,
SO: 0x64,
OSO: 0x66,
LSYM: 0x80,
BINCL: 0x82,
SOL: 0x84,
PARAMS: 0x86,
VERSION: 0x88,
OLEVEL: 0x8a,
PSYM: 0xa0,
EINCL: 0xa2,
ENTRY: 0xa4,
LBRAC: 0xc0,
EXCL: 0xc2,
RBRAC: 0xe0,
BCOMM: 0xe2,
ECOMM: 0xe4,
ECOML: 0xe8,
LENG: 0xfe,
toString: function() {
return JSON.stringify(this);
}
};

View file

@ -0,0 +1,8 @@
var SubClientCommand = function SubClientCommand(cmd, cmdsize, client) {
this.cmd = cmd || 0x00000000;
this.cmdsize = cmdsize || 0x00000000;
this.client = client || 0x00000000;
this.toString = function() {
return JSON.stringify(this);
};
};

View file

@ -0,0 +1,5 @@
var SubFrameworkCommand = function SubFrameworkCommand(cmd, cmdsize, umbrella) {
this.cmd = cmd || 0x00000000;
this.cmdsize = cmdsize || 0x00000000;
this.umbrella = umbrella || 0x00000000;
};

View file

@ -0,0 +1,8 @@
var SubLibraryCommand = function SubLibraryCommand(cmd, cmdsize, sub_library) {
this.cmd = cmd || 0x00000000;
this.cmdsize = cmdsize || 0x00000000;
this.sub_library = sub_library || 0x00000000;
this.toString = function() {
return JSON.stringify(this);
};
};

View file

@ -0,0 +1,8 @@
var SubUmbrellaCommand = function SubUmbrellaCommand(cmd, cmdsize, sub_umbrella) {
this.cmd = cmd || 0x00000000;
this.cmdsize = cmdsize || 0x00000000;
this.sub_umbrella = sub_umbrella || 0x00000000;
this.toString = function() {
return JSON.stringify(this);
};
};

View file

@ -0,0 +1,56 @@
var SymtabCommand = function SymtabCommand(cmd, cmdsize, symoff, nsyms, stroff, strsize) {
this.cmd = cmd || 0x00000000;
this.cmdsize = cmdsize || 0x00000000;
this.symoff = symoff || 0x00000000;
this.nsyms = nsyms || 0x00000000;
this.stroff = stroff || 0x00000000;
this.strsize = strsize || 0x00000000;
this.toString = function() {
return JSON.stringify(this);
};
};
var DySymtabCommand = function DySymtabCommand(cmd,
cmdsize,
ilocalsym,
nlocalsym,
iextdefsym,
nextdefsym,
iundefsym,
nundefsym,
ntoc,
modtaboff,
nmodtab,
extrefsymoff,
nextrefsymoff,
nextrefsyms,
indirectsymoff,
ninderectsyms,
extreloff,
nextrel,
locreloff,
nlocrel) {
this.cmd = cmd || 0x00000000;
this.cmdsize = cmdsize || 0x00000000;
this.ilocalsym = ilocalsym || 0x00000000;
this.nlocalsym = nlocalsym || 0x00000000;
this.iextdefsym = iextdefsym || 0x00000000;
this.nextdefsym = nextdefsym || 0x00000000;
this.iundefsym = iundefsym || 0x00000000;
this.nundefsym = nundefsym || 0x00000000;
this.ntoc = ntoc || 0x00000000;
this.modtaboff = modtaboff || 0x00000000;
this.nmodtab = nmodtab || 0x00000000;
this.extrefsymoff = extrefsymoff || 0x00000000;
this.nextrefsymoff = nextrefsymoff || 0x00000000;
this.nextrefsyms = nextrefsyms || 0x00000000;
this.indirectsymoff= indirectsymoff || 0x00000000;
this.ninderectsyms = ninderectsyms || 0x00000000;
this.extreloff = extreloff || 0x00000000;
this.nextrel = nextrel || 0x00000000;
this.locreloff = locreloff || 0x00000000;
this.nlocrel = nlocrel || 0x00000000;
this.toString = function() {
return JSON.stringify(this);
};
};

View file

@ -0,0 +1,8 @@
var ThreadCommand = function ThreadCommand(cmd, cmdsize, name) {
this.cmd = cmd || 0x00000000;
this.cmdsize = cmdsize || 0x00000000;
this.name = name || 0x00000000;
this.toString = function() {
return JSON.stringify(this);
};
};

View file

@ -0,0 +1,17 @@
var TwoLevelHintsCommand = function TwoLevelHintsCommand(cmd, cmdsize, offset, nhints) {
this.cmd = cmd || 0x00000000;
this.cmdsize = cmdsize || 0x00000000;
this.offset = offset || 0x00000000;
this.nhints = nhints || 0x00000000;
this.toString = function() {
return JSON.stringify(this);
};
};
var TwoLevelHint = {
isub_image:8,
itoc:24,
toString: function() {
return JSON.stringify(this);
}
};

View file

@ -0,0 +1,8 @@
var UUIDCommand = function UUIDCommand(cmd, cmdsize, uuid) {
this.cmd = cmd || 0x00000000;
this.cmdsize = cmdsize || 0x00000000;
this.uuid = uuid || new Uint8Array(16); //needs better input validation
this.toString = function() {
return JSON.stringify(this);
};
};

429
helpers/macho/memory.js Normal file
View file

@ -0,0 +1,429 @@
//memory.js
//Written by Sem Voigtländer
//Licensed under the MIT License
/*
Functionality for geting the memory size of a javascript object
*/
export function free(objectName)
{
if(eval(objectName) != 'undefined')
{
console.log('Helping the garbage collector a little bit with freeing.');
eval(objectName + '=undefined;');
}
}
export function sizeof(object) {
var objectList = [];
var stack = [object];
var bytes = 0;
while (stack.length) {
var value = stack.pop();
if (typeof value === 'boolean') {
bytes += 4;
} else if (typeof value === 'string') {
bytes += value.length * 2;
} else if (typeof value === 'number') {
bytes += 8;
} else if (
typeof value === 'object' &&
objectList.indexOf(value) === -1
) {
objectList.push(value);
for (var i in value) {
stack.push(value[i]);
}
}
}
return bytes;
}
/*
Functions for swapping the endianness of an integer
Supports 16, 32 and 64 bit integers. (Experimental 128-bits as well)
Smaller integers are automatically casted to the corresponding size.
Bigger integers are not casted to smaller integers as they may lose precision.
*/
export function SwapEndian16(integer) {
var _hex = '0';
var _output = '';
//Input validation
if(typeof integer !== 'number')
throw new Error('Invalid argument. argument provided is not an integer.');
if(integer < 0)
throw new Error('Invalid argument. argument provided may not be negative.');
_hex = integer.toString(16); //Conver the input to a hexadecimal string
//Conver the hexadecimal string to a 16-bit integer hexadecimal string
while(_hex.length < 4)
_hex = '0'+_hex;
let _arr = _hex.split(''); //Convert the 16-bit integer hexadecimal string to a char array
//Sanity check
if (_arr.length != 4)
throw new Error('Invalid argument. argument provided is not a 16-bit integer.');
//Swap the endianness
_output += (_arr[2] + _arr[3]).toString();
_output += (_arr[0] + _arr[1]).toString();
//Output sanity check
if(_output.length != 4)
throw new Error('Sanity check failed. Output is not a 16-bit integer');
_output = parseInt('0x'+_output); //convert the hexadecimal output string to an integer
//Conversion sanity check
if(_output === NaN)
throw new Error('Conversion from a hexadecimal string to an integer failed.');
return _output;
}
export function SwapEndian32(integer) {
var _hex = '0';
var _output = '';
//Input validation
if(typeof integer !== 'number')
throw new Error('Invalid argument. argument provided is not an integer.');
if(integer < 0)
throw new Error('Invalid argument. argument provided may not be negative.');
_hex = integer.toString(16); //Conver the input to a hexadecimal string
//Conver the hexadecimal string to a 32-bit integer hexadecimal string
while(_hex.length < 8)
_hex = '0'+_hex;
let _arr = _hex.split(''); //Convert the 32-bit integer hexadecimal string to a char array
//Sanity check
if (_arr.length != 8)
throw new Error('Invalid argument. argument provided is not a 32-bit integer.');
//Swap the endianness
_output += (_arr[6] + _arr[7]).toString();
_output += (_arr[4] + _arr[5]).toString();
_output += (_arr[2] + _arr[3]).toString();
_output += (_arr[0] + _arr[1]).toString();
//Output sanity check
if(_output.length != 8)
throw new Error('Sanity check failed. Output is not a 32-bit integer');
_output = parseInt('0x'+_output); //convert the hexadecimal output string to an integer
//Conversion sanity check
if(_output === NaN)
throw new Error('Conversion from a hexadecimal string to an integer failed.');
//Lets help javascripts garbage collector a bit
_arr = undefined;
_hex = undefined;
return _output;
}
export function SwapEndian64(integer) {
var _hex = '0';
var _output = '';
//Input validation
if(typeof integer !== 'number')
throw new Error('Invalid argument. argument provided is not an integer.');
if(integer < 0)
throw new Error('Invalid argument. argument provided may not be negative.');
_hex = integer.toString(16); //Conver the input to a hexadecimal string
//Conver the hexadecimal string to a 64-bit integer hexadecimal string
while(_hex.length < 16)
_hex = '0'+_hex;
let _arr = _hex.split(''); //Convert the 64-bit integer hexadecimal string to a char array
//Sanity check
if (_arr.length != 16)
throw new Error('Invalid argument. argument provided is not a 64-bit integer.');
//Swap the endianness
_output += (_arr[14] + _arr[15]).toString();
_output += (_arr[12] + _arr[13]).toString();
_output += (_arr[10] + _arr[11]).toString();
_output += (_arr[8] + _arr[9]).toString();
_output += (_arr[6] + _arr[7]).toString();
_output += (_arr[4] + _arr[5]).toString();
_output += (_arr[2] + _arr[3]).toString();
_output += (_arr[0] + _arr[1]).toString();
//Output sanity check
if(_output.length != 16)
throw new Error('Sanity check failed. Output is not a 64-bit integer');
_output = parseInt('0x'+_output); //convert the hexadecimal output string to an integer
//Conversion sanity check
if(_output === NaN)
throw new Error('Conversion from a hexadecimal string to an integer failed.');
//Lets help javascripts garbage collector a bit
_arr = undefined;
_hex = undefined;
return _output;
}
export function SwapEndian128(integer) {
var _hex = '0';
var _output = '';
//Input validation
if(typeof integer !== 'number')
throw new Error('Invalid argument. argument provided is not an integer.');
if(integer < 0)
throw new Error('Invalid argument. argument provided may not be negative.');
_hex = integer.toString(16); //Conver the input to a hexadecimal string
//Conver the hexadecimal string to a 128-bit integer hexadecimal string
while(_hex.length < 32)
_hex = '0'+_hex;
let _arr = _hex.split(''); //Convert the 128-bit integer hexadecimal string to a char array
//Sanity check
if (_arr.length != 32)
throw new Error('Invalid argument. argument provided is not a 128-bit integer.');
//Swap the endianness
_output += (_arr[30] + _arr[31]).toString();
_output += (_arr[28] + _arr[29]).toString();
_output += (_arr[26] + _arr[27]).toString();
_output += (_arr[24] + _arr[25]).toString();
_output += (_arr[22] + _arr[23]).toString();
_output += (_arr[20] + _arr[21]).toString();
_output += (_arr[18] + _arr[19]).toString();
_output += (_arr[16] + _arr[17]).toString();
_output += (_arr[14] + _arr[15]).toString();
_output += (_arr[12] + _arr[13]).toString();
_output += (_arr[10] + _arr[11]).toString();
_output += (_arr[8] + _arr[9]).toString();
_output += (_arr[6] + _arr[7]).toString();
_output += (_arr[4] + _arr[5]).toString();
_output += (_arr[2] + _arr[3]).toString();
_output += (_arr[0] + _arr[1]).toString();
//Output sanity check
if(_output.length != 32)
throw new Error('Sanity check failed. Output is not a 128-bit integer');
_output = parseInt('0x'+_output); //convert the hexadecimal output string to an integer
//Conversion sanity check
if(_output === NaN)
throw new Error('Conversion from a hexadecimal string to an integer failed.');
//Lets help javascripts garbage collector a bit
_arr = undefined;
_hex = undefined;
return _output;
}
/*
Functions for reading integers from a given offset in a given array.
Supports 16, 32 and 64 bit integers. (Experimental 128-bits as well)
It also supports reading with a different Endianness.
*/
//Big Endian
export function ReadUint16(arr, off) {
if(arr.length < 2 || off > arr.length) //sanity check
throw new Error('Cannot read OOB.');
return parseInt("0x" +
arr[off].toString(16) +
arr[off + 1].toString(16)
);
}
export function ReadUint32(arr, off) {
if(arr.length < 4 || off > arr.length) //sanity check
throw new Error('Cannot read OOB.');
return parseInt("0x" +
arr[off].toString(16) +
arr[off + 1].toString(16) +
arr[off + 2].toString(16) +
arr[off + 3].toString(16)
);
}
export function ReadUint64(arr, off) {
if(arr.length < 8 || off > arr.length) //sanity check
throw new Error('Cannot read OOB.');
return parseInt("0x" +
arr[off].toString(16) +
arr[off + 1].toString(16) +
arr[off + 2].toString(16) +
arr[off + 3].toString(16) +
arr[off + 4].toString(16) +
arr[off + 5].toString(16) +
arr[off + 6].toString(16) +
arr[off + 7].toString(16)
);
}
export function ReadUint128(arr, off) {
if(arr.length < 16 || off > arr.length) //sanity check
throw new Error('Cannot read OOB.');
return parseInt("0x" +
arr[off].toString(16) +
arr[off + 1].toString(16) +
arr[off + 2].toString(16) +
arr[off + 3].toString(16) +
arr[off + 4].toString(16) +
arr[off + 5].toString(16) +
arr[off + 6].toString(16) +
arr[off + 7].toString(16) +
arr[off + 8].toString(16) +
arr[off + 9].toString(16) +
arr[off + 10].toString(16) +
arr[off + 11].toString(16) +
arr[off + 12].toString(16) +
arr[off + 13].toString(16) +
arr[off + 14].toString(16) +
arr[off + 15].toString(16)
);
}
//Little Endian
export function ReadUint16LE(arr, off) {
if(arr.length < 2 || off > arr.length) //sanity check
throw new Error('Cannot read OOB.');
return parseInt("0x" +
arr[off + 1].toString(16) +
arr[off].toString(16)
);
}
export function ReadUint32LE(arr, off) {
if(arr.length < 4 || off > arr.length) //sanity check
throw new Error('Cannot read OOB.');
return parseInt("0x" +
arr[off + 3].toString(16) +
arr[off + 2].toString(16) +
arr[off + 1].toString(16) +
arr[off].toString(16)
);
}
export function ReadUint64LE(arr, off) {
if(arr.length < 8 || off > arr.length) //sanity check
throw new Error('Cannot read OOB.');
return parseInt("0x" +
arr[off + 7].toString(16) +
arr[off + 6].toString(16) +
arr[off + 5].toString(16) +
arr[off + 4].toString(16) +
arr[off + 3].toString(16) +
arr[off + 2].toString(16) +
arr[off + 1].toString(16) +
arr[off].toString(16)
);
}
export function ReadUint128LE(arr, off) {
if(arr.length < 16 || off > arr.length) //sanity check
throw new Error('Cannot read OOB.');
return parseInt("0x" +
arr[off + 15].toString(16) +
arr[off + 14].toString(16) +
arr[off + 13].toString(16) +
arr[off + 12].toString(16) +
arr[off + 11].toString(16) +
arr[off + 10].toString(16) +
arr[off + 9].toString(16) +
arr[off + 8].toString(16) +
arr[off + 7].toString(16) +
arr[off + 6].toString(16) +
arr[off + 5].toString(16) +
arr[off + 4].toString(16) +
arr[off + 3].toString(16) +
arr[off + 2].toString(16) +
arr[off + 1].toString(16) +
arr[off].toString(16)
);
}
export function writeUint8(arr, off, val) {
if(arr.length < 2 || off > arr.length || off < 0) {
throw new Error('Cannot write OOB.');
}
if(val.length > 0xff)
throw new Error('Invalid argument. This should be a valid 8-bit integer.');
let old = arr[off];
arr[off] = val;
}
export function writeUint16(arr, off, val) {
if(arr.length < 4 || off > arr.length || off < 0) { //We should never underflow or overflow our buffer
throw new Error('Cannot write OOB.');
}
if(val.length > 0xffff) //Values that after serialization never will be a 16 bit integer should never be treated
throw new Error('Invalid argument. This should be a valid 16-bit integer.');
let old = new Array(arr[off], arr[off+1]);
if(val <= 0xff) { //Integers below 256 are always valid
arr[off] = val;
} else if(val > 0xff && val <= 0xfff) { //Integers bigger than 256 but below 4096 should be treated as two bytes instead of one and fixed with a leading zero
arr[off] = parseInt('0x'+(val.toString(16).split('')[0] + val.toString(16).split('')[1]));
arr[off+1] = parseInt('0x0'+val.toString(16).split('')[2]);
} else if(val > 0xff && val <= 0xffff) { //Integers bigger than 256 and below 65535 should be treated as two bytes and can be splitted without having to fix them with a leading zero
arr[off] = parseInt('0x'+(val.toString(16).split('')[0] + val.toString(16).split('')[1]));
arr[off+1] = parseInt('0x'+val.toString(16).split('')[2] + val.toString(16).split('')[3]);
}
}

View file

@ -0,0 +1,6 @@
//MimeTypes Library
export let mime_binary = 'application/octet-stream';
export let mime_zip = 'application/octet-stream';
export let mime_html = 'text/html';
export let mime_text = 'text/plain';