diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/ImageRuntimeFunctionEntries.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/ImageRuntimeFunctionEntries.java index b045da0127..36084aaf6c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/ImageRuntimeFunctionEntries.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/ImageRuntimeFunctionEntries.java @@ -19,10 +19,12 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; -import ghidra.app.util.bin.StructConverter; import ghidra.app.util.bin.format.FactoryBundledWithBinaryReader; -import ghidra.program.model.data.*; -import ghidra.util.exception.AssertException; +import ghidra.program.model.address.Address; +import ghidra.program.model.data.DataType; +import ghidra.program.model.data.DataUtilities; +import ghidra.program.model.listing.Program; +import ghidra.program.model.util.CodeUnitInsertionException; import ghidra.util.exception.DuplicateNameException; /** @@ -65,12 +67,7 @@ import ghidra.util.exception.DuplicateNameException; * } UNWIND_INFO, *PUNWIND_INFO; */ public class ImageRuntimeFunctionEntries { - private final static int UNWIND_INFO_VERSION_BITMASK = 0x07; - private final static int UNWIND_INFO_FLAGS_SHIFT = 0x03; - private final static int UNWIND_INFO_FRAME_REGISTER_MASK = 0x0F; - private final static int UNWIND_INFO_FRAME_OFFSET_SHIFT = 0x04; - private final static int UNWIND_INFO_OPCODE_MASK = 0x0F; - private final static int UNWIND_INFO_OPCODE_INFO_SHIFT = 0x04; + private final static int UNWIND_INFO_SIZE = 0x0C; List<_IMAGE_RUNTIME_FUNCTION_ENTRY> functionEntries = new ArrayList<>(); @@ -132,7 +129,8 @@ public class ImageRuntimeFunctionEntries { // Read and process the UNWIND_INFO structures the RUNTIME_INFO // structures point to - entry.unwindInfo = readUnwindInfo(reader, entry.unwindInfoAddressOrData, ntHeader); + entry.unwindInfo = + PEx64UnwindInfo.readUnwindInfo(reader, entry.unwindInfoAddressOrData, ntHeader); functionEntries.add(entry); } @@ -140,317 +138,32 @@ public class ImageRuntimeFunctionEntries { reader.setPointerIndex(origIndex); } - private UNWIND_INFO readUnwindInfo(FactoryBundledWithBinaryReader reader, long offset, - NTHeader ntHeader) throws IOException { - long origIndex = reader.getPointerIndex(); - - long pointer = ntHeader.rvaToPointer(offset); - UNWIND_INFO unwindInfo = new UNWIND_INFO(pointer); - - if (pointer < 0) { - return unwindInfo; - } - - reader.setPointerIndex(pointer); - byte splitByte = reader.readNextByte(); - unwindInfo.version = (byte) (splitByte & UNWIND_INFO_VERSION_BITMASK); - unwindInfo.flags = (byte) (splitByte >> UNWIND_INFO_FLAGS_SHIFT); - - unwindInfo.sizeOfProlog = reader.readNextUnsignedByte(); - unwindInfo.countOfUnwindCodes = reader.readNextUnsignedByte(); - - splitByte = reader.readNextByte(); - unwindInfo.frameRegister = (byte) (splitByte & UNWIND_INFO_FRAME_REGISTER_MASK); - unwindInfo.frameOffset = (byte) (splitByte >> UNWIND_INFO_FRAME_OFFSET_SHIFT); - - unwindInfo.unwindCodes = new UNWIND_CODE[unwindInfo.countOfUnwindCodes]; - for (int i = 0; i < unwindInfo.countOfUnwindCodes; i++) { - UNWIND_CODE code = new UNWIND_CODE(); - code.offsetInProlog = reader.readNextByte(); - - int opCodeData = reader.readNextUnsignedByte(); - code.opCode = UNWIND_CODE_OPCODE.fromInt((opCodeData & UNWIND_INFO_OPCODE_MASK)); - code.opInfoRegister = - UNWIND_CODE_OPINFO_REGISTER.fromInt(opCodeData >> UNWIND_INFO_OPCODE_INFO_SHIFT); - - unwindInfo.unwindCodes[i] = code; - } - - // You can have an exception handler or you can have chained exception handling info only. - if (unwindInfo.hasExceptionHandler() || unwindInfo.hasUnwindHandler()) { - unwindInfo.exceptionHandlerFunction = reader.readNextInt(); - } - else if (unwindInfo.hasChainedUnwindInfo()) { - unwindInfo.unwindHandlerChainInfo = new _IMAGE_RUNTIME_FUNCTION_ENTRY(); - unwindInfo.unwindHandlerChainInfo.beginAddress = reader.readNextInt(); - unwindInfo.unwindHandlerChainInfo.endAddress = reader.readNextInt(); - unwindInfo.unwindHandlerChainInfo.unwindInfoAddressOrData = reader.readNextInt(); - - // Follow the chain to the referenced UNWIND_INFO structure until we - // get to the end - unwindInfo.unwindHandlerChainInfo.unwindInfo = readUnwindInfo(reader, - unwindInfo.unwindHandlerChainInfo.unwindInfoAddressOrData, ntHeader); - } - - reader.setPointerIndex(origIndex); - - return unwindInfo; - } - public List<_IMAGE_RUNTIME_FUNCTION_ENTRY> getRuntimeFunctionEntries() { return functionEntries; } - public class _IMAGE_RUNTIME_FUNCTION_ENTRY { - public long beginAddress; - public long endAddress; - public long unwindInfoAddressOrData; - public UNWIND_INFO unwindInfo; - } + // FIXME: change name to conform to Java naming standards + // FIXME: If public visibility is required improved member protection is needed + public static class _IMAGE_RUNTIME_FUNCTION_ENTRY { + long beginAddress; + long endAddress; + long unwindInfoAddressOrData; + PEx64UnwindInfo unwindInfo; - public enum UNWIND_CODE_OPCODE { - UWOP_PUSH_NONVOL(0x00), - UWOP_ALLOC_LARGE(0x01), - UWOP_ALLOC_SMALL(0x02), - UWOP_SET_FPREG(0x03), - UWOP_SAVE_NONVOL(0x04), - UWOP_SAVE_NONVOL_FAR(0x05), - UWOP_SAVE_XMM(0x06), - UWOP_SAVE_XMM_FAR(0x07), - UWOP_SAVE_XMM128(0x08), - UWOP_SAVE_XMM128_FAR(0x09), - UWOP_PUSH_MACHFRAME(0x0A); + public void createData(Program program) { + if (unwindInfoAddressOrData > 0) { + try { + DataType dt = unwindInfo.toDataType(); + Address start = program.getImageBase().add(unwindInfoAddressOrData); - private final int id; - - UNWIND_CODE_OPCODE(int value) { - id = value; - } - - public int id() { - return id; - } - - public static UNWIND_CODE_OPCODE fromInt(int id) { - UNWIND_CODE_OPCODE[] values = UNWIND_CODE_OPCODE.values(); - for (UNWIND_CODE_OPCODE value : values) { - if (value.id == id) { - return value; + DataUtilities.createData(program, start, dt, dt.getLength(), true, + DataUtilities.ClearDataMode.CHECK_FOR_SPACE); + } + catch (CodeUnitInsertionException | DuplicateNameException | IOException e) { + // ignore } } - return null; } } - public enum UNWIND_CODE_OPINFO_REGISTER { - UNWIND_OPINFO_REGISTER_RAX(0x00), - UNWIND_OPINFO_REGISTER_RCX(0x01), - UNWIND_OPINFO_REGISTER_RDX(0x02), - UNWIND_OPINFO_REGISTER_RBX(0x03), - UNWIND_OPINFO_REGISTER_RSP(0x04), - UNWIND_OPINFO_REGISTER_RBP(0x05), - UNWIND_OPINFO_REGISTER_RSI(0x06), - UNWIND_OPINFO_REGISTER_RDI(0x07), - UNWIND_OPINFO_REGISTER_R8(0x08), - UNWIND_OPINFO_REGISTER_R9(0x09), - UNWIND_OPINFO_REGISTER_R10(0x0A), - UNWIND_OPINFO_REGISTER_R11(0x0B), - UNWIND_OPINFO_REGISTER_R12(0x0C), - UNWIND_OPINFO_REGISTER_R13(0x0D), - UNWIND_OPINFO_REGISTER_R14(0x0E), - UNWIND_OPINFO_REGISTER_R15(0x0F); - - private final int id; - - UNWIND_CODE_OPINFO_REGISTER(int value) { - id = value; - } - - public int id() { - return id; - } - - public static UNWIND_CODE_OPINFO_REGISTER fromInt(int id) { - UNWIND_CODE_OPINFO_REGISTER[] values = UNWIND_CODE_OPINFO_REGISTER.values(); - for (UNWIND_CODE_OPINFO_REGISTER value : values) { - if (value.id == id) { - return value; - } - } - return null; - } - } - - public class UNWIND_CODE { - public byte offsetInProlog; - public UNWIND_CODE_OPCODE opCode; - public UNWIND_CODE_OPINFO_REGISTER opInfoRegister; - } - - public class UNWIND_INFO implements StructConverter { - private static final String NAME = "UNWIND_INFO"; - - private final static int UNW_FLAG_NHANDLER = 0x0; - private final static int UNW_FLAG_EHANDLER = 0x1; - private final static int UNW_FLAG_UHANDLER = 0x2; - private final static int UNW_FLAG_CHAININFO = 0x4; - - private final static int UNWIND_VERSION_FIELD_LENGTH = 0x03; - private final static int UNWIND_FLAGS_FIELD_LENGTH = 0x05; - private final static int UNWIND_FRAME_REGISTER_LENGTH = 0x04; - private final static int UNWIND_FRAME_OFFSET_LENGTH = 0x04; - private final static int UNWIND_OP_FIELD_LENGTH = 0x04; - private final static int UNWIND_OP_INFO_FIELD_LENGTH = 0x04; - - byte version; - byte flags; - int sizeOfProlog; - int countOfUnwindCodes; - byte frameRegister; - byte frameOffset; - UNWIND_CODE[] unwindCodes; - int exceptionHandlerFunction; - _IMAGE_RUNTIME_FUNCTION_ENTRY unwindHandlerChainInfo; - - long startOffset; - - public UNWIND_INFO(long offset) { - startOffset = offset; - } - - @Override - public DataType toDataType() throws DuplicateNameException, IOException { - - StructureDataType struct = new StructureDataType(NAME + "_" + startOffset, 0); - struct.setPackingEnabled(true); - try { - struct.addBitField(BYTE, UNWIND_VERSION_FIELD_LENGTH, "Version", null); - struct.addBitField(defineFlagsEnum(), UNWIND_FLAGS_FIELD_LENGTH, "Flags", null); - struct.add(BYTE, "SizeOfProlog", null); - struct.add(BYTE, "CountOfUnwindCodes", null); - struct.addBitField(BYTE, UNWIND_FRAME_REGISTER_LENGTH, "FrameRegister", null); - struct.addBitField(BYTE, UNWIND_FRAME_OFFSET_LENGTH, "FrameOffset", null); - - if (countOfUnwindCodes > 0) { - ArrayDataType unwindInfoArray = - new ArrayDataType(defineUnwindCodeStructure(), countOfUnwindCodes, -1); - struct.add(unwindInfoArray, "UnwindCodes", null); - } - - } - catch (InvalidDataTypeException e) { - throw new AssertException(e); // should never happen with byte bit-fields - } - - if (hasExceptionHandler() || hasUnwindHandler()) { - struct.add(IBO32, "ExceptionHandler", null); - if (hasUnwindHandler()) { - struct.setFlexibleArrayComponent(UnsignedLongDataType.dataType, "ExceptionData", - null); - } - } - else if (hasChainedUnwindInfo()) { - struct.add(IBO32, "FunctionStartAddress", null); - struct.add(IBO32, "FunctionEndAddress", null); - struct.add(IBO32, "FunctionUnwindInfoAddress", null); - } - - return struct; - } - - public boolean hasExceptionHandler() { - return (flags & UNW_FLAG_EHANDLER) == UNW_FLAG_EHANDLER; - } - - public boolean hasUnwindHandler() { - return (flags & UNW_FLAG_UHANDLER) == UNW_FLAG_UHANDLER; - } - - public boolean hasChainedUnwindInfo() { - return (flags & UNW_FLAG_CHAININFO) == UNW_FLAG_CHAININFO; - } - - private EnumDataType defineFlagsEnum() { - EnumDataType flagsField = new EnumDataType("UNW_FLAGS", 1); - flagsField.add("UNW_FLAG_NHANDLER", UNW_FLAG_NHANDLER); - flagsField.add("UNW_FLAG_EHANDLER", UNW_FLAG_EHANDLER); - flagsField.add("UNW_FLAG_UHANDLER", UNW_FLAG_UHANDLER); - flagsField.add("UNW_FLAG_CHAININFO", UNW_FLAG_CHAININFO); - return flagsField; - } - - private Structure defineUnwindCodeStructure() { - StructureDataType unwindCode = new StructureDataType("UnwindCode", 0); - unwindCode.setPackingEnabled(true); - try { - unwindCode.add(BYTE, "OffsetInProlog", null); - unwindCode.addBitField(defineUnwindOpCodeField(), UNWIND_OP_FIELD_LENGTH, - "UnwindOpCode", null); - unwindCode.addBitField(defineUnwindCodeRegisterField(), UNWIND_OP_INFO_FIELD_LENGTH, - "OpInfo", null); - } - catch (InvalidDataTypeException e) { - throw new AssertException(e); // should never happen with byte bit-fields - } - return unwindCode; - } - - private EnumDataType defineUnwindOpCodeField() { - EnumDataType unwindOpCodeField = new EnumDataType("UNWIND_CODE_OPCODE", 1); - unwindOpCodeField.add("UWOP_PUSH_NONVOL", UNWIND_CODE_OPCODE.UWOP_PUSH_NONVOL.id); - unwindOpCodeField.add("UWOP_ALLOC_LARGE", UNWIND_CODE_OPCODE.UWOP_ALLOC_LARGE.id); - unwindOpCodeField.add("UWOP_ALLOC_SMALL", UNWIND_CODE_OPCODE.UWOP_ALLOC_SMALL.id); - unwindOpCodeField.add("UWOP_SET_FPREG", UNWIND_CODE_OPCODE.UWOP_SET_FPREG.id); - unwindOpCodeField.add("UWOP_SAVE_NONVOL", UNWIND_CODE_OPCODE.UWOP_SAVE_NONVOL.id); - unwindOpCodeField.add("UWOP_SAVE_NONVOL_FAR", - UNWIND_CODE_OPCODE.UWOP_SAVE_NONVOL_FAR.id); - unwindOpCodeField.add("UWOP_SAVE_XMM", UNWIND_CODE_OPCODE.UWOP_SAVE_XMM.id); - unwindOpCodeField.add("UWOP_SAVE_XMM_FAR", UNWIND_CODE_OPCODE.UWOP_SAVE_XMM_FAR.id); - unwindOpCodeField.add("UWOP_SAVE_XMM128", UNWIND_CODE_OPCODE.UWOP_SAVE_XMM128.id); - unwindOpCodeField.add("UWOP_SAVE_XMM128_FAR", - UNWIND_CODE_OPCODE.UWOP_SAVE_XMM128_FAR.id); - unwindOpCodeField.add("UWOP_PUSH_MACHFRAME", UNWIND_CODE_OPCODE.UWOP_PUSH_MACHFRAME.id); - - return unwindOpCodeField; - } - - private EnumDataType defineUnwindCodeRegisterField() { - EnumDataType unwindCodeRegisterField = - new EnumDataType("UNWIND_CODE_OPINFO_REGISTER", 1); - unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_RAX", - UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_RAX.id); - unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_RCX", - UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_RCX.id); - unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_RDX", - UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_RDX.id); - unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_RBX", - UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_RBX.id); - unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_RSP", - UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_RSP.id); - unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_RBP", - UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_RBP.id); - unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_RSI", - UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_RSI.id); - unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_RDI", - UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_RDI.id); - unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_R8", - UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_R8.id); - unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_R9", - UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_R9.id); - unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_R10", - UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_R10.id); - unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_R11", - UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_R11.id); - unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_R12", - UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_R12.id); - unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_R13", - UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_R13.id); - unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_R14", - UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_R14.id); - unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_R15", - UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_R15.id); - - return unwindCodeRegisterField; - } - } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/PEx64UnwindInfo.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/PEx64UnwindInfo.java new file mode 100644 index 0000000000..5796ed71d3 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/PEx64UnwindInfo.java @@ -0,0 +1,219 @@ +/* ### + * 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; + +import java.io.IOException; + +import ghidra.app.util.bin.StructConverter; +import ghidra.app.util.bin.format.FactoryBundledWithBinaryReader; +import ghidra.app.util.bin.format.pe.ImageRuntimeFunctionEntries._IMAGE_RUNTIME_FUNCTION_ENTRY; +import ghidra.program.model.data.DataType; +import ghidra.util.exception.DuplicateNameException; + +// TODO: If public visibility is required improved member protection is needed +class PEx64UnwindInfo implements StructConverter { + + final static int UNW_FLAG_NHANDLER = 0x0; + final static int UNW_FLAG_EHANDLER = 0x1; + final static int UNW_FLAG_UHANDLER = 0x2; + final static int UNW_FLAG_CHAININFO = 0x4; + + private final static int UNWIND_INFO_VERSION_MASK = 0x07; + private final static int UNWIND_INFO_FLAGS_MASK = 0x1F; + private final static int UNWIND_INFO_FLAGS_SHIFT = 0x03; + private final static int UNWIND_INFO_FRAME_REGISTER_MASK = 0x0F; + private final static int UNWIND_INFO_FRAME_OFFSET_SHIFT = 0x04; + private final static int UNWIND_INFO_OPCODE_MASK = 0x0F; + private final static int UNWIND_INFO_OPCODE_INFO_SHIFT = 0x04; + private final static int UNWIND_INFO_OPCODE_INFO_MASK = 0x0F; + + byte version; + byte flags; + int sizeOfProlog; + int countOfUnwindCodes; + byte frameRegister; + byte frameOffset; + UNWIND_CODE[] unwindCodes; + int exceptionHandlerFunction; + _IMAGE_RUNTIME_FUNCTION_ENTRY unwindHandlerChainInfo; + + long startOffset; + + public PEx64UnwindInfo(long offset) { + startOffset = offset; + } + + @Override + public DataType toDataType() throws DuplicateNameException, IOException { + return PEx64UnwindInfoDataType.INSTANCE; + } + + public boolean hasExceptionHandler() { + return (flags & UNW_FLAG_EHANDLER) == UNW_FLAG_EHANDLER; + } + + public boolean hasUnwindHandler() { + return (flags & UNW_FLAG_UHANDLER) == UNW_FLAG_UHANDLER; + } + + public boolean hasChainedUnwindInfo() { + return (flags & UNW_FLAG_CHAININFO) == UNW_FLAG_CHAININFO; + } + + // FIXME: change name to conform to Java naming standards + public static enum UNWIND_CODE_OPCODE { + UWOP_PUSH_NONVOL(0x00), + UWOP_ALLOC_LARGE(0x01), + UWOP_ALLOC_SMALL(0x02), + UWOP_SET_FPREG(0x03), + UWOP_SAVE_NONVOL(0x04), + UWOP_SAVE_NONVOL_FAR(0x05), + UWOP_SAVE_XMM(0x06), + UWOP_SAVE_XMM_FAR(0x07), + UWOP_SAVE_XMM128(0x08), + UWOP_SAVE_XMM128_FAR(0x09), + UWOP_PUSH_MACHFRAME(0x0A); + + public final int id; + + UNWIND_CODE_OPCODE(int value) { + id = value; + } + + public int id() { + return id; + } + + public static UNWIND_CODE_OPCODE fromInt(int id) { + UNWIND_CODE_OPCODE[] values = UNWIND_CODE_OPCODE.values(); + for (UNWIND_CODE_OPCODE value : values) { + if (value.id == id) { + return value; + } + } + return null; + } + } + + // FIXME: change name to conform to Java naming standards +// public static enum UNWIND_INFO_REGISTER { +// RAX(0x00), +// RCX(0x01), +// RDX(0x02), +// RBX(0x03), +// RSP(0x04), +// RBP(0x05), +// RSI(0x06), +// RDI(0x07), +// R8(0x08), +// R9(0x09), +// R10(0x0A), +// R11(0x0B), +// R12(0x0C), +// R13(0x0D), +// R14(0x0E), +// R15(0x0F); +// +// public final int id; +// +// UNWIND_INFO_REGISTER(int value) { +// id = value; +// } +// +// public int id() { +// return id; +// } +// +// public static UNWIND_INFO_REGISTER fromInt(int id) { +// UNWIND_INFO_REGISTER[] values = UNWIND_INFO_REGISTER.values(); +// for (UNWIND_INFO_REGISTER value : values) { +// if (value.id == id) { +// return value; +// } +// } +// return null; +// } +// } + + // FIXME: change name to conform to Java naming standards + // TODO: If public visibility is required improved member protection is needed + static class UNWIND_CODE { + byte offsetInProlog; + UNWIND_CODE_OPCODE opCode; + byte opInfo; // encoding varies based upon opCode + } + + static PEx64UnwindInfo readUnwindInfo(FactoryBundledWithBinaryReader reader, + long offset, NTHeader ntHeader) throws IOException { + long origIndex = reader.getPointerIndex(); + + long pointer = ntHeader.rvaToPointer(offset); + PEx64UnwindInfo unwindInfo = new PEx64UnwindInfo(pointer); + + if (pointer < 0) { + return unwindInfo; + } + + reader.setPointerIndex(pointer); + byte splitByte = reader.readNextByte(); + unwindInfo.version = (byte) (splitByte & UNWIND_INFO_VERSION_MASK); + unwindInfo.flags = (byte) ((splitByte >> UNWIND_INFO_FLAGS_SHIFT) & UNWIND_INFO_FLAGS_MASK); + + unwindInfo.sizeOfProlog = reader.readNextUnsignedByte(); + unwindInfo.countOfUnwindCodes = reader.readNextUnsignedByte(); + + splitByte = reader.readNextByte(); + unwindInfo.frameRegister = (byte) (splitByte & UNWIND_INFO_FRAME_REGISTER_MASK); + unwindInfo.frameOffset = (byte) (splitByte >> UNWIND_INFO_FRAME_OFFSET_SHIFT); + + unwindInfo.unwindCodes = new UNWIND_CODE[unwindInfo.countOfUnwindCodes]; + for (int i = 0; i < unwindInfo.countOfUnwindCodes; i++) { + UNWIND_CODE code = new UNWIND_CODE(); + code.offsetInProlog = reader.readNextByte(); + + int opCodeData = reader.readNextUnsignedByte(); + code.opCode = UNWIND_CODE_OPCODE.fromInt((opCodeData & UNWIND_INFO_OPCODE_MASK)); + code.opInfo = (byte) ((opCodeData >> UNWIND_INFO_OPCODE_INFO_SHIFT) & + UNWIND_INFO_OPCODE_INFO_MASK); +// code.opInfoRegister = +// UNWIND_CODE_OPINFO_REGISTER.fromInt(opCodeData >> UNWIND_INFO_OPCODE_INFO_SHIFT); + + unwindInfo.unwindCodes[i] = code; + } + + // You can have an exception handler or you can have chained exception handling info only. + if (unwindInfo.hasExceptionHandler() || unwindInfo.hasUnwindHandler()) { + unwindInfo.exceptionHandlerFunction = reader.readNextInt(); + } + else if (unwindInfo.hasChainedUnwindInfo()) { + unwindInfo.unwindHandlerChainInfo = + new _IMAGE_RUNTIME_FUNCTION_ENTRY(); + unwindInfo.unwindHandlerChainInfo.beginAddress = reader.readNextInt(); + unwindInfo.unwindHandlerChainInfo.endAddress = reader.readNextInt(); + unwindInfo.unwindHandlerChainInfo.unwindInfoAddressOrData = reader.readNextInt(); + + // Follow the chain to the referenced UNWIND_INFO structure until we + // get to the end + unwindInfo.unwindHandlerChainInfo.unwindInfo = readUnwindInfo(reader, + unwindInfo.unwindHandlerChainInfo.unwindInfoAddressOrData, ntHeader); + } + + reader.setPointerIndex(origIndex); + + return unwindInfo; + } + +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/PEx64UnwindInfoDataType.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/PEx64UnwindInfoDataType.java new file mode 100644 index 0000000000..34bd83c1a8 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/PEx64UnwindInfoDataType.java @@ -0,0 +1,210 @@ +/* ### + * 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; + +import ghidra.app.util.bin.format.pe.PEx64UnwindInfo.UNWIND_CODE_OPCODE; +import ghidra.docking.settings.Settings; +import ghidra.program.model.data.*; +import ghidra.program.model.mem.MemBuffer; +import ghidra.program.model.mem.MemoryAccessException; +import ghidra.util.exception.AssertException; + +public class PEx64UnwindInfoDataType extends DynamicDataType { + + public static final PEx64UnwindInfoDataType INSTANCE = new PEx64UnwindInfoDataType(); + + private final static int UNWIND_VERSION_FIELD_LENGTH = 0x03; + private final static int UNWIND_FLAGS_FIELD_LENGTH = 0x05; + private final static int UNWIND_FRAME_REGISTER_LENGTH = 0x04; + private final static int UNWIND_FRAME_OFFSET_LENGTH = 0x04; + private final static int UNWIND_OP_FIELD_LENGTH = 0x04; + private final static int UNWIND_OP_INFO_FIELD_LENGTH = 0x04; + + private final static DataType BYTE = ByteDataType.dataType; + private final static DataType IBO32 = new ImageBaseOffset32DataType(); + + public PEx64UnwindInfoDataType() { + this(null); + } + + public PEx64UnwindInfoDataType(DataTypeManager dtm) { + super("PEx64_UnwindInfo", dtm); + } + + @Override + public DataType clone(DataTypeManager dtm) { + if (dtm == getDataTypeManager()) { + return this; + } + return new PEx64UnwindInfoDataType(dtm); + } + + @Override + public String getDescription() { + return "Dynamic structure for PE Exception UNWIND_INFO"; + } + + @Override + public String getMnemonic(Settings settings) { + return "UNWIND_INFO"; + } + + @Override + public String getDefaultLabelPrefix() { + return "UNWIND_INFO"; + } + + @Override + public String getRepresentation(MemBuffer buf, Settings settings, int length) { + return ""; + } + + @Override + public Object getValue(MemBuffer buf, Settings settings, int length) { + return null; // TODO: Should we return filled-out structure? Caching? + } + + private Structure getStructure(MemBuffer buf) { + + StructureDataType struct; + try { + byte flags = (byte) (buf.getByte(0) >> UNWIND_VERSION_FIELD_LENGTH); + + struct = new StructureDataType("UNWIND_INFO", 0, dataMgr); + struct.setPackingEnabled(true); + try { + struct.addBitField(BYTE, UNWIND_VERSION_FIELD_LENGTH, "Version", null); + struct.addBitField(defineUnwindInfoFlags(), UNWIND_FLAGS_FIELD_LENGTH, "Flags", + null); + struct.add(BYTE, "SizeOfProlog", null); + struct.add(BYTE, "CountOfUnwindCodes", null); + struct.addBitField(BYTE, UNWIND_FRAME_REGISTER_LENGTH, "FrameRegister", null); + struct.addBitField(BYTE, UNWIND_FRAME_OFFSET_LENGTH, "FrameOffset", null); + + int countOfUnwindCodes = buf.getByte(2); + if (countOfUnwindCodes > 0) { + ArrayDataType unwindInfoArray = + new ArrayDataType(defineUnwindCodeStructure(), countOfUnwindCodes, -1); + struct.add(unwindInfoArray, "UnwindCodes", null); + } + } + catch (InvalidDataTypeException e) { + throw new AssertException(e); // should never happen with byte bit-fields + } + + if (hasExceptionHandler(flags) || hasUnwindHandler(flags)) { + struct.add(IBO32, "ExceptionHandler", null); + if (hasUnwindHandler(flags)) { + // NOTE: Dynamic structure does not reflect flex-array + struct.setFlexibleArrayComponent(UnsignedLongDataType.dataType, "ExceptionData", + null); + } + } + else if (hasChainedUnwindInfo(flags)) { + struct.add(IBO32, "FunctionStartAddress", null); + struct.add(IBO32, "FunctionEndAddress", null); + struct.add(IBO32, "FunctionUnwindInfoAddress", null); + } + } + catch (MemoryAccessException e) { + return null; + } + + return struct; + } + + @Override + protected DataTypeComponent[] getAllComponents(MemBuffer buf) { + Structure struct = getStructure(buf); + if (struct == null) { + return null; + } + DataTypeComponent[] components = struct.getComponents(); + if (struct.hasFlexibleArrayComponent()) { + DataTypeComponent[] newArray = new DataTypeComponent[components.length + 1]; + System.arraycopy(components, 0, newArray, 0, components.length); + newArray[components.length] = struct.getFlexibleArrayComponent(); + components = newArray; + } + return components; + } + + private boolean hasExceptionHandler(int flags) { + return (flags & PEx64UnwindInfo.UNW_FLAG_EHANDLER) == PEx64UnwindInfo.UNW_FLAG_EHANDLER; + } + + private boolean hasUnwindHandler(int flags) { + return (flags & PEx64UnwindInfo.UNW_FLAG_UHANDLER) == PEx64UnwindInfo.UNW_FLAG_UHANDLER; + } + + private boolean hasChainedUnwindInfo(int flags) { + return (flags & PEx64UnwindInfo.UNW_FLAG_CHAININFO) == PEx64UnwindInfo.UNW_FLAG_CHAININFO; + } + + private Structure defineUnwindCodeStructure() { + StructureDataType unwindCode = new StructureDataType("UnwindCode", 0); + unwindCode.setPackingEnabled(true); + try { + unwindCode.add(BYTE, "OffsetInProlog", null); + unwindCode.addBitField(defineUnwindOpCodeEnum(), UNWIND_OP_FIELD_LENGTH, "UnwindOpCode", + null); + // UnwindOpInfo encoding varies with UnwindOpCode + unwindCode.addBitField(BYTE, UNWIND_OP_INFO_FIELD_LENGTH, "UnwindOpInfo", null); + } + catch (InvalidDataTypeException e) { + throw new AssertException(e); // should never happen with byte bit-fields + } + return unwindCode; + } + + private static EnumDataType unwindInfoFlagsEnum; + + private EnumDataType defineUnwindInfoFlags() { + if (unwindInfoFlagsEnum == null) { + unwindInfoFlagsEnum = new EnumDataType("UNW_FLAGS", 1); + unwindInfoFlagsEnum.add("UNW_FLAG_NHANDLER", PEx64UnwindInfo.UNW_FLAG_NHANDLER); + unwindInfoFlagsEnum.add("UNW_FLAG_EHANDLER", PEx64UnwindInfo.UNW_FLAG_EHANDLER); + unwindInfoFlagsEnum.add("UNW_FLAG_UHANDLER", PEx64UnwindInfo.UNW_FLAG_UHANDLER); + unwindInfoFlagsEnum.add("UNW_FLAG_CHAININFO", PEx64UnwindInfo.UNW_FLAG_CHAININFO); + } + return unwindInfoFlagsEnum; + } + + private static EnumDataType unwindCodeOpcodeEnum; + + private static synchronized EnumDataType defineUnwindOpCodeEnum() { + if (unwindCodeOpcodeEnum == null) { + unwindCodeOpcodeEnum = new EnumDataType("UNWIND_CODE_OPCODE", 1); + for (UNWIND_CODE_OPCODE value : UNWIND_CODE_OPCODE.values()) { + unwindCodeOpcodeEnum.add(value.name(), value.id); + } + } + return unwindCodeOpcodeEnum; + } + +// private static EnumDataType unwindRegisterEnum; +// +// private static EnumDataType defineUnwindRegisterEnum() { +// if (unwindRegisterEnum == null) { +// unwindRegisterEnum = new EnumDataType("UNWIND_CODE_OPINFO_REGISTER", 1); +// for (UNWIND_INFO_REGISTER value : UNWIND_INFO_REGISTER.values()) { +// unwindRegisterEnum.add(value.name(), value.id); +// } +// } +// return unwindRegisterEnum; +// } + +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/PeLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/PeLoader.java index c6c01362b9..6ea103389a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/PeLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/PeLoader.java @@ -304,18 +304,7 @@ public class PeLoader extends AbstractPeDebugLoader { // which also needs to be laid out. When they contain chaining data // they're recursive but the toDataType() function handles that. for (_IMAGE_RUNTIME_FUNCTION_ENTRY entry : irfes) { - if (entry.unwindInfoAddressOrData > 0) { - try { - dt = (StructureDataType) entry.unwindInfo.toDataType(); - start = program.getImageBase().add(entry.unwindInfoAddressOrData); - - DataUtilities.createData(program, start, dt, dt.getLength(), true, - DataUtilities.ClearDataMode.CHECK_FOR_SPACE); - } - catch (CodeUnitInsertionException | DuplicateNameException | IOException e) { - continue; - } - } + entry.createData(program); } }