diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/SectionNames.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/SectionNames.java index f93b8e0f60..ff446c765a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/SectionNames.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/SectionNames.java @@ -73,4 +73,9 @@ public final class SectionNames { public final static String IMPORT_POINTERS = "__pointers"; /** Section dedicated to holding global program variables */ public final static String PROGRAM_VARS = "__program_vars"; + + /** Section containing dyld_chained_starts_offsets structure */ + public final static String CHAIN_STARTS = "__chain_starts"; + /** Section containing chained fixups */ + public final static String THREAD_STARTS = "__thread_starts"; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/dyld/DyldChainedStartsOffsets.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/dyld/DyldChainedStartsOffsets.java new file mode 100644 index 0000000000..b8abf9f61f --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/dyld/DyldChainedStartsOffsets.java @@ -0,0 +1,87 @@ +/* ### + * 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.dyld; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.StructConverter; +import ghidra.app.util.bin.format.macho.MachConstants; +import ghidra.app.util.bin.format.macho.dyld.DyldChainedPtr.DyldChainType; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Represents a dyld_chained_starts_offsets structure. + * + * @see mach-o/fixup-chains.h + */ +public class DyldChainedStartsOffsets implements StructConverter { + + private int pointerFormat; + private int startsCount; + private int[] chainStarts; + + /** + * Creates a new {@link DyldChainedStartsOffsets} + * + * @param reader A {@link BinaryReader} positioned at the start of the structure + * @throws IOException if there was an IO-related problem creating the structure + */ + public DyldChainedStartsOffsets(BinaryReader reader) throws IOException { + pointerFormat = reader.readNextInt(); + startsCount = reader.readNextInt(); + chainStarts = reader.readNextIntArray(startsCount); + } + + /** + * Gets the pointer format + * + * @return The pointer format + */ + public DyldChainType getPointerFormat() { + return DyldChainType.lookupChainPtr(pointerFormat); + } + + /** + * Gets the starts count + * + * @return The starts count + */ + public int getStartsCount() { + return startsCount; + } + + /** + * Gets the chain start offsets + * + * @return The chain start offsets + */ + public int[] getChainStartOffsets() { + return chainStarts; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType("dyld_chained_starts_offset", 0); + struct.add(DWORD, "pointer_format", "DYLD_CHAINED_PTR_*"); + struct.add(DWORD, "starts_count", "number of starts in array"); + struct.add(new ArrayDataType(IBO32, startsCount, 1), "chain_starts", + "array chain start offsets"); + struct.setCategoryPath(new CategoryPath(MachConstants.DATA_TYPE_CATEGORY)); + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MachoProgramBuilder.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MachoProgramBuilder.java index 0d161a9589..1b17cf5e0c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MachoProgramBuilder.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MachoProgramBuilder.java @@ -21,8 +21,7 @@ import java.math.BigInteger; import java.util.*; import ghidra.app.util.MemoryBlockUtils; -import ghidra.app.util.bin.ByteProvider; -import ghidra.app.util.bin.StructConverter; +import ghidra.app.util.bin.*; import ghidra.app.util.bin.format.RelocationException; import ghidra.app.util.bin.format.macho.*; import ghidra.app.util.bin.format.macho.commands.*; @@ -30,6 +29,7 @@ import ghidra.app.util.bin.format.macho.commands.ExportTrie.ExportEntry; import ghidra.app.util.bin.format.macho.commands.dyld.*; import ghidra.app.util.bin.format.macho.dyld.DyldChainedPtr; import ghidra.app.util.bin.format.macho.dyld.DyldChainedPtr.DyldChainType; +import ghidra.app.util.bin.format.macho.dyld.DyldChainedStartsOffsets; import ghidra.app.util.bin.format.macho.relocation.*; import ghidra.app.util.bin.format.macho.threadcommand.ThreadCommand; import ghidra.app.util.bin.format.objectiveC.ObjectiveC1_Constants; @@ -1117,7 +1117,16 @@ public class MachoProgramBuilder { continue; } - if (section.getType() == SectionTypes.S_CSTRING_LITERALS) { + if (section.getSectionName().equals(SectionNames.CHAIN_STARTS)) { + ByteProvider p = new MemoryByteProvider(memory, block.getStart()); + BinaryReader reader = new BinaryReader(p, machoHeader.isLittleEndian()); + DyldChainedStartsOffsets chainedStartsOffsets = + new DyldChainedStartsOffsets(reader); + DataUtilities.createData(program, block.getStart(), + chainedStartsOffsets.toDataType(), -1, + DataUtilities.ClearDataMode.CHECK_FOR_SPACE); + } + else if (section.getType() == SectionTypes.S_CSTRING_LITERALS) { markupBlock(block, new TerminatedStringDataType()); } else if (section.getType() == SectionTypes.S_4BYTE_LITERALS) { @@ -1580,60 +1589,61 @@ public class MachoProgramBuilder { * @return A list of addresses where chained fixups were performed. * @throws Exception if there was a problem reading/writing memory. */ - protected List
processChainedFixups() throws Exception { + public List processChainedFixups() throws Exception { + monitor.setMessage("Fixing up chained pointers..."); List fixedAddresses = new ArrayList<>(); - // if has Chained Fixups load command, use it + // First look for a DyldChainedFixupsCommand List