diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/BinaryReader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/BinaryReader.java index 17c212513c..fe8491398d 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/BinaryReader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/BinaryReader.java @@ -507,12 +507,9 @@ public class BinaryReader { * @exception IOException if an I/O error occurs */ public String readAsciiString(long index, int length) throws IOException { - StringBuilder buffer = new StringBuilder(); - for (int i = 0; i < length; ++i) { - byte b = provider.readByte(index++); - buffer.append((char) (b & 0x00FF)); - } - return buffer.toString().trim(); + byte[] readBytes = provider.readBytes(index, length); + String str = new String(readBytes); + return str.trim(); } /** diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/MachHeaderFileTypes.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/MachHeaderFileTypes.java index b484dc8de4..9978184dd3 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/MachHeaderFileTypes.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/MachHeaderFileTypes.java @@ -45,6 +45,8 @@ public final class MachHeaderFileTypes { public final static int MH_DSYM = 0xa; /** x86_64 kexts */ public final static int MH_KEXT_BUNDLE = 0xb; + /** kernel cache fileset **/ + public final static int MH_FILESET = 0xc; public final static String getFileTypeName(int fileType) { Field [] fields = MachHeaderFileTypes.class.getDeclaredFields(); @@ -77,6 +79,7 @@ public final class MachHeaderFileTypes { case MH_DYLIB_STUB: return "Shared Library Stub for Static Linking Only"; case MH_DSYM: return "Companion file with only debug sections"; case MH_KEXT_BUNDLE: return "x86 64 Kernel Extension"; + case MH_FILESET: return "Kernel Cache Fileset"; } return "Unrecognized file type: 0x"+Integer.toHexString(fileType); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/commands/DyldChainedFixupHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/commands/DyldChainedFixupHeader.java new file mode 100644 index 0000000000..4a1361fa34 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/commands/DyldChainedFixupHeader.java @@ -0,0 +1,134 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.bin.format.macho.commands; + +import java.io.IOException; + +import ghidra.app.util.bin.StructConverter; +import ghidra.app.util.bin.format.FactoryBundledWithBinaryReader; +import ghidra.app.util.bin.format.macho.MachConstants; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a dyld_chained_fixups_header structure. + * + * @see mach-o/fixup-chains.h + */ +public class DyldChainedFixupHeader implements StructConverter { + + private int fixups_version; // 0 + private int starts_offset; // offset of dyld_chained_starts_in_image in chain_data + private int imports_offset; // offset of imports table in chain_data + private int symbols_offset; // offset of symbol strings in chain_data + private int imports_count; // number of imported symbol names + private int imports_format; // DYLD_CHAINED_IMPORT* + private int symbols_format; // 0 => uncompressed, 1 => zlib compressed + + DyldChainedStartsInImage chainedStartsInImage; + DyldChainedImports chainedImports; + + static DyldChainedFixupHeader createDyldChainedFixupHeader( + FactoryBundledWithBinaryReader reader) throws IOException { + DyldChainedFixupHeader dyldChainedFixupHeader = + (DyldChainedFixupHeader) reader.getFactory().create(DyldChainedFixupHeader.class); + dyldChainedFixupHeader.initDyldChainedFixupHeader(reader); + return dyldChainedFixupHeader; + } + + /** + * DO NOT USE THIS CONSTRUCTOR, USE create*(GenericFactory ...) FACTORY METHODS INSTEAD. + */ + public DyldChainedFixupHeader() { + } + + private void initDyldChainedFixupHeader(FactoryBundledWithBinaryReader reader) + throws IOException { + long ptrIndex = reader.getPointerIndex(); + + fixups_version = reader.readNextInt(); + starts_offset = reader.readNextInt(); + imports_offset = reader.readNextInt(); + symbols_offset = reader.readNextInt(); + imports_count = reader.readNextInt(); + imports_format = reader.readNextInt(); + symbols_format = reader.readNextInt(); + + reader.setPointerIndex(ptrIndex + starts_offset); + chainedStartsInImage = DyldChainedStartsInImage.createDyldChainedStartsInImage(reader); + + reader.setPointerIndex(ptrIndex + imports_offset); + chainedImports = DyldChainedImports.createDyldChainedImports(reader, this); + + reader.setPointerIndex(ptrIndex + symbols_offset); + chainedImports.initSymbols(reader, this); + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType("dyld_chained_fixups_header", 0); + struct.add(DWORD, "fixups_version", null); + struct.add(DWORD, "starts_offset", null); + struct.add(DWORD, "imports_offset", null); + struct.add(DWORD, "symbols_offset", null); + struct.add(DWORD, "imports_count", null); + struct.add(DWORD, "imports_format", null); + struct.add(DWORD, "symbols_format", null); + + struct.setCategoryPath(new CategoryPath(MachConstants.DATA_TYPE_CATEGORY)); + return struct; + } + + public int getFixups_version() { + return fixups_version; + } + + public int getStarts_offset() { + return starts_offset; + } + + public int getImports_offset() { + return imports_offset; + } + + public int getSymbols_offset() { + return symbols_offset; + } + + public int getImports_count() { + return imports_count; + } + + public int getImports_format() { + return imports_format; + } + + public int getSymbols_format() { + return symbols_format; + } + + public boolean isCompress() { + return symbols_format != 0; + } + + public DyldChainedStartsInImage getChainedStartsInImage() { + return chainedStartsInImage; + } + + public DyldChainedImports getChainedImports() { + return chainedImports; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/commands/DyldChainedFixupsCommand.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/commands/DyldChainedFixupsCommand.java new file mode 100644 index 0000000000..da4e8a62ef --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/commands/DyldChainedFixupsCommand.java @@ -0,0 +1,114 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.bin.format.macho.commands; + +import java.io.IOException; +import java.util.List; + +import ghidra.app.util.bin.format.FactoryBundledWithBinaryReader; +import ghidra.app.util.bin.format.macho.MachHeader; +import ghidra.app.util.importer.MessageLog; +import ghidra.program.flatapi.FlatProgramAPI; +import ghidra.program.model.address.Address; +import ghidra.program.model.data.DataType; +import ghidra.program.model.listing.ProgramModule; +import ghidra.program.model.util.CodeUnitInsertionException; +import ghidra.util.exception.DuplicateNameException; +import ghidra.util.task.TaskMonitor; + +/** + * Represents a LC_DYLD_CHAINED_FIXUPS command. + * + * @see mach-o/loader.h + */ +public class DyldChainedFixupsCommand extends LinkEditDataCommand { + + private DyldChainedFixupHeader chainHeader; + + static LinkEditDataCommand createDyldChainedFixupsCommand(FactoryBundledWithBinaryReader reader) + throws IOException { + DyldChainedFixupsCommand command = + (DyldChainedFixupsCommand) reader.getFactory().create(DyldChainedFixupsCommand.class); + command.initLinkEditDataCommand(reader); + + long ptrIndex = reader.getPointerIndex(); + reader.setPointerIndex(command.getDataOffset()); + command.chainHeader = DyldChainedFixupHeader.createDyldChainedFixupHeader(reader); + reader.setPointerIndex(ptrIndex); + + return command; + } + + /** + * DO NOT USE THIS CONSTRUCTOR, USE create*(GenericFactory ...) FACTORY METHODS INSTEAD. + */ + public DyldChainedFixupsCommand() { + } + + @Override + public String getCommandName() { + return "dyld_chained_fixups_command"; + } + + @Override + public void markup(MachHeader header, FlatProgramAPI api, Address baseAddress, boolean isBinary, + ProgramModule parentModule, TaskMonitor monitor, MessageLog log) { + updateMonitor(monitor); + try { + if (isBinary) { + super.markup(header, api, baseAddress, isBinary, parentModule, monitor, log); + + List
addrs = + api.getCurrentProgram().getMemory().locateAddressesForFileOffset( + getDataOffset()); + if (addrs.size() <= 0) { + throw new Exception("Chain Header does not exist in program"); + } + Address dyldChainedHeader = addrs.get(0); + + markupChainedFixupHeader(header, api, dyldChainedHeader, parentModule, monitor); + } + } + catch (Exception e) { + log.appendMsg("Unable to create " + getCommandName()); + log.appendException(e); + } + } + + private void markupChainedFixupHeader(MachHeader header, FlatProgramAPI api, + Address baseAddress, ProgramModule parentModule, TaskMonitor monitor) + throws DuplicateNameException, IOException, CodeUnitInsertionException, Exception { + DataType cHeader = chainHeader.toDataType(); + api.createData(baseAddress, cHeader); + + Address segsAddr = baseAddress.add(chainHeader.getStarts_offset()); + + DyldChainedStartsInImage chainedStartsInImage = chainHeader.getChainedStartsInImage(); + int[] seg_info_offset = chainedStartsInImage.getSeg_info_offset(); + + DyldChainedStartsInSegment[] chainedStarts = chainedStartsInImage.getChainedStarts(); + for (int i = 0; i < chainedStarts.length; i++) { + DyldChainedStartsInSegment startsInSeg = chainedStarts[i]; + DataType dataType = startsInSeg.toDataType(); + + api.createData(segsAddr.add(seg_info_offset[i]), dataType); + } + } + + public DyldChainedFixupHeader getChainHeader() { + return chainHeader; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/commands/DyldChainedImport.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/commands/DyldChainedImport.java new file mode 100644 index 0000000000..68441a94dd --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/commands/DyldChainedImport.java @@ -0,0 +1,149 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.bin.format.macho.commands; + +import java.io.IOException; + +import ghidra.app.util.bin.StructConverter; +import ghidra.app.util.bin.format.FactoryBundledWithBinaryReader; +import ghidra.app.util.bin.format.macho.MachConstants; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a dyld_chained_import structure. + * + * @see mach-o/fixup-chains.h + */ +public class DyldChainedImport implements StructConverter { + private static final int DYLD_CHAINED_IMPORT = 1; + private static final int DYLD_CHAINED_IMPORT_ADDEND = 2; + private static final int DYLD_CHAINED_IMPORT_ADDEND64 = 3; + + private int imports_format; + private int lib_ordinal; + private boolean weak_import; + private long name_offset; + private long addend; + private String symbolName; + + static DyldChainedImport createDyldChainedImport(FactoryBundledWithBinaryReader reader, + DyldChainedFixupHeader cfh, int imports_format) throws IOException { + DyldChainedImport dyldChainedImport = + (DyldChainedImport) reader.getFactory().create(DyldChainedImport.class); + dyldChainedImport.initDyldChainedImport(reader, cfh, imports_format); + return dyldChainedImport; + } + + /** + * DO NOT USE THIS CONSTRUCTOR, USE create*(GenericFactory ...) FACTORY METHODS INSTEAD. + */ + public DyldChainedImport() { + } + + private void initDyldChainedImport(FactoryBundledWithBinaryReader reader, + DyldChainedFixupHeader cfh, int format) throws IOException { + + this.imports_format = format; + switch (format) { + case DYLD_CHAINED_IMPORT: { + int ival = reader.readNextInt(); + lib_ordinal = ival & 0xff; + weak_import = ((ival >> 8) & 1) == 1; + name_offset = (ival >> 9 & 0x7fffff); + break; + } + case DYLD_CHAINED_IMPORT_ADDEND: { + int ival = reader.readNextInt(); + lib_ordinal = ival & 0xff; + weak_import = ((ival >> 8) & 1) == 1; + name_offset = (ival >> 9 & 0x7fffff); + addend = reader.readNextInt(); + break; + } + case DYLD_CHAINED_IMPORT_ADDEND64: { + long ival = reader.readNextLong(); + lib_ordinal = (int) (ival & 0xffff); + weak_import = ((ival >> 8) & 1) == 1; + name_offset = (ival >> 32 & 0xffffffff); + addend = reader.readNextLong(); + break; + } + default: + throw new IOException("Bad Chained import format: " + format); + } + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType dt = new StructureDataType("dyld_chained_import", 0); + + try { + switch (imports_format) { + case DYLD_CHAINED_IMPORT: + dt.addBitField(DWORD, 8, "lib_ordinal", "ordinal in imports"); + dt.addBitField(DWORD, 1, "weak_import", null); + dt.addBitField(DWORD, 23, "name_offset", null); + break; + case DYLD_CHAINED_IMPORT_ADDEND: + dt.addBitField(DWORD, 8, "lib_ordinal", "ordinal in imports"); + dt.addBitField(DWORD, 1, "weak_import", null); + dt.addBitField(DWORD, 23, "name_offset", null); + dt.add(DWORD, "addend", null); + break; + case DYLD_CHAINED_IMPORT_ADDEND64: + dt.addBitField(QWORD, 16, "lib_ordinal", "ordinal in imports"); + dt.addBitField(QWORD, 1, "weak_import", null); + dt.addBitField(QWORD, 15, "reserved", null); + dt.addBitField(QWORD, 32, "name_offset", null); + dt.add(QWORD, "addend", null); + break; + default: + throw new IOException("Bad Chained import format: " + imports_format); + } + } + catch (InvalidDataTypeException exc) { + // ignore + } + dt.setCategoryPath(new CategoryPath(MachConstants.DATA_TYPE_CATEGORY)); + return dt; + } + + public int getLibOrdinal() { + return lib_ordinal; + } + + public boolean isWeakImport() { + return weak_import; + } + + public long getNameOffset() { + return name_offset; + } + + public long getAddend() { + return addend; + } + + public String getName() { + return symbolName; + } + + public void initString(FactoryBundledWithBinaryReader reader) throws IOException { + symbolName = reader.readNextNullTerminatedAsciiString(); + } + +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/commands/DyldChainedImports.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/commands/DyldChainedImports.java new file mode 100644 index 0000000000..de4e1e895b --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/commands/DyldChainedImports.java @@ -0,0 +1,106 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.bin.format.macho.commands; + +import java.io.IOException; +import java.util.ArrayList; + +import ghidra.app.util.bin.StructConverter; +import ghidra.app.util.bin.format.FactoryBundledWithBinaryReader; +import ghidra.program.model.data.ArrayDataType; +import ghidra.program.model.data.DataType; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a dyld_chained_import array. + * + * @see mach-o/fixup-chains.h + */ +public class DyldChainedImports implements StructConverter { + + private int imports_count; + private int imports_format; + private long imports_offset; + private DyldChainedImport chainedImports[]; + + static DyldChainedImports createDyldChainedImports(FactoryBundledWithBinaryReader reader, + DyldChainedFixupHeader cfh) throws IOException { + DyldChainedImports dyldChainedImports = + (DyldChainedImports) reader.getFactory().create(DyldChainedImports.class); + dyldChainedImports.initDyldChainedStartsInImage(reader, cfh); + return dyldChainedImports; + } + + /** + * DO NOT USE THIS CONSTRUCTOR, USE create*(GenericFactory ...) FACTORY METHODS INSTEAD. + */ + public DyldChainedImports() { + } + + private void initDyldChainedStartsInImage(FactoryBundledWithBinaryReader reader, + DyldChainedFixupHeader cfh) throws IOException { + + long ptrIndex = reader.getPointerIndex(); + imports_offset = ptrIndex; + + this.imports_count = cfh.getImports_count(); + this.imports_format = cfh.getImports_format(); + + ArrayList