diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java index d775f045d0..f8ae30e3cb 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java @@ -1516,6 +1516,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { highFunction, recoveredClass, constructor, vbtableOffset); if (vbtableAddress != null) { + if (isInvalidVbtable(vbtableAddress)) { + continue; + } return vbtableAddress; } } @@ -1541,6 +1544,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { highFunction, recoveredClass, constructor, vbtableOffset); if (vbtableAddress != null) { + if (isInvalidVbtable(vbtableAddress)) { + continue; + } return vbtableAddress; } } @@ -1549,6 +1555,27 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer { } + private boolean isInvalidVbtable(Address address) { + + // check to see if already has a non-default symbol that is not vbtable + Symbol symbol = program.getSymbolTable().getPrimarySymbol(address); + if (symbol.getSource() != SourceType.DEFAULT && + !symbol.getName().contains("vbtable")) { + return true; + } + + // check to see if table contains an address reference + // if it is an address then is very unlikely this is a vbtable since + // it needs offset values and most are either large negatives (FFFFF....) or small offsets + // both of which are not valid addresses in a normal PE binary + Address referencedAddress = extendedFlatAPI.getPointer(address); + if (program.getMemory().contains(referencedAddress)) { + return true; + } + return false; + + } + /** * Method to find the address of the vbtable referenced at the given offset in the given function * @param fillStructHelper a reusable {@link FillOutStructureHelper} instance to be used diff --git a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/CreateTypeDescriptorBackgroundCmd.java b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/CreateTypeDescriptorBackgroundCmd.java index f6a92889e2..99b1d35efe 100644 --- a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/CreateTypeDescriptorBackgroundCmd.java +++ b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/CreateTypeDescriptorBackgroundCmd.java @@ -22,10 +22,10 @@ import ghidra.program.model.address.Address; import ghidra.program.model.data.*; import ghidra.program.model.listing.*; import ghidra.program.model.symbol.Namespace; +import ghidra.program.model.symbol.SourceType; import ghidra.program.model.util.CodeUnitInsertionException; import ghidra.util.Msg; -import ghidra.util.exception.CancelledException; -import ghidra.util.exception.InvalidInputException; +import ghidra.util.exception.*; /** * This command will create a TypeDescriptor data type. Since unsized arrays are not properly @@ -133,8 +133,10 @@ public class CreateTypeDescriptorBackgroundCmd Program program = model.getProgram(); String demangledName = model.getDemangledTypeDescriptor(); + + // if cannot demangle then use the mangled name if (demangledName == null) { - return false; + demangledName = model.getOriginalTypename(); } String prefix = demangledName + " "; @@ -147,9 +149,25 @@ public class CreateTypeDescriptorBackgroundCmd // Label Namespace classNamespace = model.getDescriptorAsNamespace(); - if (classNamespace == null) { - Msg.error(RttiUtil.class, "Cannot get namespace from model " + model.getAddress()); - return false; + // if cannot demangle then use the mangled name as the namespace + if (classNamespace == null || classNamespace.isGlobal()) { + Msg.error(RttiUtil.class, "Cannot get demangled namespace from model " + + model.getAddress() + " so will use the mangled name for the namespace"); + try { + classNamespace = program.getSymbolTable() + .getOrCreateNameSpace(program.getGlobalNamespace(), demangledName, + SourceType.IMPORTED); + } + catch (DuplicateNameException e) { + // ok if it is duplicate as it was likely created in another rtti handling method + } + catch (InvalidInputException e) { + Msg.error(TypeDescriptorModel.class, + "Failed to create mangled namespace: " + e.getMessage()); + classNamespace = null; + return false; + } + } // If PDB had been run, then the namespace here might already have been promoted to diff --git a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/TypeDescriptorModel.java b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/TypeDescriptorModel.java index 9264228616..c99805ad24 100644 --- a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/TypeDescriptorModel.java +++ b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/TypeDescriptorModel.java @@ -28,11 +28,9 @@ import ghidra.program.model.listing.Program; import ghidra.program.model.mem.DumbMemBufferImpl; import ghidra.program.model.mem.Memory; import ghidra.program.model.scalar.Scalar; -import ghidra.program.model.symbol.Namespace; -import ghidra.program.model.symbol.Symbol; +import ghidra.program.model.symbol.*; import ghidra.util.Msg; -import ghidra.util.exception.AssertException; -import ghidra.util.exception.CancelledException; +import ghidra.util.exception.*; import ghidra.util.task.TaskMonitor; /** @@ -473,6 +471,10 @@ public class TypeDescriptorModel extends AbstractCreateDataTypeModel { return hasComplexType() ? demangledDataType.getOriginalDemangled() : null; } + public String getOriginalTypename() { + return originalTypeName; + } + /** * Gets just the name of the type descriptor. * @return the name of the thing referred to by this descriptor, or null if it couldn't @@ -583,6 +585,23 @@ public class TypeDescriptorModel extends AbstractCreateDataTypeModel { Program program = getProgram(); namespace = DemangledObject.createNamespace(program, demangledDataType, program.getGlobalNamespace(), false); + + // if for some reason the mangled name can't be demangled, use the mangled name + if (namespace.isGlobal()) { + try { + namespace = program.getSymbolTable() + .getOrCreateNameSpace(program.getGlobalNamespace(), originalTypeName, + SourceType.IMPORTED); + } + catch (DuplicateNameException e) { + // ok if it is duplicate as it was likely created in another rtti handling method + } + catch (InvalidInputException e) { + Msg.error(TypeDescriptorModel.class, + "Failed to create namespace: " + e.getMessage()); + namespace = null; + } + } return namespace; } diff --git a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/CreateVfTableBackgroundCmd.java b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/CreateVfTableBackgroundCmd.java index f45a80ce46..1d1d351c5a 100644 --- a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/CreateVfTableBackgroundCmd.java +++ b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/CreateVfTableBackgroundCmd.java @@ -119,7 +119,7 @@ public class CreateVfTableBackgroundCmd extends AbstractCreateDataBackgroundCmd< String demangledTypeDescriptor = rtti0Model.getDemangledTypeDescriptor(); String prefixString = ((demangledTypeDescriptor != null) ? (demangledTypeDescriptor + Namespace.DELIMITER) - : ""); + : rtti0Model.getOriginalTypename() + Namespace.DELIMITER); data.setComment(CommentType.EOL, "terminator for " + prefixString + VF_TABLE_LABEL); return true; } diff --git a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/RttiUtil.java b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/RttiUtil.java index 34add83b2d..2584b88629 100644 --- a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/RttiUtil.java +++ b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/rtti/RttiUtil.java @@ -321,7 +321,11 @@ public class RttiUtil { public static String getDescriptorTypeNamespace(TypeDescriptorModel rtti0Model) { String descriptorTypeNamespace = rtti0Model.getDescriptorTypeNamespace(); // Can be null. if (descriptorTypeNamespace == null) { - descriptorTypeNamespace = ""; // Couldn't get namespace so leave it off. + + descriptorTypeNamespace = rtti0Model.getOriginalTypename(); + + Msg.warn(RttiUtil.class, rtti0Model.getAddress().toString() + + ": Could not demangle TypeDescriptor namespace so using the mangled string as the namespace."); } return descriptorTypeNamespace; }