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);
+ }
+}