mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-21 08:31:36 +08:00
GP-3568: Backporting to patch
This commit is contained in:
@@ -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";
|
||||
}
|
||||
|
||||
+87
@@ -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;
|
||||
}
|
||||
}
|
||||
+57
-40
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user