diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/BaseRelocation.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/BaseRelocation.java index 89c6073c5f..fb88d68f71 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/BaseRelocation.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/BaseRelocation.java @@ -20,9 +20,14 @@ import java.util.ArrayList; import java.util.List; import ghidra.app.util.bin.*; +import ghidra.app.util.importer.MessageLog; +import ghidra.program.model.address.Address; import ghidra.program.model.data.*; +import ghidra.program.model.listing.*; +import ghidra.program.model.symbol.*; import ghidra.util.DataConverter; import ghidra.util.exception.DuplicateNameException; +import ghidra.util.task.TaskMonitor; /** * A class to represent the IMAGE_BASE_RELOCATION @@ -66,24 +71,36 @@ public class BaseRelocation implements StructConverter, ByteArrayConverter { /** * Names of the available base relocations. */ - public final static String [] TYPE_STRINGS = { - "ABSOLUTE", // 0 - "HIGH", // 1 - "LOW", // 2 - "HIGHLOW", // 3 - "HIGHADJ", // 4 - "MIPS_JMPADDR", // 5 - "???6", - "???7", - "???8", - "IA64_IMM64", // 9 - "DIR64", // 10 - }; + public final static String[] TYPE_STRINGS = { + "ABSOLUTE", + "HIGH", + "LOW", + "HIGHLOW", + "HIGHADJ", + "MIPS_JMPADDR", + "RESERVED", + "THUMB_MOV32", + "RISCV_LOW12S", + "MIPS_JMPADDR16", + "DIR64" + }; private int virtualAddress; private int sizeOfBlock; private List typeOffsetList = new ArrayList(); + public BaseRelocation(BinaryReader reader) throws IOException { + virtualAddress = reader.readNextInt(); + sizeOfBlock = reader.readNextInt(); + + int len = (sizeOfBlock - IMAGE_SIZEOF_BASE_RELOCATION) / BinaryReader.SIZEOF_SHORT; + + for (int i = 0; i < len; ++i) { + short typeOffset = reader.readNextShort(); + typeOffsetList.add(new TypeOffset(typeOffset)); + } + } + BaseRelocation(BinaryReader reader, int index) throws IOException { virtualAddress = reader.readInt(index); index += BinaryReader.SIZEOF_INT; sizeOfBlock = reader.readInt(index); index += BinaryReader.SIZEOF_INT; @@ -139,12 +156,22 @@ public class BaseRelocation implements StructConverter, ByteArrayConverter { return typeOffsetList.size(); } + /** + * Returns the {@link TypeOffset} + * + * @param index the ith relocation + * @return the {@link TypeOffset} of the relocation + */ + public TypeOffset getTypeOffset(int index) { + return typeOffsetList.get(index); + } + /** - * Returns the lower 12 bits of the offset. - * - * @param index the ith relocation - * @return int the offset of the relocation - */ + * Returns the lower 12 bits of the offset. + * + * @param index the ith relocation + * @return the offset of the relocation + */ public int getOffset(int index) { return typeOffsetList.get(index).offset; } @@ -153,19 +180,51 @@ public class BaseRelocation implements StructConverter, ByteArrayConverter { * Returns the upper 4 bits of the offset. * * @param index the ith relocation - * @return int the type of the relocation -, */ + * @return the type of the relocation + */ public int getType(int index) { return typeOffsetList.get(index).type; } + public String getName(int type) { + return (type >= 0 && type < TYPE_STRINGS.length) ? TYPE_STRINGS[type] : ""; + } + + public void markup(Program program, Address addr, boolean isBinary, TaskMonitor monitor, + MessageLog log, NTHeader ntHeader) throws DuplicateNameException, IOException { + ReferenceManager refMgr = program.getReferenceManager(); + Listing listing = program.getListing(); + Address imageBase = program.getImageBase(); + DataType dt = toDataType(); + PeUtils.createData(program, addr, dt, log); + addr = addr.add(dt.getLength()); + + for (TypeOffset typeOffset : typeOffsetList) { + if (monitor.isCancelled()) { + return; + } + DataType typeOffsetDt = typeOffset.toDataType(); + PeUtils.createData(program, addr, typeOffsetDt, log); + + if (typeOffset.typeOffset != 0) { + refMgr.addMemoryReference(addr, imageBase.add(virtualAddress + typeOffset.offset), + RefType.DATA, SourceType.IMPORTED, 0); + listing.setComment(addr, CommentType.EOL, getName(typeOffset.type)); + } + else { + listing.setComment(addr, CommentType.EOL, "padding"); + } + + addr = addr.add(typeOffsetDt.getLength()); + } + } + @Override public DataType toDataType() throws DuplicateNameException { StructureDataType struct = new StructureDataType(NAME, 0); - struct.add(DWORD,"VirtualAddress",null); + struct.add(IBO32, "VirtualAddress", null); struct.add(DWORD,"SizeOfBlock",null); - struct.add(new ArrayDataType(WORD, typeOffsetList.size(), WORD.getLength()),"TypeOffset",null); struct.setCategoryPath(new CategoryPath("/PE")); @@ -188,7 +247,7 @@ public class BaseRelocation implements StructConverter, ByteArrayConverter { return bytes; } - private class TypeOffset { + public class TypeOffset implements StructConverter { short typeOffset; int type; int offset; @@ -204,5 +263,21 @@ public class BaseRelocation implements StructConverter, ByteArrayConverter { this.type = type; this.offset = offset; } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { +// StructureDataType struct = new StructureDataType("TypeOffset", 4); +// struct.setPackingEnabled(true); +// try { +// struct.addBitField(WORD, 12, "Offset", null); +// struct.addBitField(WORD, 4, "Type", null); +// } +// catch (InvalidDataTypeException e) { +// throw new IOException(e); +// } +// struct.setCategoryPath(new CategoryPath("/PE")); +// return struct; + return WORD; + } } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/BaseRelocationDataDirectory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/BaseRelocationDataDirectory.java index da47e071dd..d33e22a60a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/BaseRelocationDataDirectory.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/BaseRelocationDataDirectory.java @@ -23,11 +23,11 @@ import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.ByteArrayConverter; import ghidra.app.util.importer.MessageLog; import ghidra.program.model.address.Address; -import ghidra.program.model.data.DWordDataType; -import ghidra.program.model.data.WordDataType; import ghidra.program.model.listing.Program; +import ghidra.program.model.mem.MemoryAccessException; import ghidra.program.model.util.CodeUnitInsertionException; import ghidra.util.DataConverter; +import ghidra.util.exception.DuplicateNameException; import ghidra.util.task.TaskMonitor; /** @@ -51,7 +51,8 @@ public class BaseRelocationDataDirectory extends DataDirectory implements ByteAr @Override public void markup(Program program, boolean isBinary, TaskMonitor monitor, MessageLog log, - NTHeader nt) throws CodeUnitInsertionException { + NTHeader nt) throws CodeUnitInsertionException, DuplicateNameException, IOException, + MemoryAccessException { monitor.setMessage(program.getName()+": base relocation(s)..."); Address addr = PeUtils.getMarkupAddress(program, isBinary, nt, virtualAddress); @@ -59,26 +60,13 @@ public class BaseRelocationDataDirectory extends DataDirectory implements ByteAr return; } createDirectoryBookmark(program, addr); - + for (BaseRelocation reloc : relocs) { if (monitor.isCancelled()) { return; } - - PeUtils.createData(program, addr, DWordDataType.dataType, log); - addr = addr.add(DWordDataType.dataType.getLength()); - - PeUtils.createData(program, addr, DWordDataType.dataType, log); - addr = addr.add(DWordDataType.dataType.getLength()); - - int count = reloc.getCount(); - for (int j = 0 ; j < count ; ++j) { - if (monitor.isCancelled()) { - return; - } - PeUtils.createData(program, addr, WordDataType.dataType, log); - addr = addr.add(WordDataType.dataType.getLength()); - } + reloc.markup(program, addr, isBinary, monitor, log, nt); + addr = addr.add(reloc.getSizeOfBlock()); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/LoadConfigDataDirectory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/LoadConfigDataDirectory.java index 0d329c1821..8025e5e6ab 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/LoadConfigDataDirectory.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/LoadConfigDataDirectory.java @@ -18,10 +18,12 @@ package ghidra.app.util.bin.format.pe; import java.io.IOException; import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.format.pe.dvrt.ImageDynamicRelocationTable; import ghidra.app.util.importer.MessageLog; import ghidra.program.model.address.Address; import ghidra.program.model.data.*; import ghidra.program.model.listing.Program; +import ghidra.program.model.mem.MemoryAccessException; import ghidra.program.model.util.CodeUnitInsertionException; import ghidra.util.exception.DuplicateNameException; import ghidra.util.task.TaskMonitor; @@ -50,7 +52,8 @@ public class LoadConfigDataDirectory extends DataDirectory { @Override public void markup(Program program, boolean isBinary, TaskMonitor monitor, MessageLog log, - NTHeader nt) throws DuplicateNameException, CodeUnitInsertionException, IOException { + NTHeader nt) throws DuplicateNameException, CodeUnitInsertionException, IOException, + MemoryAccessException { monitor.setMessage(program.getName()+": load config directory..."); @@ -64,6 +67,11 @@ public class LoadConfigDataDirectory extends DataDirectory { markupSeHandler(program, isBinary, monitor, log, nt); ControlFlowGuard.markup(lcd, program, log, nt); + + ImageDynamicRelocationTable dvrt = lcd.getDynamicRelocationTable(); + if (dvrt != null) { + dvrt.markup(program, isBinary, monitor, log, nt); + } } private void markupSeHandler(Program program, boolean isBinary, TaskMonitor monitor, @@ -100,7 +108,7 @@ public class LoadConfigDataDirectory extends DataDirectory { return false; } - lcd = new LoadConfigDirectory(reader, ptr, ntHeader.getOptionalHeader()); + lcd = new LoadConfigDirectory(reader, ptr, ntHeader); return true; } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/LoadConfigDirectory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/LoadConfigDirectory.java index 10135cba2d..27d1ca50aa 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/LoadConfigDirectory.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/LoadConfigDirectory.java @@ -19,7 +19,9 @@ import java.io.IOException; import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.StructConverter; +import ghidra.app.util.bin.format.pe.dvrt.ImageDynamicRelocationTable; import ghidra.program.model.data.*; +import ghidra.util.Msg; import ghidra.util.exception.DuplicateNameException; /** @@ -74,9 +76,12 @@ public class LoadConfigDirectory implements StructConverter { private long reserved3; private boolean is64bit; + private ImageDynamicRelocationTable dvrt; - LoadConfigDirectory(BinaryReader reader, int index, OptionalHeader oh) throws IOException { - is64bit = oh.is64bit(); + LoadConfigDirectory(BinaryReader reader, int index, NTHeader nt) throws IOException { + FileHeader fh = nt.getFileHeader(); + OptionalHeader oh = nt.getOptionalHeader(); + is64bit = nt.getOptionalHeader().is64bit(); long oldIndex = reader.getPointerIndex(); reader.setPointerIndex(index); @@ -149,143 +154,139 @@ public class LoadConfigDirectory implements StructConverter { reserved2 = reader.readNextInt(); reserved3 = readPointer(reader); } + + if (dynamicValueRelocTableOffset != 0 && dynamicValueRelocTableSection != 0) { + SectionHeader section = fh.getSectionHeader(dynamicValueRelocTableSection - 1); + if (section != null) { + long fileOffset = section.getPointerToRawData() + dynamicValueRelocTableOffset; + long rva = section.getVirtualAddress() + dynamicValueRelocTableOffset; + dvrt = new ImageDynamicRelocationTable(reader.clone(fileOffset), rva); + } + else { + Msg.error(this, + "Dynamic value relocation table specifies invalid section number: " + + dynamicValueRelocTableSection); + } + } reader.setPointerIndex(oldIndex); } /** - * Returns the size (in bytes) of this structure. - * - * @return the size (in bytes) of this structure + * {@return the size (in bytes) of this structure} */ public int getSize() { return size; } /** - * Returns the critical section default time-out value. - * - * @return the critical section default time-out value + * {@return the critical section default time-out value} */ public int getCriticalSectionDefaultTimeout() { return criticalSectionDefaultTimeout; } /** - * Gets the safe exception handler table. - * - * @return the safe exception handler table. + * {@return the safe exception handler table} */ public long getSeHandlerTable() { return seHandlerTable; } /** - * Gets the safe exception handler table count. - * - * @return the safe exception handler table count. + * {@return the safe exception handler table count} */ public long getSeHandlerCount() { return seHandlerCount; } /** - * Gets the ControlFlowGuard {@link GuardFlags}. - * - * @return The ControlFlowGuard {@link GuardFlags}. + * {@return the ControlFlowGuard {@link GuardFlags}} */ public GuardFlags getCfgGuardFlags() { return guardFlags; } /** - * Gets the ControlFlowGuard check function pointer address. - * - * @return The ControlFlowGuard check function pointer address. - * Could be 0 if ControlFlowGuard is not being used. + * {@return the ControlFlowGuard check function pointer address (could be 0 if ControlFlowGuard + * is not being used)} */ public long getCfgCheckFunctionPointer() { return guardCfcCheckFunctionPointer; } /** - * Gets the ControlFlowGuard dispatch function pointer address. - * - * @return The ControlFlowGuard dispatch function pointer address. - * Could be 0 if ControlFlowGuard is not being used. + * {@return the ControlFlowGuard dispatch function pointer address (could be 0 if + * ControlFlowGuard is not being used)} */ public long getCfgDispatchFunctionPointer() { return guardCfDispatchFunctionPointer; } /** - * Gets the ControlFlowGuard function table pointer address. - * - * @return The ControlFlowGuard function table function pointer address. - * Could be 0 if ControlFlowGuard is not being used. + * {@return the ControlFlowGuard function table function pointer address (could be 0 if + * ControlFlowGuard is not being used)} */ public long getCfgFunctionTablePointer() { return guardCfFunctionTable; } /** - * Gets the ControlFlowGuard function count. - * - * @return The ControlFlowGuard function count. Could be 0 if ControlFlowGuard is - * not being used. + * {@return the ControlFlowGuard function count (could be 0 if ControlFlowGuard is not being + * used)} */ public long getCfgFunctionCount() { return guardCfFunctionCount; } /** - * Gets the ControlFlowGuard IAT table pointer address. - * - * @return The ControlFlowGuard IAT table function pointer address. Could be 0 if ControlFlowGuard is not being used + * {@return the ControlFlowGuard IAT table function pointer address (could be 0 if + * ControlFlowGuard is not being used)} */ public long getGuardAddressIatTableTablePointer() { return guardAddressTakenIatEntryTable; } /** - * Gets the ControlFlowGuard IAT entries count. - * - * @return The ControlFlowGuard IAT entries count. Could be 0 if ControlFlowGuard is not being used + * {@return the ControlFlowGuard IAT entries count (could be 0 if ControlFlowGuard is not being + * used)} */ public long getGuardAddressIatTableCount() { return guardAddressTakenIatEntryCount; } /** - * Gets the ReturnFlowGuard failure routine address. - * - * @return The ReturnFlowGuard failure routine address. - * Could be 0 if ReturnFlowGuard is not being used. + * {@return the ReturnFlowGuard failure routine address (could be 0 if ReturnFlowGuard is not + * being used)} */ public long getRfgFailureRoutine() { return guardRfFailureRoutine; } /** - * Gets the ReturnFlowGuard failure routine function pointer address. - * - * @return The ReturnFlowGuard failure routine function pointer address. - * Could be 0 if ReturnFlowGuard is not being used. + * {@return the ReturnFlowGuard failure routine function pointer address (could be 0 if + * ReturnFlowGuard is not being used)} */ public long getRfgFailureRoutineFunctionPointer() { return guardRfFailureRoutineFunctionPointer; } /** - * Gets the ReturnFlowGuard verify stack pointer function pointer address. - * - * @return The ReturnFlowGuard verify stack pointer function pointer address. - * Could be 0 if ReturnFlowGuard is not being used. + * {@return the ReturnFlowGuard verify stack pointer function pointer address (could be 0 if + * ReturnFlowGuard is not being used)} */ public long getRfgVerifyStackPointerFunctionPointer() { return guardRfVerifyStackPointerFunctionPointer; } + /** + * {@return the Dynamic Value Relocation Table (could be {@code null} if DVRT is not being + * used)} + */ + public ImageDynamicRelocationTable getDynamicRelocationTable() { + return dvrt; + } + @Override public DataType toDataType() throws DuplicateNameException { StructureDataType struct = new StructureDataType(is64bit ? NAME64 : NAME32, 0); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/AbstractImageDynamicRelocationHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/AbstractImageDynamicRelocationHeader.java new file mode 100644 index 0000000000..9d0675020e --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/AbstractImageDynamicRelocationHeader.java @@ -0,0 +1,40 @@ +/* ### + * 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.pe.dvrt; + +import java.io.IOException; + +import ghidra.app.util.bin.StructConverter; +import ghidra.app.util.bin.format.pe.PeMarkupable; + +/** + * An abstract dynamic value relocation header + */ +public abstract class AbstractImageDynamicRelocationHeader + implements StructConverter, PeMarkupable { + + protected long rva; + + /** + * Creates a new {@link AbstractImageDynamicRelocationHeader} + * + * @param rva The relative virtual address of the structure + * @throws IOException if there was an IO-related error + */ + public AbstractImageDynamicRelocationHeader(long rva) throws IOException { + this.rva = rva; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/DvrtType.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/DvrtType.java new file mode 100644 index 0000000000..30d15210d4 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/DvrtType.java @@ -0,0 +1,81 @@ +/* ### + * 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.pe.dvrt; + +import java.io.IOException; +import java.util.Arrays; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.StructConverter; +import ghidra.program.model.data.*; +import ghidra.util.exception.DuplicateNameException; + +/** + * Defined symbol dynamic relocation entries + */ +public enum DvrtType implements StructConverter { + + IMAGE_DYNAMIC_RELOCATION_GUARD_RF_PROLOGUE(0x1), + IMAGE_DYNAMIC_RELOCATION_GUARD_RF_EPILOGUE(0x2), + IMAGE_DYNAMIC_RELOCATION_IMPORT_CONTROL_TRANSFER(0x3), + IMAGE_DYNAMIC_RELOCATION_INDIR_CONTROL_TRANSFER(0x4), + IMAGE_DYNAMIC_RELOCATION_SWITCHABLE_BRANCH(0x5), + IMAGE_DYNAMIC_RELOCATION_ARM64X(0x6), + IMAGE_DYNAMIC_RELOCATION_FUNCTION_OVERRIDE(0x7), + IMAGE_DYNAMIC_RELOCATION_ARM64_KERNEL_IMPORT_CALL_TRANSFER(0x8); + + private long value; + + /** + * Creates a new {@link DvrtType} + * + * @param value The defined value of the type + */ + private DvrtType(int value) { + this.value = value; + } + + /** + * {@return the type's defined value} + */ + public long getValue() { + return value; + } + + /** + * Reads a {@link DvrtType} + * + * @param reader A {@link BinaryReader} that points to the start of the type value + * @return The type that was read, or {@code null} if the value read does not correspond to a + * valid type + * @throws IOException if there was an IO-related error + */ + public static DvrtType type(BinaryReader reader) throws IOException { + long value = reader.readNextLong(); + return Arrays.stream(DvrtType.values()) + .filter(e -> value == e.getValue()) + .findFirst() + .orElse(null); + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + EnumDataType enumDt = new EnumDataType("DvrtType", 8); + Arrays.stream(values()).forEach(e -> enumDt.add(e.name(), e.getValue())); + enumDt.setCategoryPath(new CategoryPath("/PE")); + return enumDt; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageArm64X.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageArm64X.java new file mode 100644 index 0000000000..64dedeee7d --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageArm64X.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.pe.dvrt; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.format.pe.NTHeader; +import ghidra.app.util.bin.format.pe.PeUtils; +import ghidra.app.util.importer.MessageLog; +import ghidra.program.model.address.Address; +import ghidra.program.model.data.*; +import ghidra.program.model.listing.Program; +import ghidra.program.model.mem.MemoryAccessException; +import ghidra.program.model.symbol.*; +import ghidra.program.model.util.CodeUnitInsertionException; +import ghidra.util.exception.DuplicateNameException; +import ghidra.util.task.TaskMonitor; + +/** + * Contains a list of {@link ImageArm64XDynamicRelocation}s + */ +public class ImageArm64X extends AbstractImageDynamicRelocationHeader { + + private int virtualAddress; + private int sizeOfBlock; + private List relocs = new ArrayList<>(); + + /** + * Creates a new {@link ImageIndirControlTransfer} + * + * @param reader A {@link BinaryReader} that points to the start of the structure + * @param rva The relative virtual address of the structure + * @throws IOException if there was an IO-related error + */ + public ImageArm64X(BinaryReader reader, long rva) throws IOException { + super(rva); + long origIndex = reader.getPointerIndex(); + + virtualAddress = reader.readNextInt(); + sizeOfBlock = reader.readNextInt(); + + long startIndex = reader.getPointerIndex(); + for (long i = startIndex; i < origIndex + sizeOfBlock; i = reader.getPointerIndex()) { + relocs.add(new ImageArm64XDynamicRelocation(reader, rva + (i - origIndex))); + } + } + + /** + * {@return the virtual address} + */ + public int getVirualAddress() { + return virtualAddress; + } + + /** + * {@return the size of the block} + */ + public int getSizeOfBlock() { + return sizeOfBlock; + } + + /** + * {@return the {@link List} of {@link ImageArm64XDynamicRelocation}s} + */ + public List getRelocs() { + return relocs; + } + + @Override + public void markup(Program program, boolean isBinary, TaskMonitor monitor, MessageLog log, + NTHeader ntHeader) throws DuplicateNameException, CodeUnitInsertionException, + IOException, MemoryAccessException { + ReferenceManager refMgr = program.getReferenceManager(); + Address imageBase = program.getImageBase(); + DataType dt = toDataType(); + Address addr = imageBase.add(rva); + PeUtils.createData(program, addr, dt, log); + addr = addr.add(dt.getLength()); + for (ImageArm64XDynamicRelocation reloc : relocs) { + reloc.markup(program, isBinary, monitor, log, ntHeader); + int pageRelativeOffset = reloc.getPageRelativeOffset(); + if (pageRelativeOffset != 0) { + refMgr.addMemoryReference(addr, imageBase.add(virtualAddress + pageRelativeOffset), + RefType.DATA, SourceType.IMPORTED, 0); + } + addr = addr.add(reloc.toDataType().getLength() + reloc.getData().length); + } + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType("IMAGE_ARM64X", 0); + struct.add(IBO32, "VirtualAddress", null); + struct.add(DWORD, "SizeOfBlock", null); + struct.setCategoryPath(new CategoryPath("/PE")); + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageArm64XDynamicRelocation.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageArm64XDynamicRelocation.java new file mode 100644 index 0000000000..4820a0d992 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageArm64XDynamicRelocation.java @@ -0,0 +1,132 @@ +/* ### + * 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.pe.dvrt; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.StructConverter; +import ghidra.app.util.bin.format.pe.*; +import ghidra.app.util.importer.MessageLog; +import ghidra.program.model.address.Address; +import ghidra.program.model.data.*; +import ghidra.program.model.listing.Program; +import ghidra.program.model.mem.MemoryAccessException; +import ghidra.program.model.util.CodeUnitInsertionException; +import ghidra.util.exception.DuplicateNameException; +import ghidra.util.task.TaskMonitor; + +/** + * Represents a {@code IMAGE_ARM64X_DYNAMIC_RELOCATION} structure + */ +public class ImageArm64XDynamicRelocation implements StructConverter, PeMarkupable { + + private int pageRelativeOffset; + private int type; + private int meta; + private byte[] data; + + private long rva; + + /** + * Creates a new {@link ImageArm64XDynamicRelocation} + * + * @param reader A {@link BinaryReader} that points to the start of the structure + * @param rva The relative virtual address of the structure + * @throws IOException if there was an IO-related error + */ + public ImageArm64XDynamicRelocation(BinaryReader reader, long rva) throws IOException { + this.rva = rva; + + int bitfield = reader.readNextUnsignedShort(); + if (bitfield == 0) { + data = new byte[0]; + return; + } + + pageRelativeOffset = bitfield & 0xfff; + type = (bitfield >> 12) & 0x3; + meta = (bitfield >> 14) & 0x3; + + int size = switch (type) { + case 0 -> 0; // zero fill + case 1 -> 1 << meta; // assign value + case 2 -> 2; // add (or sub) delta + default -> 2; + }; + data = reader.readNextByteArray(size); + } + + /** + * {@return the page relative offset} + */ + public int getPageRelativeOffset() { + return pageRelativeOffset; + } + + /** + * {@return the type} + */ + public int getType() { + return type; + } + + /** + * {@return the data} + */ + public byte[] getData() { + return data; + } + + @Override + public void markup(Program program, boolean isBinary, TaskMonitor monitor, MessageLog log, + NTHeader ntHeader) throws DuplicateNameException, CodeUnitInsertionException, + IOException, MemoryAccessException { + Address imageBase = program.getImageBase(); + DataType dt = toDataType(); + Address addr = imageBase.add(rva); + PeUtils.createData(program, addr, dt, log); + addr = addr.add(dt.getLength()); + DataType dataDt = switch (data.length) { + case 1 -> BYTE; + case 2 -> WORD; + case 4 -> DWORD; + case 8 -> QWORD; + default -> null; + }; + if (dataDt != null) { + PeUtils.createData(program, addr, dataDt, log); + } + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = + new StructureDataType("IMAGE_ARM64X_DYNAMIC_RELOCATION", 0); + struct.setPackingEnabled(true); + try { + struct.addBitField(WORD, 12, "PageRelativeOffset", null); + struct.addBitField(WORD, 2, "Type", null); + struct.addBitField(WORD, 2, "Meta", null); + } + catch (InvalidDataTypeException e) { + throw new IOException(e); + } + struct.setCategoryPath(new CategoryPath("/PE")); + return struct; + } +} + diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageBddDynamicRelocation.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageBddDynamicRelocation.java new file mode 100644 index 0000000000..5724015e7f --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageBddDynamicRelocation.java @@ -0,0 +1,97 @@ +/* ### + * 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.pe.dvrt; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.StructConverter; +import ghidra.app.util.bin.format.pe.*; +import ghidra.app.util.importer.MessageLog; +import ghidra.program.model.address.Address; +import ghidra.program.model.data.*; +import ghidra.program.model.listing.Program; +import ghidra.program.model.mem.MemoryAccessException; +import ghidra.program.model.util.CodeUnitInsertionException; +import ghidra.util.exception.DuplicateNameException; +import ghidra.util.task.TaskMonitor; + +/** + * Represents a {@code IMAGE_BDD_DYNAMIC_RELOCATION} structure + */ +public class ImageBddDynamicRelocation implements StructConverter, PeMarkupable { + + private int left; + private int right; + private int value; + + private long rva; + + /** + * Creates a new {@link ImageBddInfo} + * + * @param reader A {@link BinaryReader} that points to the start of the structure + * @param rva The relative virtual address of the structure + * @throws IOException if there was an IO-related error + */ + public ImageBddDynamicRelocation(BinaryReader reader, long rva) throws IOException { + this.rva = rva; + + left = reader.readNextUnsignedShort(); + right = reader.readNextUnsignedShort(); + value = reader.readNextInt(); + } + + /** + * {@return the index of the FALSE edge in the BDD array} + */ + public int getLeft() { + return left; + } + + /** + * {@return the index of the TRUE edge in the BDD array} + */ + public int getRight() { + return right; + } + + /** + * {@return either the feature number or index in RVAs array} + */ + public int getValue() { + return value; + } + + @Override + public void markup(Program program, boolean isBinary, TaskMonitor monitor, MessageLog log, + NTHeader ntHeader) throws DuplicateNameException, CodeUnitInsertionException, + IOException, MemoryAccessException { + Address imageBase = program.getImageBase(); + DataType dt = toDataType(); + PeUtils.createData(program, imageBase.add(rva), dt, log); + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType("IMAGE_BDD_DYNAMIC_RELOCATION", 0); + struct.add(WORD, "Left", "Index of FALSE edge in BDD array"); + struct.add(WORD, "Right", "Index of TRUE edge in BDD array"); + struct.add(DWORD, "Value", "Either FeatureNumber or Index into RVAs array"); + struct.setCategoryPath(new CategoryPath("/PE")); + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageBddInfo.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageBddInfo.java new file mode 100644 index 0000000000..8fa187a4c6 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageBddInfo.java @@ -0,0 +1,101 @@ +/* ### + * 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.pe.dvrt; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.StructConverter; +import ghidra.app.util.bin.format.pe.*; +import ghidra.app.util.importer.MessageLog; +import ghidra.program.model.address.Address; +import ghidra.program.model.data.*; +import ghidra.program.model.listing.Program; +import ghidra.program.model.mem.MemoryAccessException; +import ghidra.program.model.util.CodeUnitInsertionException; +import ghidra.util.exception.DuplicateNameException; +import ghidra.util.task.TaskMonitor; + +/** + * Represents a {@code IMAGE_BDD_INFO} structure + */ +public class ImageBddInfo implements StructConverter, PeMarkupable { + + private int version; + private int bddSize; + + private long rva; + private List bddNodes = new ArrayList<>(); + + /** + * Creates a new {@link ImageBddInfo} + * + * @param reader A {@link BinaryReader} that points to the start of the structure + * @param rva The relative virtual address of the structure + * @throws IOException if there was an IO-related error + */ + public ImageBddInfo(BinaryReader reader, long rva) throws IOException { + this.rva = rva; + long origIndex = reader.getPointerIndex(); + + version = reader.readNextInt(); + bddSize = reader.readNextInt(); + + long startIndex = reader.getPointerIndex(); + for (long i = startIndex; i < startIndex + bddSize; i = reader.getPointerIndex()) { + bddNodes.add(new ImageBddDynamicRelocation(reader, + rva + (reader.getPointerIndex() - origIndex))); + } + } + + /** + * {@return the BDD version} + */ + public int getVersion() { + return version; + } + + /** + * {@return the BDD size} + */ + public int getBddSize() { + return bddSize; + } + + @Override + public void markup(Program program, boolean isBinary, TaskMonitor monitor, MessageLog log, + NTHeader ntHeader) throws DuplicateNameException, CodeUnitInsertionException, + IOException, MemoryAccessException { + Address imageBase = program.getImageBase(); + DataType dt = toDataType(); + PeUtils.createData(program, imageBase.add(rva), dt, log); + for (ImageBddDynamicRelocation node : bddNodes) { + node.markup(program, isBinary, monitor, log, ntHeader); + } + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType("IMAGE_BDD_INFO", 0); + struct.add(DWORD, "Version", "decides the semantics of serialzed BDD"); + struct.add(DWORD, "BDDSize", null); + struct.setCategoryPath(new CategoryPath("/PE")); + return struct; + } + +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageDynamicRelocation.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageDynamicRelocation.java new file mode 100644 index 0000000000..ffdc97b593 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageDynamicRelocation.java @@ -0,0 +1,116 @@ +/* ### + * 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.pe.dvrt; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.StructConverter; +import ghidra.app.util.bin.format.pe.*; +import ghidra.app.util.importer.MessageLog; +import ghidra.program.model.address.Address; +import ghidra.program.model.data.*; +import ghidra.program.model.listing.*; +import ghidra.program.model.mem.MemoryAccessException; +import ghidra.program.model.util.CodeUnitInsertionException; +import ghidra.util.exception.DuplicateNameException; +import ghidra.util.task.TaskMonitor; + +/** + * Represents a {@code IMAGE_DYNAMIC_RELOCATION} structure + */ +public class ImageDynamicRelocation implements StructConverter, PeMarkupable { + + private DvrtType symbol; + private int baseRelocSize; + + private long rva; + private List headers = new ArrayList<>(); + + /** + * Creates a new {@link ImageDynamicRelocation} + * + * @param reader A {@link BinaryReader} that points to the start of the structure + * @param rva The relative virtual address of the structure + * @throws IOException if there was an IO-related error + */ + public ImageDynamicRelocation(BinaryReader reader, long rva) throws IOException { + this.rva = rva; + long origIndex = reader.getPointerIndex(); + + symbol = reader.readNext(DvrtType::type); + baseRelocSize = reader.readNextInt(); + + long startIndex = reader.getPointerIndex(); + for (long i = startIndex; i < startIndex + baseRelocSize; i = reader.getPointerIndex()) { + long newRva = rva + (i - origIndex); + headers.add(switch (symbol) { + case IMAGE_DYNAMIC_RELOCATION_IMPORT_CONTROL_TRANSFER -> new ImageImportControlTransfer( + reader, newRva); + case IMAGE_DYNAMIC_RELOCATION_INDIR_CONTROL_TRANSFER -> new ImageIndirControlTransfer( + reader, newRva); + case IMAGE_DYNAMIC_RELOCATION_SWITCHABLE_BRANCH -> new ImageSwitchtableBranch( + reader, newRva); + case IMAGE_DYNAMIC_RELOCATION_ARM64X -> new ImageArm64X(reader, newRva); + case IMAGE_DYNAMIC_RELOCATION_FUNCTION_OVERRIDE -> new ImageFunctionOverrideHeader( + reader, newRva, baseRelocSize); + case null -> new ImageUnsupportedRelocationHeader(reader, newRva, baseRelocSize); + default -> new ImageUnsupportedRelocationHeader(reader, newRva, baseRelocSize); + }); + } + } + + /** + * {@return the relocation "symbol", which is really a {@link DvrtType type} + */ + public DvrtType getSymbol() { + return symbol; + } + + /** + * {@return the size in bytes of the relocation} + */ + public int getBaseRelocSize() { + return baseRelocSize; + } + + @Override + public void markup(Program program, boolean isBinary, TaskMonitor monitor, MessageLog log, + NTHeader ntHeader) throws DuplicateNameException, CodeUnitInsertionException, + IOException, MemoryAccessException { + Listing listing = program.getListing(); + Address imageBase = program.getImageBase(); + Address start = imageBase.add(rva); + PeUtils.createData(program, start, toDataType(), log); + for (AbstractImageDynamicRelocationHeader header : headers) { + header.markup(program, isBinary, monitor, log, ntHeader); + } + listing.setComment(start, CommentType.PLATE, + symbol != null ? symbol.name() : "IMAGE_DYNAMIC_RELOCATION_"); + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType("IMAGE_DYNAMIC_RELOCATION", 0); + struct.add(symbol != null ? symbol.toDataType() : QWORD, "Symbol", null); + struct.add(DWORD, "BaseRelocSize", null); + struct.setCategoryPath(new CategoryPath("/PE")); + return struct; + } + +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageDynamicRelocationTable.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageDynamicRelocationTable.java new file mode 100644 index 0000000000..62e08a8f0f --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageDynamicRelocationTable.java @@ -0,0 +1,98 @@ +/* ### + * 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.pe.dvrt; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.StructConverter; +import ghidra.app.util.bin.format.pe.*; +import ghidra.app.util.importer.MessageLog; +import ghidra.program.model.address.Address; +import ghidra.program.model.data.*; +import ghidra.program.model.listing.Program; +import ghidra.program.model.mem.MemoryAccessException; +import ghidra.program.model.util.CodeUnitInsertionException; +import ghidra.util.exception.DuplicateNameException; +import ghidra.util.task.TaskMonitor; + +/** + * Represents a {@code IMAGE_DYNAMIC_RELOCATION_TABLE} structure + */ +public class ImageDynamicRelocationTable implements StructConverter, PeMarkupable { + + private int version; + private int size; + + private long rva; + private List relocations = new ArrayList<>(); + + /** + * Creates a new {@link ImageDynamicRelocationTable} + * + * @param reader A {@link BinaryReader} that points to the start of the structure + * @param rva The relative virtual address of the structure + * @throws IOException if there was an IO-related error + */ + public ImageDynamicRelocationTable(BinaryReader reader, long rva) throws IOException { + this.rva = rva; + long origIndex = reader.getPointerIndex(); + + version = reader.readNextInt(); + size = reader.readNextInt(); + + long startIndex = reader.getPointerIndex(); + for (long i = startIndex; i < startIndex + size; i = reader.getPointerIndex()) { + relocations.add(new ImageDynamicRelocation(reader, rva + (i - origIndex))); + } + } + + /** + * {@return the dynamic value relocation table version} + */ + public int getVersion() { + return version; + } + + /** + * {@return the size in bytes of the dynamic value relocation table} + */ + public int getSize() { + return size; + } + + @Override + public void markup(Program program, boolean isBinary, TaskMonitor monitor, MessageLog log, + NTHeader ntHeader) throws DuplicateNameException, CodeUnitInsertionException, + IOException, MemoryAccessException { + Address imageBase = program.getImageBase(); + PeUtils.createData(program, imageBase.add(rva), toDataType(), log); + for (ImageDynamicRelocation reloc : relocations) { + reloc.markup(program, isBinary, monitor, log, ntHeader); + } + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType("IMAGE_DYNAMIC_RELOCATION_TABLE", 0); + struct.add(DWORD, "Version", null); + struct.add(DWORD, "Size", null); + struct.setCategoryPath(new CategoryPath("/PE")); + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageFunctionOverrideDynamicRelocation.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageFunctionOverrideDynamicRelocation.java new file mode 100644 index 0000000000..c0e2ca4ff0 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageFunctionOverrideDynamicRelocation.java @@ -0,0 +1,138 @@ +/* ### + * 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.pe.dvrt; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.StructConverter; +import ghidra.app.util.bin.format.pe.*; +import ghidra.app.util.importer.MessageLog; +import ghidra.program.model.address.Address; +import ghidra.program.model.data.*; +import ghidra.program.model.listing.Program; +import ghidra.program.model.mem.MemoryAccessException; +import ghidra.program.model.util.CodeUnitInsertionException; +import ghidra.util.exception.DuplicateNameException; +import ghidra.util.task.TaskMonitor; + +/** + * Represents a {@code IMAGE_FUNCTION_OVERRIDE_DYNAMIC_RELOCATION} structure + */ +public class ImageFunctionOverrideDynamicRelocation implements StructConverter, PeMarkupable { + + private int originalRva; + private int bddOffset; + private int rvaSize; + private int baseRelocSize; + + private long rva; + private int[] rvas; + private List baseRelocs = new ArrayList<>(); + + /** + * Creates a new {@link ImageFunctionOverrideDynamicRelocation} + * + * @param reader A {@link BinaryReader} that points to the start of the structure + * @param rva The relative virtual address of the structure + * @throws IOException if there was an IO-related error + */ + public ImageFunctionOverrideDynamicRelocation(BinaryReader reader, long rva) + throws IOException { + this.rva = rva; + + originalRva = reader.readNextInt(); + bddOffset = reader.readNextInt(); + rvaSize = reader.readNextInt(); + baseRelocSize = reader.readNextInt(); + + rvas = reader.readNextIntArray(rvaSize / 4); + + long startIndex = reader.getPointerIndex(); + for (long i = startIndex; i < startIndex + baseRelocSize; i = reader.getPointerIndex()) { + baseRelocs.add(new BaseRelocation(reader)); + } + } + + /** + * {@return the relative virtual address of the original function} + */ + public int getOriginalRva() { + return originalRva; + } + + /** + * {@return the offset into the BDD region} + */ + public int getBddOffset() { + return bddOffset; + } + + /** + * {@return the size in bytes taken by relative virtual addresses} + */ + public int getRvaSize() { + return rvaSize; + } + + /** + * {@return the size in bytes taken by BaseRelocs} + */ + public int getBaseRelocSize() { + return baseRelocSize; + } + + /** + * {@return the {@link List} of {@link BaseRelocation}s} + */ + public List getBaseRelocs() { + return baseRelocs; + } + + @Override + public void markup(Program program, boolean isBinary, TaskMonitor monitor, MessageLog log, + NTHeader ntHeader) throws DuplicateNameException, CodeUnitInsertionException, + IOException, MemoryAccessException { + Address imageBase = program.getImageBase(); + DataType dt = toDataType(); + Address addr = imageBase.add(rva); + PeUtils.createData(program, addr, dt, log); + addr = addr.add(dt.getLength()); + for (int i = 0; i < rvas.length; i++) { + PeUtils.createData(program, addr, IBO32, log); + addr = addr.add(IBO32.getLength()); + } + for (BaseRelocation baseReloc : baseRelocs) { + baseReloc.markup(program, addr, isBinary, monitor, log, ntHeader); + addr = addr.add(baseReloc.getSizeOfBlock()); + } + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = + new StructureDataType("IMAGE_FUNCTION_OVERRIDE_DYNAMIC_RELOCATION", 0); + struct.add(IBO32, "OriginalRva", "RVA of original function"); + struct.add(DWORD, "BDDOffset", "Offset into the BDD region"); + struct.add(DWORD, "RvaSize", + "Size in bytes taken by RVAs. Must be multiple of sizeof(DWORD)."); + struct.add(DWORD, "BaseRelocSize", "Size in bytes taken by BaseRelocs"); + struct.setCategoryPath(new CategoryPath("/PE")); + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageFunctionOverrideHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageFunctionOverrideHeader.java new file mode 100644 index 0000000000..522d5d5959 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageFunctionOverrideHeader.java @@ -0,0 +1,116 @@ +/* ### + * 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.pe.dvrt; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.format.pe.NTHeader; +import ghidra.app.util.bin.format.pe.PeUtils; +import ghidra.app.util.importer.MessageLog; +import ghidra.program.model.address.Address; +import ghidra.program.model.data.*; +import ghidra.program.model.listing.Program; +import ghidra.program.model.mem.MemoryAccessException; +import ghidra.program.model.util.CodeUnitInsertionException; +import ghidra.util.exception.DuplicateNameException; +import ghidra.util.task.TaskMonitor; + +/** + * Represents a {@code IMAGE_FUNCTION_OVERRIDE_HEADER} structure + */ +public class ImageFunctionOverrideHeader extends AbstractImageDynamicRelocationHeader { + + private int funcOverrideSize; + + private List funcOverrideInfos = new ArrayList<>(); + private List bddInfos = new ArrayList<>(); + + /** + * Creates a new {@link ImageFunctionOverrideHeader} + * + * @param reader A {@link BinaryReader} that points to the start of the structure + * @param rva The relative virtual address of the structure + * @param dvrtEntrySize The size in bytes of this header's + * {@link ImageDynamicRelocation DVRT entry} + * @throws IOException if there was an IO-related error + */ + public ImageFunctionOverrideHeader(BinaryReader reader, long rva, int dvrtEntrySize) + throws IOException { + super(rva); + long origIndex = reader.getPointerIndex(); + + funcOverrideSize = reader.readNextInt(); + + long startIndex = reader.getPointerIndex(); + for (long i = startIndex; i < startIndex + funcOverrideSize; i = reader.getPointerIndex()) { + funcOverrideInfos + .add(new ImageFunctionOverrideDynamicRelocation(reader, rva + (i - origIndex))); + } + + int bddSize = dvrtEntrySize - 4 - funcOverrideSize; + startIndex = reader.getPointerIndex(); + for (long i = startIndex; i < startIndex + bddSize; i = reader.getPointerIndex()) { + bddInfos.add(new ImageBddInfo(reader, rva + (i - origIndex))); + } + } + + /** + * {@return the function override size} + */ + public int getFuncOverrideSize() { + return funcOverrideSize; + } + + /** + * {@return the {@link List} of {@link ImageFunctionOverrideDynamicRelocation}s + */ + public List getFuncOverrideInfo() { + return funcOverrideInfos; + } + + /** + * {@return the {@link List} of {@link ImageBddInfo}s} + */ + public List getBddInfo() { + return bddInfos; + } + + @Override + public void markup(Program program, boolean isBinary, TaskMonitor monitor, MessageLog log, + NTHeader ntHeader) throws DuplicateNameException, CodeUnitInsertionException, + IOException, MemoryAccessException { + Address imageBase = program.getImageBase(); + DataType dt = toDataType(); + PeUtils.createData(program, imageBase.add(rva), dt, log); + for (ImageFunctionOverrideDynamicRelocation info : funcOverrideInfos) { + info.markup(program, isBinary, monitor, log, ntHeader); + } + for (ImageBddInfo info : bddInfos) { + info.markup(program, isBinary, monitor, log, ntHeader); + } + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType("IMAGE_FUNCTION_OVERRIDE_HEADER", 0); + struct.add(DWORD, "FuncOverrideSize", null); + struct.setCategoryPath(new CategoryPath("/PE")); + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageImportControlTransfer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageImportControlTransfer.java new file mode 100644 index 0000000000..eb7f5db947 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageImportControlTransfer.java @@ -0,0 +1,115 @@ +/* ### + * 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.pe.dvrt; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.format.pe.NTHeader; +import ghidra.app.util.bin.format.pe.PeUtils; +import ghidra.app.util.importer.MessageLog; +import ghidra.program.model.address.Address; +import ghidra.program.model.data.*; +import ghidra.program.model.listing.Program; +import ghidra.program.model.mem.MemoryAccessException; +import ghidra.program.model.symbol.*; +import ghidra.program.model.util.CodeUnitInsertionException; +import ghidra.util.exception.DuplicateNameException; +import ghidra.util.task.TaskMonitor; + +/** + * Contains a list of {@link ImageImportControlTransferDynamicRelocation}s + */ +public class ImageImportControlTransfer extends AbstractImageDynamicRelocationHeader { + + private int virtualAddress; + private int sizeOfBlock; + private List relocs = new ArrayList<>(); + + /** + * Creates a new {@link ImageIndirControlTransfer} + * + * @param reader A {@link BinaryReader} that points to the start of the structure + * @param rva The relative virtual address of the structure + * @throws IOException if there was an IO-related error + */ + public ImageImportControlTransfer(BinaryReader reader, long rva) throws IOException { + super(rva); + long origIndex = reader.getPointerIndex(); + + virtualAddress = reader.readNextInt(); + sizeOfBlock = reader.readNextInt(); + + long startIndex = reader.getPointerIndex(); + for (long i = startIndex; i < origIndex + sizeOfBlock; i = reader.getPointerIndex()) { + relocs.add( + new ImageImportControlTransferDynamicRelocation(reader, rva + (i - origIndex))); + } + } + + /** + * {@return the virtual address} + */ + public int getVirualAddress() { + return virtualAddress; + } + + /** + * {@return the size of the block} + */ + public int getSizeOfBlock() { + return sizeOfBlock; + } + + /** + * {@return the {@link List} of {@link ImageImportControlTransferDynamicRelocation}s} + */ + public List getRelocs() { + return relocs; + } + + @Override + public void markup(Program program, boolean isBinary, TaskMonitor monitor, MessageLog log, + NTHeader ntHeader) throws DuplicateNameException, CodeUnitInsertionException, + IOException, MemoryAccessException { + ReferenceManager refMgr = program.getReferenceManager(); + Address imageBase = program.getImageBase(); + DataType dt = toDataType(); + Address addr = imageBase.add(rva); + PeUtils.createData(program, addr, dt, log); + addr = addr.add(dt.getLength()); + for (ImageImportControlTransferDynamicRelocation reloc : relocs) { + reloc.markup(program, isBinary, monitor, log, ntHeader); + int pageRelativeOffset = reloc.getPageRelativeOffset(); + if (pageRelativeOffset != 0) { + refMgr.addMemoryReference(addr, imageBase.add(virtualAddress + pageRelativeOffset), + RefType.DATA, SourceType.IMPORTED, 0); + } + addr = addr.add(reloc.toDataType().getLength()); + } + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType("IMAGE_IMPORT_CONTROL_TRANSFER", 0); + struct.add(IBO32, "VirtualAddress", null); + struct.add(DWORD, "SizeOfBlock", null); + struct.setCategoryPath(new CategoryPath("/PE")); + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageImportControlTransferDynamicRelocation.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageImportControlTransferDynamicRelocation.java new file mode 100644 index 0000000000..be9d02c890 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageImportControlTransferDynamicRelocation.java @@ -0,0 +1,109 @@ +/* ### + * 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.pe.dvrt; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.StructConverter; +import ghidra.app.util.bin.format.pe.*; +import ghidra.app.util.importer.MessageLog; +import ghidra.program.model.address.Address; +import ghidra.program.model.data.*; +import ghidra.program.model.listing.Program; +import ghidra.program.model.mem.MemoryAccessException; +import ghidra.program.model.util.CodeUnitInsertionException; +import ghidra.util.exception.DuplicateNameException; +import ghidra.util.task.TaskMonitor; + +/** + * Represents a {@code IMAGE_IMPORT_CONTROL_TRANSFER_DYNAMIC_RELOCATION} structure + */ +public class ImageImportControlTransferDynamicRelocation implements StructConverter, PeMarkupable { + + private int pageRelativeOffset; + private boolean indirectCall; + private int iatIndex; + + // TODO: IMAGE_IMPORT_CONTROL_TRANSFER_ARM64_RELOCATION has a different bitfield + + private long rva; + + /** + * Creates a new {@link ImageImportControlTransferDynamicRelocation} + * + * @param reader A {@link BinaryReader} that points to the start of the structure + * @param rva The relative virtual address of the structure + * {@link ImageDynamicRelocation DVRT entry} + * @throws IOException if there was an IO-related error + */ + public ImageImportControlTransferDynamicRelocation(BinaryReader reader, long rva) + throws IOException { + this.rva = rva; + + int bitfield = reader.readNextInt(); + pageRelativeOffset = bitfield & 0xfff; + indirectCall = ((bitfield >> 12) & 0x1) != 0; + iatIndex = (bitfield >> 13) & 0x7ffff; + } + + /** + * {@return the page relative offset} + */ + public int getPageRelativeOffset() { + return pageRelativeOffset; + } + + /** + * {@return whether or not it's an indirect call} + */ + public boolean isIndirectCall() { + return indirectCall; + } + + /** + * {@return the IAT index} + */ + public int getIatIndex() { + return iatIndex; + } + + @Override + public void markup(Program program, boolean isBinary, TaskMonitor monitor, MessageLog log, + NTHeader ntHeader) throws DuplicateNameException, CodeUnitInsertionException, + IOException, MemoryAccessException { + Address imageBase = program.getImageBase(); + DataType dt = toDataType(); + PeUtils.createData(program, imageBase.add(rva), dt, log); + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = + new StructureDataType("IMAGE_IMPORT_CONTROL_TRANSFER_DYNAMIC_RELOCATION", 0); + struct.setPackingEnabled(true); + try { + struct.addBitField(DWORD, 12, "PageRelativeOffset", null); + struct.addBitField(DWORD, 1, "IndirectCall", null); + struct.addBitField(DWORD, 19, "IATIndex", null); + } + catch (InvalidDataTypeException e) { + throw new IOException(e); + } + struct.setCategoryPath(new CategoryPath("/PE")); + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageIndirControlTransfer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageIndirControlTransfer.java new file mode 100644 index 0000000000..87d1c3f316 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageIndirControlTransfer.java @@ -0,0 +1,115 @@ +/* ### + * 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.pe.dvrt; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.format.pe.NTHeader; +import ghidra.app.util.bin.format.pe.PeUtils; +import ghidra.app.util.importer.MessageLog; +import ghidra.program.model.address.Address; +import ghidra.program.model.data.*; +import ghidra.program.model.listing.Program; +import ghidra.program.model.mem.MemoryAccessException; +import ghidra.program.model.symbol.*; +import ghidra.program.model.util.CodeUnitInsertionException; +import ghidra.util.exception.DuplicateNameException; +import ghidra.util.task.TaskMonitor; + +/** + * Contains a list of {@link ImageIndirControlTransferDynamicRelocation}s + */ +public class ImageIndirControlTransfer extends AbstractImageDynamicRelocationHeader { + + private int virtualAddress; + private int sizeOfBlock; + private List relocs = new ArrayList<>(); + + /** + * Creates a new {@link ImageIndirControlTransfer} + * + * @param reader A {@link BinaryReader} that points to the start of the structure + * @param rva The relative virtual address of the structure + * @throws IOException if there was an IO-related error + */ + public ImageIndirControlTransfer(BinaryReader reader, long rva) throws IOException { + super(rva); + long origIndex = reader.getPointerIndex(); + + virtualAddress = reader.readNextInt(); + sizeOfBlock = reader.readNextInt(); + + long startIndex = reader.getPointerIndex(); + for (long i = startIndex; i < origIndex + sizeOfBlock; i = reader.getPointerIndex()) { + relocs.add( + new ImageIndirControlTransferDynamicRelocation(reader, rva + (i - origIndex))); + } + } + + /** + * {@return the virtual address} + */ + public int getVirualAddress() { + return virtualAddress; + } + + /** + * {@return the size of the block} + */ + public int getSizeOfBlock() { + return sizeOfBlock; + } + + /** + * {@return the {@link List} of {@link ImageIndirControlTransferDynamicRelocation}s} + */ + public List getRelocs() { + return relocs; + } + + @Override + public void markup(Program program, boolean isBinary, TaskMonitor monitor, MessageLog log, + NTHeader ntHeader) throws DuplicateNameException, CodeUnitInsertionException, + IOException, MemoryAccessException { + ReferenceManager refMgr = program.getReferenceManager(); + Address imageBase = program.getImageBase(); + DataType dt = toDataType(); + Address addr = imageBase.add(rva); + PeUtils.createData(program, addr, dt, log); + addr = addr.add(dt.getLength()); + for (ImageIndirControlTransferDynamicRelocation reloc : relocs) { + reloc.markup(program, isBinary, monitor, log, ntHeader); + int pageRelativeOffset = reloc.getPageRelativeOffset(); + if (pageRelativeOffset != 0) { + refMgr.addMemoryReference(addr, imageBase.add(virtualAddress + pageRelativeOffset), + RefType.DATA, SourceType.IMPORTED, 0); + } + addr = addr.add(reloc.toDataType().getLength()); + } + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType("IMAGE_INDIR_CONTROL_TRANSFER", 0); + struct.add(IBO32, "VirtualAddress", null); + struct.add(DWORD, "SizeOfBlock", null); + struct.setCategoryPath(new CategoryPath("/PE")); + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageIndirControlTransferDynamicRelocation.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageIndirControlTransferDynamicRelocation.java new file mode 100644 index 0000000000..a60afc8f1f --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageIndirControlTransferDynamicRelocation.java @@ -0,0 +1,127 @@ +/* ### + * 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.pe.dvrt; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.StructConverter; +import ghidra.app.util.bin.format.pe.*; +import ghidra.app.util.importer.MessageLog; +import ghidra.program.model.address.Address; +import ghidra.program.model.data.*; +import ghidra.program.model.listing.Program; +import ghidra.program.model.mem.MemoryAccessException; +import ghidra.program.model.util.CodeUnitInsertionException; +import ghidra.util.exception.DuplicateNameException; +import ghidra.util.task.TaskMonitor; + +/** + * Represents a {@code IMAGE_INDIR_CONTROL_TRANSFER_DYNAMIC_RELOCATION} structure + */ +public class ImageIndirControlTransferDynamicRelocation implements StructConverter, PeMarkupable { + + private int pageRelativeOffset; + private boolean indirectCall; + private boolean rexWPrefix; + private boolean cfgCheck; + private int reserved; + + private long rva; + + /** + * Creates a new {@link ImageIndirControlTransferDynamicRelocation} + * + * @param reader A {@link BinaryReader} that points to the start of the structure + * @param rva The relative virtual address of the structure + * @throws IOException if there was an IO-related error + */ + public ImageIndirControlTransferDynamicRelocation(BinaryReader reader, long rva) + throws IOException { + this.rva = rva; + + int bitfield = reader.readNextUnsignedShort(); + pageRelativeOffset = bitfield & 0xfff; + indirectCall = ((bitfield >> 12) & 0x1) != 0; + rexWPrefix = ((bitfield >> 13) & 0x1) != 0; + cfgCheck = ((bitfield >> 14) & 0x1) != 0; + reserved = (bitfield >> 15) & 0x1; + } + + /** + * {@return the page relative offset} + */ + public int getPageRelativeOffset() { + return pageRelativeOffset; + } + + /** + * {@return whether or not it's an indirect call} + */ + public boolean isIndirectCall() { + return indirectCall; + } + + /** + * {@return whether or not there is a rexw prefix} + */ + public boolean isRexWPrefix() { + return rexWPrefix; + } + + /** + * {@return whether or not it's a CFG check} + */ + public boolean isCfgCheck() { + return cfgCheck; + } + + /** + * {@return the reserved bit} + */ + public int getReserved() { + return reserved; + } + + @Override + public void markup(Program program, boolean isBinary, TaskMonitor monitor, MessageLog log, + NTHeader ntHeader) throws DuplicateNameException, CodeUnitInsertionException, + IOException, MemoryAccessException { + Address imageBase = program.getImageBase(); + DataType dt = toDataType(); + PeUtils.createData(program, imageBase.add(rva), dt, log); + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = + new StructureDataType("IMAGE_INDIR_CONTROL_TRANSFER_DYNAMIC_RELOCATION", 0); + struct.setPackingEnabled(true); + try { + struct.addBitField(WORD, 12, "PageRelativeOffset", null); + struct.addBitField(WORD, 1, "IndirectCall", null); + struct.addBitField(WORD, 1, "RexWPrefix", null); + struct.addBitField(WORD, 1, "CfgCheck", null); + struct.addBitField(WORD, 1, "Reserved", null); + } + catch (InvalidDataTypeException e) { + throw new IOException(e); + } + struct.setCategoryPath(new CategoryPath("/PE")); + return struct; + } + +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageSwitchtableBranch.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageSwitchtableBranch.java new file mode 100644 index 0000000000..d98ee5634c --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageSwitchtableBranch.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.pe.dvrt; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.format.pe.NTHeader; +import ghidra.app.util.bin.format.pe.PeUtils; +import ghidra.app.util.importer.MessageLog; +import ghidra.program.model.address.Address; +import ghidra.program.model.data.*; +import ghidra.program.model.listing.Program; +import ghidra.program.model.mem.MemoryAccessException; +import ghidra.program.model.symbol.*; +import ghidra.program.model.util.CodeUnitInsertionException; +import ghidra.util.exception.DuplicateNameException; +import ghidra.util.task.TaskMonitor; + +/** + * Contains a list of {@link ImageSwitchtableBranchDynamicRelocation}s + */ +public class ImageSwitchtableBranch extends AbstractImageDynamicRelocationHeader { + + private int virtualAddress; + private int sizeOfBlock; + private List relocs = new ArrayList<>(); + + /** + * Creates a new {@link ImageSwitchtableBranch} + * + * @param reader A {@link BinaryReader} that points to the start of the structure + * @param rva The relative virtual address of the structure + * @throws IOException if there was an IO-related error + */ + public ImageSwitchtableBranch(BinaryReader reader, long rva) throws IOException { + super(rva); + long origIndex = reader.getPointerIndex(); + + virtualAddress = reader.readNextInt(); + sizeOfBlock = reader.readNextInt(); + + long startIndex = reader.getPointerIndex(); + for (long i = startIndex; i < origIndex + sizeOfBlock; i = reader.getPointerIndex()) { + relocs.add(new ImageSwitchtableBranchDynamicRelocation(reader, rva + (i - origIndex))); + } + } + + /** + * {@return the virtual address} + */ + public int getVirualAddress() { + return virtualAddress; + } + + /** + * {@return the size of the block} + */ + public int getSizeOfBlock() { + return sizeOfBlock; + } + + /** + * {@return the {@link List} of {@link ImageIndirControlTransferDynamicRelocation}s} + */ + public List getRelocs() { + return relocs; + } + + @Override + public void markup(Program program, boolean isBinary, TaskMonitor monitor, MessageLog log, + NTHeader ntHeader) throws DuplicateNameException, CodeUnitInsertionException, + IOException, MemoryAccessException { + ReferenceManager refMgr = program.getReferenceManager(); + Address imageBase = program.getImageBase(); + DataType dt = toDataType(); + Address addr = imageBase.add(rva); + PeUtils.createData(program, addr, dt, log); + addr = addr.add(dt.getLength()); + for (ImageSwitchtableBranchDynamicRelocation reloc : relocs) { + reloc.markup(program, isBinary, monitor, log, ntHeader); + int pageRelativeOffset = reloc.getPageRelativeOffset(); + if (pageRelativeOffset != 0) { + refMgr.addMemoryReference(addr, imageBase.add(virtualAddress + pageRelativeOffset), + RefType.DATA, SourceType.IMPORTED, 0); + } + addr = addr.add(reloc.toDataType().getLength()); + } + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = new StructureDataType("IMAGE_SWITCHTABLE_BRANCH", 0); + struct.add(IBO32, "VirtualAddress", null); + struct.add(DWORD, "SizeOfBlock", null); + struct.setCategoryPath(new CategoryPath("/PE")); + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageSwitchtableBranchDynamicRelocation.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageSwitchtableBranchDynamicRelocation.java new file mode 100644 index 0000000000..f5d23395c4 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageSwitchtableBranchDynamicRelocation.java @@ -0,0 +1,97 @@ +/* ### + * 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.pe.dvrt; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.StructConverter; +import ghidra.app.util.bin.format.pe.*; +import ghidra.app.util.importer.MessageLog; +import ghidra.program.model.address.Address; +import ghidra.program.model.data.*; +import ghidra.program.model.listing.Program; +import ghidra.program.model.mem.MemoryAccessException; +import ghidra.program.model.util.CodeUnitInsertionException; +import ghidra.util.exception.DuplicateNameException; +import ghidra.util.task.TaskMonitor; + +/** + * Represents a {@code IMAGE_SWITCHTABLE_BRANCH_DYNAMIC_RELOCATION} structure + */ +public class ImageSwitchtableBranchDynamicRelocation implements StructConverter, PeMarkupable { + + private int pageRelativeOffset; + private int registerNumber; + + private long rva; + + /** + * Creates a new {@link ImageSwitchtableBranchDynamicRelocation} + * + * @param reader A {@link BinaryReader} that points to the start of the structure + * @param rva The relative virtual address of the structure + * {@link ImageDynamicRelocation DVRT entry} + * @throws IOException if there was an IO-related error + */ + public ImageSwitchtableBranchDynamicRelocation(BinaryReader reader, long rva) + throws IOException { + this.rva = rva; + + int bitfield = reader.readNextUnsignedShort(); + pageRelativeOffset = bitfield & 0xfff; + registerNumber = (bitfield >> 12) & 0xf; + } + + /** + * {@return the page relative offset} + */ + public int getPageRelativeOffset() { + return pageRelativeOffset; + } + + /** + * {@return the register number} + */ + public int getRegisterNumber() { + return registerNumber; + } + + @Override + public void markup(Program program, boolean isBinary, TaskMonitor monitor, MessageLog log, + NTHeader ntHeader) throws DuplicateNameException, CodeUnitInsertionException, + IOException, MemoryAccessException { + Address imageBase = program.getImageBase(); + DataType dt = toDataType(); + PeUtils.createData(program, imageBase.add(rva), dt, log); + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + StructureDataType struct = + new StructureDataType("IMAGE_SWITCHTABLE_BRANCH_DYNAMIC_RELOCATION", 0); + struct.setPackingEnabled(true); + try { + struct.addBitField(WORD, 12, "PageRelativeOffset", null); + struct.addBitField(WORD, 4, "RegisterNumber", null); + } + catch (InvalidDataTypeException e) { + throw new IOException(e); + } + struct.setCategoryPath(new CategoryPath("/PE")); + return struct; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageUnsupportedRelocationHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageUnsupportedRelocationHeader.java new file mode 100644 index 0000000000..d752445e0f --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/dvrt/ImageUnsupportedRelocationHeader.java @@ -0,0 +1,73 @@ +/* ### + * 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.pe.dvrt; + +import java.io.IOException; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.format.pe.NTHeader; +import ghidra.app.util.bin.format.pe.PeUtils; +import ghidra.app.util.importer.MessageLog; +import ghidra.program.model.address.Address; +import ghidra.program.model.data.ArrayDataType; +import ghidra.program.model.data.DataType; +import ghidra.program.model.listing.Program; +import ghidra.program.model.mem.MemoryAccessException; +import ghidra.program.model.util.CodeUnitInsertionException; +import ghidra.util.exception.DuplicateNameException; +import ghidra.util.task.TaskMonitor; + +/** + * Represents an unsupported dynamic value relocation header + */ +public class ImageUnsupportedRelocationHeader extends AbstractImageDynamicRelocationHeader { + + private byte[] data; + + /** + * Creates a new {@link ImageUnsupportedRelocationHeader} + * + * @param reader A {@link BinaryReader} that points to the start of the structure + * @param rva The relative virtual address of the structure + * @param size The size in bytes of this header's data + * @throws IOException if there was an IO-related error + */ + public ImageUnsupportedRelocationHeader(BinaryReader reader, long rva, int size) + throws IOException { + super(rva); + data = reader.readNextByteArray(size); + } + + /** + * {@return the data associated with the unknown header} + */ + public byte[] getData() { + return data; + } + + @Override + public void markup(Program program, boolean isBinary, TaskMonitor monitor, MessageLog log, + NTHeader ntHeader) throws DuplicateNameException, CodeUnitInsertionException, + IOException, MemoryAccessException { + Address imageBase = program.getImageBase(); + PeUtils.createData(program, imageBase.add(rva), toDataType(), log); + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + return new ArrayDataType(BYTE, data.length, 1); + } +}