GP-3568: Backporting to patch

This commit is contained in:
Ryan Kurtz
2023-07-05 07:03:34 -04:00
parent 70bb7f9af7
commit b796fe5233
3 changed files with 149 additions and 40 deletions
@@ -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";
}
@@ -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 <a href="https://github.com/apple-oss-distributions/dyld/blob/main/include/mach-o/fixup-chains.h">mach-o/fixup-chains.h</a>
*/
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;
}
}
@@ -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<Address> processChainedFixups() throws Exception {
public List<Address> processChainedFixups() throws Exception {
monitor.setMessage("Fixing up chained pointers...");
List<Address> fixedAddresses = new ArrayList<>();
// if has Chained Fixups load command, use it
// First look for a DyldChainedFixupsCommand
List<DyldChainedFixupsCommand> loadCommands =
machoHeader.getLoadCommands(DyldChainedFixupsCommand.class);
for (LoadCommand loadCommand : loadCommands) {
DyldChainedFixupsCommand linkCmd = (DyldChainedFixupsCommand) loadCommand;
DyldChainedFixupHeader chainHeader = linkCmd.getChainHeader();
for (DyldChainedFixupsCommand loadCommand : loadCommands) {
DyldChainedFixupHeader chainHeader = loadCommand.getChainHeader();
DyldChainedStartsInImage chainedStartsInImage = chainHeader.getChainedStartsInImage();
DyldChainedStartsInSegment[] chainedStarts = chainedStartsInImage.getChainedStarts();
for (DyldChainedStartsInSegment chainStart : chainedStarts) {
fixedAddresses.addAll(processSegmentPointerChain(chainHeader, chainStart));
}
log.appendMsg("Fixed up " + fixedAddresses.size() + " chained pointers.");
}
// if pointer chains fixed by DyldChainedFixupsCommands, then all finished
if (loadCommands.size() > 0) {
if (!loadCommands.isEmpty()) {
return fixedAddresses;
}
// if has thread_starts use to fixup chained pointers
Section threadStarts = machoHeader.getSection(SegmentNames.SEG_TEXT, "__thread_starts");
if (threadStarts == null) {
return Collections.emptyList();
}
// Didn't find a DyldChainedFixupsCommand, so look for the sections with fixup info
Section chainStartsSection =
machoHeader.getSection(SegmentNames.SEG_TEXT, SectionNames.CHAIN_STARTS);
Section threadStartsSection =
machoHeader.getSection(SegmentNames.SEG_TEXT, SectionNames.THREAD_STARTS);
Address threadSectionStart = null;
Address threadSectionEnd = null;
threadSectionStart = space.getAddress(threadStarts.getAddress());
threadSectionEnd = threadSectionStart.add(threadStarts.getSize() - 1);
monitor.setMessage("Fixing up chained pointers...");
long nextOffSize = (memory.getInt(threadSectionStart) & 1) * 4 + 4;
Address chainHead = threadSectionStart.add(4);
while (chainHead.compareTo(threadSectionEnd) < 0 && !monitor.isCancelled()) {
int headStartOffset = memory.getInt(chainHead);
if (headStartOffset == 0xFFFFFFFF || headStartOffset == 0) {
break;
if (chainStartsSection != null) {
Address sectionStart = space.getAddress(chainStartsSection.getAddress());
ByteProvider p = new MemoryByteProvider(memory, sectionStart);
BinaryReader reader = new BinaryReader(p, machoHeader.isLittleEndian());
DyldChainedStartsOffsets chainedStartsOffsets = new DyldChainedStartsOffsets(reader);
for (int offset : chainedStartsOffsets.getChainStartOffsets()) {
processPointerChain(null, fixedAddresses, chainedStartsOffsets.getPointerFormat(),
program.getImageBase().add(offset).getOffset(), 0, 0);
}
Address chainStart = program.getImageBase().add(headStartOffset & 0xffffffffL);
fixedAddresses.addAll(processPointerChain(chainStart, nextOffSize));
chainHead = chainHead.add(4);
log.appendMsg("Fixed up " + fixedAddresses.size() + " chained pointers.");
}
else if (threadStartsSection != null) {
Address threadSectionStart = space.getAddress(threadStartsSection.getAddress());
Address threadSectionEnd = threadSectionStart.add(threadStartsSection.getSize() - 1);
long nextOffSize = (memory.getInt(threadSectionStart) & 1) * 4 + 4;
Address chainHead = threadSectionStart.add(4);
while (chainHead.compareTo(threadSectionEnd) < 0 && !monitor.isCancelled()) {
int headStartOffset = memory.getInt(chainHead);
if (headStartOffset == 0xFFFFFFFF || headStartOffset == 0) {
break;
}
Address chainStart = program.getImageBase().add(headStartOffset & 0xffffffffL);
fixedAddresses.addAll(processPointerChain(chainStart, nextOffSize));
chainHead = chainHead.add(4);
}
log.appendMsg("Fixed up " + fixedAddresses.size() + " chained pointers.");
}
log.appendMsg("Fixed up " + fixedAddresses.size() + " chained pointers.");
return fixedAddresses;
}
@@ -1721,7 +1731,7 @@ public class MachoProgramBuilder {
/**
* Fixes up any chained pointers, starting at the given address.
*
* @param chainHeader fixup header chains
* @param chainHeader fixup header chains (could be null)
* @param unchainedLocList list of locations that were unchained
* @param pointerFormat format of pointers within this chain
* @param page within data pages that has pointers to be unchained
@@ -1736,7 +1746,7 @@ public class MachoProgramBuilder {
long auth_value_add) throws MemoryAccessException, CancelledException {
long imageBaseOffset = program.getImageBase().getOffset();
Address chainStart = memory.getProgram().getLanguage().getDefaultSpace().getAddress(page);
Address chainStart = space.getAddress(page);
long next = -1;
boolean start = true;
@@ -1750,6 +1760,13 @@ public class MachoProgramBuilder {
boolean isAuthenticated = DyldChainedPtr.isAuthenticated(pointerFormat, chainValue);
boolean isBound = DyldChainedPtr.isBound(pointerFormat, chainValue);
if (isBound && chainHeader == null) {
log.appendMsg(
"Error: dyld_chained_fixups_header required to process bound chain fixup at " +
chainLoc);
return;
}
String symName = null;
if (isAuthenticated && !isBound) {